# CI on the self-hosted GitLab, ported from .github/workflows/release.yml when # the GitHub account was suspended on 2026-09-20. The Actions file stays in the # tree: it is the reference this was written from and works unchanged if the # appeal succeeds. # # e2e.yml is deliberately NOT ported. e2e/public.sh publishes 25, 80, 443, # 465, 993, 995 and 4190 on the machine it runs on, which on GitHub was a # throwaway VM and here would be Web_Host -- where 80 and 443 are nginx # serving every live site and the mail ports belong to the mail netns. # Running it on this runner would take the sites down for the length of the # test. It stays a manual check on a disposable host until there is a runner # that can safely be given those ports. # # The shape is the same -- tag-driven, amd64 and arm64, reproducible -- but the # publishing half is necessarily different. There is no `gh release`, so the # tarballs go to this project's generic package registry and the Release is # created with release-cli, linking to them. The docs guide installs from # release assets, so those links are the part that has to keep working. # # Images are pinned by digest, with the tag in the trailing comment: the # replacement for the workflow's SHA-pinned actions, since GitLab has no # action allowlist. stages: [test, build, release] variables: PKG: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/ihasmail-oneshot" default: interruptible: true .go: &go image: golang:1.26-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d # 1.26-bookworm cache: key: go-mod paths: [.gocache/] variables: GOPATH: "$CI_PROJECT_DIR/.gocache" test: <<: *go stage: test script: - go vet ./... - go test ./... # Kept as `go run ...@latest` exactly as the workflow had it: the point of # a vulnerability check is to use today's database, not a pinned copy of # last month's. - go run golang.org/x/vuln/cmd/govulncheck@latest ./... rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG build: <<: *go stage: build needs: [test] script: # The workflow refused to release a tag that is not an ancestor of main, # so that a release can never describe code that was never reviewed onto # the default branch. GIT_DEPTH is unset below to make the ancestry # available -- a shallow clone cannot answer this. - git fetch --quiet origin "$CI_DEFAULT_BRANCH" - | git merge-base --is-ancestor "$(git rev-parse "${CI_COMMIT_TAG}^{commit}")" "origin/$CI_DEFAULT_BRANCH" \ || { echo "!! $CI_COMMIT_TAG is not on $CI_DEFAULT_BRANCH"; exit 1; } # SOURCE_DATE_EPOCH is what makes the tarballs reproducible: without it # every build stamps a new mtime and two builds of one tag differ. - SOURCE_DATE_EPOCH="$(git log -1 --format=%ct "$CI_COMMIT_TAG")" scripts/build-release.sh "$CI_COMMIT_TAG" dist - sha256sum dist/*.tar.gz variables: GIT_DEPTH: "0" artifacts: paths: [dist/] expire_in: 1 week rules: - if: $CI_COMMIT_TAG release: stage: release image: registry.gitlab.com/gitlab-org/cli:latest@sha256:3f0a591b3b96c39ac8e28480ee99bb93201b7bcea1fbca7ed50c034098111db2 # latest needs: [build] script: # Upload first, then create the Release pointing at what was uploaded. A # Release whose assets 404 is worse than no Release: the install guide # sends people straight at these URLs. - | set -eu for f in dist/*; do n=$(basename "$f") echo "uploading $n" curl --fail --silent --show-error \ --header "JOB-TOKEN: ${CI_JOB_TOKEN}" \ --upload-file "$f" \ "${PKG}/${CI_COMMIT_TAG}/${n}" done - | set -eu args="" for f in dist/*; do n=$(basename "$f") # direct_asset_path is what makes the permalink work. Without it the # only stable URL is the package registry one, which carries the tag # and so cannot be a "latest" link. With it, every release exposes # /-/releases/permalink/latest/downloads/binaries/ # which is the GitLab equivalent of the GitHub # /releases/latest/download/ URL the install guide has always # used. Changing this path breaks documented install commands. args="$args --assets-link {\"name\":\"${n}\",\"url\":\"${PKG}/${CI_COMMIT_TAG}/${n}\",\"direct_asset_path\":\"/binaries/${n}\"}" done # shellcheck disable=SC2086 release-cli create --name "$CI_COMMIT_TAG" --tag-name "$CI_COMMIT_TAG" \ --description "Binaries for linux/amd64 and linux/arm64. Verify with SHA256SUMS." $args rules: - if: $CI_COMMIT_TAG