Files
monky-deployd/.gitlab-ci.yml
T
mdella 8fde0ba079 ci: wheel/package are blocking — runner egress proven on the v0.1.0 tag pipeline
Pipeline 6999 built the openziti 1.7.1 wheel (github.com + pypi.org) and the
nfpm .deb; the allow_failure escape hatches are no longer honest. package now
requires the wheel so a .deb can never ship without transport sdk.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLB7jieMNRkTsJ2epr4Ds1
2026-09-05 08:11:25 +00:00

193 lines
9.3 KiB
YAML

# monky-deployd CI/CD (mirrors monky-tenancy's conventions)
#
# lint -> test -> build (openziti wheel) -> package (.deb via nfpm) -> release (v* tags) -> docs
#
# Every script line is single-quoted (a bare ": " turns the line into a YAML map and silently
# yields a 0-job pipeline). Runner egress to github.com + pypi.org was PROVEN on the v0.1.0 tag
# pipeline (6999: openziti 1.7.1 wheel built, nfpm .deb packaged), so wheel/package are blocking.
#
# CI/CD variables (project or group level):
# GITEA_TOKEN — Gitea API token (write:repository) for `release:gitea`; without it the job is manual
# GITLAB_TRANSLATE_TOKEN — used by the translate-docs component (group level)
include:
# doc-translator via the CI/CD component; PARTIAL PIN @11.3 tracks 11.3.x (no `v`).
- component: $CI_SERVER_FQDN/tikali/platform/doc-translator/translate-docs@11.3
inputs:
docs_stage: docs
stages: [lint, test, build, package, release, docs]
# One pipeline per change: MR pipeline for merge requests, branch pipeline otherwise, never both.
workflow:
rules:
- if: '$CI_COMMIT_TAG'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
when: never
- if: '$CI_COMMIT_BRANCH'
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
OPENZITI_VERSION: "1.7.1"
NFPM_VERSION: "2.43.0"
cache:
key: "$CI_JOB_NAME"
paths: [.cache/pip]
.run_rules:
rules:
- if: '$CI_COMMIT_TAG'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
lint:
extends: [.run_rules]
stage: lint
image: python:3.12-slim
before_script:
- 'pip install -q "ruff>=0.16,<0.17"'
script:
- 'ruff check .'
- 'ruff format --check .'
- 'bash -n packaging/install.sh'
- 'bash -n packaging/scripts/postinstall.sh packaging/scripts/preremove.sh packaging/scripts/postremove.sh'
- 'python -c "import ast,sys; [ast.parse(open(f).read()) for f in sys.argv[1:]]" tests/fakebin/docker'
# the release version must match the tag when there is one
- 'if [ -n "$CI_COMMIT_TAG" ]; then v=$(python -c "import monky_deployd;print(monky_deployd.__version__)"); [ "v$v" = "$CI_COMMIT_TAG" ] || { echo "tag $CI_COMMIT_TAG != __version__ $v"; exit 1; }; fi'
test:
extends: [.run_rules]
stage: test
image: python:3.12-slim
before_script:
- 'pip install -q pytest'
script:
- 'chmod +x tests/fakebin/docker'
- 'pytest --junitxml=report.xml'
artifacts:
when: always
reports:
junit: report.xml
# --- the openziti wheel ---------------------------------------------------------------------
# PyPI ships `openziti` as an sdist whose build fetches ziti-sdk-c (+ prebuilt tlsuv/uv-mbed
# via cmake FetchContent) from github.com at install time. Building it here on ubuntu:26.04
# (the target OS; python3 = the target's python3) gives us a wheel to vendor into the venv.
# NEEDS runner egress to github.com + pypi.org (proven 2026-09-05, pipeline 6999).
wheel:
stage: build
image: ubuntu:26.04
needs: ["test"]
rules:
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
allow_failure: true
variables:
DEBIAN_FRONTEND: noninteractive
script:
- 'apt-get update -qq && apt-get install -y -qq --no-install-recommends python3 python3-venv python3-dev build-essential cmake ninja-build git pkg-config libssl-dev zlib1g-dev ca-certificates curl >/dev/null'
- 'python3 -m venv /tmp/wb && /tmp/wb/bin/pip install -q --upgrade pip wheel setuptools'
- 'mkdir -p vendor'
- '/tmp/wb/bin/pip wheel --no-deps --no-binary openziti "openziti==${OPENZITI_VERSION}" -w vendor/'
- 'ls -l vendor/'
artifacts:
paths: [vendor/*.whl]
expire_in: 30 days
# --- the .deb --------------------------------------------------------------------------------------
# venv at its final path (/opt/monky-deployd/venv is where the .deb puts it; venvs are not
# relocatable) + nfpm. nfpm comes from GitHub releases (egress) with the goreleaser apt repo as
# fallback (proven 2026-09-05, pipeline 6999). The wheel is required: a .deb without it would
# silently ship a broken `transport: sdk`.
package:
stage: package
image: ubuntu:26.04
needs:
- job: test
- job: wheel
rules:
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
allow_failure: true
variables:
DEBIAN_FRONTEND: noninteractive
script:
- 'apt-get update -qq && apt-get install -y -qq --no-install-recommends python3 python3-venv python3-pip ca-certificates curl gnupg >/dev/null'
- 'VERSION=$(python3 -c "import monky_deployd;print(monky_deployd.__version__)"); echo "VERSION=$VERSION" | tee build.env'
- 'python3 -m venv /opt/monky-deployd/venv'
- '/opt/monky-deployd/venv/bin/pip install -q --upgrade pip'
- '/opt/monky-deployd/venv/bin/pip install -q .'
- 'ls vendor/*.whl >/dev/null 2>&1 || { echo "no vendored openziti wheel (wheel job artifact missing)"; exit 1; }'
- '/opt/monky-deployd/venv/bin/pip install -q vendor/*.whl'
- '/opt/monky-deployd/venv/bin/python -c "import openziti; print(\"openziti import ok\")"'
- '/opt/monky-deployd/venv/bin/python -m monky_deployd version'
- 'mkdir -p build dist && cp -a /opt/monky-deployd/venv build/venv'
# nfpm: GitHub release .deb, else the goreleaser apt repo
- 'curl -fsSL -o /tmp/nfpm.deb "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_amd64.deb" && apt-get install -y -qq /tmp/nfpm.deb >/dev/null || { echo "deb [trusted=yes] https://repo.goreleaser.com/apt/ /" > /etc/apt/sources.list.d/goreleaser.list; apt-get update -qq; apt-get install -y -qq nfpm; }'
- 'VERSION=$VERSION nfpm package --config packaging/nfpm.yaml --packager deb --target dist/'
- 'cd dist && for f in *.deb; do sha256sum "$f" > "$f.sha256"; done && ls -l && cd ..'
- 'cp packaging/install.sh dist/install.sh'
artifacts:
paths: [dist/]
reports:
dotenv: build.env
expire_in: 90 days
# --- GitLab release (v* tags): generic package registry + release with asset links -------------
release:
stage: release
image:
name: registry.gitlab.com/gitlab-org/release-cli:latest
entrypoint: [""]
needs: ["package"]
rules:
- if: '$CI_COMMIT_TAG =~ /^v/'
script:
- 'apk add --no-cache curl >/dev/null 2>&1 || true'
- 'VERSION=${CI_COMMIT_TAG#v}; PKG="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/monky-deployd/${VERSION}"'
- 'for f in dist/*.deb dist/*.sha256 dist/install.sh; do curl -fsS --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file "$f" "$PKG/$(basename "$f")"; echo; done'
- 'DEB=$(basename dist/*.deb)'
- >-
release-cli create --name "monky-deployd $CI_COMMIT_TAG" --tag-name "$CI_COMMIT_TAG"
--description "See CHANGELOG.md. Public install assets are on the Gitea mirror: https://gitea.cbs.tikali.net/mdella/monky-deployd/releases/tag/$CI_COMMIT_TAG"
--assets-link "{\"name\":\"$DEB\",\"url\":\"$PKG/$DEB\",\"link_type\":\"package\"}"
--assets-link "{\"name\":\"$DEB.sha256\",\"url\":\"$PKG/$DEB.sha256\",\"link_type\":\"other\"}"
--assets-link "{\"name\":\"install.sh\",\"url\":\"$PKG/install.sh\",\"link_type\":\"other\"}"
# --- Gitea release (the PUBLIC download the installer uses) ------------------------------------------
# The GitLab project is private, so install.sh fetches from the Gitea mirror
# https://gitea.cbs.tikali.net/mdella/monky-deployd/releases/download/v<ver>/... . This job
# waits for the pull-mirror to carry the tag, creates the release and uploads the assets.
# Automatic when GITEA_TOKEN is set; otherwise a manual, non-blocking job (docs/OPERATIONS.md
# has the by-hand recipe).
release:gitea:
stage: release
image:
name: alpine:3.20
entrypoint: [""]
needs: ["package"]
rules:
- if: '$CI_COMMIT_TAG =~ /^v/ && $GITEA_TOKEN'
- if: '$CI_COMMIT_TAG =~ /^v/'
when: manual
allow_failure: true
variables:
GITEA_API: "https://gitea.cbs.tikali.net/api/v1/repos/mdella/monky-deployd"
script:
- 'apk add --no-cache curl jq >/dev/null'
- '[ -n "$GITEA_TOKEN" ] || { echo "GITEA_TOKEN is not set"; exit 1; }'
- 'H="Authorization: token $GITEA_TOKEN"'
- 'curl -fsS -X POST -H "$H" "$GITEA_API/mirror-sync" >/dev/null || echo "mirror-sync trigger failed; polling anyway"'
- 'for i in $(seq 1 30); do curl -fsS -H "$H" "$GITEA_API/tags/$CI_COMMIT_TAG" >/dev/null 2>&1 && break; echo "waiting for the mirror to carry $CI_COMMIT_TAG ($i)"; sleep 10; done'
- 'curl -fsS -H "$H" "$GITEA_API/tags/$CI_COMMIT_TAG" >/dev/null || { echo "tag not on the mirror yet"; exit 1; }'
- 'RID=$(curl -fsS -H "$H" "$GITEA_API/releases/tags/$CI_COMMIT_TAG" 2>/dev/null | jq -r .id || true)'
- 'if [ -z "$RID" ] || [ "$RID" = "null" ]; then RID=$(curl -fsS -X POST -H "$H" -H "Content-Type: application/json" "$GITEA_API/releases" -d "{\"tag_name\":\"$CI_COMMIT_TAG\",\"name\":\"monky-deployd $CI_COMMIT_TAG\",\"body\":\"See CHANGELOG.md\",\"draft\":false,\"prerelease\":false}" | jq -r .id); fi'
- 'echo "release id $RID"'
- 'for f in dist/*.deb dist/*.sha256 dist/install.sh; do n=$(basename "$f"); curl -fsS -X POST -H "$H" -F "attachment=@$f" "$GITEA_API/releases/$RID/assets?name=$n" >/dev/null && echo "uploaded $n"; done'