TeamForge EventQ Reporting API

Overview

  • TeamForge EventQ Reporting API provides a means to query activity data in TeamForge EventQ. This API is for data retrieval only.
  • Submission URL: https://<eventq_hostname>/orc/api/<version>/reporting
  • Method: POST (only)
  • Authentication: Requires a valid TeamForge session id.
  • Authorization: Requires the TeamForge EventQ "EventQ READ", "REPORTING API" permission, or site admin permissions.

Convention

API requests are constructed from two building-blocks: commands with parameter(s) that can be chained one after another, followed by a single return type with its parameter(s). As such, API requests take the form:
command parameter(s)
command parameter(s)
command parameter(s) ...
return type parameter(s)
  • Each chained command is treated as an "AND" query filter
  • Use separate queries to approximate "OR" requests
  • Requests are limited to a single return type which must be supplied after the last command
  • A query itself is a String constructed by chaining commands each separated from the next (or return) by a new line '\n'.
    • This '\n' is very important since the parser looks for this when tokenizing the query

Authentication and Authorization

Note: In order to use the reporting api, your reporting client must have access to the endpoint of your TeamForge instance.

When sending query requests to the reporting api, a custom header named 'X-EventQ-Session' must be added to each http post request, the value of which is the 'session id' returned from a successful login call to the TeamForge endpoint. The TeamForge endpoint is found here: http(s)://TeamForgeHost/ce-soap60/services/CollabNet

To gain access to the Reporting API the user must have one either of the below permissions set in TeamForge:
  • TeamForge SITE ADMINISTRATOR
    • This will provided access to all active projects in EventQ
  • REPORTING API EventQ Permissions on at least one project
    • This limits the projects to query against to only those which the user has REPORTING API permissions
    • If the user is both SITE ADMIN and REPORTING API, SITE ADMIN will be used. There is no way to limit a SITE ADMIN's access
See the Examples below for a simple Java client.

Commands and Parameters

Command Description
restrict_to (string) Filter query results for certain classes of activity objects.
Example: restrict_to reviews
Accepted values: builds, commits, reviews, work_items, custom.
associated_to (array) Takes one or more object IDs and returns a list of activity summaries with associations to the object IDs specified.
Example: associated_to ["artf1002", "artf1002", "artf1003"]
associations (none) Used in command chains to modify query results to return associations. No parameters.
Example: associations
in_project (array) Restrict query results to activities in a given project. Takes array of project IDs as a parameter.
Example: in_project ["proj1123", "proj1134"]
sort_by (array) Sort the result set by the fields of the objects which are supplied as a parameter, ascending or descending order.
Example: sort_by ["status", "asc"]
Accepted values: any object field; see MQ API docs for object descriptions or XDS schema for custom objects. For instance, builds may be sorted by remote_id, status, test_results, duration, created_by, or time_created.

Accepted values: asc, desc

has_any (string) Filter query results to those activities that have matching class associations.
Example: has_any "builds"
Accepted values: builds, commits, review, work_items, custom.
has_none (string) Filter query results to those activities that do not have matching class associations.
Example: has_none "reviews"
Accepted values: builds, commits, review, work_items, custom.
limit (integer) Limit query results to the specified integer for pagination of results and performance. May be used in conjunction with offset.
Example: limit 100
Accepted values: positive integers.
offset (integer) Offset query results to specified integer for pagination of results and performance. May be used in conjunction with limit.
Example: offset 10
Accepted values: positive integers.
before (date/time) Filter results set to those activity summaries with events that occurred prior to the supplied date and time. May be used in conjunction with after.
  • Example: before 2014-10-02T17:15:45.320Z
  • Example: before 2.weeks.ago
Accepted values: RFC 3339 format date times in UTC and Ruby-style date references (minutes, hours, days, weeks, months, years).
after (date/time) Filter results set to those activity summaries with events that occurred after the supplied date and time. May be used in conjunction with before.
  • Example: after 2014-11-02T12:45:45.320Z
  • Example: before 1.day.ago
Accepted values: RFC 3339 format date times in UTC and Ruby-style date references (minutes, hours, days, weeks, months, years).
tagged_as (array) Filter results set to those activities from sources labeled with the supplied tag. Takes multiple tags to create an OR condition. Two or more tagged_as commands may be chained which constructs an AND condition, returning only those activities with tag A and tag B.
Example: tagged_as ["deploy","binary repository"] tagged_as ["production"]

