2 releases

0.9.1 Nov 19, 2020
0.9.0 Nov 16, 2020

#1416 in Development tools

MIT/Apache

76KB
1.5K SLoC

GitLab pipeline Crates.io Matrix

Gitlab Butler

What is gitlab-butler

gitlab-butler is a GitLab cli, that wraps a growing number of GitLab APIs.

Most options can be given as command line arguments or through environment variables.

Example usage

asciicast

Usage

.env is supported, a special .private.env is also loaded to allow private uncommited entries beside the common ones:

  • .env may contain GITLAB_BUTLER_PROJECT and GITLAB_BUTLER_API_SERVER (committed)
  • .private.env may contain GITLAB_BUTLER_PRIVATE_TOKEN (uncommitted / upper directory)

You can also mix dotenv and direnv as you like.

Getting a private token

One can get a private token from the Gitlab personal Profile page, or using ssh:

$ ssh git@gitlab.com personal_access_token
remote: 
remote: ========================================================================
remote: 
remote: Usage: personal_access_token <name> <scope1[,scope2,...]> [ttl_days]
remote: 
remote: ========================================================================
remote: 
$ ssh git@gitlab.com personal_access_token cli-friendly-token read_repository,read_api 10
Token:   7...ixvzoW...szp
Scopes:  read_repository,read_api
Expires: 2020-11-08

Create an api scoped token with the command ssh git@gitlab.com personal_access_token gitlab-butler api and put it in a .private.env file, like:

GITLAB_BUTLER_PRIVATE_TOKEN=7...ixvzoW...szp

And create a standard .env file to point the right server and project, for example:

GITLAB_BUTLER_API_SERVER=https://gitlab.com/
GITLAB_BUTLER_PROJECT=naufraghi/gitlab-butler

Example help

Use gitlab-butler install to create a git-lab symlink that allows the usage as git lab <command>

Most commads will print a colored response, but if issued with the -x / --execute option, will spawn a subshell with a set of environment variables about the current command. See the list below in the git lab issues list --help message.

gitlab-butler-issue-list 0.9.0
List issues

USAGE:
    gitlab-butler issue list [OPTIONS]

FLAGS:
    -h, --help
            Prints help information

    -V, --version
            Prints version information


OPTIONS:
    -x, --execute <execute>
            Execute command for each returned issue (in a bash subshell)

            The current issue is exported as environment variables:
              - `issue_id`: 234
              - `issue_title`: Resolve some problem
              - `issue_description` (optional): Long description
              - `issue_slug`: 234-resolve-some-problem
              - `issue_reference`: #234
              - `issue_full_reference`: group/project#234
              - `issue_web_url`: http://gitlab.com/group/project/issues/234

            Example:
              - `... issue list -x 'echo ${issue_reference}: ${issue_title}'`

            Or to use the fully qualified reference:
              - `... issue list -x 'echo ${issue_full_reference}: ${issue_title}'`
    -l, --labels <labels>
            Filter issues by comma-separated list of label names

            Issues must have all labels to be returned.
            - `None` lists all issues with no labels. `Any` lists all issues with at least one label.
            - `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive.
    -n, --limit <limit>
             [default: 100]

    -m, --milestone <milestone>
            Filter issues by the milestone title. `None` lists all issues with no milestone.

            - `Any` lists all issues that have an assigned milestone.
    -p, --project <project>
            Project name or id (defaults to CI_PROJECT_PATH) [env: GITLAB_BUTLER_PROJECT=naufraghi/gitlab-butler]

    -s, --state <state>
            Filter issues by state: all, opened, closed [default: opened]

This features allows the creation of complex pipelines, like backport command, that, from the current branch (which maps to a specific issue):

  1. creates a new issue with a back reference in the description
  2. creates a new local branch with the canonical <issue>-<title-slug> name
  3. creates a new MR, that starts from the current branch and targets the provided branch

Here the implementation using the just command runner:

backport TARGET:
    git lab issue get -x "just _backport-issue {{TARGET}}"
_backport-issue TARGET:
    git lab issue new "$issue_title ({{TARGET}})" -d "Backport of issue $issue_reference" -x "just _backport-mr {{TARGET}}"
_backport-mr TARGET:
    git branch $issue_slug origin/{{TARGET}}
    git push origin $issue_slug
    git lab mr new "Resolve \"$issue_title\"" -d "Closes $issue_reference" -s $issue_slug -t {{TARGET}}

Here the execution log:

image

merge-ready subcommand

The merge-ready subcommand tries to merge a marked MR in the queue, rebasing and waiting for the pipeline to complete successfully.

Very like Marge-bot but made to run inside the CI itself (in fact, gitlab-butler is still in alpha and may eat your repos).

TL;DR: you have a project, you'd like an always green master and a semi linear history, so if your team is big enough you'll end up fighting to be the first to rebase and merge. An initial solution can be to make someone the merger, and the TL can in fact do this, having a second look[^1] on the code before, but the rebase/merge work is tedious.

Here enters gitlab-butler:

  1. Alice works on a feature and creates MR1, and assign it to Bob
  2. Bob does the review and eventually adds the ~"Merge ready 🐙" label to the MR, and assigns the MR to the Tech Lead,
  3. The TL does the final review and eventually adds the 🐙 emoji
  4. gitlab-butler triggers a rebase and/or merge actions

merge-ready CI Usage

You can run gitlab-butler in a while loop or directly in the CI itself (you'll need to export some variables, and set up a schedule), like:

gitlab-butler:
  image: registry.gitlab.com/naufraghi/gitlab-butler:latest
  variables:
    GIT_STRATEGY: none
  script:
    - /run/gitlab-butler mr merge-ready
  only:
    - schedules
    - master

The current implementation does not use the Approved feature, but relies only on a label / emojii convention because I started using it before unlocking the feature.

Notes

[^1]: Modern Code Review: A Case Study at Google, 2 reviews seems a good number: image

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~19–32MB
~566K SLoC