Getting Started

This tutorial will take you through the development of a command line Helix TeamHub client for managing version control repositories. We hope to show you how everything in TeamHub can be accessed through our RESTful APIs, using plain HTTPS calls with JSON payloads.

The tool will be implemented in Ruby. We are working on making tutorials available for other programming languages. In the meantime, we hope you'll be able to follow along even if you're working in some other language.

The Tool

The tool we're building can be used for managing source code repositories: Listing them, creating them, or destroying them.

Listing all repositories of a project

repo list my_project

Creating a repository in a project:

repo create my_project a_repo git

Deleting a repository from a project

repo delete my_project a_repo

Prerequisites

The tutorial is written assuming a Unix based operating system, such as Linux or macOS. However, there is nothing inherently Unix dependent here, so you should be able to apply the tutorial on Windows as well.

You will need to have Ruby 1.9 or later installed. Follow the official installation documentation to get Ruby up and running on your machine.

We'll be using two Ruby gems to help with the lower level details:

  • rest-client for making HTTP(S) calls to the API
  • json for JSON parsing and serialization

You can get these installed with the gem command once you have Ruby installed:

gem install rest-client json --no-rdoc --no-ri
Note

Depending on how you installed Ruby you may need to use sudo to install Gems.

Set Up The TeamHub Endpoint URL

To make the rest of our work easier, let's put the base URL of the TeamHub API to an environment variable.

If you are using the TeamHub Cloud, this URL is https://helixteamhub.cloud/api. If you are using an on-premises installation, replace helixteamhub.com with the hostname or IP of your internal TeamHub instance.

Set up an environment variable HTH_ENDPOINT with this value. The best way to do this depends on your operating system and shell. For example, on macOS and most Linux installations you can put the following line in ~/.bash_profile:

export HTH_ENDPOINT="https://helixteamhub.cloud/api"

Set Up Keys

In order to access TeamHub from tools such as this one, we need two keys. They allow for fine-grained access control, and for making sure whoever's running the tool has the permission to execute the action under question.

We are going to put all keys into environment variables so that the script – as well as any other scripts you want to develop – is easy to run.

The Company And Account Keys

The Company Key identifies which company within TeamHub we are dealing with. Most people will only ever have access to a single company's data, but this is not always the case. Because every company in TeamHub has it's own "universe" with unique user and project identifiers, we need to use the Company Key to scope each request to a specific company.

