$ curl -u "apiuser:password" https://myswarm.url/api/v8/projects
This chapter describes the REST-like API provided by Swarm, which can be used to automate common Swarm interactions or integrate with external systems.
Swarm’s API requires an authenticated connection for all data-modifying endpoints. Authenticated connections are achieved using HTTP Basic Access Authentication.
If the require_login configuration flag
is set to true , all API endpoints require authentication.
|
For example:
$ curl -u "apiuser:password" https://myswarm.url/api/v8/projects
Swarm accepts a ticket from the Helix Versioning Engine (previous versions of Swarm required this ticket to be host-unlocked, this is no longer true since Swarm 2017.1). It may also be possible to use a password in place of the ticket.
To acquire a ticket, run the following command:
$ p4 -p myp4host:1666 -u apiuser login -p
For a Helix Versioning Engine that has been configured for security level 3, passwords are not accepted. For more information on security levels, see: |
If you use a ticket to authenticate against the Swarm API and the ticket expires, you need to acquire a new ticket to continue using the API. |
If you make a request that requires authentication and you have not authenticated, the response is:
{
"error": "Unauthorized"
}
Swarm’s API includes endpoints that provide, create, and update information within Swarm.
If you make a request against an endpoint that is not supported, the response is:
{
"error": "Method Not Allowed"
}
Use HTTP <literal>GET</literal> requests to ask for information from the API.
For example, to get the list of reviews:
$ curl https://myswarm.url/api/v8/reviews
Certain API calls support a fields
parameter that allows you to specify which
fields to include in the response, enabling more compact data sets. The
following endpoints support fields:
/api/v8/projects
/api/v8/reviews
/api/v8/reviews/{id}
Fields can be expressed as a comma-separated list, or using array-notation. For example:
$ curl 'https://myswarm.url/api/v8/reviews?fields=id,description,participants'
Or:
$ curl 'https://myswarm.url/api/v8/reviews?fields[]=id,fields[]=description,fields[]=participants'
Use HTTP <literal>POST</literal> requests to create information via the API.
For example, to create a review using form-encoded values:
$ curl -u "apiuser:password" -d"change=12345" https://myswarm.url/api/v8/reviews
The response should be similar to:
{
"isValid": true,
"id": 12206
}
To create a review using JSON:
$ curl -u "apiuser:password" -H "Content-type: application/json" \
-d'{"change": 12345}' https://myswarm.url/api/v8/reviews
Use HTTP <literal>PATCH</literal> requests to update information via the API.
If your HTTP client does not support PATCH
requests, you can emulate this
behavior by submitting an HTTP POST
with a "?_method=PATCH"
parameter.
Most Swarm endpoints that provide data include the ability to paginate their results.
Each time data is requested, up to max
results are included in the
response, as is a value called lastSeen
. lastSeen
identifies the id
of the
last entry included in the results. If there are no further results, lastSeen
is null
.
To get the next set of results, include after
set to the value of lastSeen
in the API request. Entries up to and including the id
specified by after
are
excluded from the response, and the next max
entries are included.
See the Activity endpoint for example usage that demonstrates pagination.
Swarm’s API responses are JSON formatted.
The current Swarm API version is v8
. Here is a list of historical API
versions:
API version | Swarm Release | Date | Description |
---|---|---|---|
v8 |
2017.4 |
December 2017 |
Include support for default reviewers on a project or project branch. |
v7 |
2017.3 |
October 2017 |
Include support for groups as participants of a review and groups as moderators of a project branch. |
v6 |
2017.1 |
May 2017 |
Include support for activity dashboard, archiving of inactive reviews, cleaning completed reviews and for voting reviews up and down. |
v5 |
2016.3 |
December 2016 |
Include support for limiting comments to a specific review version. |
v4 |
2016.2 |
October 2016 |
Include support for private projects, as well as file-level and line-level inline comments. |
v3 |
2016.1 SP1 |
September 2016 |
Include new endpoint for comments. |
v2 |
2016.1 |
May 2016 |
Include new endpoints for projects, groups, etc. |
v1.2 |
2015.3 |
October 2015 |
Add author filter to the list reviews endpoint. |
v1.1 |
2014.4 |
January 2015 |
Addition of required reviewers, and |
v1 |
2014.3 |
July 2014 |
Initial release. |
This section includes coverage for each of the major endpoints provided by the API.
Summary: List Activity Entries
Retrieve the Activity List.
Parameter | Description | Type | Parameter Type | Required | Default Value |
---|---|---|---|---|---|
|
Optionally filter activity entries by associated Changelist ID. This only includes records for which there is an activity entry in Swarm. |
integer |
form |
No |
|
|
Optional activity stream to query for entries. This can include user-initiated actions ( |
string |
form |
No |
|
|
Type of activity, e.g., |
string |
form |
No |
|
|
An activity ID to seek to. Activity entries up to and including the specified ID are excluded from the results and do not count towards |
integer |
query |
No |
|
|
Maximum number of activity entries to return. This does not guarantee that |
integer |
query |
No |
100 |
|
An optional comma-separated list (or array) of fields to show. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"activity": [
{
"id": 123,
"action": "committed",
"behalfOf": null,
"behalfOfExists": false,
"change": 1,
"date": "2016-01-15T12:12:12-08:00",
"depotFile": null,
"description": "test\n",
"details": [],
"followers": [],
"link": ["change", {"change": 1}],
"preposition": "into",
"projectList": {"restricted": ["main"]},
"projects": {"restricted": ["main"]},
"streams": ["review-2", "user-foo", "personal-foo", "project-restricted"],
"target": "change 1",
"time": 1404776681,
"topic": "changes/1",
"type": "change",
"url": "/changes/1",
"user": "bruno",
"userExists": true
}
],
"lastSeen": 1
}
To get the latest activity entries on a review:
curl -u "username:password" "https://myswarm.url/api/v8/activity?stream=review-1234\
&fields=id,date,description,type\
&max=2"
You can tweak max
and fields
to fetch the data that works best for you.
Swarm responds with an array of activity entities, and a lastSeen
value that can be used for pagination:
{
"activity": [
{
"id": 10,
"date": "2016-04-15T16:10:32-07:00",
"description": "This is a test comment.",
"type": "comment"
},
{
"id": 9,
"date": "2016-03-31T13:48:15-07:00",
"description": "Updating RELNOTE review",
"type": "review"
}
],
"lastSeen": 9
}
To get the second page of activity entries for a review (based on the previous example):
curl -u "username:password" "https://myswarm.url/api/v8/activity?stream=review-1234\
&fields=id,date,description,type\
&max=2\
&lastSeen=9"
Swarm again responds with a list of activity entities and a lastSeen
value:
{
"activity": [
{
"id": 8,
"date": "2016-03-30T12:12:12-07:00",
"description": "This is the first test comment.",
"type": "comment"
},
{
"id": 7,
"date": "2016-03-29T12:13:14-07:00",
"description": "Updating RELNOTE review",
"type": "review"
}
],
"lastSeen": 7
}
Summary: Create Activity Entry
Creates an entry in the Activity List. Note: admin-level privileges are required for this action.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Type of activity, used for filtering activity streams (values can include |
string |
form |
Yes |
|
User who performed the action. |
string |
form |
Yes |
|
Action that was performed - past-tense, e.g., |
string |
form |
Yes |
|
Target that the action was performed on, e.g., |
string |
form |
Yes |
|
Optional topic for the activity entry. Topics are essentially comment thread IDs. Examples: |
string |
form |
No |
|
Optional description of object or activity to provide context. |
string |
form |
No |
|
Optional changelist ID this activity is related to. Used to filter activity related to restricted changes. |
integer |
form |
No |
|
Optional array of streams to display on. This can include user-initiated actions ( |
array (of strings) |
form |
No |
|
Optional URL for |
string |
form |
No |
HTTP/1.1 200 OK
{
"activity": {
"id": 123,
"action": "ate",
"behalfOf": null,
"change": null,
"depotFile": null,
"details": [],
"description": "",
"followers": [],
"link": "",
"preposition": "for",
"projects": [],
"streams": [],
"target": "the manual",
"time": 1404776681,
"topic": "",
"type": "comment",
"user": "A dingo"
}
}
To create a plain activity entry:
curl -u "username:password" -d "type=job" -d "user=jira" -d "action=punted" -d "target=review 123" \
"https://myswarm.url/api/v8/activity"
JSON Response:
{
"activity": {
"id": 1375,
"action": "punted",
"behalfOf": null,
"change": null,
"depotFile": null,
"description": "",
"details": [],
"followers": [],
"link": "",
"preposition": "for",
"projects": [],
"streams": [],
"target": "review 123",
"time": 1461607739,
"topic": "",
"type": "job",
"user": "jira"
}
}
Linking activity entries to reviews is useful. This involves providing link
, stream
, and topic
fields in
the activity data. The link
field is used to make the review 123
string in the activity entry clickable.
The stream
field is needed so that the activity entry can be attached to the review in the Swarm interface.
The topic
field is used to link the activity entry to the comment thread for that topic, in the event that a
user wants to comment on the activity.
To create a fully linked activity entry:
curl -u "username:password" -d "type=job" -d "user=jira" -d "action=punted" -d "target=review 123" \
-d "streams[]=review-123" \
-d "link=reviews/123" \
-d "topic=reviews/123" \
"https://myswarm.url/api/v8/activity"
Swarm responds with an activity entity:
{
"activity": {
"id": 1375,
"action": "punted",
"behalfOf": null,
"change": null,
"depotFile": null,
"description": "",
"details": [],
"followers": [],
"link": "reviews/123",
"preposition": "for",
"projects": [],
"streams": ["review-123"],
"target": "review 123",
"time": 1461607739,
"topic": "reviews/123",
"type": "job",
"user": "jira"
}
}
Summary: Get projects, and branches, affected by a given change id.
All authenticated users are able to use this API.
HTTP/1.1 200 OK
{
"change": {
"id":"1050",
"projects": {
"jam": [
"live",
"main"
]
}
}
}
Summary: Get default reviewers for a given change id.
All authenticated users are able to use this API.
HTTP/1.1 200 OK
{
"change": {
"id": "1050",
"defaultReviewers": {
"groups": {
"group1": {"required": "1"},
"group2": {}
},
"users": {
"user1": {},
"user2": {"required": "true"}
}
}
}
}
Summary: Get List of Comments
List comments.
Parameter | Description | Type | Parameter Type | Required | Default Value |
---|---|---|---|---|---|
|
A comment ID to seek to. Comments up to and including the specified ID are excluded from the results and do not count towards |
integer |
query |
No |
|
|
Maximum number of comments to return. This does not guarantee that |
integer |
query |
No |
100 |
|
Only comments for given topic are returned. Examples: |
string |
query |
No |
|
|
If a |
integer |
query |
No |
|
|
Prevents archived comments from being returned. (v5+) |
boolean |
query |
No |
|
|
Returns only comments that have been flagged as tasks. (v5+) |
boolean |
query |
No |
|
|
Limit the returned comments to ones that match the provided task state (one or more of |
array (of strings) |
query |
No |
|
|
An optional comma-separated list (or array) of fields to show for each comment. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"topic": "",
"comments": {
"51": {
"id": 51,
"attachments": [],
"body": "Short loin ground round sin reprehensible, venison west participle triple.",
"context": [],
"edited": null,
"flags": [],
"likes": [],
"taskState": "comment",
"time": 1461164347,
"topic": "reviews/885",
"updated": 1461164347,
"user": "bruno"
}
},
"lastSeen": 51
}
lastSeen can often be used as an offset for pagination, by using the value
in the after parameter of subsequent requests.
|
comments
array is empty:HTTP/1.1 200 OK
{
"topic": "jobs/job000011",
"comments": [],
"lastSeen": null
}
To list comments:
curl -u "username:password" "https://my-swarm-host/api/v8/comments\
?topic=reviews/911&max=2&fields=id,body,time,user"
Swarm responds with a list of the first two comments for review 911 and a lastSeen
value for pagination:
{
"topic": "reviews/911",
"comments": {
"35": {
"id": 35,
"body": "Excitation thunder cats intelligent man braid organic bitters.",
"time": 1461164347,
"user": "bruno"
},
"39": {
"id": 39,
"body": "Chamber tote bag butcher, shirk truffle mode shabby chic single-origin coffee.",
"time": 1461164347,
"user": "swarm_user"
}
},
"lastSeen": 39
}
To obtain the next page of a comments list (based on the previous example):
curl -u "username:password" "https://my-swarm-host/api/v8/comments\
?topic=reviews/911&max=2&fields=id,body,time,user&after=39"
Swarm responds with the second page of results, if any comments are present after the last seen comment:
{
"topic": "reviews/911",
"comments": {
"260": {
"id": 260,
"body": "Reprehensible do lore flank ham hock.",
"time": 1461164349,
"user": "bruno"
},
"324": {
"id": 324,
"body": "Sinter lo-fi temporary, nihilist tote bag mustache swag consequence interest flexible.",
"time": 1461164349,
"user": "bruno"
}
},
"lastSeen": 324
}
Summary: Add A Comment
Add a comment to a topic (such as a review or a job)
Parameter | Description | Type | Parameter Type | Required | Default Value |
---|---|---|---|---|---|
|
Topic to comment on. Examples: |
string |
form |
Yes |
|
|
Content of the comment. |
string |
form |
Yes |
|
|
Optional task state of the comment. Valid values when adding a comment are |
string |
form |
No |
comment |
|
Optional flags on the comment. Typically set to |
array (of strings) |
form |
No |
|
|
File to comment on. Valid only for |
string |
form |
No |
|
|
Left-side diff line to attach the inline comment to. Valid only for |
integer |
form |
No |
|
|
Right-side diff line to attach the inline comment to. Valid only for |
integer |
form |
No |
|
|
Optionally provide content of the specified line and its four preceding lines. This is used to specify a short excerpt of context in case the lines being commented on change during the review. When not provided, Swarm makes an effort to build the content on its own - as this involves file operations, it could become slow. |
array (of strings) |
form |
No |
|
|
With a |
integer |
form |
No |
HTTP/1.1 200 OK
{
"comment": {
"id": 42,
"attachments": [],
"body": "Best. Comment. EVER!",
"context": [],
"edited": null,
"flags": [],
"likes": [],
"taskState": "comment",
"time": 123456789,
"topic": "reviews/2",
"updated": 123456790,
"user": "bruno"
}
}
To create a comment on a review:
curl -u "username:password" \
-d "topic=reviews/2" \
-d "body=This is my comment. It is an excellent comment. It contains a beginning, a middle, and an end." \
"https://my-swarm-host/api/v8/comments"
JSON Response:
{
"comment": {
"id": 42,
"attachments": [],
"body": "This is my comment. It is an excellent comment. It contains a beginning, a middle, and an end.",
"context": [],
"edited": null,
"flags": [],
"likes": [],
"taskState": "comment",
"time": 123456789,
"topic": "reviews/2",
"updated": 123456790,
"user": "username"
}
}
To create a comment on a review, and flag it as an open task:
curl -u "username:password" \
-d "topic=reviews/2" \
-d "taskState=open" \
-d "body=If you could go ahead and attach a cover page to your TPS report, that would be great." \
"https://my-swarm-host/api/v8/comments"
JSON Response:
{
"comment": {
"id": 43,
"attachments": [],
"body": "If you could go ahead and attach a cover page to your TPS report, that would be great.",
"context": [],
"edited": null,
"flags": [],
"likes": [],
"taskState": "open",
"time": 123456789,
"topic": "reviews/2",
"updated": 123456790,
"user": "username"
}
}
Summary: Edit A Comment
Edit a comment
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
ID of the comment to be edited |
integer |
path |
Yes |
|
Topic to comment on. Examples: |
string |
form |
No |
|
Content of the comment. |
string |
form |
Yes |
|
Optional task state of the comment. Note that certain transitions (such as moving from |
string |
form |
No |
|
Optional flags on the comment. Typically set to |
array (of strings) |
form |
No |
HTTP/1.1 200 OK
{
"comment": {
"id": 1,
"attachments": [],
"body": "Best. Comment. EVER!",
"context": [],
"edited": 123466790,
"flags": [],
"likes": [],
"taskState": "comment",
"time": 123456789,
"topic": "reviews/42",
"updated": 123456790,
"user": "bruno"
}
}
To edit and archive a comment on a review:
curl -u "username:password" \
-X PATCH \
-d "flags[]=closed" \
-d "body=This comment wasn't as excellent as I may have lead you to believe. A thousand apologies." \
"https://my-swarm-host/api/v8/comments/42"
JSON Response:
{
"comment": {
"id": 42,
"attachments": [],
"body": "This comment wasn't as excellent as I may have lead you to believe. A thousand apologies.",
"context": [],
"edited": 123466790,
"flags": ["closed"],
"likes": [],
"taskState": "comment",
"time": 123456789,
"topic": "reviews/2",
"updated": 123456790,
"user": "username"
}
}
To flag an open task as addressed on a review:
curl -u "username:password" \
-X PATCH \
-d "taskState=addressed" \
"https://my-swarm-host/api/v8/comments/43"
JSON Response:
{
"comment": {
"id": 43,
"attachments": [],
"body": "If you could go ahead and attach a cover page to your TPS report, that would be great.",
"context": [],
"edited": 123466790,
"flags": ["closed"],
"likes": [],
"taskState": "comment",
"time": 123456789,
"topic": "reviews/2",
"updated": 123456790,
"user": "username"
}
}
Summary: Get List of Groups
Returns the complete list of groups in Swarm.
Parameter | Description | Type | Parameter Type | Required | Default Value |
---|---|---|---|---|---|
|
A group ID to seek to. Groups prior to and including the specified ID are excluded from the results and do not count towards |
string |
query |
No |
|
|
Maximum number of groups to return. This does not guarantee that |
integer |
query |
No |
100 |
|
An optional comma-separated list (or array) of fields to show for each group. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
|
|
Keywords to limit groups on. Only groups where the group ID, group name (if set), or description contain the specified keywords are returned. |
string |
query |
No |
HTTP/1.1 200 OK
{
"groups": [
{
"Group": "test-group",
"MaxLockTime": null,
"MaxResults": null,
"MaxScanRows": null,
"Owners": [],
"PasswordTimeout": null,
"Subgroups": [],
"Timeout": 43200,
"Users": ["bruno"],
"config": {
"description": "Our testing group",
"emailAddress": "test-group3@host.domain",
"emailFlags": [],
"name": "Test Group",
"useMailingList": true
}
}
]
}
To list groups:
curl -u "username:password" \
"https://myswarm.url/api/v8/groups?keywords=test-group&fields=Group,Owners,Users,config&max=2"
Swarm responds with a list of groups:
{
"groups": [
{
"Group": "test-group",
"Owners": [],
"Users": ["bruno"],
"config": {
"description": "Our testing group",
"emailAddress": "test-group@host.domain",
"emailFlags": {
"reviews": "1",
"commits": "0"
},
"name": "Test Group",
"useMailingList: true
}
},
{
"Group": "test-group2",
"Owners": [],
"Users": ["bruno"],
"config": {
"description": "Our second testing group",
"emailAddress": "test-group2@host.domain",
"emailFlags": [],
"name": "Test Group 2",
"useMailingList: true
}
}
],
"lastSeen": "test-group2"
}
Based on the previous example, we can pass a lastSeen value of test-group2
to see if there are any subsequent
groups in Swarm.
curl -u "username:password" \
"https://myswarm.url/api/v8/groups?keywords=test-group&fields=Group,config&max=2&lastSeen=test-group2"
Swarm responds with a list of groups (minus the Owners and Users fields, as we haven’t requested them):
{
"groups": [
{
"Group": "test-group3",
"config": {
"description": "Our 3rd testing group",
"emailAddress": "test-group3@host.domain",
"emailFlags": [],
"name": "Test Group 3",
"useMailingList": true
}
}
],
"lastSeen": "test-group3"
}
Summary: Get Group Information
Retrieve information about a group.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Group ID |
string |
path |
Yes |
|
An optional comma-separated list (or array) of fields to show for each group. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"group": {
"Group": "test-group",
"MaxLockTime": null,
"MaxResults": null,
"MaxScanRows": null,
"Owners": [],
"PasswordTimeout": null,
"Subgroups": [],
"Timeout": 43200,
"Users": ["bruno"],
"config": {
"description": "Our testing group",
"emailFlags": [],
"name": "Test Group"
}
}
}
To fetch an individual group:
curl -u "username:password" "https://myswarm.url/api/v8/groups/my-group"
Swarm responds with the group entity:
{
"group": {
"Group": "test-group",
"LdapConfig": null,
"LdapSearchQuery": null,
"LdapUserAttribute": null,
"MaxLockTime": null,
"MaxResults": null,
"MaxScanRows": null,
"Owners": [],
"Users": ["bruno"],
"config": {
"description": "Our testing group",
"emailAddress": "test-group@host.domain",
"emailFlags": {
"reviews": "1",
"commits": "0"
},
"name": "Test Group",
"useMailingList": true
}
}
}
To limit the returned fields when fetching an individual group:
curl -u "username:password" "https://myswarm.url/api/v8/groups/my-group?fields=Group,Owners,Users,config"
Swarm responds with the group entity:
{
"group": {
"Group": "test-group",
"Owners": [],
"Users": ["bruno"],
"config": {
"description": "Our testing group",
"emailFlags": [],
"name": "Test Group"
}
}
}
Summary: Create a new Group
Creates a new group in Swarm.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Group identifier string. |
string |
form |
Yes |
|
An optional array of group users. At least one of Users, Owners, or Subgroups is required. |
array |
form |
No |
|
An optional array of group owners. At least one of Users, Owners, or Subgroups is required. |
array |
form |
No |
|
An optional array of subgroups. At least one of Users, Owners, or Subgroups is required. |
array |
form |
No |
|
An optional full name for the group. |
string |
form |
No |
|
An optional group description. |
string |
form |
No |
|
The email address for this group. |
string |
form |
No |
|
Email members when a new review is requested. |
boolean |
form |
No |
|
Email members when a new review is requested. |
boolean |
form |
No |
|
Whether to use the configured email address or expand individual members addresses. |
boolean |
form |
No |
HTTP/1.1 200 OK
{
"group": {
"Group": "test-group",
"MaxLockTime": null,
"MaxResults": null,
"MaxScanRows": null,
"Owners": [],
"PasswordTimeout": null,
"Subgroups": [],
"Timeout": null,
"Users": ["alice"],
"config": {
"description": "Test test test",
"emailAddress": "test-group@host.domain",
"emailFlags": [],
"name": "TestGroup",
"useMailingList": true
}
}
}
|
To create a new group:
curl -u "username:password" \
-d "Group=my-group" \
-d "Owners[]=alice" \
-d "Owners[]=bob" \
-d "Users[]=bruno" \
-d "Users[]=user2" \
-d "config[description]=This group is special to me." \
-d "config[name]=My Group" \
-d "config[emailFlags][reviews]=1" \
-d "config[emailFlags][commits]=0" \
-d "config[emailAddress]=my-group@host.domain" \
-d "config[useMailingList]=false" \
"https://myswarm.url/api/v8/groups"
Assuming that the authenticated user has permission, Swarm responds with the new group entity:
{
"group": {
"Group": "my-group",
"MaxLockTime": null,
"MaxResults": null,
"MaxScanRows": null,
"Owners": ["username"],
"PasswordTimeout": null,
"Subgroups": [],
"Timeout": null,
"Users": [],
"config": {
"description": "This group is special to me.",
"emailFlags": {
"reviews": "1",
"commits": "0"
},
"name": "My Group",
"useMailingList": true
}
}
}
Summary: Edit a Group
Change the settings of a group in Swarm. Only super users and group owners can perform this action.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Group ID |
string |
path |
Yes |
|
An optional array of group users. |
array |
form |
No |
|
An optional array of group owners. |
array |
form |
No |
|
An optional array of group subgroups. |
array |
form |
No |
|
An optional full name for the group. |
string |
form |
No |
|
An optional group description. |
string |
form |
No |
|
The email address for this group. |
string |
form |
No |
|
Email members when a change is committed. |
boolean |
form |
No |
|
Email members when a new review is requested. |
boolean |
form |
No |
|
Whether to use the configured email address or expand individual members addresses. |
boolean |
form |
No |
HTTP/1.1 200 OK
{
"group": {
"Group": "test-group",
"Users": [],
"Owners": [],
"Subgroups": [],
"config": {
"description": "New Group Description",
"name": "TestGroup",
"useMailingList": true
}
}
}
|
Here is how to update the name
, description
, and emailFlags
configuration of the group my-group
:
curl -u "username:password" -X PATCH \
-d "config[description]=This group is special to me." \
-d "config[name]=My Group" \
-d "config[emailFlags][commits]=1" \
"https://myswarm.url/api/v8/groups/my-group"
Assuming that the authenticated user has permission, Swarm responds with the modified group entity:
{
"group": {
"Group": "my-group",
"Users": [],
"Owners": [],
"Subgroups": [],
"config": {
"description": "This group is special to me.",
"emailAddress": "test-group@host.domain",
"emailFlags": {
"reviews": "1",
"commits": "1"
},
"name": "My Group",
"useMailingList": true
}
}
}
Summary: Delete a Group
Delete a group. Only super users and group owners can perform this action.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Group ID. |
string |
path |
Yes |
HTTP/1.1 200 OK
{
"id": "test-group"
}
Only super users and group owners can delete groups. |
curl -u "username:password" -X DELETE "https://myswarm.url/api/v8/groups/my-group"
Assuming that the authenticated user has permission, Swarm
responds with the id
of the deleted group:
{
"id": "my-group"
}
Summary: Show Version Information
This can be used to determine the currently-installed Swarm version, and also to check that Swarm’s API is responding as expected.
HTTP/1.1 200 OK
{
"year": "2017",
"version": "SWARM/2017.3-MAIN/8499605 (2017/10/25)"
}
Note: year refers to the year of the Swarm release, not necessarily the current year.
|
Summary: Get List of Projects
Returns a list of projects in Swarm that are visible to the current user. Administrators will see all projects, including private ones.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
An optional comma-separated list (or array) of fields to show for each project. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"projects": [
{
"id": "testproject3",
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": []
}
],
"deleted": false,
"description": "Test test test",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": []
}
]
}
To list all projects:
curl -u "username:password" "https://my-swarm-host/api/v8/projects?fields=id,description,members,name"
Pagination is not currently supported by this endpoint. Swarm responds with a list of all projects:
{
"projects": [
{
"id": "testproject1",
"description": "Test test test",
"members": ["alice"],
"name": "TestProject"
},
{
"id": "testproject2",
"description": "Test test test",
"members": ["alice"],
"name": "TestProject"
}
]
}
Project administrators wishing to see the tests
and deploy
fields must fetch projects
individually.
Summary: Get Project Information
Retrieve information about a project.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Project ID |
string |
path |
Yes |
|
An optional comma-separated list (or array) of fields to show for each project. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"project": {
"id": "testproject4",
"defaults": [],
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": [],
"defaults": []
}
],
"deleted": false,
"description": "Test test test",
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": []
}
}
To fetch an individual project:
curl -u "username:password" \
"https://my-swarm-host/api/v8/projects/testproject2?fields=id,description,members,name"
Swarm responds with a project entity:
{
"project": {
"id": "testproject2",
"defaults": [],
"description": "Test test test",
"members": ["alice"],
"name": "TestProject 2"
}
}
Project administrators have access to additional fields (tests
and deploy
) when fetching
individual projects using this endpoint.
Summary: Create a new Project
Creates a new project in Swarm.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Project Name (is also used to generate the Project ID) |
string |
form |
Yes |
|
An array of project members. |
array |
form |
Yes |
|
An optional array of project subgroups. |
array |
form |
No |
|
An optional array of project owners. |
array |
form |
No |
|
An optional project description. |
string |
form |
No |
|
Private projects are visible only to Members, Moderators, Owners, and Administrators. (Default: false) |
boolean |
form |
No |
|
Configuration for automated deployment. Example: {"enabled": true, "url": "http://localhost/?change={change}"} |
array |
form |
No |
|
Configuration for testing/continuous integration. |
array |
form |
No |
|
Optional branch definitions for this project. |
array |
form |
No |
|
An optional jobview for associating certain jobs with this project. |
string |
form |
No |
|
Email members, moderators and followers when a change is committed. |
boolean |
form |
No |
|
Email members and moderators when a new review is requested. |
boolean |
form |
No |
|
An optional array of defaults at a project level (for example default reviewers). |
array |
form |
No |
HTTP/1.1 200 OK
{
"project": {
"id": "testproject5",
"defaults": [],
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": [],
"defaults": []
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "Test test test",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
HTTP/1.1 200 OK
{
"project": {
"id": "testproject6",
"defaults": {"user2":{"required":true}},
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": [],
"defaults": {
"reviewers":{
"groups":{"swarm-group-group1":{"required":"1"}},
"users":{"user1":{"required":true}}
}
}
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "New Project Description",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
To create a project:
curl -u "username:password" \
-d "name=TestProject 3" \
-d "description=The third iteration of our test project." \
-d "members[]=alice" \
-d "members[]=bob" \
"https://my-swarm-host/api/v8/projects/"
Swarm responds with the new project entity:
{
"project": {
"id": "testproject3",
"defaults": [],
"branches": [],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "The third iteration of our test project.",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice", "bob"],
"name": "TestProject 3",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
Specifying a branch requires using array notation and providing at least two fields (name
and paths
) for
each branch you wish to create. Creating more than one branch involves incrementing the branches[0]
specifier
for each branch - an example of this accompanies the PATCH endpoint documentation.
Projects are public by default. Marking a project as Private requires using {private: true}
in JSON, and
using -d "private=1"
in regular form-encoded requests.
Form-encoded requests only accept 0 for false in boolean values — using the word false will be
evaluated as a non-zero (and therefore non-false) value.
|
curl -u "username:password" \
-d "name=TestProject 4" \
-d "private=1" \
-d "members[]=bob" \
-d "branches[0][name]=Branch One" \
-d "branches[0][paths][]=//depot/main/TestProject/..." \
"https://my-swarm-host/api/v8/projects"
Swarm responds with the new project entity:
{
"project": {
"id": "testproject-4",
"defaults": [],
"branches": [
{
"paths": [
"//depot/main/TestProject/..."
],
"name": "Branch One",
"id": "branch-one",
"moderators": [],
"moderators-groups": [],
"defaults": []
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": null,
"emailFlags": [],
"jobview": null,
"members": ["bob"],
"name": "TestProject 4",
"owners": [],
"private": true,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
curl -u "<user>:<password>" \
-H "Content-Type: application/json" \
-X PATCH \
-d '"name": "testproject-4", \
"members": ["bob"], \
"defaults":{"reviewers":{"user2":{"required":true}} \
"branches":[{ \
"name":"Branch One", \
"paths":{"//depot/main/TestProject/..."} \
"defaults":{"reviewers":{"swarm-group-group1":{"required":"1"},"user1":{"required":true}}]' \
"https://my-swarm-host/api/v8/projects/testproject-4"
Or without JSON content:
curl -u "username:password" \
-X PATCH \
-d "name=TestProject 4" \
-d "members[]=bob" \
-d "defaults[reviewers][user2][required]=true" \
-d "branches[0][name]=Branch One" \
-d "branches[0][paths][]=//depot/main/TestProject/..." \
-d "branches[0][defaults][reviewers][swarm-group-group1][required]=1" \
-d "branches[0][defaults][reviewers][user1][required]=true" \
"https://my-swarm-host/api/v8/projects/testproject-4"
Swarm responds with project entity similar to:
{
"project": {
"id": "testproject-4",
"defaults": ["user2":["required":true]]],
"branches": [
{
"paths": [
"//depot/main/TestProject/..."
],
"name": "Branch One",
"id": "branch-one",
"moderators": [],
"moderators-groups": [],
"defaults": ["reviewers":["swarm-group-group1":["required":"1"], "user1":["required":true]]]
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": null,
"emailFlags": [],
"jobview": null,
"members": ["bob"],
"name": "TestProject 4",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
Summary: Edit a Project
Change the settings of a project in Swarm. If a project has owners set, only the owners can perform this action.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Project ID |
string |
path |
Yes |
|
Project Name (changing the project name does not change the project ID) |
string |
form |
No |
|
An array of project members. |
array |
form |
No |
|
An optional array of project subgroups. |
array |
form |
No |
|
An optional array of project owners. |
array |
form |
No |
|
Your project description. |
string |
form |
No |
|
Private projects are visible only to Members, Moderators, Owners, and Administrators. (Default: false) |
boolean |
form |
No |
|
Configuration for automated deployment. Example: {"enabled": true, "url": "http://localhost/?change={change}"} |
array |
form |
No |
|
Configuration for testing/continuous integration. |
array |
form |
No |
|
Optional branch definitions for this project. |
array |
form |
No |
|
A jobview for associating certain jobs with this project. |
string |
form |
No |
|
Email members, moderators and followers when a change is committed. |
boolean |
form |
No |
|
Email members and moderators when a new review is requested. |
boolean |
form |
No |
|
An optional array of defaults at a project level (for example default reviewers). |
array |
form |
No |
HTTP/1.1 200 OK
{
"project": {
"id": "testproject7",
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": []
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "New Project Description",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
HTTP/1.1 200 OK
{
"project": {
"id": "testproject8",
"defaults": {"user2":{"required":true}},
"branches": [
{
"id": "main",
"name": "main",
"paths": ["//depot/main/TestProject/..."],
"moderators": [],
"moderators-groups": [],
"defaults": {
"reviewers":{
"groups":{"swarm-group-group1":{"required":"1"}},
"users":{"user1":{"required":true}}
}
}
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "New Project Description",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
To edit a project:
It is safe to edit a project without specifying branches, but the instructions for adding branches contain important information for modifying branch configuration. |
curl -u "username:password" \
-X PATCH
-d "description=Witness the power of a fully operational Swarm project." \
"https://my-swarm-host/api/v8/projects/testproject3"
Swarm responds with the updated project entity:
{
"project": {
"id": "testproject3",
"branches": [],
"defaults": [],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": "Witness the power of a fully operational Swarm project.",
"followers": [],
"jobview": "subsystem=testproject",
"members": ["alice"],
"name": "TestProject 3",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
Specifying a branch requires using array notation and providing at least two fields (name
and paths
) for
each branch you wish to create. Creating more than one branch involves incrementing the branches[0]
specifier
for each branch.
If you have existing branches, you must specify all of them in the query to avoid data loss.
This operation sets the value of the entire branches property to match the provided input.
|
Marking a private project as Public requires using {private: false}
in JSON, or using -d "private=0"
in
regular form-encoded requests.
Form-encoded requests only accept 0 for false in boolean values — using the word false will be
evaluated as a non-zero (and therefore non-false) value.
|
curl -u "username:password" \
-X PATCH \
-d "private=0" \
-d "branches[0][name]=Branch One" \
-d "branches[0][paths][]=//depot/main/TestProject/..." \
-d "branches[1][name]=Branch Two" \
-d "branches[1][paths][]=//depot/main/SecondBranch/..." \
-d "branches[1][moderators][]=bob" \
-d "branches[1][moderators-groups][]=group1" \
"https://my-swarm-host/api/v8/projects/testproject-4"
Swarm responds with the new project entity:
{
"project": {
"id": "testproject-4",
"branches": [
{
"paths": [
"//depot/main/TestProject/..."
],
"name": "Branch One",
"id": "branch-one",
"moderators": [],
"moderators-groups": [],
"defaults": []
},
{
"paths": [
"//depot/main/SecondBranch/..."
],
"name": "Branch Two",
"id": "branch-two",
"moderators": ["bob"],
"moderators-groups": ["group1"],
"defaults": []
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": null,
"emailFlags": [],
"jobview": null,
"members": ["bob"],
"name": "TestProject 4",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
curl -u "<user>:<password>" \
-H "Content-Type: application/json" \
-X PATCH \
-d '"defaults":{"reviewers":{"user2":{"required":true}} \
"branches":[{ \
"name":"Branch One", \
"paths":{"//depot/main/TestProject/..."} \
"defaults": { \
"reviewers":{ \
"groups":{"group1":{"required":"1"}}, \
"users":{"user1":{"required":true}} \
} \
}]' \
"https://my-swarm-host/api/v8/projects/testproject-4"
Or without JSON content:
curl -u "username:password" \
-X PATCH \
-d "name=TestProject 4" \
-d "members[]=bob" \
-d "defaults[reviewers][user2][required]=true" \
-d "branches[0][name]=Branch One" \
-d "branches[0][paths][]=//depot/main/TestProject/..." \
-d "branches[0][defaults][reviewers][groups][group1][required]=1" \
-d "branches[0][defaults][reviewers][users][user1][required]=true" \
"https://my-swarm-host/api/v8/projects/testproject-4"
Swarm responds with project entity similar to:
{
"project": {
"id": "testproject-4",
"defaults": ["user2":["required":true]]],
"branches": [
{
"paths": [
"//depot/main/TestProject/..."
],
"name": "Branch One",
"id": "branch-one",
"moderators": [],
"moderators-groups": [],
"defaults": {
"reviewers":{
"groups":{"group1":{"required":"1"}},
"users":{"user1":{"required":true}}
}
}
}
],
"deleted": false,
"deploy": {"url": "", "enabled": false},
"description": null,
"emailFlags": [],
"jobview": null,
"members": ["bob"],
"name": "TestProject 4",
"owners": [],
"private": false,
"subgroups": [],
"tests": {"url": "", "enabled": false}
}
}
Summary: Delete a Project
Mark a Swarm project as deleted. The project ID and name cannot be reused. If a project has owners set, only the owners can perform this action.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Project ID |
string |
path |
Yes |
HTTP/1.1 200 OK
{
"id": "testproject"
}
Super users, administrators, and owners can delete projects. Members can delete projects that have no owners set.
curl -u "username:password" -X DELETE "https://my-swarm-host/api/v8/projects/testproject3"
Assuming that the authenticated user has permission, Swarm responds with the id of the deleted project:
{
"id": "testproject3"
}
Summary: Get reviews for action dashboard
Gets reviews for the action dashboard for the authenticated user
HTTP/1.1 200 OK
{
"lastSeen": 120,
"reviews": [
{
"id": 7,
"author": "swarm_admin",
"changes": [6],
"comments": [0,0],
"commits": [6],
"commitStatus": [],
"created": 1485793976,
"deployDetails": [],
"deployStatus": null,
"description": "test\n",
"groups": ["swarm-project-test"],
"participants": {"swarm_admin":[]},
"pending": false,
"projects": {"test":["test"]},
"roles": ["moderator|reviewer|required_reviewer|author"],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1485958875,
"updateDate": "2017-02-01T06:21:15-08:00"
}
],
"totalCount": null
}
To list reviews:
curl -u "username:password" "http://my-swarm-host/api/v8/dashboards/action"
Swarm responds with a list of the latest reviews, a totalCount
field, and a lastSeen
value for pagination:
{
"lastSeen": 120,
"reviews": [
{
"id": 7,
"author": "swarm_admin",
"changes": [6],
"comments": [0,0],
"commits": [6],
"commitStatus": [],
"created": 1485793976,
"deployDetails": [],
"deployStatus": null,
"description": "test\n",
"groups": ["swarm-project-test"],
"participants": {"swarm_admin":[]},
"pending": false,
"projects": {"test":["test"]},
"roles": ["moderator|reviewer|required_reviewer|author"],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1485958875,
"updateDate": "2017-02-01T06:21:15-08:00"
}
],
"totalCount": null
}
Summary: Get List of Reviews
List and optionally filter reviews.
Parameter | Description | Type | Parameter Type | Required | Default Value |
---|---|---|---|---|---|
|
A review ID to seek to. Reviews up to and including the specified |
integer |
query |
No |
|
|
Maximum number of reviews to return. This does not guarantee that |
integer |
query |
No |
1000 |
|
An optional comma-separated list (or array) of fields to show. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
|
|
One or more authors to limit reviews by. Reviews with any of the specified authors are returned. (v1.2+) |
array (of strings) |
query |
No |
|
|
One or more change IDs to limit reviews by. Reviews associated with any of the specified changes are returned. |
array (of integers) |
query |
No |
|
|
Boolean option to limit to reviews to those with or without reviewers. Use |
boolean |
query |
No |
|
|
One or more review IDs to fetch. Only the specified reviews are returned. This filter cannot be combined with the |
array (of integers) |
query |
No |
|
|
Keywords to limit reviews by. Only reviews where the description, participants list or project list contain the specified keywords are returned. |
string |
query |
No |
|
|
One or more participants to limit reviews by. Reviews with any of the specified participants are returned. |
array (of strings) |
query |
No |
|
|
One or more projects to limit reviews by. Reviews affecting any of the specified projects are returned. |
array (of strings) |
query |
No |
|
|
One or more states to limit reviews by. Reviews in any of the specified states are returned. |
array (of strings) |
query |
No |
|
|
Boolean option to limit reviews by tests passing or failing. Use |
string |
query |
No |
|
|
Option to fetch unchanged reviews. Requires the date to be in the format YYYY-mm-dd, for example 2017-01-01. Reviews to be returned are determined by looking at the last updated date of the review. |
string |
query |
No |
|
|
Should have the value 'up' or 'down' to filter reviews that have been voted up or down by the current authenticated user. |
string |
query |
No |
|
|
True or false to support filtering reviews that include comments by the current authenticated user. |
boolean |
query |
No |
HTTP/1.1 200 OK
{
"lastSeen": 12209,
"reviews": [
{
"id": 12206,
"author": "swarm",
"changes": [12205],
"comments": 0,
"commits": [],
"commitStatus": [],
"created": 1402507043,
"deployDetails": [],
"deployStatus": null,
"description": "Review Description\n",
"participants": {
"swarm": []
},
"pending": true,
"projects": [],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1402518492
}
],
"totalCount": 1
}
Swarm returns null for totalCount if no search filters were provided.
lastSeen can often be used as an offset for pagination, by using the value
in the after parameter of subsequent requests.
|
reviews
array is empty:HTTP/1.1 200 OK
{
"lastSeen": null,
"reviews": [],
"totalCount": 0
}
To list reviews:
curl -u "username:password" "https://my-swarm-host/api/v8/reviews?max=2&fields=id,description,author,state"
Swarm responds with a list of the latest reviews, a totalCount
field, and a lastSeen
value for pagination:
{
"lastSeen": 120,
"reviews": [
{
"id": 123,
"author": "bruno",
"description": "Adding .jar that should have been included in r110\n",
"state": "needsReview"
},
{
"id": 120,
"author": "bruno",
"description": "Fixing a typo.\n",
"state": "needsReview"
}
],
"totalCount": null
}
The totalCount
field is populated when keywords are supplied. It indicates how many total matches there are.
If keywords are not supplied the totalCount
field remains null
, indicating that the list of all reviews is
being queried.
To obtain the next page of a reviews list (based on the previous example):
curl -u "username:password" "https://my-swarm-host/api/v8/reviews\
?max=2&fields=id,description,author,state&after=120"
Swarm responds with the second page of results, if any reviews are present after the last seen review:
{
"lastSeen": 100,
"reviews": [
{
"id": 110,
"author": "bruno",
"description": "Updating Java files\n",
"state": "needsReview"
},
{
"id": 100,
"author": "bruno",
"description": "Marketing materials for our new cutting-edge product\n",
"state": "needsReview"
}
],
"totalCount": null
}
Given a list of change IDs (5, 6, 7), here is how to check if any of them have reviews attached:
curl -u "username:password" "https://my-swarm-host/api/v8/reviews\
?max=2&fields=id,changes,description,author,state&change\[\]=5&change\[\]=6&change\[\]=7"
Swarm responds with a list of reviews that include these changes:
{
"lastSeen": 100,
"reviews": [
{
"id": 110,
"author": "bruno",
"changes": [5],
"description": "Updating Java files\n",
"state": "needsReview"
},
{
"id": 100,
"author": "bruno",
"changes": [6,7],
"description": "Marketing materials for our new cutting-edge product\n",
"state": "needsReview"
}
],
"totalCount": 2
}
If no corresponding reviews are found, Swarm responds with an empty reviews list:
{
"lastSeen": null,
"reviews": [],
"totalCount": 0
}
curl -u "username:password" "https://my-swarm-host/api/v8/reviews\
?max=2&fields=id,changes,description,author,state¬UpdatedSince=2017-01-01"
Swarm responds with a list of reviews that have not been updated since the notUpdatedSince date:
{
"lastSeen": 100,
"reviews": [
{
"id": 110,
"author": "bruno",
"changes": [5],
"description": "Updating Java files\n",
"state": "needsReview"
},
{
"id": 100,
"author": "bruno",
"changes": [6,7],
"description": "Marketing materials for our new cutting-edge product\n",
"state": "needsReview"
}
],
"totalCount": 2
}
curl -u "username:password" "https://my-swarm-host/api/v8/reviews\
?max=2&fields=id,changes,description,author,state&hasVoted=up"
Swarm responds with a list of reviews that include these changes:
{
"lastSeen": 100,
"reviews": [
{
"id": 110,
"author": "bruno",
"changes": [5],
"description": "Updating Java files\n",
"state": "needsReview"
},
{
"id": 100,
"author": "bruno",
"changes": [6,7],
"description": "Marketing materials for our new cutting-edge product\n",
"state": "needsReview"
}
],
"totalCount": 2
}
If no corresponding reviews are found, Swarm responds with an empty reviews list:
{
"lastSeen": null,
"reviews": [],
"totalCount": 0
}
curl -u "username:password" "https://my-swarm-host/api/v8/reviews\
?max=2&fields=id,changes,description,author,state&myComments=true"
Swarm responds with a list of reviews that include these changes:
{
"lastSeen": 100,
"reviews": [
{
"id": 110,
"author": "bruno",
"changes": [5],
"description": "Updating Java files\n",
"state": "needsReview"
},
{
"id": 100,
"author": "bruno",
"changes": [6,7],
"description": "Marketing materials for our new cutting-edge product\n",
"state": "needsReview"
}
],
"totalCount": 2
}
If no corresponding reviews are found, Swarm responds with an empty reviews list:
{
"lastSeen": null,
"reviews": [],
"totalCount": 0
}
Summary: Get Review Information
Retrieve information about a review.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Review ID |
integer |
path |
Yes |
|
An optional comma-separated list (or array) of fields to show. Omitting this parameter or passing an empty value shows all fields. |
string |
query |
No |
HTTP/1.1 200 OK
{
"review": {
"id": 12204,
"author": "bruno",
"changes": [10667],
"commits": [10667],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r10145\n",
"participants": {
"alex_qc": [],
"bruno": {
"vote": 1,
"required": true
},
"vera": []
},
"reviewerGroups": {
"group1" : [],
"group2" : {
"required" : true
},
"group3" : {
"required" : true,
"quorum": "1"
}
},
"pending": false,
"projects": {
"swarm": ["main"]
},
"state": "archived",
"stateLabel": "Archived",
"testDetails": {
"url": "http://jenkins.example.com/job/project_ci/123/"
},
"testStatus": null,
"type": "default",
"updated": 1399325913
}
}
HTTP/1.1 404 Not Found
{
"error": "Not Found"
}
To fetch a review:
curl -u "username:password" "https://my-swarm-host/api/v8/reviews/123"
Swarm responds with a review entity:
{
"review": {
"id": 123,
"author": "bruno",
"changes": [122,124],
"commits": [124],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r110\n",
"groups": [],
"participants": {
"alex_qc": [],
"bruno": {
"vote": 1,
"required": true
},
"vera": []
},
"reviewerGroups": {
"group1" : [],
"group2" : {
"required" : true
},
"group3" : {
"required" : true,
"quorum": "1"
}
},
"pending": false,
"projects": {
"swarm": ["main"]
},
"state": "archived",
"stateLabel": "Archived",
"testDetails": {
"url": "http://jenkins.example.com/job/project_ci/123/"
},
"testStatus": null,
"type": "default",
"updated": 1399325913,
"versions": []
}
}
Summary: Create a Review
Pass in a changelist ID to create a review. Optionally, you can also provide a description and a list of reviewers.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Change ID to create a review from |
integer |
form |
Yes |
|
Description for the new review (defaults to change description) |
string |
form |
No |
|
A list of reviewers for the new review |
array (of strings) |
form |
No |
|
A list of required reviewers for the new review (v1.1+) |
array (of strings) |
form |
No |
|
A list of required reviewers for the new review (v7+) |
array |
form |
No |
HTTP/1.1 200 OK
{
"review": {
"id": 12205,
"author": "bruno",
"changes": [10667],
"commits": [10667],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r10145\n",
"participants": {
"bruno": []
},
"reviewerGroups": {
"group1" : [],
"group2" : {
"required" : true
},
"group3" : {
"required" : true,
"quorum": "1"
}
},
"pending": false,
"projects": [],
"state": "archived",
"stateLabel": "Archived",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913
}
}
To start a review for a committed change or a non-empty shelved changelist specifying reviewer groups:
curl -u "username:password" \
-d "change=122" \
-d "reviewerGroups[0][name]=group1" \
-d "reviewerGroups[1][name]=group2" \
-d "reviewerGroups[1][required]=true" \
-d "reviewerGroups[2][name]=group3" \
-d "reviewerGroups[2][required]=true" \
-d "reviewerGroups[2][quorum]=1" \
"https://my-swarm-host/api/v8/reviews/"
Swarm responds with the new review entity:
{
"review": {
"id": 123,
"author": "bruno",
"changes": [122],
"commits": [],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r110\n",
"groups": [],
"participants": {
"bruno": []
},
"reviewerGroups": {
"group1" : [],
"group2" : {
"required" : true
},
"group3" : {
"required" : true,
"quorum": "1"
}
},
"pending": true,
"projects": [],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913,
"versions": []
}
}
Summary: Archiving the inactive reviews (v6+)
Archiving reviews not updated since the date (v6+)
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Updated since date. Requires the date to be in the format YYYY-mm-dd, for example 2017-01-01 |
string |
form |
Yes |
|
A description that is posted as a comment for archiving. |
string |
form |
Yes |
HTTP/1.1 200 OK
{
"archivedReviews": [
{
"id": 836,
"author": "swarm",
"changes": [789],
"commits": [],
"commitStatus": [],
"created": 1461164339,
"deployDetails": [],
"deployStatus": null,
"description": "Review description\n",
"groups": [],
"participants": {
"swarm": []
},
"pending": false,
"projects": [],
"state": "archived",
"stateLabel": "Archived",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1478191607
}
],
"failedReviews": []
}
To archive reviews not updated since 2016/06/30 inclusive:
curl -u "username:password" -d "notUpdatedSince=2016-06-30" \
"https://my-swarm-host/api/v8/reviews/archive/"
Swarm responds with the list of archived reviews and failed reviews if there are any:
{
"archivedReviews":[
{
"id": 911,
"author": "swarm",
"changes": [601],
"commits": [],
"commitStatus": [],
"created": 1461164344,
"deployDetails": [],
"deployStatus": null,
"description": "Touch up references on html pages.\n",
"groups": [],
"participants": {
"swarm":[]
},
"pending": false,
"projects": [],
"state": "archived",
"stateLabel": "Archived",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1478191605
},
{
"id": 908,
"author": "earl",
"changes": [605],
"commits": [],
"commitStatus": [],
"created": 1461947794,
"deployDetails": [],
"deployStatus": null,
"description": "Remove (attempted) installation of now deleted man pages.\n",
"groups": [],
"participants": {
"swarm": []
},
"pending": false,
"projects": [],
"state": "archived",
"stateLabel": "Archived",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1478191605
}
],
"failedReviews":[
{
}
]
}
If no reviews are archived, Swarm responds with an empty reviews list:
{
"archivedReviews": [],
"failedReviews": []
}
Summary: Add Change to Review
Links the given change to the review and schedules an update.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Review ID |
integer |
path |
Yes |
|
Change ID |
integer |
form |
Yes |
HTTP/1.1 200 OK
{
"review": {
"id": 12206,
"author": "bruno",
"changes": [10667, 12000],
"commits": [10667, 12000],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r10145\n",
"participants": {
"bruno": []
},
"pending": false,
"projects": [],
"state": "archived",
"stateLabel": "Archived",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913
}
}
You may want to update a review from a shelved or committed change that is different from the initiating change. This is done by adding a change to the review.
To add a change:
curl -u "username:password" -d "change=124" "https://my-swarm-host/api/v8/reviews/123/changes/"
Swarm responds with the updated review entity:
{
"review": {
"id": 123,
"author": "bruno",
"changes": [122, 124],
"commits": [],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r110\n",
"groups": [],
"participants": {
"bruno": []
},
"pending": true,
"projects": [],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913,
"versions": [
{
"difference": 1,
"stream": null,
"change": 124,
"user": "bruno",
"time": 1399330003,
"pending": true,
"archiveChange": 124
}
]
}
}
Summary: Clean up a review (v6+)
Clean up a review for the given id.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Expected to be a boolean (defaulting to false). If true then an attempt will be made to reopen files into a default changelist |
boolean |
form |
No |
HTTP/1.1 200 OK
{
"complete": [
{
"1": ["2"]
}
],
"incomplete": []
}
Cleanup review number 1, reopening any files into the default changelist.
curl -u "username:password" -d "reopen=true" \
"https://my-swarm-host/api/v8/reviews/1/cleanup"
Swarm responds with the review and the changelists cleaned. Depending on the completion they will be either detailed in 'complete' or 'incomplete'. Incomplete changelists will have messages indicating why it was not possible to complete:
{
"complete": [
{
"1": ["2"]
}
],
"incomplete": []
}
Summary: Transition the Review State (v2+)
Transition the review to a new state. When transitioning to approved, you can optionally commit the review. (v2+)
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Review ID |
integer |
path |
Yes |
|
Review State. Valid options: needsReview, needsRevision, approved, archived, rejected |
string |
form |
Yes |
|
An optional description that is posted as a comment for non-commit transitions. Commits that do not include a description default to using the Review description in the resulting change description. |
string |
form |
No |
|
Set this flag to true and provide a state of |
boolean |
form |
No |
|
Instruct Swarm to wait for a commit to finish before returning. |
boolean |
form |
No |
|
When performing an 'Approve and Commit', one or more jobs can be attached to the review as part of the commit process. |
stringArray |
form |
No |
|
Provide a fix status for the attached job(s) when performing an 'Approve and Commit'. Possible status values vary by job specification, but often include: open, suspended, closed, review, fixed. |
string |
form |
No |
HTTP/1.1 200 OK
{
"review": {
"id": 12207,
"author": "bruno",
"changes": [10667, 12000],
"commits": [],
"commitStatus": [],
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r10145\n",
"participants": {
"bruno": []
},
"pending": false,
"projects": [],
"state": "needsRevision",
"stateLabel": "Needs Revision",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913
},
"transitions": {
"needsReview": "Needs Review",
"approved": "Approve",
"rejected": "Reject",
"archived": "Archive"
}
}
HTTP/1.1 200 OK
{
"review": {
"id": 12208,
"author": "bruno",
"changes": [10667, 12000, 12006],
"commits": [12006],
"commitStatus": {
"start": 1399326910,
"change": 12006,
"status": "Committed",
"committer": "bruno",
"end": 1399326911
},
"created": 1399325900,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r10145\n",
"participants": {
"bruno": []
},
"pending": false,
"projects": [],
"state": "needsRevision",
"stateLabel": "Needs Revision",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325905
},
"transitions": {
"needsReview": "Needs Review",
"needsRevision": "Needs Revision",
"rejected": "Reject",
"archived": "Archive"
},
"commit": 12006
}
To commit a review:
curl -u "username:password" -X PATCH -d "state=approved" -d "commit=1" \
"https://my-swarm-host/api/v8/reviews/123/state/"
Swarm responds with the updated review entity, as well as a list of possible transitions for the review:
{
"review": {
"id": 123,
"author": "bruno",
"changes": [122, 124],
"commits": [124],
"commitStatus": {
"start": 1399326910,
"change": 124,
"status": "Committed",
"committer": "bruno",
"end": 1399326911
},
"created": 1399325913,
"deployDetails": [],
"deployStatus": null,
"description": "Adding .jar that should have been included in r110\n",
"groups": [],
"participants": {
"bruno": []
},
"pending": false,
"projects": [],
"state": "approved",
"stateLabel": "Approved",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1399325913,
"versions": []
},
"transitions": {
"needsReview": "Needs Review",
"approved": "Approve",
"rejected": "Reject",
"archived": "Archive"
}
}
Summary: Update Review Description
Update the description field of a review.
Parameter | Description | Type | Parameter Type | Required |
---|---|---|---|---|
|
Review ID |
integer |
path |
Yes |
|
The new author for the specified review. (At least one of Author or Description are required.) |
string |
form |
No |
|
The new description for the specified review. (At least one of Description or Author are required.) |
string |
form |
No |
|
Method Override. If your client cannot submit HTTP PATCH, use an HTTP POST with the parameter ?_method=PATCH to override. |
string |
query |
No |
HTTP/1.1 200 OK
{
"review": {
"id": 12306,
"author": "swarm",
"changes": [12205],
"comments": 0,
"commits": [],
"commitStatus": [],
"created": 1402507043,
"deployDetails": [],
"deployStatus": null,
"description": "Updated Review Description\n",
"participants": {
"swarm": []
},
"pending": true,
"projects": [],
"state": "needsReview",
"stateLabel": "Needs Review",
"testDetails": [],
"testStatus": null,
"type": "default",
"updated": 1402518492
},
"transitions": {
"needsRevision": "Needs Revision",
"approved": "Approve",
"rejected": "Reject",
"archived": "Archive"
},
"canEditAuthor": true
}
Swarm returns null for totalCount if no search filters were provided.
lastSeen can often be used as an offset for pagination, by using the value
in the after parameter of subsequent requests.
|
reviews
array is empty:HTTP/1.1 200 OK
{
"lastSeen": null,
"reviews": [],
"totalCount": 0
}
Summary: Unfollow all Users and Projects
Admin and super users are permitted to execute unfollow all against any target user. Other users are only permitted to execute the call if they themselves are the target user
HTTP/1.1 200 OK
{
"isValid": true,
"messages": "User {user} is no longer following any Projects or Users."
}
This section includes an extended API example, involving multiple API calls to answer a more complicated kind of question than any single API endpoint can provide: which reviews does a specific userid need to attend to?
<?php
/**
* vim:set ai si et ts=4 sw=4 syntax=php:
*
* reviews.php
*
* Queries the Swarm API and reports which reviews a specified user
* needs to attend to.
*
* Required attention is determined by the following criteria:
* - the user is a participant in a review
* - and the user has not voted on the review
* - and the user has not commented on the review
* - or the user's comment on the review is a
* task that has been addressed and needs verification
*/
if (ini_set('track_errors', 1) === false) {
echo "Warning: unable to track errors.\n";
}
# process command-line arguments
$options = getopt(
'hs:r:v',
array('help', 'swarm:', 'reviewer', 'verbose')
);
$swarm = '';
if (isset($options['s'])) {
$swarm = $options['s'];
}
if (isset($options['swarm'])) {
$swarm = $options['swarm'];
}
if (!$swarm) {
usage('Swarm API URL not provided.');
}
$reviewer = '';
if (isset($options['r'])) {
$reviewer = $options['r'];
}
if (isset($options['reviewer'])) {
$reviewer = $options['reviewer'];
}
if (!$reviewer) {
usage('Swarm reviewer not provided.');
}
$verbose = false;
if (isset($options['v']) || isset($options['verbose'])) {
$verbose = true;
}
if (isset($options['h']) || isset($options['help'])) {
usage();
}
function usage($message = null)
{
if ($message) {
echo "$message\n\n";
}
$script = basename(__FILE__);
echo <<<EOU
$script: -s <Swarm URL> -u <API userid> -p <API user's password> \
-r <reviewer userid to report on> -h
-s|--swarm Swarm's URL (e.g. https://user@password:myswarm.url/)
-r|--reviewer The reviewer to report on.
-h|--help This help text.
-v|--verbose Verbose output.
This script queries the Swarm API and reports on reviews that the
specified user needs to attend to.
Note: If your Helix Versioning Engine (p4d) has security level 3 set, you
cannot use a password to authenticate; you must acquire a host-unlocked
ticket from p4d, and use the ticket in place of a password when
communicating with the Swarm API connected to p4d.
EOU;
exit;
}
function msg($message)
{
global $verbose;
if ($verbose) {
echo $message;
}
}
function call_api($url, $params)
{
global $php_errormsg;
$query = http_build_query($params);
$request = $url . '?' . $query;
$response = @file_get_contents($request);
if ($php_errormsg) {
echo "Unable to call api: $php_errormsg\n";
exit;
}
$json = @json_decode($response, true);
if ($php_errormsg) {
echo "Unable to decode api response: $php_errormsg\n";
exit;
}
return $json;
}
# remove trailing / from URL, if it exists
$swarm = rtrim(trim($swarm), '/');
# fetch the list of reviews
$reviews = call_api(
"$swarm/api/v4/reviews",
array(
'hasReviewers' => 1, # only reviews with participants
'participants' => array($reviewer), # only review for this reviewer
'max' => 9, # get plenty of reviews, if available
'fields' => array('id', 'description', 'commits'), # get these fields
)
);
$report = array();
foreach ($reviews['reviews'] as $review) {
if (is_null($review)) {
continue;
}
$flag = false;
msg('Review: ' . $review['id'] . ' ');
# if the review is already committed, it likely does not need attention
if (array_key_exists('commits', $review)
&& count($review['commits'])
) {
msg("is committed, skipping...\n");
continue;
}
# if the review has a vote from the reviewer, they are already aware
if (array_key_exists('participants', $review)
&& array_key_exists('vote', $review['participants'][$reviewer])
) {
msg("has vote from reviewer, skipping...\n");
continue;
}
# if there are no open comments on the review, the reviewer's
# attention is required
if (array_key_exists('comments', $review)
&& $review['comments'][0] == 0
) {
msg("has no open comments, skipping...\n");
continue;
}
# fetch the comments for this review
$comments = call_api(
"$swarm/api/v4/comments",
array(
'topic' => 'reviews/' . $review['id'], # comments for this review
'max' => 9, # get plenty of comments, if available
)
);
foreach ($comments['comments'] as $comment) {
msg("\n Comment: " . $comment['id'] . ' ');
// skip over comments from other reviewers
if (array_key_exists('user', $comment) && $reviewer != $comment['user']) {
msg("is by another user, carry on...\n");
continue;
}
# skip archived comments
if (array_key_exists('flags', $comment)
&& count($comment['flags']) > 0
&& $comment['flags'][0] == 'closed'
) {
msg("is archived, carry on...\n");
continue;
}
# skip marked tasks
if (array_key_exists('taskState', $comment)
&& ($comment['taskState'] == 'comment'
|| $comment['taskState'] == 'verified'
|| $comment['taskState'] == 'open'
)
) {
msg("reviewer's comment needs attention, carry on...\n");
continue;
}
// anything else means that the reviewer's comment needs attention
// by the reviewer
$flag = true;
msg("needs attention!\n");
break;
}
// evaluation is complete. Does this review need attention?
if ($flag) {
$report[] = $review;
}
}
if (count($report)) {
echo "User '$reviewer' needs to attend to these reviews:\n";
foreach ($report as $review) {
$description = trim($review['description']);
if (strlen($description) > 60) {
$description = substr($description, 0, 60) . ' ...';
}
echo $review['id'] . ": $description\n";
}
} else {
echo "User '$reviewer' has no reviews to attend to.\n";
}
The example is written in PHP. To use it, download the code,
or copy and paste it into a file called reviews.php
. Then, execute it like this:
$ php reviews.php -s https://myswarm.host:port/ -r bob
Replace http://myswarm.host/
with the URL to your Swarm installation.
Replace bob
with the userid you’d like to report on.
To authenticate, insert username:password@
before the hostname. If your Helix
Versioning Engine’s security counter is set to 3
or higher, you need to
acquire a ticket and use the ticket in place of the password (see
Authentication for details). If your Swarm is installed on a
custom port, or is installed in a
sub-folder, include those elements in the URL as well.
For example:
$ php reviews.php -s https://me:F0FC33068BA244B1BBD8196CC9166F34@my.host:8080/swarm/ -r bob
If you do not specify the URL correctly, you might see an error like:
Unable to call api: file_get_contents(http://...@my.host:8080/swarm/api/v8/reviews?hasReviewers=1&participants%5B0%5D=bob&max=9&fields%5B0%5D=id&fields%5B1%5D=description&fields%5B2%5D=commits): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
If there are no errors, and the specified userid does have reviews to attend to, the output might look like:
1234: Added grapple-grommit support to woozlewobble class. @bob sh ...
1234
is the id of a review that bob
should attend to, followed by the first
60 characters of the review’s description.
This section contains an example script that cleans up pending changelists which are no longer needed. See the review cleanup options for how this can be done automatically when a review is committed.
For pending changelists which were present before this option was available, or for reviews which have been contributed to by multiple authors and so require super user access to tidy up, there is an API which allows the super user to bulk remove such changelists.
The script demonstrates how this API could be used. It isn’t meant as a complete solution, just a guide to demonstrate what is possible.
<?php
/**
* Perforce Swarm
*
* @copyright 2017 Perforce Software. All rights reserved.
* @license Please see LICENSE.txt in top-level folder of this distribution.
* @version <release>/<patch>
*/
/**
* This example script can be used to clean up (delete) Perforce Server pending changelists automatically when run
* as a super user. It is able to query for reviews based on parameters to establish which changelists are eligible
* for clean up. In this way, it can be tailored to run against reviews of a user's choice.
* Requirements for this script:
* - MUST be a super user
* - MUST populate the parameters below
* - MUST be using Swarm 2017.1 or later
*
* Usage of script
* php superUserReviewCleanUp.php max=10 notUpdatedSince=2017-04-01 state=approved
* php superUserReviewCleanUp.php max=10 author=bruno state=approved
*
* Each of the parameters that you can use are documented at the following URL:
* https://www.perforce.com/perforce/doc.current/manuals/swarm/api.endpoints.html#api.endpoints.Reviews.getReviews
*
*
* This returns a JSON object that contains four main objects.
*
* {
* "error": "",
* "help": "",
* "results": "[]",
* "search_criteria": {
* "fields": "id",
* "max": "10",
* "notUpdatedSince": "2017-04-01"
* }
* }
*
* Referencing the example above:
*
* The error section will contain any errors that have been encountered trying to execute the script.
*
* The help section will populated if you have run the command php superUserReviewCleanUp.php help
*
* The search_criteria section indicates which parameters have been used to fetch the reviews list.
*
* The results section returns a JSON object of each of the reviews it has processed, which may
* include actions that were incomplete.
*
* Below is an example of results being processed:
* "814": {
* "complete": [],
* "incomplete": {
* "814": {
* "813": [
* "0": "Command failed: No shelved files in changelist to delete.",
* ]
* }
* }
* },
* "818": {
* "complete": [],
* "incomplete": []
* }
* "820": {
* "complete": [],
* "incomplete": {
* "820": {
* "821": [
* "0": "Command failed: No shelved files in changelist to delete.",
* "1": "Command failed: Usage: fix [ -d ] [ -s status ] -c changelist# jobName ...\nMissing/wrong
* number of arguments."
* ]
* }
* }
* },
*
* Some reviews may have no actions or incomplete actions. Incomplete actions indicate that additional work is required
* and the review could not be entirely cleaned up. In the example above, the first message indicates a changelist was
* not found. This could be because the end user has already deleted it.
*
* An error with the fix command can indicate that the pending changelist doesn't have any jobs linked or that the jobs
* have already been removed.
*
* NOTES:
* To make the the output print nicely, you can use the python command like this:
*
* php superUserReviewCleanUp.php max=10 notUpdatedSince=2018-04-01 state=approved | python -m json.tool
*
*/
/* **************************************************** */
/* These values MUST be set before running the script. */
/* **************************************************** */
// URL to access swarm. Must not include trailing slash.
$swarmURL = 'http://my.swarm.com';
// Username of super user
$username = '';
// Ticket for user, can be created by running "p4 -u $username login -pa"
$ticket = '';
/* **************************************************** */
// If the super user wants to reopen the files of the end user.
$reopen = true;
// Prebuild the the return message helper array.
$help = array( "help" => "", "error" => "", "results" => "", "search_criteria" => "");
// @codingStandardsIgnoreEnd
/**
* function that make the GET or POST requests
*
* @param $url Url in which we want to make our request to
* @param bool $fetch Set to true for a GET request, otherwise will do a POST.
* @param array $args These are the parameter that we pass the the GET or POST request to filter the reviews
* @return JSON We return a JSON object back to be worked on.
*/
function request($url, $fetch = false, $args = array())
{
// Fetch the settings to allow this function to access them.
global $username, $ticket, $reopen, $help;
$curl = '';
// If GET request fetch should be true and args shouldn't be empty
if ($fetch === true) {
// If is args is empty just give the url, otherwise build a http query with args elements
$curl = empty($args) ? curl_init($url) : curl_init($url."?".http_build_query($args));
} else {
// Assume fetch is false and build a POST request.
$curl = curl_init($url."/".$args['id'].'/cleanup');
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('reopened'=>$reopen)));
curl_setopt($curl, CURLOPT_POST, count($reopen));
}
curl_setopt($curl, CURLOPT_USERPWD, "$username:$ticket");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$result = curl_exec($curl);
// Catch the error code in case Ticket expired or url doesn't return.
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($statusCode != 200) {
$help['error'] = array("HTTP code" => $statusCode);
}
curl_close($curl);
return json_decode($result, true);
}
/**
* Fetch a list of Reviews based on parameters
*
* @param $elements Each of the args passed from command line are treated as elements
* @return JSON We return a JSON object back to be worked on.
*/
function fetchReviews($elements)
{
global $swarmURL, $help;
$parameters = array();
if ($elements !== null) {
// Loop though each of the args we want to fetch reviews based on
foreach ($elements as $key => $value) {
// Break each of the element into key and value to allow use to build a array to pass to url
$brokenDown = explode("=", $value);
if ($key !== 0 && sizeof($brokenDown) === 2) {
$parameters[$brokenDown[0]] = $brokenDown[1];
}
}
// We only require the field id to limit the amount of data.
$parameters['fields'] = 'id';
// Helpful for debugging which parameters we have passed in the queue.
$help['search_criteria'] = $parameters;
}
// Now make the request to the Swarm server with your field options.
$result = request(
"$swarmURL/api/v6/reviews",
true,
$parameters
);
// Return the JSON object back to be worked on.
return $result;
}
/**
* Loop though each of the Reviews passed in and run clean up for them.
*
* @param $reviews JSON object of all the reviews we want to run cleanup on
* $reviews => array(
* 'reviews' => array(
* 0 => array (
* 'id' => 134,
* ),
* 1 => array (
* 'id' => 136,
* ),
* 2 => array (
* 'id' => 143,
* ),
* 3 => array (
* 'id' => 158,
* )
* )
* )
*
* @return $array return the array of work that has been carried out.
*/
function runCleanUp($reviews)
{
global $swarmURL;
$results = array();
// Check if there is an reviews element of the array
if (isset($reviews['reviews'])) {
foreach ($reviews['reviews'] as $review) {
// Now make the request to the Swarm for each review.
$results[$review['id']] = request(
"$swarmURL/api/v6/reviews",
false,
$review
);
}
}
return $results;
}
/**
* The help function in case a user doesn't set the basic settings.
*
* @param $help Pass the help array from main script to append the helpful message.
* @return $array Return the array that will be presented to the users.
*/
function helpMessage($help)
{
$help["help"] = array( "1" => "", "2" => "", "3" => "" );
$help["help"]["1"] = "Please ensure you have set the Username, Ticket and Swarm URL before using this script";
$help["help"]["2"] = "Running the script can be done by using any of the standard Swarm API fields for reviews";
$help["help"]["3"] = "Visit https://www.perforce.com/perforce/doc.current/manuals/swarm/index.html";
return $help;
}
// check the first argument is not help.
$helpSet = isset($argv[1]) && $argv[1] == "help" ? "help" : null;
// Check if the user has given help as a command to this script.
if (isset($argv[1]) && $helpSet == "help") {
// Set the $help array with the help message.
$help = helpMessage($help);
}
// Check if the basic user ticket and swarmurl are set.
if (!empty($username) && !empty($ticket) && !empty($swarmURL) && $helpSet != "help") {
try {
$help["results"] = runCleanUp(fetchReviews($argv));
} catch (Exception $e) {
$help = helpMessage($help);
}
} else {
$message = "Please ensure you have set the below before using this script";
$errorArray = array("message" => $message, "parameter" => "");
$missingParameter = array();
// Now check if the basic settings are empty and show the end user.
empty($username) ? $missingParameter[] = "Username":'';
empty($ticket) ? $missingParameter[] = "Ticket":'';
empty($swarmURL) ? $missingParameter[] = "SwarmURL":'';
$errorArray['parameter'] = $missingParameter;
$help["error"] = $errorArray ;
}
// Output the end result of the what the script does.
echo json_encode($help, JSON_FORCE_OBJECT);
// @codingStandardsIgnoreEnd
The example is written in PHP, and demonstrates how to make use of the APIs which remove unneeded pending changelists. It must be run as a super user.
For a full set of instructions on how to use the example script, see the comments in the script itself.
Abbreviated instructions:
Set the value of the $swarmURL
, $username
and $ticket
variables.
Run the script by using a command similar to the following:
$ php pendingReviewCleanUp.php max=10 author=bruno state=approved