Return types

Conclude your query with a single "return" method to transform the data and return the results. All results are returned wrapped in a top-level json hash containing the key items, which contains the results of the query. The return may also contain the optional keys source_display_data, containing a hash of display metadata for the associated sources keyed by source id, and work_item_urls, containing urls to external work items keyed by id (if applicable).

Return example
{
  "items": [
    {
      "_type": "WorkItemSummary",
      "assigned_to": "dev-bot",
      "associated_activity_summary_ids": [

      ],
      "associated_ctf_ids": [

      ],
      "closed": true,
      "comments": [

      ],
      "created_at": "2015-04-22T20:54:26.063Z",
      "created_by": "itembot!",
      "creation_time": "2014-03-29T00:26:20.091Z",
      "deleted": false,
      "description": "Autogenerated workitem description",
      "id": "55380a82109a01555d00000c",
      "opaque_id": "6kkd",
      "priority": "mecha-critical",
      "remote_id": "AUTO-6",
      "remote_status_id": "3",
      "settled": true,
      "source_id": "5537ed65109a012cec000004",
      "summary": "Release the integration",
      "tags": [
        "up",
        "strange"
      ],
      "time_created": "2015-04-22T20:54:26.000Z",
      "updated_at": "2015-04-23T16:49:19.657Z"
    }
  ],
  "source_display_data": {
    "5537ed65109a012cec000004": {
      "_type": "WorkItemSource",
      "_links": {
        "type_icon": {
          "href": "http://ctf.example.com/orc/assets/icons/work-item.png",
          "type": "image/png"
        },
        "source_icon": {
          "href": "http://external.example.com/images/icons/issuetypes/bug.png",
          "type": "image/png"
        }
      },
      "name": "External Bug Tracker",
      "background_color": "#f2511b"
    }
  },
  "work_item_urls": {
    "55380a82109a01555d00000c": "http://tracker.example.com/a_tracker_source/AUTO-6"
  }
}
Return Keys
Return Key Description
items (array or hash) Query-dependent results.
source_display_data (hash) Display metadata for sources references in results.
work_item_urls (hash) URLs for referenced work items. This key is present in the return structure only if 'items' contains WorkItemSummary objects.
Query Return Data Types
Data item Description
fields (array or hash) Returns json formatted results set limited to the fields supplied as parameters.
Example: fields ["time_created", "remote_id"]
Accepted values: any set of object fields; see MQ API docs for object descriptions or XDS schema for custom objects. For instance, builds may take: remote_id, status, test_results, duration, created_by, or time_created.
field_contains (nested array) Returns json formatted results set limited to exact value supplied as parameters.
Example: field_contains [ "remote_id", ["artf1001", "art1002"] ]
Accepted values: any object field with matching value set; see MQ API docs for object descriptions or XDS schema for custom objects. For instance, builds may take: remote_id, status, test_results, duration, created_by, or time_created.
group_by_field (string) Returns json formatted results set grouped by the field supplied as parameter.
Example: group_by_field "status"
Accepted values: created_at, remote_id, status
count (none) Returns a json structure with a count of all matching activities.
Example: count
timeseries (date/time) Useful for charting applications, the output will be a hash, where the keys are the starting points of the time series, and the value is the array of objects that fall into that series. It takes a Ruby-style date reference parameter to specify the results granularity. Requires before and after in the same query.
Example: timeseries 5.minutes
Accepted values: Ruby-style date references (minutes, hours, days, weeks, months, years).

Examples

The following code examples are Copyright 2020 CollabNet, Inc., licensed under the Apache License, Version 2.0 (the "License"); you may not use this code except in compliance with the License. You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0]

Use Cases and Query Examples
Use case: "Find the number of all failed builds across all projects"
#Query:
		restrict_to builds
		field_contains ["status_type", ["FAILURE"] ]
		count
Use case: "Given a set of artfs as inputs, give me all the associated activities"
#Query:
		associated_to: ["artf1234", "artf1235", "artf1236"]
Use case: "Across two specific projects, give me the builds that pass vs fail"
#Query:
		in_project ["proj1001", "proj1002"]
		restrict_to builds
		group_by_field "status_type"
Use case: "Given a set of artfs as inputs (say, in a planning folder) give me build stats (total #, pass, fail, etc)"
#Query:
		associated_to ["artf1001", "artf1002", "artf1003"]
		associations
		restrict_to builds
		group_by_field "status_type"