The Account Key identifies who exactly is accessing TeamHub (or on whose behalf we're doing it). Each TeamHub user and bot has a unique account key.

A convenient way to acquire both of these keys is to make an authentication request to the TeamHub API. What you need for it is your TeamHub access credentials (company, login (email or user ID) and password). Run the following command, replacing your own company, login and password (as well as the TeamHub URL if you have an on-premises installation):

curl -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/vnd.hth.v1" \
  -d '{"company": "YOUR COMPANY ID", "login": "YOUR LOGIN", "password": "YOUR PASSWORD" }' \
  https://helixteamhub.cloud/api/account/sessions

The command should print out the JSON response returned by TeamHub. Included in it are the keys for the company and the account. Put the values of those to environment variables:

export HTH_COMPANY_KEY=value of company_key
export HTH_ACCOUNT_KEY=value of account_key

Implement The Script Structure

Now we are ready to start coding our tool. We are going to put everything to a single executable Ruby file. It is a good idea to put it somewhere in your PATH so that it's easy to execute. Assuming you have a directory ~/bin for this purpose, let's create the script there and make it executable:

touch ~/bin/repo
chmod +x ~/bin/repo

Next, open the newly created file in your favorite Ruby or text editor. At this point we'll add in everything except the actual TeamHub API calls. Set the file's contents as follows (we will be going through them step by step in a moment):

#!/usr/bin/env ruby

require 'rest_client'
require 'json'

module HelixTeamHub
  class Client

    def initialize(endpoint, account_key, company_key)
      @endpoint    = endpoint
      @account_key = account_key
      @company_key = company_key
    end

    def list_repos(project_id)
      raise "No project given"         if project_id.nil?

    end

    def create_repo(project_id, repo_id, repo_type)
      raise "No project given"         if project_id.nil?
      raise "No repository given"      if repo_id.nil?
      raise "No repository type given" if repo_type.nil?
      raise "Invalid repository type"  unless %w(git mercurial subversion).include?(repo_type)

    end

    def delete_repo(project_id, repo_id)
      raise "No project given"         if project_id.nil?
      raise "No repository gien"       if repo_id.nil?

    end

  end
end

command, project_id, repo_id, repo_type = ARGV

client = HelixTeamHub::Client.new(ENV['HTH_ENDPOINT'],
                           ENV['HTH_ACCOUNT_KEY'],
                           ENV['HTH_COMPANY_KEY'])

case command
when 'list'   then client.list_repos(project_id)
when 'create' then client.create_repo(project_id, repo_id, repo_type)
when 'delete' then client.delete_repo(project_id, repo_id)
else               puts "Unknown command: #{command}"
end

  • On line 1 we define the shebang, letting the shell know it should use Ruby to run this script.
  • On lines 3-4 we require the Ruby gems we need for the API calls.
  • On lines 5-6 we begin a Ruby class definition for a Helix TeamHub client class we'll be using later in the script: HelixTeamHub::Client.
  • On lines 9-14 we define the class constructor, which takes the Helix TeamHub API endpoint and the two keys. It stores everything as instance variables.
  • On lines 16-19 we define a method for listing the repositories of a project. It takes the project identifier as an argument, and validates that it is not nil.
  • On lines 21-27 we define a method for creating a repository to a project. It takes the project identifier, the repository identifier, and the reposioty type as arguments. It validates that each of the arguments is present, and that the repository type is one of git, mercurial, or subversion.
  • On lines 29-33 we define a method for deleting a repository from a project. It takes the project identifier and the repository identifier as arguments, and validates that both of them are present.
  • On lines 35-36 we close the HelixTeamHub::Client class definition
  • On line 38 we grab the four command line arguments that may have been given to the script: The command to execute, the project identifier in question, the repository identifier, and the repository type. Not all commands need all of these arguments, in which case their value will be nil.
  • On lines 40-43 we create an instance of the HelixTeamHub::Client class. To its constructor we pass the Helix TeamHub endpoint URL and the two keys, which we get from the environment variables we set up earlier.
  • On lines 45-50 we finally execute the command that was given, by calling the matching method from the HelixTeamHub::Client object. An error message is printed if we can't recognize the command.

Implement The List Command

To get a list of repositories, we can call the TeamHub API operation GET /projects/:project_id/repositories. Let's do exactly that, using the rest-client library we have installed as a Gem and required. Update the list_repos method so that it looks like this:

    def list_repos(project_id)
      raise "No project given"         if project_id.nil?

      response = RestClient.get "#{@endpoint}/projects/#{project_id}/repositories",
                                authorization: auth_header(),
                                accept: :json
      JSON.parse(response)["results"].each do repo
        print_repo(repo)
      end
    end
  • On lines 4-6 we make a GET request to the repositories URL, based on the configured TeamHub API endpoint. We include two HTTP headers: Authorization for letting TeamHub know who we are, and Accept for letting TeamHub know we want back JSON data.
  • On lines 7-9 we parse the returned JSON data to a Ruby data structure, and then iterate over the results (assuming it is an array of repositories). The information of each repository is printed out.

In this code we used two helper methods we haven't defined yet: auth_header for defining the contents of the Authorization header, and print_repo for printing out the information for a repository. Let's define those now.

Within the class definition for HelixTeamHub::Client, add two more private methods:

    def auth_header
      %(hth.company_key="#{@company_key}",account_key="#{@account_key}")
    end

    def print_repo(repo)
      puts repo["id"]
      puts "=" * 20
      puts "Type:         #{repo["type"]}"
      puts "SSH access:   #{repo["ssh_url"]}"
      puts "HTTP(s) access: #{repo["http_url"]}"
      puts
    end
  • On lines 1-3 we define the auth_header method. It constructs a value for the Authorization header that TeamHub recognizes. The value begins with the string hth, which is followed by the two API keys.
  • On lines 5-12 we define a method for printing out a repository. It prints the repository identifier, the type of the repository, and the access URLs for the SSH and HTTPS protocols.

Implement The Create Command

When creating a repository, we invoke the same endpoint as for listing repositories, but this time we use the POST method instead of GET: POST /projects/:project_id/repositories. This time we also provide a JSON payload with the information for the new repository.

Update the create_repo method so that it looks like this:

    def create_repo(project_id, repo_id, repo_type)
      raise "No project given"         if project_id.nil?
      raise "No repository given"      if repo_id.nil?
      raise "No repository type given" if repo_type.nil?
      raise "Invalid repository type"  unless %w(git mercurial subversion).include?(repo_type)

      response = RestClient.post "#{@endpoint}/projects/#{project_id}/repositories",
                                 {repository: {id: repo_id, type: repo_type}}.to_json,
                                 authorization: auth_header(),
                                 content_type: :json,
                                 accept: :json
      print_repo(JSON.parse(response))
    end
  • On lines 7-11 we make the call to the API. We specify the id and type of the repository in the payload, and indicate that both the POST data and the response should be JSON, by setting the Content-Type and Accept headers. We also include the same Authorization header as before.
  • On line 12 we parse the response, assuming it's a JSON representation of the newly created repository. We print it out using the same method as we used in the listing.

Implement The Delete Command

Finally, let's implement the method for deleting a repository. This will be a DELETE request to the repository's own API resource: DELETE /projects/:project_id/repositories/:repository_id.

Update the delete_repo method so that it looks like this:

    def delete_repo(project_id, repo_id)
      raise "No project given"         if project_id.nil?
      raise "No repository gien"       if repo_id.nil?

      RestClient.delete "#{@endpoint}/projects/#{project_id}/repositories/#{repo_id}",
                        authorization: auth_header()
      puts "Deleted"
    end
  • On lines 5-6 we make the call to the API. This time there is no content in the request, and we're not really interested in the response body either, so the only header we include is Authorization.
  • On line 7 we print out a simple message letting the user know what's happening.

Test Drive

We're done with our tool implementation! Let's take it for a test drive.

The tool assumes there's an existing TeamHub Project within which the operations are executed. You may want to create a separate sandbox project just for testing the tool (it's free), or you can use an existing project. In either case, the script will need a project id. Here's how you can obtain it:

  • For new projects, the value you need is the same as the one you'll put in the Identifier field of the New Project view.
  • For already existing projects, you can see the project identifier, among other places, in the browser address when you have navigated to the project: *https://helixteamhub.cloud/COMPANY_ID/projects/PROJECT_ID/activity.

