# GitLab Release command-line tool

> [Introduced](https://gitlab.com/gitlab-org/release-cli/-/merge_requests/6) in GitLab 12.10.

GitLab Release command-line tool is an application written in [Golang](https://golang.org/)
to interact with [GitLab's Releases API](https://docs.gitlab.com/ee/api/releases/index.html) through the command line and through GitLab CI/CD's configuration file, [`.gitlab-ci.yml`](https://docs.gitlab.com/ee/ci/yaml/#release).
The minimum supported Go version is v1.13.

It consumes instructions in the `:release` node of the `.gitlab-ci.yml` to create a Release object in GitLab Rails.

The GitLab Release CLI is a decoupled utility that may be called by the GitLab Runner,
by a third-party CI or directly from the command line.
It uses the CI `Job-Token` to authorize against the GitLab Rails API, which is passed to it by the GitLab Runner.

The CLI can also be called independently, and can still create the Release via Rails API
if the `Job-Token` and correct command line params are provided.

## Development

You can find development documentation [here](./development.md).

## Usage

To get started, open your project in a terminal and run `release-cli help`
for usage options. The output will be:

```plaintext
NAME:
   release-cli - A CLI tool that interacts with GitLab's Releases API

USAGE:
   help [global options] command [command options] [arguments...]

VERSION:
   0.13.0

DESCRIPTION:
   CLI tool that interacts with GitLab's Releases API https://docs.gitlab.com/ee/api/releases/.
   
   All configuration flags will default to GitLab's CI predefined environment variables (https://docs.gitlab.com/ee/ci/variables/predefined_variables.html).
   To override these values, use the [GLOBAL OPTIONS].
   
   Get started with release-cli https://gitlab.com/gitlab-org/release-cli.

AUTHOR:
   GitLab Inc. <support@gitlab.com>

COMMANDS:
   create   Create a Release using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/#create-a-release
   get      Get a Release by tag name using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/index.html#get-a-release-by-a-tag-name
   update   Update a release using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/#update-a-release
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --server-url value                 The base URL of the GitLab instance, including protocol and port, for example https://gitlab.example.com:8080 [$CI_SERVER_URL]
   --job-token value                  Job token used for authenticating with the GitLab Releases API (default:  ) [$CI_JOB_TOKEN]
   --project-id value                 The current project's unique ID; used by GitLab CI internally [$CI_PROJECT_ID]
   --timeout value                    HTTP client's timeout in Go's duration format https://golang.org/pkg/time/#ParseDuration (default: 30s) [$RELEASE_CLI_TIMEOUT]
   --private-token value              Private token used for authenticating with the GitLab Releases API, requires api scope https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html, overrides job-token (default:  ) [$GITLAB_PRIVATE_TOKEN]
   --additional-ca-cert-bundle value  Configure a custom SSL CA certificate authority, can be a path to file or the content of the certificate [$ADDITIONAL_CA_CERT_BUNDLE]
   --insecure-https                   Set to true if you want to skip the client verifying the server's certificate chain and host name (default: false) [$INSECURE_HTTPS]
   --debug                            Set to true if you want extra debug output when running release-cli (default: false) [$DEBUG]
   --help, -h                         Show help (default: false)
   --version, -v                      Print the version (default: false)
```

### Create a new release

This command uses the [Create a Release](https://docs.gitlab.com/ee/api/releases/) API.

```shell
release-cli --server-url https://gitlab.com --job-token=SOME_JOB_TOKEN --project-id 12345 create help
```

The output is:

```plaintext
NAME:
   help create - Create a Release using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/#create-a-release

USAGE:
   help create [command options] [arguments...]

OPTIONS:
   --name value               The release name
   --description value        The description of the release; you can use Markdown. A file can be used to read the description contents, must exist inside the working directory; if it contains any whitespace, it will be treated as a string
   --tag-name value           The tag the release will be created from [$CI_COMMIT_TAG]
   --tag-message value        Message to use if creating a new annotated tag
   --ref value                If tag_name doesn’t exist, the release will be created from ref; it can be a commit SHA, another tag name, or a branch name [$CI_COMMIT_SHA]
   --assets-link value        JSON string representation of an asset link (or an array of asset links); (e.g. --assets-link='{"name": "Asset1", "url":"https://example.com/some/location/1", "link_type": "other", "direct_asset_path": "xzy" } or --assets-link='[{"name": "Asset1", "url":"https://example.com/some/location/1"}, {"name": "Asset2", "url":"https://example.com/some/location/2"}]')
   --milestone value          List of the titles of each milestone the release is associated with (e.g. --milestone "v1.0" --milestone "v1.0-rc)"; each milestone needs to exist
   --released-at value        The date when the release will be/was ready; defaults to the current time; expected in ISO 8601 format (2019-03-15T08:00:00Z)
   --help, -h                 Show help (default: false)
```

### Create a new release using a file

This command uses the [Create a Release](https://docs.gitlab.com/ee/api/releases/) API.

```shell
release-cli --server-url https://gitlab.com --job-token=SOME_JOB_TOKEN --project-id 12345 create-from-file help
```

The output is:

```plaintext
NAME:
   help create-from-file - Create a Release using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/#create-a-release

USAGE:
   help create-from-file [command options] [arguments...]

OPTIONS:
   --file value               YML file which content holds data to create a release. Does not need use of any other parameters.`
   --help, -h                 Show help (default: false)
```

An example file showing all valid properties can be found [here](internal/testdata/release.yml).

### Get an existing release by tag name

The `get` command uses the [Get a Release by tag name](https://docs.gitlab.com/ee/api/releases/#get-a-release-by-a-tag-name) endpoint
from the Releases API:

```shell
release-cli --server-url https://gitlab.com --job-token=SOME_JOB_TOKEN --project-id 12345 get help
```

The output would be something like:

```plaintext
NAME:
   help get - Get a Release by tag name using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/index.html#get-a-release-by-a-tag-name

USAGE:
   help get [command options] [arguments...]

OPTIONS:
   --tag-name value            The Git tag the release is associated with [$CI_COMMIT_TAG]
   --include-html-description  If true, a response includes HTML rendered Markdown of the release description (default: false) [$INCLUDE_HTML_DESCRIPTION]
   --help, -h                  Show help (default: false)
```

The output of the `get` command is a JSON object describing the release. You can use a tool like 
[`jq`](https://stedolan.github.io/jq/) to parse the response and read certain fields from the JSON object.
For example, to read the description of a release with tag `v1.31.0`:

```shell
$ release-cli get --tag-name v1.31.0 | jq '.description'

INFO[0000] Getting Release by tag_name: "v1.31.0"        cli=release-cli command=get include-html-description=false project-id=18239424 server-url="https://gitlab.com" tag-name=v1.31.0 version=0.8.0
"Created using the release-cli\n\n## Header\n\nSome info"
```

Or to get the description as an HTML document:

```shell
$ release-cli get --tag-name v1.31.0 --include-html-description | jq '.description_html'

INFO[0000] Getting Release by tag_name: "v1.31.0"        cli=release-cli command=get include-html-description=true project-id=18239424 server-url="https://gitlab.com" tag-name=v1.31.0 version=0.8.0
"<p data-sourcepos=\"1:1-1:29\" dir=\"auto\">Created using the release-cli</p>&#x000A;<h2 data-sourcepos=\"3:1-3:9\" dir=\"auto\">&#x000A;<a id=\"user-content-header\" class=\"anchor\" href=\"#header\" aria-hidden=\"true\"></a>Header</h2>&#x000A;<p data-sourcepos=\"5:1-5:9\" dir=\"auto\">Some info</p>"
```

### Update a release

The `update` command uses the [Update a release](https://docs.gitlab.com/ee/api/releases/#update-a-release) endpoint
from the Releases API:

```shell
release-cli --server-url https://gitlab.com --job-token=SOME_JOB_TOKEN --project-id 12345 update help
```

The output would be something like:

```plaintext
NAME:
   help update - Update a release using GitLab's Releases API https://docs.gitlab.com/ee/api/releases/#update-a-release

USAGE:
   help update [command options] [arguments...]

OPTIONS:
   --tag-name value     The Git tag the release is associated with [$CI_COMMIT_TAG]
   --name value         The release name
   --description value  The description of the release; you can use Markdown. A file can be used to read the description contents, must exist inside the working directory; if it contains any whitespace, it will be treated as a string
   --milestone value    List of the titles of each milestone the release is associated with (e.g. --milestone "v1.0" --milestone "v1.0-rc)"; each milestone needs to exist. Pass an empty string to remove all milestones from the release.  (accepts multiple inputs)
   --released-at value  The date when the release will be/was ready; defaults to the current time; expected in ISO 8601 format (2019-03-15T08:00:00Z)
   --help, -h           Show help (default: false)
```

## Configuration

All configuration flags will default to [GitLab's CI predefined environment variables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html).

To override these values, use the flags available under the `GLOBAL OPTIONS`.
For example, use the flags to create a release with a custom GitLab server URL.

```shell
release-cli --server-url https://gitlab.mydomain.com create --name "My Release" --description "This is a new release for my amazing tool"
```

## Using this tool with a private token

To use an access token to authenticate with the API, do one of the following:

- Pass the token to the `release-cli` as the `--private-token` global flag.
- Define an environment variable `$GITLAB_PRIVATE_TOKEN` and set it to the token.

To create a private token, see [Creating a personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#creating-a-personal-access-token).
The `api` scope is required.

For example:

```sh
release-cli --server-url https://gitlab.mydomain.com --private-token "my-private-token" create --name "My Release" --description "This is a new release for my amazing tool"
```

**WARNING**:
The `--private-token` flag overrides the `--job-token` flag.

## Using this tool in GitLab CI

The `release-cli` is available as a [Docker image](https://docs.gitlab.com/ee/ci/yaml/#release-cli-docker-image)
through the `.gitlab-ci.yml` file's [`release`](https://docs.gitlab.com/ee/ci/yaml/#release)
keyword.

If you would like to try GitLab Release on your project, add the following `script` to your `.gitlab-ci.yml` file:

```yaml
release-branch:
  stage: release
  image: registry.gitlab.com/gitlab-org/release-cli
  when: manual
  # We recommend the use of `rules` to prevent these pipelines
  # from running. See the notes section below for details.
  rules:
    - if: $CI_COMMIT_TAG
      when: never

  script:
    - >
      release-cli create --name release-branch-$CI_JOB_ID --description release-branch-$CI_COMMIT_REF_NAME-$CI_JOB_ID
      --tag-name job-$CI_JOB_ID --ref $CI_COMMIT_SHA
      --assets-link '{"name":"Asset1","url":"https://<domain>/some/location/1","link_type":"other","direct_asset_path":"xzy"}'
      --assets-link '{"name":"Asset2","url":"https://<domain>/some/location/2"}'
      --milestone "v1.0.0" --milestone "v1.0.0-rc"
      --released-at "2020-06-30T07:00:00Z"
```

### Notes

- GitLab Release CLI is still under development. Please report any issues in
its project [issue tracker](https://gitlab.com/gitlab-org/release-cli/issues).

- A new pipeline will run when [a new tag is created](https://gitlab.com/gitlab-org/gitlab/issues/16290).
We recommend adding `rules` to your job to prevent these pipelines from
running concurrently with `release-cli`.

### Release asset links

You can generate [release links](https://docs.gitlab.com/ee/user/project/releases/index.html#permanent-links-to-release-assets)
with the `--assets-link` flag.

You can pass the value for `--assets-link` multiple times to generate multiple links, such as:

```plaintext
release-cli create --name release-branch-$CI_JOB_ID --description release-branch-$CI_COMMIT_REF_NAME-$CI_JOB_ID
      --tag-name job-$CI_JOB_ID --ref $CI_COMMIT_SHA
      --assets-link '{"name":"Asset1","url":"https://<domain>/some/location/1","link_type":"other","direct_asset_path":"xzy"}'
      --assets-link '{"name":"Asset2","url":"https://<domain>/some/location/2"}'
      --milestone "v1.0.0" --milestone "v1.0.0-rc"
      --released-at "2020-06-30T07:00:00Z"
```

When using `assets`, the [Releases API](https://docs.gitlab.com/ee/api/releases/index.html) only requires `name` and `url`, but the `release-cli` **does not** validate if they are present. If there is an issue with the defined parameters for an asset,
the release will not be created and an API error will occur, for example:

```shell
$ release-cli create \ 
    --name "Release $CI_COMMIT_TAG" \
    --description "Notes: $EXTRA_DESCRIPTION" \
    --tag-name $CI_COMMIT_TAG --ref $CI_COMMIT_SHA \
    --assets-link '{"name":"Asset1","url":"https://<domain>/some/location/1","link_type":"other","direct_asset_path":"xzy"}' \
    --assets-link '{"name":"Asset2","url":"https://<domain>/some/location/2"}' --milestone "m1" --milestone "m2" --released-at "2020-08-20T6:42:00Z"

time="2020-08-20T06:48:58Z" level=info msg="Creating Release..." cli=release-cli command=create name="Release v1.9.0-rc" project-id=18239424 ref=56a2713ede44cb567cc26778ae15f11f01a789d5 server-url="https://gitlab.com" tag-name=v1.9.0-rc version="0.3.0~beta.52.g33bbb8d"

time="2020-08-20T06:48:58Z" level=fatal msg="failed to create release: API Error Response status_code: 400 message: Validation failed: Links url is blocked: URI is invalid, Links direct_asset_path is invalid" cli=release-cli version="0.3.0~beta.52.g33bbb8d"
```

## Examples

### Release assets as Generic packages

You can use [Generic packages](https://docs.gitlab.com/ee/user/packages/generic_packages/) to host your release assets. A complete example of how to do this can be found [here](../docs/examples/release-assets-as-generic-package/).

### Use a custom certificate authority

You can specify a custom CA file via the `--additional-ca-cert-bundle` flag or the `$ADDITIONAL_CA_CERT_BUNDLE` environment variable.
See a complete example of how to [use a custom certificate authority](examples/additional-ca-cert-bundle/index.md).

### Download `release-cli` binaries

You can [download the `release-cli` binary](examples/download-release-cli-from-generic-packages/index.md)
for different platforms from the generic package registry.
