{"id":13496302,"url":"https://github.com/firecow/gitlab-ci-local","last_synced_at":"2026-04-03T11:02:43.514Z","repository":{"id":36959149,"uuid":"231806480","full_name":"firecow/gitlab-ci-local","owner":"firecow","description":"Tired of pushing to test your .gitlab-ci.yml?","archived":false,"fork":false,"pushed_at":"2025-05-12T02:31:24.000Z","size":392371,"stargazers_count":2936,"open_issues_count":41,"forks_count":154,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-12T13:09:50.303Z","etag":null,"topics":["cd","ci","git","gitlab","gitlab-ci","local","pipeline","push","uncomitted","untracked"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firecow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-01-04T18:03:14.000Z","updated_at":"2025-05-11T21:15:41.000Z","dependencies_parsed_at":"2024-12-06T13:45:19.034Z","dependency_job_id":"990bac12-b1e1-4f72-8c95-e2425b7ada96","html_url":"https://github.com/firecow/gitlab-ci-local","commit_stats":{"total_commits":1247,"total_committers":42,"mean_commits":29.69047619047619,"dds":"0.16038492381716118","last_synced_commit":"5062d6a638fffa3f7c8fb322df463399d32d5015"},"previous_names":[],"tags_count":130,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firecow%2Fgitlab-ci-local","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firecow%2Fgitlab-ci-local/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firecow%2Fgitlab-ci-local/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firecow%2Fgitlab-ci-local/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firecow","download_url":"https://codeload.github.com/firecow/gitlab-ci-local/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253747294,"owners_count":21957736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cd","ci","git","gitlab","gitlab-ci","local","pipeline","push","uncomitted","untracked"],"created_at":"2024-07-31T19:01:45.495Z","updated_at":"2026-04-03T11:02:43.499Z","avatar_url":"https://github.com/firecow.png","language":"TypeScript","readme":"Tired of pushing to test your .gitlab-ci.yml?\n\nRun gitlab pipelines locally as shell executor or docker executor.\n\nGet rid of all those dev specific shell scripts and make files.\n\n[![build](https://img.shields.io/github/actions/workflow/status/firecow/gitlab-ci-local/build.yml?branch=master)](https://github.com/firecow/gitlab-ci-local/actions)\n[![Known Vulnerabilities](https://snyk.io/test/github/firecow/gitlab-ci-local/badge.svg)](https://snyk.io/test/github/firecow/gitlab-ci-local)\n[![npm](https://img.shields.io/npm/v/gitlab-ci-local)](https://npmjs.org/package/gitlab-ci-local)\n[![license](https://img.shields.io/github/license/firecow/gitlab-ci-local)](https://npmjs.org/package/gitlab-ci-local)\n[![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com)\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=sqale_rating)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=reliability_rating)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=security_rating)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=code_smells)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=firecow_gitlab-ci-local\u0026metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=firecow_gitlab-ci-local)\n\n## Table of contents\n\n* [Examples](./examples)\n    * [docker-compose-nodejs](./examples/docker-compose-nodejs)\n    * [docker-swarm-php](./examples/docker-swarm-php)\n    * [docker-in-docker-build](./examples/docker-in-docker-build)\n    * [docker-in-docker with a local registry](./examples/docker-in-docker-build-with-local-registry)\n* [Installation](#installation)\n* [Convenience](#convenience)\n    * [CLI options](#cli-options)\n      * [Via a file](#via-a-file)\n      * [Via environment variables](#via-environment-variables)\n    * [DotEnv file](#dotenv-file)\n    * [Bash alias](#bash-alias)\n    * [Tab completion](#tab-completion)\n    * [Listing jobs](#list-pipeline-jobs)\n* [Quirks](#quirks)\n    * [Tracked Files](#tracked-files)\n    * [Local Only](#local-only)\n    * [Home File Variables](#home-file-variables)\n    * [Remote File Variables](#remote-file-variables)\n    * [Project File Variables](#project-file-variables)\n    * [Decorators](#decorators)\n    * [Includes](#includes)\n    * [Artifacts](#artifacts)\n    * [Self Hosted Custom Ports](#self-hosted-custom-ports)\n* [Development](#development)\n    * [Scripts](#scripts)\n* [Creating single executable binaries from source](#creating-single-executable-binaries-from-source)\n\n## Installation\n\n### Linux based on Debian\n\nUsers of Debian-based distributions should prefer the [the Deb822 format][deb822], installed with:\n\n```bash\nsudo wget -O /etc/apt/sources.list.d/gitlab-ci-local.sources https://gitlab-ci-local-ppa.firecow.dk/gitlab-ci-local.sources\nsudo apt-get update\nsudo apt-get install gitlab-ci-local\n```\n\n  [deb822]: https://repolib.readthedocs.io/en/latest/deb822-format.html#deb822-format\n\nIf your distribution does not support this, you can run these commands:\n\n```bash\ncurl -s \"https://gitlab-ci-local-ppa.firecow.dk/pubkey.gpg\" | sudo apt-key add -\necho \"deb https://gitlab-ci-local-ppa.firecow.dk ./\" | sudo tee /etc/apt/sources.list.d/gitlab-ci-local.list\n\n# OR\n\n# MUST be `.asc` at least for older apts (e.g. Ubuntu Focal), since the key is ASCII-armored\nPPA_KEY_PATH=/etc/apt/sources.list.d/gitlab-ci-local-ppa.asc\ncurl -s \"https://gitlab-ci-local-ppa.firecow.dk/pubkey.gpg\" | sudo tee \"${PPA_KEY_PATH}\"\necho \"deb [ signed-by=${PPA_KEY_PATH} ] https://gitlab-ci-local-ppa.firecow.dk ./\" | sudo tee /etc/apt/sources.list.d/gitlab-ci-local.list\n\n# and then\n\nsudo apt-get update\nsudo apt-get install gitlab-ci-local\n```\n\nNote that the path `/etc/apt/sources.list.d/gitlab-ci-local.list` is used in the file `gitlab-ci-local.list`.\nIf you change it in these commands you must also change it in `/etc/apt/sources.list.d/gitlab-ci-local.list`.\n\n### Arch Linux\n\n`gitlab-ci-local` is available for Arch Linux through the [AUR](https://aur.archlinux.org/packages/gitlab-ci-local). Install with your favourite AUR helper.\n\n```\nparu -S gitlab-ci-local\n```\n\n### NPM\n\n```bash\nnpm install -g gitlab-ci-local\n```\n\n### Bun\n\n```bash\nbun install -g gitlab-ci-local\n```\n\n### Macos\n\n*bash version must be above or equal 4.x.x*\n\n```bash\nbrew install gitlab-ci-local\n```\n\n### Windows (Git bash)\n\n- Install [gitbash](https://git-scm.com/downloads)\n- Install [rsync](https://gist.github.com/radleta/0b337a2b14f761951cf2aab0578512b9)\n\nDownload and put binary in `C:\\Program Files\\Git\\mingw64\\bin`\n\n```bash\ncurl -L https://github.com/firecow/gitlab-ci-local/releases/latest/download/gitlab-ci-local-windows-amd64.zip -o gcl.zip \u0026\u0026 unzip -o gcl.zip -d /c/Program\\ Files/Git/mingw64/bin \u0026\u0026 rm gcl.zip\n```\n\nExecuting `gitlab-ci-local` with `--variable MSYS_NO_PATHCONV=1` can be useful in certain situations\n\n## Convenience\n\n### CLI options\n\u003e [!NOTE]\n\u003e Most likely [home-file-variables](https://github.com/firecow/gitlab-ci-local?tab=readme-ov-file#home-file-variables) or [project-file-variables](https://github.com/firecow/gitlab-ci-local?tab=readme-ov-file#project-file-variables) is what you're looking for instead\n\nAll cli options can be assigned default values by either of the following ways:\n\n#### Via environment variables\n```bash\nexport GCL_NEEDS=true                   # --needs options\nexport GCL_FILE='.gitlab-ci-local.yml'  # --file=.gitlab-ci-local.yml\n```\n\n#### Via a file\n```sh\n# Either of the following:\n# - `.gitlab-ci-local-env` in the current working directory\n# - `$HOME/.gitlab-ci-local/.env`\nNEEDS=true               # --needs\nFILE=doctor-strange.yml  # --file=doctor-strange.yml\n```\n\n### Bash alias\n\n```bash\necho \"alias gcl='gitlab-ci-local'\" \u003e\u003e ~/.bashrc\n```\n\n### Tab completion\n\n```bash\ngitlab-ci-local --completion \u003e\u003e ~/.bashrc\n```\n\n### Logging options\n\n```shell\nexport GCL_TIMESTAMPS=true # or --timestamps: show timestamps in logs\nexport GCL_MAX_JOB_NAME_PADDING=30 # or --maxJobNamePadding: limit padding around job name\nexport GCL_QUIET=true # or --quiet: Suppress all job output\n```\n\n### List Pipeline Jobs\n\nSometimes there is the need of knowing which jobs will be added before actually executing the pipeline.\nGitLab CI Local is providing the ability of showing added jobs with the following cli flags.\n\n#### --list\n\nThe command `gitlab-ci-local --list` will return pretty output and will also filter all jobs which are set\nto `when: never`.\n\n```text\nname        description  stage   when        allow_failure  needs\ntest-job    Run Tests    test    on_success  false\nbuild-job                build   on_success  true           [test-job]\n```\n\n#### --list-all\n\nSame as `--list` but will also print out jobs which are set to `when: never` (directly and implicit e.g. via rules).\n\n```text\nname        description  stage   when        allow_failure  needs\ntest-job    Run Tests    test    on_success  false\nbuild-job                build   on_success  true           [test-job]\ndeploy-job               deploy  never       false          [build-job]\n```\n\n#### --list-csv\n\nThe command `gitlab-ci-local --list-csv` will output the pipeline jobs as csv formatted list and will also filter all\njobs which are set\nto `when: never`.\nThe description will always be wrapped in quotes (even if there is none) to prevent semicolons in the description\ndisturb the csv structure.\n\n```text\nname;description;stage;when;allow_failure;needs\ntest-job;\"Run Tests\";test;on_success;false;[]\nbuild-job;\"\";build;on_success;true;[test-job]\n```\n\n#### --list-csv-all\n\nSame as `--list-csv-all` but will also print out jobs which are set to `when: never` (directly and implicit e.g. via\nrules).\n\n```text\nname;description;stage;when;allow_failure;needs\ntest-job;\"Run Tests\";test;on_success;false;[]\nbuild-job;\"\";build;on_success;true;[test-job]\ndeploy-job;\"\";deploy;never;false;[build-job]\n```\n\n## Quirks\n\n### Tracked Files\n\nUntracked and ignored files will not be synced inside isolated jobs, only tracked files are synced.\n\nRemember `git add`\n\n### Local Only\n\n```yml\nlocal-only-job:\n  rules:\n    - { if: $GITLAB_CI == 'false' }\n```\n\n```yml\nlocal-only-subsection:\n  script:\n    - if [ $GITLAB_CI == 'false' ]; then eslint . --fix; fi\n    - eslint .\n```\n\n### Home file variables\n\nPut a file like this in `$HOME/.gitlab-ci-local/variables.yml`\n\n```yaml\n---\nproject:\n  gitlab.com/test-group/test-project.git:\n    # Will be type Variable and only available if remote is exact match\n    AUTHORIZATION_PASSWORD: djwqiod910321\n  gitlab.com:project/test-group/test-project.git: # another syntax\n    AUTHORIZATION_PASSWORD: djwqiod910321\n\ngroup:\n  gitlab.com/test-group/:\n    # Will be type Variable and only available for remotes that include group named 'test-group'\n    DOCKER_LOGIN_PASSWORD: dij3213n123n12in3\n\nglobal:\n  # Will be type File, because value is a file path\n  KNOWN_HOSTS: '~/.ssh/known_hosts'\n  DEPLOY_ENV_SPECIFIC:\n    type: variable # Optional and defaults to variable\n    values:\n      '*production*': 'Im production only value'\n      'staging': 'Im staging only value'\n  FILE_CONTENT_IN_VALUES:\n    type: file\n    values:\n      '*': |\n        Im staging only value\n        I'm great for certs n' stuff\n```\n\nVariables will now appear in your jobs, if project or group matches git remote, globals are always present\n\n### Remote file variables\n\nYou can also fetch variable files from remote git repositories. If you need multiple variable files, repeat the `--remote-variables` flag.\n\n```shell\ngitlab-ci-local --remote-variables git@gitlab.com:firecow/example.git=gitlab-variables.yml=master\n```\n\n### Project file variables\n\nThe `--variables-file` [default: $CWD/.gitlab-ci-local-variables.yml] can be used to setup the CI/CD variables for the executors\n\n#### `yaml` format\n```yaml\n---\nAUTHORIZATION_PASSWORD: djwqiod910321\nDOCKER_LOGIN_PASSWORD: dij3213n123n12in3\n# Will be type File, because value is a file path\nKNOWN_HOSTS: '~/.ssh/known_hosts'\n\n# This is only supported in the yaml format\n# https://docs.gitlab.com/ee/ci/environments/index.html#limit-the-environment-scope-of-a-cicd-variable\nEXAMPLE:\n  values:\n    \"*\": \"I am only available in all jobs\"\n    staging: \"I am only available in jobs with `environment: staging`\"\n    production: \"I am only available in jobs with `environment: production`\"\n```\n\n#### `.env` format\n```\nAUTHORIZATION_PASSWORD=djwqiod910321\nDOCKER_LOGIN_PASSWORD=dij3213n123n12in3\n# NOTE: value will be '~/.ssh/known_hosts' which is different behavior from the yaml format\nKNOWN_HOSTS='~/.ssh/known_hosts'\n```\n\n### Decorators\n\n#### The `@Description` decorator\n\nAdds descriptive text to `gitlab-ci-local --list`\n\n```yml\n# @Description Install npm packages\nnpm-install:\n  image: node\n  artifacts:\n    paths:\n      - node_modules/\n  script:\n    - npm install --no-audit\n```\n\n![description-decorator](./docs/images/description-decorator.png)\n\n#### The `@Interactive` decorator\n\n```yml\n# @Interactive\ninteractive-shell:\n  rules:\n    - if: $GITLAB_CI == 'false'\n      when: manual\n  script:\n    - docker run -it debian bash\n```\n\n![description-decorator](./docs/images/interactive-decorator.png)\n\n#### The `@InjectSSHAgent` decorator\n\n```yml\n# @InjectSSHAgent\nneed-ssh:\n  image: kroniak/ssh-client\n  script:\n    - ssh-add -L\n```\n\n#### The `@NoArtifactsToSource` decorator\n\nPrevent artifacts from being copied to source folder\n\n```yml\n# @NoArtifactsToSource\nproduce:\n  stage: build\n  script: mkdir -p path/ \u0026\u0026 touch path/file1\n  artifacts: { paths: [ path/ ] }\n```\n\nA global configuration is possible when setting the following flag\n\n```shell\ngitlab-ci-local --no-artifacts-to-source\n```\n\n### Includes\n\nIncludes from external sources are only fetched once and cached. Use `--fetch-includes` to ensure that the latest external sources are always fetched.\n\n### Artifacts\n\nShell executor jobs copies artifacts to host/cwd directory. Use --shell-isolation option to mimic correct artifact\nhandling for shell jobs.\n\nDocker executor copies artifacts to and from .gitlab-ci-local/artifacts\n\n### Self Hosted Custom Ports\n\nIf your self-hosted GitLab instance uses custom ports, it is recommended to manually define the `CI_SERVER_PORT` and/or `CI_SERVER_SHELL_SSH_PORT` variables accordingly.\n\n```yaml\n---\n# $CWD/.gitlab-ci-local-variables.yml\n\nCI_SERVER_PORT: 8443\nCI_SERVER_SHELL_SSH_PORT: 8022\n```\n\n### Special variables\n- `GCL_PROJECT_DIR_ON_HOST` Absolute path to gitlab-ci-local current working directory on the host machine. Use in docker-executor jobs only.\n\n## Development\n\nYou need [bun](https://bun.sh/) installed.\n\n### Scripts\n\n```bash\n# Install dependencies\nbun install\n\n# Run all tests\nbun run test\n\n# Run individual test-case\nbunx vitest run tests/test-cases/cache-paths-not-array\n```\n\n![example](./docs/images/example.png)\n\nIt's also possible to run individual `.gitlab-ci.yml`, via `bun src/index.ts --cwd examples/docker-compose-nodejs`\n\n## Creating single executable binaries from source\n```bash\nbun install\n\n# According to your needs:\nbun build:linux-amd64\nbun build:linux-arm64\nbun build:win\nbun build:macos-x64\nbun build:macos-arm64\nbun build-all\n# the binary will be generated in the respective ./bin/\u003cos\u003e/gitlab-ci-local\n```\n","funding_links":[],"categories":["TypeScript","git","List of Continuous Integration services"],"sub_categories":["Introduction"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirecow%2Fgitlab-ci-local","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffirecow%2Fgitlab-ci-local","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirecow%2Fgitlab-ci-local/lists"}