REST API: The Plastic SCM API
Introduction
Welcome to the Plastic SCM client REST API documentation!
This API allows programmers to perform Plastic client operations in their machine, provided that a Plastic client is
already in place and configured.
It's implemented in a REST fashion, meaning that virtually any language can interact with it through HTTP connections.
Each of the supported Plastic client operations is exposed using a different URI and HTTP method. You read the
detailed endpoint documentation for further information.
How to use the API
Executing commands through the Plastic REST API is straightforward. Use your programming language of choice and
perform an HTTP request against the appropriate URI by setting the HTTP method matching your targeted endpoint and
including the request body format stated by said endpoint.
The API requests are received by a simple, standalone HTTP server, exposed by the cm api command.
Important: The user account running the cm api command must have a valid Plastic SCM configuration.
You can issue a cm checkconnection from a command line shell to see if the user has a valid configuration.
Note: You can find the
cm application in the Plastic SCM client directory:
- Windows -
C:\Program Files\PlasticSCM5\client
- macOS -
/Applications/PlasticSCM.app/Contents/Applications
- Linux -
/opt/plasticscm5/client
Starting the API
You can execute the cm api HTTP server application in a shell by running the cm api command.
Use the cm api --help command to show the help for the cm api command.
This is how the cm api command syntax looks like:
cm api [(-p | --port) <portnumber>] [-r | --remote]
The available parameters are:
-
-p <port-number>
- Tells the server to listen on port <port-number>
instead
of 9090.
-
-r
- Allows incoming remote connections. This means connections that come from other hosts instead of
the local one.
Examples:
-
Starts the API listening on port 9090, accepting local connections only:
cm api
-
Starts the API listening on port 65000, accepting local connections only:
cm api -p 65000
-
Starts the API listening on port 9090, allowing any incoming connection (remote requests):
cm api -r
-
Starts the API listening on port 65000, allowing any incoming connection (remote requests):
cm api -p 65000 -r
In all cases, the following message indicates the successful launch of the cm api:
Plastic SCM client REST API: Press <ENTER> to exit.
Troubleshooting
The cm api does not start
-
If the API does not start, the following message displays:
Unable to start the REST API listener. Please make sure that you have HTTP permissions for the current port and user.
The most common issue that prevents the start of the cm api is that the Plastic SCM user is not configured.
The user running cm api must have a valid Plastic SCM client configuration with the
Plastic SCM server. To validate this requirement, open a command line shell from the same user account running
cm api and type cm checkconnection.
If the command output shows Test connection executed successfully, the Plastic SCM configuration is
valid. Otherwise, follow the instructions shown by the command output.
Examples
Java example
package com.codice.examples;
import com.codice.examples.actions.CreateRepositoryAction;
import com.codice.examples.actions.RenameAction;
import com.codice.examples.models.Repository;
import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
import java.util.List;
import java.util.Scanner;
public class Program {
static IApi apiClient;
static Scanner in;
static String instructions = "1 - List repositories (cm repository list)\n" +
"2 - Create a repository (cm repository create)\n" +
"3 - Rename a repository (cm repository rename)\n" +
"4 - Delete a repository (cm repository delete)\n" +
"\n" +
"Select an option (1/2/3/4): ";
static void initApiClient() {
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint("http://localhost:9090")
.build();
apiClient = adapter.create(IApi.class);
}
static void listRepositories() {
List<Repository> repositories = apiClient.getRepositories();
for(Repository repo : repositories) {
System.out.println(String.format("%d_%d %s %s",
repo.getRepId().getId(),
repo.getRepId().getModuleId(),
repo.getName(),
repo.getServer()));
}
}
static void createRepository() {
System.out.print("Write a name for the repository: ");
String name = in.nextLine();
System.out.print("Write the direction of the server: ");
String server = in.nextLine();
CreateRepositoryAction action =
new CreateRepositoryAction(name, server);
Repository newRepo = apiClient.createRepository(action);
System.out.println(String.format(
"Repository %s successfully created!", newRepo.getName()));
}
static void renameRepository() {
listRepositories();
System.out.print("Write the name of the repository to rename: ");
String repository = in.nextLine();
System.out.print(String.format("Write a new name for %s: ", repository));
String newName = in.nextLine();
RenameAction action = new RenameAction(newName);
Repository renamedRepo =
apiClient.renameRepository(repository, action);
System.out.println(
String.format("Repository %s successfully renamed to %s.",
repository, renamedRepo.getName())
);
}
static void deleteRepository() {
listRepositories();
System.out.print("Write the name of the repository to delete: ");
String repository = in.nextLine();
apiClient.deleteRepository(repository, new Callback<Void>() {
@Override
public void success(Void aVoid, Response response) {
// Retrofit limitation. Here, we should only check the
// status code.
System.out.println("Repository successfully deleted!");
}
@Override
public void failure(RetrofitError retrofitError) {
}
});
}
public static void main(String[] args) {
initApiClient();
System.out.print(instructions);
in = new Scanner(System.in);
String optionStr = in.nextLine();
int option;
try {
option = Integer.valueOf(optionStr);
} catch (NumberFormatException e) {
option = 1;
}
switch (option) {
case 1:
default:
listRepositories();
break;
case 2:
createRepository();
break;
case 3:
renameRepository();
break;
case 4:
deleteRepository();
break;
}
}
}
package com.codice.examples.actions;
import com.sun.istack.internal.NotNull;
public class CreateRepositoryAction {
private String name;
private String server;
public CreateRepositoryAction(@NotNull String name,
@NotNull String server) {
this.name = name;
this.server = server;
}
}
package com.codice.examples.actions;
import com.sun.istack.internal.NotNull;
public class RenameAction {
private String name;
public RenameAction(@NotNull String name) {
this.name = name;
}
}
package com.codice.examples.models;
public class Owner {
private String name;
private boolean isGroup;
public String getName() { return name; }
public boolean isGroup() { return isGroup; }
}
package com.codice.examples.models;
public class RepId {
private int id;
private int moduleId;
public int getId() { return id; }
public int getModuleId() { return moduleId; }
}
package com.codice.examples.models;
import java.util.UUID;
public class Repository {
private RepId repId;
private Owner owner;
private String name;
private UUID guid;
private String server;
public RepId getRepId() { return repId; }
public Owner getOwner() { return owner; }
public String getName() { return name; }
public UUID getGuid() { return guid; }
public String getServer() { return server; }
}
package com.codice.examples;
import com.codice.examples.actions.CreateRepositoryAction;
import com.codice.examples.actions.RenameAction;
import com.codice.examples.models.Repository;
import retrofit.Callback;
import retrofit.http.*;
import java.util.List;
public interface IApi {
@GET("/api/v1/repos")
List<Repository> getRepositories();
@POST("/api/v1/repos")
Repository createRepository(@Body CreateRepositoryAction params);
@PUT("/api/v1/repos/{repname}")
Repository renameRepository(@Path("repname") String repositoryName,
@Body RenameAction params);
@DELETE("/api/v1/repos/{repname}")
void deleteRepository(@Path("repname") String repositoryName,
Callback<Void> callback); // Retrofit limitation.
}
C# example
using Csharp_examples.Actions;
using Csharp_examples.Models;
using Csharp_examples.Utils;
using System;
using System.Collections.Generic;
namespace Csharp_examples
{
class Program
{
static void Main(string[] args)
{
Console.Write(mActions);
string optionStr = Console.ReadLine();
int option;
Int32.TryParse(optionStr, out option);
switch (option)
{
case 1:
default:
ListRepositories();
break;
case 2:
CreateRepository();
break;
case 3:
RenameRepository();
break;
case 4:
DeleteRepository();
break;
}
}
static void ListRepositories()
{
List<Repository> repositories = ApiUtils.ReadRepositoryList().Result;
foreach (Repository repo in repositories)
{
Console.WriteLine(string.Format(" {0}_{1} {2} {3}",
repo.RepId.Id, repo.RepId.ModuleId, repo.Name, repo.Server));
}
}
static void CreateRepository()
{
Console.Write("Write a name for the repository: ");
string name = Console.ReadLine();
Console.Write("Write the direction of the server: ");
string server = Console.ReadLine();
CreateRepository action = new CreateRepository()
{
Name = name,
Server = server
};
Repository newRepo = ApiUtils.CreateRepository(action).Result;
Console.Write(string.Format("Repository {0} successfully created!", newRepo.Name));
}
static void RenameRepository()
{
ListRepositories();
Console.Write("Write the name of the repository to rename: ");
string repository = Console.ReadLine();
Console.Write(string.Format("Write a new name for {0}: ", repository));
string newName = Console.ReadLine();
Rename action = new Rename()
{
Name = newName
};
Repository renamedRepo = ApiUtils.RenameRepository(repository, action).Result;
Console.Write(string.Format("Repository {0} successfully renamed to {1}.",
repository, renamedRepo.Name));
}
static void DeleteRepository()
{
ListRepositories();
Console.Write("Write the name of the repository to delete: ");
string repository = Console.ReadLine();
ApiUtils.DeleteRepository(repository).Wait();
Console.Write(string.Format("Repository {0} successfully deleted!", repository));
}
static string mActions = @"1 - List repositories (cm repository list)
2 - Create a repository (cm repository create)
3 - Rename a repository (cm repository rename)
4 - Delete a repository (cm repository delete)
Select an option (1/2/3/4): ";
}
}
namespace Csharp_examples.Actions
{
public class CreateRepository
{
public string Name { get; set; }
public string Server { get; set; }
}
}
namespace Csharp_examples.Actions
{
public class Rename
{
public string Name { get; set; }
}
}
namespace Csharp_examples.Models
{
public class Owner
{
public string Name { get; set; }
public bool IsGroup { get; set; }
}
}
namespace Csharp_examples.Models
{
public class RepId
{
public int Id { get; set; }
public int ModuleId { get; set; }
}
}
using System;
namespace Csharp_examples.Models
{
public class Repository
{
public RepId RepId { get; set; }
public Owner Owner { get; set; }
public string Name { get; set; }
public Guid Guid { get; set; }
public string Server { get; set; }
}
}
using Csharp_examples.Actions;
using Csharp_examples.Models;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Csharp_examples.Utils
{
public class ApiUtils
{
static HttpClient GetHttpClient()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:9090/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public static async Task<List<Repository>> ReadRepositoryList()
{
HttpClient client = GetHttpClient();
using (client)
{
HttpResponseMessage response = await client.GetAsync("api/v1/repos");
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception(string.Format(
"API Status Code {0}. Expected OK.", response.StatusCode));
return await response.Content.ReadAsAsync<List<Repository>>();
}
}
public static async Task<Repository> CreateRepository(CreateRepository createParams)
{
HttpClient client = GetHttpClient();
using (client)
{
HttpResponseMessage response =
await client.PostAsJsonAsync("api/v1/repos", createParams);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception(string.Format(
"API Status Code {0}. Expected OK.", response.StatusCode));
return await response.Content.ReadAsAsync<Repository>();
}
}
public static async Task<Repository> RenameRepository(string repositoryName, Rename renameParam)
{
HttpClient client = GetHttpClient();
string uri = string.Format("api/v1/repos/{0}", repositoryName);
using (client)
{
HttpResponseMessage response =
await client.PutAsJsonAsync(uri, renameParam);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception(string.Format(
"API Status Code {0}. Expected OK.", response.StatusCode));
return await response.Content.ReadAsAsync<Repository>();
}
}
public static async Task DeleteRepository(string repositoryName)
{
HttpClient client = GetHttpClient();
string uri = string.Format("api/v1/repos/{0}", repositoryName);
using (client)
{
HttpResponseMessage response =
await client.DeleteAsync(uri);
if (response.StatusCode != System.Net.HttpStatusCode.NoContent)
throw new Exception(string.Format(
"API Status Code {0}. Expected NoContent.", response.StatusCode));
}
}
}
}
Python example
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_repositories(repositories):
line = "{0} {1} {2}"
for repo in repositories:
print(line.format(repo["repId"]["id"],
repo["name"],
repo["server"]))
def get_repositories():
url = __api_url + "/repos"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("The repository list could not be retrieved.", file=sys.stderr)
exit(-1)
def main():
try:
print_repositories(get_repositories())
except requests.RequestException as e:
print(e)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def create_repository(name, server):
url = __api_url + "/repos"
params = {"name": name,
"server": server}
req = requests.post(url, params)
if req.status_code is not 200:
print("The repository could not be created", file=sys.stderr)
exit(-1)
def main():
name = input("Write a name for the new repository: ")
server = input("Enter the PlasticSCM server address: ")
try:
create_repository(name, server)
except requests.RequestException as e:
print(e)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_repositories(repositories):
line = "{0} {1} {2}"
for repo in repositories:
print(line.format(repo["repId"]["id"],
repo["name"],
repo["server"]))
def get_repositories():
url = __api_url + "/repos"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("The repository list could not be retrieved.", file=sys.stderr)
exit(-1)
def rename_repo(old_name, new_name):
url = __api_url + "/repos/" + old_name
params = {"name": new_name}
req = requests.put(url, params)
if req.status_code is not 200:
print("The repository could not be created.", file=sys.stderr)
exit(-1)
def main():
try:
print_repositories(get_repositories())
old_name = input("\nWrite the name of the repository to rename: ")
new_name = input("Write a new name for the repository " + old_name + ": ")
rename_repo(old_name, new_name)
print_repositories(get_repositories())
except requests.RequestException as e:
print(e, file=sys.stderr)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_repositories(repositories):
line = "{0} {1} {2}"
for repo in repositories:
print(line.format(repo["repId"]["id"],
repo["name"],
repo["server"]))
def get_repositories():
url = __api_url + "/repos"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("The repository list could not be retrieved.", file=sys.stderr)
exit(-1)
def remove_repo(name):
url = __api_url + "/repos/" + name
req = requests.delete(url)
if req.status_code is not 204:
print("The repository could not be deleted", file=sys.stderr)
exit(-1)
def main():
try:
print_repositories(get_repositories())
repo = input("Write the name of the repository to delete: ")
remove_repo(repo)
print_repositories(get_repositories())
except requests.RequestException as e:
print(e, file=sys.stderr)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_workspaces(wkspaces):
line = "Name: {0}, path: {1}"
for wkspace in wkspaces:
print(line.format(wkspace["name"],
wkspace["path"]))
def get_workspaces():
url = __api_url + "/wkspaces"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("Workspace list could not be retrieved.", file=sys.stderr)
exit(-1)
def main():
try:
print_workspaces(get_workspaces())
except requests.RequestException as e:
print(e, file=sys.stderr)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_repositories(repositories):
line = "{0} {1} {2}"
for repo in repositories:
print(line.format(repo["repId"]["id"],
repo["name"],
repo["server"]))
def get_repositories():
url = __api_url + "/repos"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("The repository list could not be retrieved.", file=sys.stderr)
exit(-1)
def create_workspace(name, path, repository):
url = __api_url + "/wkspaces"
params = {"name": name,
"path": path,
"repository": repository}
req = requests.post(url, params)
if req.status_code is not 200:
print("The workspace could not be created.", file=sys.stderr)
exit(-1)
def main():
try:
print_repositories(get_repositories())
repository = input("Write the name of a repository to create a new workspace to: ")
name = input("Write the name for the new workspace: ")
path = input("Write the path for the new workspace: ")
create_workspace(name, path, repository)
except requests.RequestException as e:
print(e, file=sys.stderr)
exit(-1)
if __name__ == "__main__":
main()
import sys
import requests
__api_url = "http://localhost:9090/api/v1"
def print_workspaces(wkspaces):
line = "Name: {0}, path: {1}"
for wkspace in wkspaces:
print(line.format(wkspace["name"],
wkspace["path"]))
def get_workspaces():
url = __api_url + "/wkspaces"
req = requests.get(url)
if req.status_code is 200:
return req.json()
print("Workspace list could not be retrieved.", file=sys.stderr)
exit(-1)
def remove_workspace(name):
url = __api_url + "/wkspaces/" + name
req = requests.delete(url)
if req.status_code is not 204:
print("The workspace could not be deleted.", file=sys.stderr)
sys.exit(-1)
def main():
try:
print_workspaces(get_workspaces())
name = input("Write the name of the workspace to delete: ")
remove_workspace(name)
except requests.RequestException as e:
print(e, file=sys.stderr)
exit(-1)
if __name__ == "__main__":
main()
API Reference
Repositories
GET /api/v1/repos
Response
Status: 200 OK
[
{
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "default",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
]
GET /api/v1/repos/:repname
Response
Status: 200 OK
{
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "default",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
POST /api/v1/repos
Parameters
Name |
Type |
Description |
name |
string |
Required. The name of the new repository. |
server |
string |
The target server where the repository should be created. |
Example
{
"name": "repName",
"server": "myserver:8084"
}
Response
The repository data will be returned once the operation is complete.
Status: 200 OK
{
"repId":
{
"id": 2,
"moduleId": 0
},
"name": "repName",
"guid": "c45b8af3-1a10-d31f-baca-c00590d12456",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "myserver:8084"
}
PUT /api/v1/repos/:repname
Parameters
Name |
Type |
Description |
name |
string |
Required. The new name for the repository. |
Example
{
"name": "newName"
}
Response
The updated repository data will be returned once the operation is complete.
Status: 200 OK
{
"repId":
{
"id": 2,
"moduleId": 0
},
"name": "newName",
"guid": "c45b8af3-1a10-d31f-baca-c00590d12456",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "myserver:8084"
}
DELETE /api/v1/repos/:repname
Response
Status: 204 No Content
Workspaces
GET /api/v1/wkspaces
Response
Status: 200 OK
[
{
"name": "my_wk",
"guid": "e93518f8-20a6-4534-a7c6-f3d9ebac45cb",
"path": "c:\\path\\to\\workspace",
"machineName": "MACHINE"
}
]
GET /api/v1/wkspaces/:wkname
Response
Status: 200 OK
{
"name": "my_wk",
"guid": "e93518f8-20a6-4534-a7c6-f3d9ebac45cb",
"path": "c:\\path\\to\\workspace",
"machineName": "MACHINE"
}
POST /api/v1/wkspaces
Parameters
Name |
Type |
Description |
name |
string |
Required. The name of the new workspace. |
path |
string |
Required. The target path where the repository should be created. |
repository |
string |
The source repository for the new workspace. |
Example
{
"name": "new_wk",
}
Response
The workspace data will be returned once the operation is complete.
Status: 200 OK
{
"name": "new_wk"
"guid": "ed3248d2-5591-407a-94e6-84dac0ce015b"
"path": "c:\\the\\path\\to\\new_wk"
"machineName": "MACHINE"
}
PUT /api/v1/wkspaces/:wkname
Parameters
Name |
Type |
Description |
name |
string |
Required. The new name for the workspace. |
Example
{
"name": "newName"
}
Response
The updated workspace data will be returned once the operation is complete.
Status: 200 OK
{
"name": "newName"
"guid": "ed3248d2-5591-407a-94e6-84dac0ce015b"
"path": "c:\\the\\path\\to\\new_wk"
"machineName": "MACHINE"
}
DELETE /api/v1/wkspaces/:wkname
Response
Status: 204 No Content
Branches
GET /api/v1/repos/:repname/branches
Parameters
Name |
Type |
Description |
q |
string |
An optional constraints string using the cm find command syntax. |
Example
GET http://localhost:9090/api/v1/repos/myrepo/branches?q=id > 50
Response
Status: 200 OK
[
{
"name": "/main/task001/task002",
"id": 1388,
"parentId": 1067,
"lastChangeset": 1383,
"comment": "Testing: implement new smoke tests.",
"creationDate": "2015-06-30T15:18:08",
"guid": "0ced86fe-37cb-4801-8f6d-0081edb46d39",
"owner": {
"name": "codice-master",
"isGroup": false
},
"repository": {
"name": "mainrepo",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
]
GET /api/v1/repos/:repname/branches/:branchname
Please note that branch names are hierarchical.
Request example
GET /api/v1/repos/mainrepo/branches/main/task001/task002
Response
Status: 200 OK
{
"name": "/main/task001/task002",
"id": 1388,
"parentId": 1067,
"lastChangeset": 1383,
"comment": "Testing: implement new smoke tests.",
"creationDate": "2015-06-30T15:18:08",
"guid": "0ced86fe-37cb-4801-8f6d-0081edb46d39",
"owner": {
"name": "codice-master",
"isGroup": false
},
"repository": {
"name": "mainrepo",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
POST /api/v1/repos/:repname/branches
Parameters
Name |
Type |
Description |
name |
string |
Required. The branch name. Do not use hierarchy here. |
originType |
string |
Required. The type of source to retrieve the parent changeset of the new branch. It can be changeset, label or branch. See examples for further detail. |
origin |
string |
Required. The point of origin from which the branch will be created. |
topLevel |
boolean |
Whether or not the branch will be top-level (i.e. it will have no parent). Set to false by default. |
Examples
{
"name": "newBranch",
"originType": "branch",
"origin": "/main/scm003",
"topLevel": false
}
{
"name": "newBranch",
"originType": "label",
"origin": "BL000",
"topLevel": true
}
{
"name": "newBranch",
"originType": "changeset",
"origin": "97",
"topLevel": false
}
Response
The created branch info will be returned once the operation is complete.
Status: 200 OK
{
"name": "/main/scm003/newBranch",
"id": 1395,
"parentId": 1067,
"lastChangeset": 1383,
"creationDate": "2015-07-01T09:01:08",
"guid": "3416a2b4-f88a-43b1-8319-3424bc23c77b",
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
PATCH /api/v1/repos/:repname/branches/:branchname
Parameters
Name |
Type |
Description |
name |
string |
Required. The new name for the branch. Please have in mind that branch hierarchy cannot be changed. |
Example
{
"name": "/main/task001/task003"
}
Response
The updated branch info will be returned once the operation is complete.
Status: 200 OK
{
"name": "/main/task001/task003",
"id": 1388,
"parentId": 1067,
"lastChangeset": 1383,
"comment": "Testing: implement new smoke tests.",
"creationDate": "2015-06-30T15:18:08",
"guid": "0ced86fe-37cb-4801-8f6d-0081edb46d39",
"owner": {
"name": "codice-master",
"isGroup": false
},
"repository": {
"name": "mainrepo",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
Only empty branches with no children can be removed.
DELETE /api/v1/repos/:repname/branches/:branchname
Response
Status: 204 No Content
Labels
GET /api/v1/repos/:repname/labels
Parameters
Name |
Type |
Description |
q |
string |
An optional constraints string using the cm find command syntax. |
Example
GET http://localhost:9090/api/v1/repos/myrepo/labels?q=date > '2015-07-01'
Response
Status: 200 OK
[
{
"name": "BL000",
"id": 1391,
"changeset": 100,
"comment": "",
"creationDate": "2015-07-01T07:45:56",
"branch": {
"name": "/main",
"id": 3,
"parentId": -1,
"lastChangeset": 101,
"comment": "main branch",
"creationDate": "2015-04-09T07:17:00",
"guid": "5fc2d7c8-05e1-4987-9dd9-74eaec7c27eb",
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
]
GET /api/v1/repos/:repname/labels/:labelname
Response
Status: 200 OK
{
"name": "BL000",
"id": 1391,
"changeset": 100,
"branch": {
"name": "/main",
"id": 3,
"parentId": -1,
"lastChangeset": 101,
"comment": "main branch",
"creationDate": "2015-04-09T07:17:00",
"guid": "5fc2d7c8-05e1-4987-9dd9-74eaec7c27eb",
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"comment": "",
"creationDate": "2015-07-01T07:45:56",
"owner": {
"name": "tester",
"isGroup": false
}
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
POST /api/v1/repos/:repname/labels/
Parameters
Name |
Type |
Description |
name |
string |
Required. The new name for the label. |
changeset |
integer |
Required. The changeset to label. |
comment |
string |
The comment to add to the label. |
applyToXlinks |
boolean |
If true, all xlinked changesets present in the specified changeset tree will be labelled as well. Set to false by default. |
Example
{
"name": "BL001",
"changeset": 99,
"comment": "Stable baseline - 1",
"applyToXlinks": false
}
Response
The created label info will be returned once the operation is complete.
Status: 200 OK
{
"name": "BL001",
"id": 1401,
"changeset": 99,
"comment": "Stable baseline - 1",
"creationDate": "2015-07-01T10:19:14",
"branch": {
"name": "/main",
"id": 3,
"parentId": -1,
"lastChangeset": 101,
"comment": "main branch",
"creationDate": "2015-04-09T07:17:00",
"guid": "5fc2d7c8-05e1-4987-9dd9-74eaec7c27eb",
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
PATCH /api/v1/repos/:repname/labels/:labelname
Parameters
Name |
Type |
Description |
name |
string |
Required. The new name for the label. |
Example
{
"name": "v1.0.0",
}
Response
The updated label info will be returned once the operation is complete.
Status: 200 OK
{
"name": "v1.0.0",
"id": 1401,
"changeset": 99,
"comment": "Stable baseline - 1",
"creationDate": "2015-07-01T10:19:14",
"branch": {
"name": "/main",
"id": 3,
"parentId": -1,
"lastChangeset": 101,
"comment": "main branch",
"creationDate": "2015-04-09T07:17:00",
"guid": "5fc2d7c8-05e1-4987-9dd9-74eaec7c27eb",
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
DELETE /api/v1/repos/:repname/labels/:labelname
Response
Status: 204 No Content
Changesets
GET /api/v1/repos/:repname/changesets
Parameters
Name |
Type |
Description |
q |
string |
An optional constraints string using the cm find command syntax. |
Example
GET http://localhost:9090/api/v1/repos/myrepo/changesets?q=date > '2015-07-01'
Response
Status: 200 OK
[
{
"id": 0,
"parentId": -1,
"comment": "Root dir",
"creationDate": "2015-04-09T07:17:00",
"guid": "0497ef04-4c81-4090-8458-649885400c84",
"branch": {
"name": "\/main",
"id": 3,
"parentId": -1,
"lastChangeset": 101,
"comment": "main branch",
"creationDate": "2015-04-09T07:17:00",
"guid": "5fc2d7c8-05e1-4987-9dd9-74eaec7c27eb",
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "all",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
...
]
GET /api/v1/repos/:repname/branches/:branchname/changesets
Parameters
Name |
Type |
Description |
q |
string |
An optional constraints string using the cm find command syntax. |
Example
GET http://localhost:9090/api/v1/repos/myrepo/branches/main/changesets?q=changesetid > 50
Response
Status: 200 OK
[
{
"id": 77,
"parentId": 76,
"comment": "checkin TaskOnBranch test",
"creationDate": "2015-06-02T08:59:12",
"guid": "799e4fd3-1161-4f8f-be4f-067dbe98ed89",
"branch": {
"name": "/main/scm003",
"id": 1067,
"parentId": 3,
"lastChangeset": 1383,
"comment": "text\r\n",
"creationDate": "2015-06-02T08:46:11",
"guid": "e99e8843-9bd9-43eb-ad67-c170b516a032",
"owner": {
"name": "testing01",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "testing01",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
]
GET /api/v1/repos/:repname/changesets/:changesetid
Response
Status: 200 OK
{
"id": 77,
"parentId": 76,
"comment": "checkin TaskOnBranch test",
"creationDate": "2015-06-02T08:59:12",
"guid": "799e4fd3-1161-4f8f-be4f-067dbe98ed89",
"branch": {
"name": "/main/scm003",
"id": 1067,
"parentId": 3,
"lastChangeset": 1383,
"comment": "text\r\n",
"creationDate": "2015-06-02T08:46:11",
"guid": "e99e8843-9bd9-43eb-ad67-c170b516a032",
"owner": {
"name": "testing01",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
},
"owner": {
"name": "testing01",
"isGroup": false
},
"repository": {
"name": "default",
"repId": {
"id": 1,
"moduleId": 0
},
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner": {
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
Changes
GET /api/v1/wkspaces/:wkname/changes
Parameters
Name |
Type |
Description |
types |
string |
A comma-separated list detailing the desired change types to display in the response. Available types: added , checkout , changed , copied , replaced , deleted , localdeleted , moved , localmoved , private , ignored , hiddenchanged , controlledchanged , all |
Response
Status: 200 OK
[
{
"changes": [
"CH",
"MV"
],
"path": "c:\\Users\\scm-user\\wkspaces\\main-wk\\audio-prj\\orchestrated.fspro",
"oldPath": "c:\\Users\\scm-user\\wkspaces\\main-wk\\audio-prj\\audio-prj.fspro",
"serverPath": "/audio-prj/orchestrated.fspro",
"oldServerPath": "/audio-prj/audio-prj.fspro",
"isXlink": false,
"localInfo": {
"modifiedTime": "2015-07-02T11:16:07.0042908Z",
"size": 57906,
"isMissing": false
},
"revisionInfo": {
"id": 65,
"parentId": -1,
"itemId": 187,
"type": "text",
"size": 57896,
"hash": "tLq1aWZ24MGupAHKZAgYFA==",
"branchId": 3,
"changesetId": 3,
"isCheckedOut": false,
"creationDate": "2015-04-09T09:51:20",
"repositoryId": {
"id": 1,
"moduleId": 0
},
"owner": {
"name": "scm-user",
"isGroup": false
}
}
}
]
DELETE /api/v1/wkspaces/:wkname/changes
Parameters
Name |
Type |
Description |
paths |
string[] |
A list of file paths to be restored. They can be either full paths or workspace-relative paths. See examples for further info. |
Examples
{
"paths": [
"c:\\Users\\scm-user\\wkspaces\\main-wk\\audio-prj\\orchestrated.fspro"
]
}
{
"paths": [
"audio-prj/orchestrated.fspro"
]
}
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\Users\\scm-user\\wkspaces\\main-wk\\audio-prj\\orchestrated.fspro"
]
}
Workspace Update and Switch
GET /api/v1/wkspaces/:wkname/update
GET /api/v1/wkspaces/:wkname/switch
Response
Status: 200 OK
{
"status": "Not running"
}
Status: 200 OK
{
"status": "Failed",
"message": "No route to host 'localhost:8084'"
}
Status: 200 OK
{
"status": "Calculating",
"totalFiles": 1356,
"totalBytes": 3246739,
"updatedFiles": 0,
"updatedBytes": 0
}
Status: 200 OK
{
"status": "Running",
"totalFiles": 1356,
"totalBytes": 3246739,
"updatedFiles": 356,
"updatedBytes": 894433
}
Status: 200 OK
{
"status": "Finished",
"totalFiles": 1356,
"totalBytes": 3246739,
"updatedFiles": 1356,
"updatedBytes": 3246739
}
POST /api/v1/wkspaces/:wkname/update
Response
Status: 200 OK
{
"status": "Running",
"totalFiles": 0,
"totalBytes": 0,
"updatedFiles": 0,
"updatedBytes": 0
}
POST /api/v1/wkspaces/:wkname/switch
Parameters
Name |
Type |
Description |
objectType |
string |
Required. The type of switch destination. It can be changeset, label or branch.
When performing the switch operation on a partial workspace, this object can be a changeset or a branch.
See examples for further detail.
|
object |
string |
Required. The target point the workspace will be set to. |
Examples
{
"objectType": "branch",
"object": "/main/task001"
}
{
"objectType": "changeset",
"object": "1136"
}
{
"objectType": "label",
"object": "BL001"
}
Response
Status: 200 OK
{
"status": "Running",
"totalFiles": 0,
"totalBytes": 0,
"updatedFiles": 0,
"updatedBytes": 0
}
Checkin
GET /api/v1/wkspaces/:wkname/checkin
Response
Status: 200 OK
{
"status": "Not running"
}
Status: 200 OK
{
"status": "Failed",
"message": "No route to host 'localhost:8084'"
}
Status: 200 OK
{
"status": "Checkin finished",
"totalSize": 57990,
"transferredSize": 57990
}
POST /api/v1/wkspaces/:wkname/checkin
Parameters
Name |
Type |
Description |
paths |
string[] |
The list of target paths to be checked in. Set to the workspace root if empty or not present. |
comment |
string |
The checkin comment. |
recurse |
boolean |
If set to true, directories present in the paths parameter will have their children recursively checked in. If paths is empty or not present, its value is overridden to true. Defaults to false. |
Examples
{
}
{
"comment": "Upgrade core engine"
}
{
"paths": [
"src/foo.c",
"src/bar/baz.c",
"doc"
],
"comment": "Upgrade core engine",
"recurse": true
}
Response
Status: 200 OK
{
"status": "Checkin operation starting...",
"totalSize": 0,
"transferredSize": 0
}
Repository contents
GET /api/v1/repos/:repname/branches/:branchname/contents/:itempath
GET /api/v1/repos/:repname/changesets/:changesetid/contents/:itempath
GET /api/v1/repos/:repname/labels/:labelname/contents/:itempath
Directories will contain a list of items. Xlinks will contain an object referencing to the xlinked changeset.
Examples
GET /api/v1/repos/myrepo/branches/main/scm003/contents/src/lib/foo.c
GET /api/v1/repos/myrepo/changesets/5378/contents/src/lib/foo.c
GET /api/v1/repos/myrepo/labels/BL001/contents/src/lib/foo.c
Response
Status: 200 OK
{
"revisionId": 771,
"type": "file",
"size": 57913,
"name": "soundproject.fspro",
"path": "/fmod/soundproject.fspro",
"isUnderXlink": false,
"hash": "/2ygGGfoXDq9bbKZJCzj9g==",
"content": "http://localhost:9090/api/v1/repos/myrepo/revisions/771/blob",
"repository": {
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "myrepo",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
Status: 200 OK
{
"revisionId": 3648,
"type": "directory",
"size": 0,
"name": "lib",
"path": "/lib",
"isUnderXlink": false,
"items": [
{
"revisionId": 6878,
"type": "xlink",
"size": 0,
"name": "xlink",
"path": "/lib/xlink",
"xlinkTarget": {
"changesetGuid": "41acf2bd-1484-4679-a634-2570d9a7801b",
"changesetId": 2,
"repository": "big",
"server": "localhost:8084"
}
}
],
"repository": {
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "myrepo",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
Status: 200 OK
{
"revisionId": 2427,
"type": "directory",
"size": 0,
"name": "mono",
"path": "/lib/xlink/mono",
"isUnderXlink": true,
"items": [
{
"revisionId": 46348,
"type": "file",
"size": 26383,
"name": "COPYING.LIB",
"path": "/lib/xlink/mono/COPYING.LIB",
"hash": "uFbSL8ON1UNln1XUYeAc7w==",
"content": "http://localhost:9090/api/v1/repos/myrepo/revisions/46348/blob"
},
{
"type": "directory",
"size": 0,
"name": "data",
"path": "/lib/xlink/mono/data"
}
],
"repository": {
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "myrepo",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
GET /api/v1/repos/:repname/revisions/:revid
Response
Status: 200 OK
{
"revisionId": 3526,
"type": "file",
"size": 71,
"name": "foo.c",
"path": "/src/lib/foo.c",
"changeset": 1406,
"branch": "br:/main/scm003",
"hash": "tNYiUA4VyMJxJrK0kic7mg==",
"contents": "http://localhost:9090/api/v1/repos/myrepo/revisions/3526/blob",
"repository": {
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "myrepo",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
Status: 200 OK
{
"revisionId": 5355,
"type": "directory",
"size": 0,
"name": "lib",
"path": "/src/lib",
"changeset": 1406,
"branch": "br:/main/scm003",
"repository": {
"repId":
{
"id": 1,
"moduleId": 0
},
"name": "myrepo",
"guid": "c43e1cf9-50b0-4e0d-aca5-c1814d016425",
"owner":
{
"name": "all",
"isGroup": false
},
"server": "localhost:8084"
}
}
GET /api/v1/repos/:repname/revisions/:revid/blob
Response
Stream: application/octet-stream
GET /api/v1/repos/:repname/branches/:branchname/history/:itempath
GET /api/v1/repos/:repname/changesets/:changesetid/history/:itempath
GET /api/v1/repos/:repname/labels/:labelname/history/:itempath
Examples
GET /api/v1/repos/myrepo/branches/main/scm003/history/src/lib/foo.c
GET /api/v1/repos/myrepo/changesets/5378/history/src/lib/foo.c
GET /api/v1/repos/myrepo/labels/BL001/history/src/lib/foo.c
Response
Status: 200 OK
[
{
"revisionId": 104,
"type": "text",
"owner": {
"name": "tester",
"isGroup": false
},
"creationDate": "2015-04-09T09:51:20",
"comment": "Restore method implementation",
"revisionLink": "http://localhost:9090/api/v1/repos/myrepo/revisions/104",
"changesetId": 3,
"changesetLink": "http://localhost:9090/api/v1/repos/myrepo/changesets/3",
"branchName": "/main",
"branchLink": "http://localhost:9090/api/v1/repos/myrepo/branches/main",
"repositoryName": "myrepo",
"repositoryLink": "http://localhost:9090/api/v1/repos/myrepo"
}
]
Diff
GET /api/v1/repos/:repname/changesets/:changesetid/diff
GET /api/v1/repos/:repname/changesets/:changesetid/diff/:sourcechangesetid
If no source changeset ID is passed, the diff operation is performed using the parent changeset as source.
Response
Status: 200 OK
[
{
"status": "Changed",
"path": "/lib/xlink",
"isDirectory": true,
"isUnderXlink": false,
"xlink": {
"changesetGuid": "ff92e897-b662-40f1-9a1f-a17349cbc7c6",
"repository": "big",
"server": "localhost:8084"
},
"baseXlink": {
"changesetGuid": "c75c04ec-3546-46e4-bbb7-031b523dca7d",
"repository": "big",
"server": "localhost:8084"
},
"isItemFSProtectionChanged": false,
"itemFileSystemProtection": "NOT_DEFINED",
"repository": {
"name": "default",
"server": "localhost:8084"
}
},
{
"status": "Changed",
"path": "/lib/xlink/mono/.gitignore",
"revisionId": 150892,
"isDirectory": false,
"size": 1616,
"hash": "u0gJQzQnjLNUUHRI1+QQLg==",
"isUnderXlink": true,
"merges": [
{
"mergeType": "Merged",
"sourceChangeset": {
"id": 3,
"parentId": 2,
"comment": "multiple changes",
"creationDate": "2015-07-16T10:01:32",
"guid": "4d064ea0-4694-41b2-adec-15c3df243dd7",
"branch": {
"name": "\/main\/scm002",
"id": 150865,
"parentId": 3,
"lastChangeset": 3,
"comment": "",
"creationDate": "2015-07-16T10:01:30",
"guid": "764c4842-aab8-451a-b802-29162d2a399f",
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"guid": "301b269c-6d24-4347-afc1-f095da43f3f2",
"owner": {
"name": "testing01",
"isGroup": false
},
"server": "localhost:8084"
}
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"guid": "301b269c-6d24-4347-afc1-f095da43f3f2",
"owner": {
"name": "testing01",
"isGroup": false
},
"server": "localhost:8084"
}
}
}
],
"isItemFSProtectionChanged": false,
"itemFileSystemProtection": "NOT_DEFINED",
"modifiedTime": "2015-07-16T10:04:21",
"createdBy": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"server": "localhost:8084"
}
}
]
GET /api/v1/repos/:repname/branches/:branchname/diff
Response
Status: 200 OK
[
{
"status": "Changed",
"path": "/lib/xlink",
"isDirectory": true,
"isUnderXlink": false,
"xlink": {
"changesetGuid": "ff92e897-b662-40f1-9a1f-a17349cbc7c6",
"repository": "big",
"server": "localhost:8084"
},
"baseXlink": {
"changesetGuid": "c75c04ec-3546-46e4-bbb7-031b523dca7d",
"repository": "big",
"server": "localhost:8084"
},
"isItemFSProtectionChanged": false,
"itemFileSystemProtection": "NOT_DEFINED",
"repository": {
"name": "default",
"server": "localhost:8084"
}
},
{
"status": "Changed",
"path": "/lib/xlink/mono/.gitignore",
"revisionId": 150892,
"isDirectory": false,
"size": 1616,
"hash": "u0gJQzQnjLNUUHRI1+QQLg==",
"isUnderXlink": true,
"merges": [
{
"mergeType": "Merged",
"sourceChangeset": {
"id": 3,
"parentId": 2,
"comment": "multiple changes",
"creationDate": "2015-07-16T10:01:32",
"guid": "4d064ea0-4694-41b2-adec-15c3df243dd7",
"branch": {
"name": "\/main\/scm002",
"id": 150865,
"parentId": 3,
"lastChangeset": 3,
"comment": "",
"creationDate": "2015-07-16T10:01:30",
"guid": "764c4842-aab8-451a-b802-29162d2a399f",
"owner": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"guid": "301b269c-6d24-4347-afc1-f095da43f3f2",
"owner": {
"name": "testing01",
"isGroup": false
},
"server": "localhost:8084"
}
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"guid": "301b269c-6d24-4347-afc1-f095da43f3f2",
"owner": {
"name": "testing01",
"isGroup": false
},
"server": "localhost:8084"
}
}
}
],
"isItemFSProtectionChanged": false,
"itemFileSystemProtection": "NOT_DEFINED",
"modifiedTime": "2015-07-16T10:04:21",
"createdBy": {
"name": "tester",
"isGroup": false
},
"repository": {
"name": "big",
"repId": {
"id": 4,
"moduleId": 0
},
"server": "localhost:8084"
}
}
]
Workspace actions
POST api/v1/wkpaces/:wkname/content/:path
Parameters
Name |
Type |
Description |
addPrivateParents |
boolean |
If true, the command will add any parent directories which are not under version control yet. |
checkoutParent |
boolean |
If true, the parent node of the selected item will be checked out as a result. |
recurse |
boolean |
If true, causes all the children items to be recursively added. |
Example
POST http://localhost:9090/api/v1/wkspaces/mywk/content/src/lib
{
"addPrivateParents": true,
"checkoutParent": false,
"recurse": true
}
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\src\\lib\\descriptor.h",
"c:\\wkspaces\\mywk\\src\\lib\\code.c"
]
}
PUT api/v1/wkspaces/:wkname/content/:path
Example
PUT http://localhost:9090/api/v1/wkspaces/mywk/content/src/lib/code.c
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\src\\lib\\code.c"
]
}
PATCH api/v1/wkspaces/:wkname/content/:path
Parameters
Name |
Type |
Description |
destination |
string |
Required. Destination path to move the selected item. |
Example
PATCH http://localhost:9090/api/v1/wkspaces/mywk/content/src/lib/foo.c
{
"destination": "src/bar.c"
}
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\src\\bar.c"
]
}
DELETE api/v1/wkspaces/:wkname/content/:path
Example
DELETE http://localhost:9090/api/v1/wkspaces/mywk/content/src/lib/code.c
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\src\\lib\\code.c"
]
}
Merge
POST /api/v1/wkspaces/:wkName/merge
This operation doesn't support conflict resolution at the moment.
Parameters
Name |
Type |
Description |
sourceSpec |
string |
Required. Specification of the source object to merge from. This specification can be: a
branch specification, a label specification, a changeset specification, or a shelve specification.
|
Example
POST api/v1/wkspaces/mywk/merge
{
"sourceSpec": "br:/main/mybranch"
}
Response
Status: 200 OK
{
"resultStatus": "AncestorCalculated",
"success": true,
"status": "Completed",
"message": ""
}
Revert
PUT api/v1/wkspaces/:wkName/revert/:path_to_revert
Parameters
Name |
Type |
Description |
changeset |
number |
Required. Number of the changeset that contains the revision which content you want to
load in the workspace.
|
Example
PUT api/v1/wkspaces/mywk/revert/README.md
{
"changeset": 28
}
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\README.md"
]
}
File info
GET api/v1/wkspaces/:wkName/fileinfo/:path
Example
GET api/v1/wkspaces/mywk/fileinfo/mypath/testFile
Response
Status: 200 OK
{
"clientPath": "c:\\wkspaces\\mywk\\mypath\\testfile",
"relativePath": "/mypath/testFile",
"serverPath": "/testFile",
"repSpec": "default@localhost:18084",
"size": 7,
"hash": "NfQs54soPuRtsMAnxwAK7O==",
"owner": "user",
"revisionHeadChangeset": 2,
"revisionChangeset": 2,
"status": "controlled",
"type": "txt",
"changelist": ""
}
If the targeted path doesn't exist, this path will be treated as a private file:
{
"clientPath": "c:\\wkspaces\\mywk\\mypath\\testfile",
"relativePath": "/mypath/testFile",
"serverPath": "/testFile",
"repSpec": "",
"size": 0,
"hash": "",
"owner": "",
"revisionHeadChangeset": -1,
"revisionChangeset": -1,
"status": "private",
"type": "unknown",
"changelist": ""
}
If the targeted path is locked, the returned object will include the field locked
:
{
...,
"locked": {
"lockedBy": "john",
"lockedWhere": "coderepo"
}
}
If the targeted path is an Xlink, the returned object will include the field xlink
:
{
...,
"xlink": {
"xlinkWritable": true,
"xlinkRelative": true,
"xlinkTarget": "15011@libraryrepo@myserver:8085",
"xlinkName": "libxlink"
}
}
If the targeted path is under an Xlink, the returned object will include the field underXlink
:
{
...,
"underXlink": {
"underXlinkWritable": false,
"underXlinkRelative": true,
"underXlinkTarget": "2@default@localhost:18084",
"underXlinkPath": "/myxlink"
}
}
Undelete
POST api/v1/wkspaces/:wkName/undelete
Parameters
Name |
Type |
Description |
revSpec |
string |
Required. Specification of the revision whose contents will be loaded in the workspace.
|
path |
string |
Required. Restore path.
|
Example
POST api/v1/wkspaces/mywk/undelete
{
"revSpec": "rev:itemid:70#cs:16",
"path": "c:\\wkspaces\\mywk\\restoredFile"
}
Response
Status: 200 OK
{
"affectedPaths": [
"c:\\wkspaces\\mywk\\restoredFile"
]
}
Shelveset
POST api/v1/wkspaces/:wkName/shelvesets
Parameters
Name |
Type |
Description |
comment |
string |
Comment to apply when creating the shelveset. If empty or not present, the shelveset will have an empty comment.
|
paths |
string[] |
A list of file paths to shelve. If empty or not present, shelves all the pending changes in the current workspace.
|
Example
POST api/v1/wkspaces/mywk/shelvesets
{
"comment": "Shelving text files.",
"paths": ["c:\\wkspaces\\mywk\\file1.txt", "c:\\wkspaces\\mywk\\file 2.txt"]
}
Response
Status: 200 OK
{
"totalSize": 57990,
"transferredSize": 57990,
"status": "Checkin operation starting..."
}
As this operation is actually a checkin, you can
retrieve the checkin status
by invoking:
GET api/v1/wkspaces/:wkName/checkin
And the response could be:
{
"status": "Checkin finished",
"totalSize": 57990,
"transferredSize": 57990
}
PATCH api/v1/wkspaces/:wkName/shelvesets/:shelvesetId
Example
PATCH http://localhost:9090/api/v1/wkspaces/mywk/shelvesets/5
Response
The information with the file conflicts, if any, will be returned.
Status: 200 OK
{
"conflicts": [
"c:\\wkspaces\\mywk\\conflictive_file"
]
}
Folder conflicts are not supported and cause exception.
Gluon compatibility (cm partial)
POST api/v1/wkspaces/:wkName/partialconfigure
Parameters
Name |
Type |
Description |
instructions |
string[] |
Required. One or more set of instructions. Each instruction is a pair of strings:
- path: The path to configure.
- action: This can be
load or unload .
|
Example
POST api/v1/wkspaces/mywk/partialconfigure
{
"instructions": [
{
"path": "c:\\wkspaces\\mywk\\animations\\move01.mov",
"action": "unload"
},
{
"path": "c:\\wkspaces\\mywk\\sounds\\sound02.wav",
"action": "load"
}
]
}
Response
Status: 200 OK
{
"totalFiles": 2,
"totalBytes": 57893,
"updatedFiles": 0,
"updatedBytes": 0,
"status": "Calculating"
}
As this operation is actually an update, you can
retrieve the update status
by invoking:
GET api/v1/wkspaces/:wkName/update
And the response could be:
{
"status": "Finished",
"totalFiles": 2,
"totalBytes": 57893,
"updatedFiles": 1,
"updatedBytes": 25446,
}
To perform an update operation on a partial workspace, you can launch the
workspace update
operation.
To perform a switch operation to a branch or to a changeset on a partial workspace, you can launch the
switch workspace
operation.
To perform a checkin operation on a partial workspace, you can launch the
checkin pending changes operation.
Current limitations
As you know, the Plastic SCM client REST API is still in a development stage. This means that not every CLI/GUI operation is available for our API at the moment, much to our regret.
Unavailable operations
-
- Merge to
-
Merge from is supported although it
doesn't support conflict resolution yet.
- Query pagination
- Xlink management
- Replication
- Permissions management
- Delete shelveset
- Code reviews
- Annotate code
- Attribute management
- Statistics
- Trigger management
-
Some Gluon compatibility (cm partial) operations: add, undo, checkout, undocheckout, move,
remove.
Last updated
February 25, 2022
This REST API guide is now updated to cover the recent changes and improvements
about embedding the Plastic SCM API in the CLI.
This update includes the following:
-
Removed the "Windows configuration" section. Now, there is no need to perform any extra configuration.
-
Updated the Troubleshooting section to remove one of the issues because
now it won't apply anymore.
-
Updated the Current limitations section because now the Plastic SCM API
supports more operations:
December 16, 2021
The Plastic SCM API is now embedded in the CLI. Now, there is a cm api command that starts the Plastic
SCM API. It allows the same arguments as the old plasticapi.exe application.
The Plastic SCM REST API is temporarily unsupported in Windows.
March 26, 2019
We replaced the references to deprecated workspace administration commands like cm mkwk for their new counterparts.
March 22, 2019
We replaced the references to deprecated repository administration commands like cm mkrep for their new counterparts.
February 26, 2018
Added the Examples sections.
August 4, 2016
Fixed the parameter names in the Switch workspace to a different branch/label/changeset reference.
July 7, 2016
Limitation removed - The execution on Linux is available.
August 31, 2015
Welcome to the Plastic SCM client REST API documentation.