README.md 10.8 KB
Newer Older
Olivier Robardet's avatar
Olivier Robardet committed
1
# .gitlab-ci.yml lint helper tool
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
2

Olivier Robardet's avatar
Olivier Robardet committed
3 4
> Goodbye "yaml invalid" pipeline errors, and don't come back!

5
This tool use the [Gitlab API](https://docs.gitlab.com/ce/api/ci/lint.html) to validate your local `.gitlab-ci.yml`.  
Olivier Robardet's avatar
Olivier Robardet committed
6
It can be installed as a git pre-commit hook, preventing commit (and so push) of an invalid `.gitlab-ci.yml`. 
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
7

8
**The tool itself does not lint anything: it uses the lint API of a Gitlab instance => it needs to be run somewhere with an access to the Gitlab instance where your project come from.**
Olivier Robardet's avatar
Olivier Robardet committed
9

Olivier Robardet's avatar
Olivier Robardet committed
10 11
# Installation

Olivier Robardet's avatar
Olivier Robardet committed
12 13
**Download the tool from the [releases page](https://gitlab.com/orobardet/gitlab-ci-linter/tags).**

14 15
The tool is made in [Go](https://golang.org/). So it's cross platform and can be run in Linux, Windows, Mac or any other 
operating system supported by Go.
Olivier Robardet's avatar
Olivier Robardet committed
16

17
It is currently tested on Linux x64 (Ubuntu, WSL) and Windows x64 (7 and 10). 
Olivier Robardet's avatar
Olivier Robardet committed
18

Olivier Robardet's avatar
Olivier Robardet committed
19
To install, just [download the binary](https://gitlab.com/orobardet/gitlab-ci-linter/tags) matching you system and put it somewhere (preferably in your `$PATH`).  
20 21 22
Upgrade is just overriding the binary with a new one.

> For now, releases only build binaries for some common platforms, not all supported by Go.  
Olivier Robardet's avatar
Olivier Robardet committed
23
> If yours is not available, you can try building it by yourself and check if it works (it should, but never tested).  
24 25 26 27 28 29 30 31 32 33
> Feedbacks are welcome :)

## Requirements

None.
  
You don't even need a Git client.

The only thing required is a network connection to the Gitlab instance you are using in the repository you want to check.    
And a git repository to check of course, having an `origin` remote corresponding to a Gitlab instance and a `.gitlab-ci.yml` file. 
Olivier Robardet's avatar
Olivier Robardet committed
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
## Migrating from old bash script version

If you don't want to/can't update your existing repositories with a a pre-commit hook to the old bash script, the best 
way is to replace the script with a symlink to the new binary. It's a drop-in replacement.

But it would be better to remove (manually) the previous pre-commit hook link, and then install the new go version:

```shell
# check if the current pre-commit hook is a link to the old bash script
ls -lsa .git/hooks/pre-commit
# if so, remove it
rm .git/hooks/pre-commit
# and then install the new version normally
gitlab-ci-linter install
```  

Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
51 52
# Usage

53
Once installed, it can be used as a simple standalone program, by launching it from any directory 
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
54 55 56 57 58 59
inside a git repository clone.

Let's say you have a Gitlab project cloned in `~/dev/my-super-project`:

```shell
cd ~/dev/my-super-project
60
gitlab-ci-linter
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
61 62
```
If the `.gitlab-ci.yml` is valid:
Olivier Robardet's avatar
Olivier Robardet committed
63

Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
64 65 66 67 68
![.gitlab-ci.yml is valid!](doc/screen-standalone-ok.png)

You don't need to be in the root of the git repository:
```shell
cd ~/dev/my-super-project/src/public
69
gitlab-ci-linter
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
70 71
```
If the `.gitlab-ci.yml` is invalid:
Olivier Robardet's avatar
Olivier Robardet committed
72

Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
73 74 75 76
![Arg! An error!](doc/screen-standalone-ko.png)

## As git pre-commit hook

77
The tool can be used as a git pre-commit hook. It means it will be run by git automatically each time you ask for a 
Olivier Robardet's avatar
Olivier Robardet committed
78
commit, and git will stop if your `.gitlab-ci.yml` is invalid:
Olivier Robardet's avatar
Olivier Robardet committed
79

Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
80 81
![Thanks alerting me!](doc/screen-hook-ko.png)

82 83 84 85 86 87 88 89
The tool can install (and uninstall) itself as a pre-commit hook, using the commands `install` and `uninstall`.

```shell
# Inside a git repository tree, install the pre-commit hook:
gitlab-ci-linter install
# Uninstall the pre-commit hook:
gitlab-ci-linter uninstall
```
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
90

Olivier Robardet's avatar
Olivier Robardet committed
91 92
The self installation is pretty simple: it will just create a `.git/hooks/pre-commit` file as a symbolic link to itself.

93 94 95
> It means updating the tool to a newer version will update all the hooks installed in all your repo => Good!  
> But moving the executable will broke commit in these repo until you manually remove the hook and reinstall it => Not so good...  
> Conclusion: install the tool in a safe and viable place :)
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
96

97 98 99
> **Note for Windows users:** Windows require administrator privileges to create symbolic links. So the `gitlab-ci-linter install` 
> command will only work if run with administrator privileges. 

Olivier Robardet's avatar
Fix doc  
Olivier Robardet committed
100
It won't be able to self install if a `.git/hooks/pre-commit` already exists (and is not a link to itself).
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
101 102 103
 
Self uninstall will only works if `.git/hooks/pre-commit` is a link to itself.

104
If you are already using a pre-commit hook, you'll have to install manually: simply add a call to the tool in your 
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
105 106
existing pre-commit script.

Dan Levin's avatar
Dan Levin committed
107 108 109 110 111 112 113 114 115 116 117 118 119
### Integration with the pre-commit project

There is also native support for using gitlab-ci-linter as a pre-commit-hook in
the [pre-commit project](https://pre-commit.com/). If you're using pre-commit,
include this tool in your `.pre-commit-config.yaml` like this:

```
  - repo: https://gitlab.com/orobardet/gitlab-ci-linter/
    rev: < you define a git revision or tag here >
    hooks:
      - id: gitlab-ci-linter
```

120
## Things to know
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
121

122
- If no `.gitlab-ci.yml` is detected in the git repository root, the tool does nothing (if installed as pre-commit hook, it will not prevent the commit).
123
- This tool works (or should) with any instance of Gitlab: gitlab.com or custom instance.
Olivier Robardet's avatar
Olivier Robardet committed
124
- It uses the url of the remote `origin` to guess the url of the Gitlab to use (also works if the remote is ssh, as soon as the Gitlab respond on HTTP using the same FQDN as ssh)
125
- If the `/ci/lint` API is not publicly accessible (e.g. 2FA is enforced), you can specify a personal access token using `--personal-access-token|-p` option or `GCL_PERSONAL_ACCESS_TOKEN` environment variable. The token must have `api` scope. 
Olivier Robardet's avatar
Add doc  
Olivier Robardet committed
126 127 128

## --help 

129 130 131 132 133 134 135 136
A bunch of options are available to configure the binary. All options can be also set using environment variables.  
Option's value on the command line have precedence over environment variables. 

```
Usage:
   gitlab-ci-linter [global options] [command [command options]] [PATH]

Global options:
137 138 139 140 141 142 143 144 145
   --gitlab-url URL, -u URL             root URL of the Gitlab instance to use API (default: auto-detect from remote origin, else "https://gitlab.com") [$GCL_GITLAB_URL]
   --ci-file FILE, -f FILE              FILE is the relative or absolute path to the gitlab-ci file [$GCL_GITLAB_CI_FILE]
   --directory DIR, -d DIR              DIR is the directory from where to search for gitlab-ci file and git repository (default: ".") [$GCL_DIRECTORY]
   --personal-access-token TOK, -p TOK  personal access token TOK for accessing repositories when you have 2FA enabled [$GCL_PERSONAL_ACCESS_TOKEN]
   --timeout value, -t value            timeout in second after which http request to Gitlab API will timeout (and the program will fails) (default: 5) [$GCL_TIMEOUT]
   --no-color, -n                       don't color output. By defaults the output is colorized if a compatible terminal is detected. (default: false) [$GCL_NOCOLOR]
   --verbose, -v                        verbose mode (default: false) [$GCL_VERBOSE]
   --help, -h                           show help (default: false)
   --version                            print the version information (default: false)
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
   
Arguments:
   If PATH if given, it will depending of its type on filesystem:
    - if a file, it will be used as the gitlab-ci file to check (similar to global --ci-file option)
    - if a directory, it will be used as the folder from where to search for a ci file and a git repository (similar to global --directory option)
   PATH have precedence over --ci-file and --directory options.

Commands:
   check, c      Check the .gitlab-ci.yml (default command if none is given)
   install, i    install as git pre-commit hook
   uninstall, u  uninstall the git pre-commit hook
   version, v    Print the version information
   help, h       Shows a list of commands or help for one command

   If no command is given, 'check 'is used by default
```

## Usage examples

Check the `.gitlab-ci.yml` of the git repository containing the current working directory:

```shell
gitlab-ci-lint
# or
gitlab-ci-lint check
```

Check the `.gitlab-ci.yml` of another git repository directory:

```shell
gitlab-ci-lint /path/to/another/git
# or 
gitlab-ci-lint check /path/to/another/git
# or
gitlab-ci-lint --directory /path/to/another/git check
```

Check a specific CI file (not at the root of the git repository, or not name `.gitlab-ci-.yml`):

```shell
gitlab-ci-lint /path/to/ci-file.yml
# or 
gitlab-ci-lint check /path/to/ci-file.yml
# or
gitlab-ci-lint --ci-file /path/to/ci-file.yml check
```

Install a pre-commit hook in the current git repository:

```shell
gitlab-ci-lint install
```

Install a pre-commit hook in another git repository:

```shell
gitlab-ci-lint -d /path/to/another/git install
```

205 206
You don't want https://gitlab.com to be the default Gitlab URL to use? There is no origin remote configured in your repository?
Or you don't want to use this gitlab?
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

```shell
gitlab-ci-lint --gitlab-url https://gitlab.my.org check
```

But you may prefer to use define the environment variable `GCL_GITLAB_URL=https://gitlab.my.org`, possibly in your shell 
init script, to configure this globally and also for pre-commit hooks.


# Contributing

This tool was my very first Go development, while learning the language.

It was done to fit my personal needs in context of my own day work.

So there is should be plenty room for improvement. Do not hesitate to propose bugfix, new features, or code improvements.  
Open issues.

As I may not have a lot of time to implement propositions, the best way to have a request landing quickly is to come with a merge request :) 
226

Olivier Robardet's avatar
Olivier Robardet committed
227 228 229

# Development

230 231 232 233 234 235
## Get the package

```shell
go get gitlab.com/orobardet/gitlab-ci-linter
```

236
## Dependencies and module
237

238
This software uses go module to handle dependencies. Just ensure to use a 
239

Olivier Robardet's avatar
Olivier Robardet committed
240 241
## Compilation

242 243 244 245 246 247
A [Makefile](Makefile) is provided, to build the executable you can simply run:

```shell
make
```

248
The Makefile accept the following targets (but not limited to):
249 250 251

- `build`
- `clean` 
252 253 254
- `test`: runs tests with code coverage
- `html-cover`: generate an html report of tests coverage
- `check`: runs some checks (fmt, vet, lint, security, cyclo, ...)
255 256
- `rebuild`: force the rebuild from scratch (simply runs `clean` followed by `build`)
- `install`: launch `go install`
257 258
- `run`: run the program, after building it, if needed. Arguments for the program can be passed after the `run target` 
or using the `RUNARGS` environment variable.
259

Olivier Robardet's avatar
Olivier Robardet committed
260
```shell
261 262 263 264 265 266 267 268 269 270 271
# The following commands are equivalent:
make run -v check
RUNARGS="-v check" make run
``` 

The Makefile also accept the following environment variables:

- `BINARY`: the name and path of the binary to build (by default `.build/gitlab-ci-linter`)
- `VERSION`: the version number to include in the program (by default use the last git tag if any, else the short commit hash, both suffixed by `-dev`)
- `REVISION`: the revision string to include in the program, typically the VCS commit hash (by default the git full commit hash) 
- `BUILDTIME`: the build date and time (by default the current ones, of course)
272
- `DEBUG`: binaries a build without debug symbols to reduce their size (`-s -w` link options) ; setting `DEBUG` to a non-zero value (0 by default) will build binary with debug symbols
273 274

Other targets exists, look directly in the [Makefile](Makefile)'s comments.