When you have a project set up, and know it's identifier, you can start playing with the script to list, create, and delete repositories:

./repo list my-test-project

./repo create my-test-project a_git_repo git
a_git_repo
====================
Type:         git
SSH access:   [email protected]:acme/projects/my-test-project/repositories/git/a_git_repo
HTTPS access: https://[email protected]/acme/projects/my-test-project/repositories/git/a_git_repo

./repo create my-test-project a_hg_repo mercurial
a_hg_repo
====================
Type:         mercurial
SSH access:   ssh://[email protected]/acme/projects/my-test-project/repositories/mercurial/a_hg_repo
HTTPS access:

./repo list my-test-project
a_hg_repo
====================
Type:         mercurial
SSH access:   ssh://[email protected]/acme/projects/my-test-project/repositories/mercurial/a_hg_repo
HTTPS access:

a_git_repo
====================
Type:         git
SSH access:   [email protected]:acme/projects/my-test-project/repositories/git/a_git_repo
HTTPS access: https://[email protected]/acme/projects/my-test-project/repositories/git/a_git_repo

./repo delete my-test-project a_git_repo
Deleted

./repo list my-test-project
a_hg_repo
====================
Type:         mercurial
SSH access:   ssh://[email protected]/acme/projects/my-test-project/repositories/mercurial/a_hg_repo
HTTPS access:

Conclusion

In this tutorial you've learned to work with the TeamHub API, and particularly the version control repository management.

All data in TeamHub has similar APIs available, and you should be able to apply what you have learned to everything else. To get an idea of what you can do, see the API Documentation.