Sharing a .gitlab-ci.yml for a docker runner that creates composer packages on push

Problem to solve

Make self hosted, private projects available via composer packages.

The below file will create composer packages versioned as dev-master once a push is executed to the master branch.

Process is:

  1. Checks for and deletes any existing package with the same version. (I needed to delete any existing first since the package was not being created with the updates if it already existed)
  2. Creates a new tag named dev-master (Composer packages are versioned according to the tags)
  3. Creates composer package based off the dev-master tag

The .gitlab-ci.yml file can be modified to create versioned packages vx.x.x if required.

I can then install/use these packages in other projects by defining in composer.json of the other projects:

"repositories": [
    {
      "type": "composer",
      "url": "https://my.gitlab-server.com/api/v4/group/{GROUP-NAME}/-/packages/composer/packages.json"
    }
  ],
"require": {
    "{GROUP-NAME}/{PACKAGE-NAME}": "dev-master",
    "{GROUP-NAME}/{PACKAGE-NAME2}": "dev-master"
  }

Configuration

Create a PAT and set in Group Variable.
A personal access token (PAT) was created and defined as a group variable GITLAB_PAT.

.gitlab-ci.yml

stages:
  - delete
  - tag
  - deploy

delete-package:
  stage: delete
  image: alpine:latest
  tags:
    - docker
  script:
    - 'apk add --no-cache jq'
    - 'apk add --no-cache curl'
    - 'PACKAGE_ID=$(curl -s --header "Job-Token: $CI_JOB_TOKEN" "https://${CI_SERVER_HOST}/api/v4/projects/$CI_PROJECT_ID/packages" | jq -r ".[] | select(.version==\"dev-master\") | .id")'
    - 'if [ -n "$PACKAGE_ID" ]; then'
    - '  curl --fail-with-body -X DELETE --header "Job-Token: $CI_JOB_TOKEN" "https://${CI_SERVER_HOST}/api/v4/projects/$CI_PROJECT_ID/packages/$PACKAGE_ID";'
    - 'else'
    - '  echo "Package dev-master not found";'
    - 'fi'
  only:
    - master

# Automatically tag the latest master commit as dev-master
tag-dev-master:
  stage: tag
  image: alpine:latest
  tags:
    - docker
  script:
    - apk add --no-cache git
    - git config --global user.name "${GITLAB_USER_NAME}"
    - git config --global user.email "${GITLAB_USER_EMAIL}"
    - git tag -f dev-master
    - git push -f https://oauth2:${GITLAB_PAT}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git dev-master
  only:
    - master

# Deploy the Composer package with the dev-master tag
deploy:
  stage: deploy
  image: curlimages/curl:latest
  tags:
    - docker
  script:
    - 'curl --fail-with-body --header "Job-Token: $CI_JOB_TOKEN" --data tag=dev-master --data ref=dev-master "https://${CI_SERVER_HOST}/api/v4/projects/$CI_PROJECT_ID/packages/composer"'
  only:
    - master

config.toml
Defined as an instance runner and runs all jobs tagged as docker. No image is defined in the runner config so the runner will pull and use any image defined in each stage of the build.

[[runners]]
  name = "DockerRunner1"
  url = "https://my.gitlab-server.com"
  id = 3
  token = "glrt-xxxxxxxxxxxxxxxxxxxxxxxxx"
  token_obtained_at = 2024-11-01T00:48:24Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.custom_build_dir]
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = ""
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0

Versions

Please select whether options apply, and add the version information.

  • Self-managed
  • GitLab.com SaaS
  • Dedicated
  • Self-hosted Runners

Versions

  • GitLab 17.4.1-ee
  • GitLab Runner, self-hosted 17.5.3