Use case: "For a given user, give me a list of commits over X timeline, associated build stats"
#Query:
		restrict_to commits
		after 2.weeks.ago
		before 1.week.ago
		field_contains [ "created_by", ["jdoe"] ]
		associations
		restrict_to builds
		group_by_field "status_type"
Use case: "Give me code review stats on a whole project (total #, total reviewed commits, total un-reviewed)"
#Query 1 to find un-reviewed commits
		in_project ["proj1706"]
		restrict_to commits
		has_none "reviews"
		count

		#Query 2 to find reviewed commits:
		in_project ["proj1706"]
		restrict_to commits
		has_any "reviews"
		count
Use case: "Given a set of artfs, give me associated build results starting 1 week ago ending 5 minutes ago, grouped into 4 hour intervals."
#Query:
		associated_to ["artf1001", "artf1002", "artf1003"]
		associations
		restrict_to builds
		after 1.week.ago
		before 5.minutes.ago
		timeseries 4.hours
Use case: "Give me all binary artifact activities grouped by status"
#To query XDS sources like binary artifacts, restrict_to "custom" source type, then
		#filter to narrow the results using tagged_as
		#Query:
		restrict_to custom
		tagged_as ["binary artifact"]
		group_by_field "status_type"
Code samples

Create a Java client using Apache Axis & Apache HttpComponents

Get an X-EventQ-Session value from TeamForge.

/**
		* @param ctfEndpoint
		* @param ctfUserName
		* @param ctfUserPassword
		* @return sessionId (X-EventQ-Session)
		*/
		private static String getSessionIdFromCTF(String ctfEndpoint, String ctfUserName, String ctfUserPassword) {
		try {
			Service service = new Service();
			Call call = (Call) service.createCall();
			call.setTargetEndpointAddress(new java.net.URL(ctfEndpoint));
			call.setOperationName(new QName("http://schema.open.collab.net/sfee50/soap60/service", "login"));
			String sessionId = (String) call.invoke(new Object[]{ctfUserName, ctfUserPassword});
			return sessionId;
		} catch (Exception e) {
			System.err.println(e.toString());
			return e.toString();
			}
		}

Post a request to the Reporting endpoint containing the custom header and a query.

/**
		* @param url
		* @param token
		* @param query
		* @return queryResults
		* @throws Exception
		*/
		String sendPostHttpClient(String url, String token, String query) throws Exception {
		String queryResults;
		CloseableHttpClient client = HttpClients.custom().build();

		HttpUriRequest request = RequestBuilder.post().setUri(url)
		.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")
		.setHeader("X-EventQ-Session", token)
		.setEntity(new StringEntity(query))
		.build();

		CloseableHttpResponse response = client.execute(request);
		queryResults = EntityUtils.toString(response.getEntity(), "UTF-8");
		return queryResults;
		}

Build your client using the above methods.

public class ReportingClient {

		/* EventQ End Point represents the EventQ instance which you will be querying against*/
		static String eventqEndPoint = "http(s)://EventQHost/orc/api/1/reporting/";

		/* teamForgeEndPoint represents the soap endpoint for the TeamForge instance which your EventQ
		* server is bound to*/
		static String teamForgeEndPoint = "http(s)://TeamforgeHost/ce-soap60/services/CollabNet";

		/* orcReportingQuery is your query in String format. Each LINE represents a different command
		* so in this example every distinct command must be separated by a newline character '\n'*/
		static String orcReportingQuery = "restrict_to reviews\ngroup_by_field \"status_type\"";

		/* TeamForge username and password for the account which the queries will be run under. This account
		* must have REPORTING_API permissions on at least one project in EventQ or must be a SITE ADMIN
		* in Teamforge. If the user is NOT a TeamForge SITE ADMIN, only those projects for which the user has
		* REPORTING_API permissions will be considered in the query.*/
		static String teamForgeUserName = "userName";
		static String teamForgeUserPassword = "userPassword";


		public static void main(String... args) {
			EventQReportingClient sampleClient = new EventQReportingClient();
			String xEventQSession = sampleClient.getSessionIdFromCTF(teamForgeEndPoint,
			teamForgeUserName, teamForgeUserPassword);
			try {
				String serverResponse = sampleClient.sendPostHttpClient(eventqEndPoint,
				xEventQSession, orcReportingQuery);
				System.out.println(serverResponse);
			} catch (Exception e) {
				System.out.println(e.toString());
			}

			}
		}