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.

You can have a look to our API client examples or to our advanced API examples if you need a starting point.

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

Program

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;
        }

    }
}

Actions

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;
    }
}

Models

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; }
}

IApi

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

Program

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): ";
    }
}

Actions

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; }
    }
}

Models

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; }
    }
}

Utils

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

cm repository list

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()

cm repository create

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()

cm repository rename

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()

cm repository delete

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()

cm workspace list

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()

cm workspace create

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()

cm workspace delete

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

List all 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 a single repository

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"
}

Create a repository

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"
}

Rename a repository

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"
}

Remove a repository

DELETE /api/v1/repos/:repname

Response

Status: 204 No Content


Workspaces

List all 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 a single workspace

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"
}

Create a workspace

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"
}

Rename a workspace

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"
}

Remove a workspace

DELETE /api/v1/wkspaces/:wkname

Response

Status: 204 No Content


Branches

List all 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 a single branch

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"
    }
}

Create a branch

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"
  }
}

Rename a branch

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"
    }
}

Remove a branch

Only empty branches with no children can be removed.

DELETE /api/v1/repos/:repname/branches/:branchname

Response

Status: 204 No Content


Labels

List all 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 a single label

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"
  }
}

Create a label

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"
  }
}

Rename a label

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"
  }
}

Remove a label

DELETE /api/v1/repos/:repname/labels/:labelname

Response

Status: 204 No Content


Changesets

List all 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"
    }
  },
  ...
]

List all changesets by branch

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 a single changeset

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 pending changes in workspace

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
            }
        }
    }
]

Undo pending changes in workspace

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

Retrieve update/switch status

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
}

Launch a workspace update

POST /api/v1/wkspaces/:wkname/update

Response

Status: 200 OK

{
    "status": "Running",
    "totalFiles": 0,
    "totalBytes": 0,
    "updatedFiles": 0,
    "updatedBytes": 0
}

Switch workspace to a different branch/label/changeset

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

Retrieve checkin status

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
}

Check in pending changes

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

Retrieve an item

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"
  }
}

Retrieve a single revision

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"
  }
}

Retrieve revision contents

GET /api/v1/repos/:repname/revisions/:revid/blob

Response

Stream: application/octet-stream

Retrieve the revision history of an item

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

Changeset 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"
    }
  }
]

Branch diff

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

Add

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"
    ]
}

Checkout

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"
    ]
}

Move

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"
    ]
}

Remove

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

Merge from

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

Create 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
}

Apply shelveset

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)

Partial configure

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,
}

Partial update

To perform an update operation on a partial workspace, you can launch the workspace update operation.

Partial switch

To perform a switch operation to a branch or to a changeset on a partial workspace, you can launch the switch workspace operation.

Partial checkin

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.


The Plastic SCM REST API is temporarily unsupported in Windows

The cm api command is only available in macOS and Linux as those platforms run the .NET Core Plastic CLI client. So, the old plasticapi.exe application is removed from all installers. It will be back as soon as we distribute our .NET Core CLI client in the Windows installers.


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:
  • 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.