ci: add CCMA release builds

This commit is contained in:
Marcel Peterkau
2026-06-23 20:19:53 +02:00
parent 302170230a
commit 0e3087a780
16 changed files with 842 additions and 24 deletions
+40
View File
@@ -0,0 +1,40 @@
name: PR Check
on:
pull_request:
jobs:
pr_check:
name: Project PR check (linux-amd64)
runs-on: linux-amd64
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
git fetch --depth=1 origin "${{ github.event.pull_request.head.ref }}"
git checkout --force FETCH_HEAD
- name: Load central CI templates
shell: bash
run: |
set -euo pipefail
git submodule sync --recursive
git submodule update --init --remote ci-templates
git -C ci-templates rev-parse --short HEAD
- name: Run config-driven PR check
uses: ./ci-templates/actions/ci-runner
with:
command: pr-check
config: ci-config.yaml
+42
View File
@@ -0,0 +1,42 @@
name: Push Smoke Build
on:
push:
branches: [dev, main]
jobs:
smoke_build:
name: Project smoke build (linux-amd64)
runs-on: linux-amd64
if: ${{ !contains(github.event.head_commit.message, '[nobuild]') }}
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
git fetch --depth=1 origin "${{ github.ref_name }}"
git checkout --force FETCH_HEAD
- name: Load central CI templates
shell: bash
run: |
set -euo pipefail
git submodule sync --recursive
git submodule update --init --remote ci-templates
git -C ci-templates rev-parse --short HEAD
- name: Run config-driven smoke build
uses: ./ci-templates/actions/ci-runner
with:
command: smoke-build
config: ci-config.yaml
+106
View File
@@ -0,0 +1,106 @@
name: Dev Version Bump
on:
workflow_run:
workflows: ["Push Smoke Build"]
types: [completed]
branches: [dev]
env:
CI_GIT_EMAIL: 'git-ci@hiabuto.net'
CI_GIT_NAME: 'Git-CI'
GITEA_REPO: ${{ github.repository }}
jobs:
bump:
runs-on: linux-amd64
if: "${{ gitea.event.workflow_run.conclusion == 'success' && gitea.event.workflow_run.head_branch == 'dev' }}"
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
else
echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
fi
git fetch --depth=50 origin "${{ gitea.event.workflow_run.head_branch }}"
git checkout --force "${{ gitea.event.workflow_run.head_sha }}"
- name: Load central CI templates
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
git submodule sync --recursive
git submodule update --init --remote ci-templates
git -C ci-templates rev-parse --short HEAD
- id: ver
name: Compute version
uses: ./ci-templates/.gitea/actions/actions-versioning
with:
config_file: ci-config.yaml
ref_name: ${{ gitea.event.workflow_run.head_branch }}
- name: Commit + push VERSION (dev)
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
subj=$(git log -1 --pretty=format:%s)
if [[ "$subj" == *"[nobuild]"* ]]; then
echo "[nobuild] present; skipping dev bump."
exit 0
fi
if [[ "$subj" == ci:\ bump\ dev\ version* ]]; then
echo "Already a dev bump commit; nothing to do."
exit 0
fi
version="${{ steps.ver.outputs.program_version }}"
version_file=$(python3 - <<'PY'
import re
p='VERSION'
for line in open('ci-config.yaml', encoding='utf-8'):
if re.match(r'^\s*file\s*:', line):
p=line.split(':',1)[1].strip().strip('"\'')
break
print(p)
PY
)
git config user.email "${CI_GIT_EMAIL}"
git config user.name "${CI_GIT_NAME}"
echo "$version" > "$version_file"
git add "$version_file"
if git diff --cached --quiet; then
echo "VERSION already up-to-date; nothing to commit."; exit 0
fi
git commit -m "ci: bump dev version to ${version} [skip ci]"
git config --local --unset-all http.https://git.hiabuto.net/.extraheader || true
git config --global --unset-all http.https://git.hiabuto.net/.extraheader || true
git remote set-url origin "https://matcha:${CI_MATCHA_GITEA_TOKEN}@git.hiabuto.net/${GITEA_REPO}.git"
git push origin HEAD:dev
+352
View File
@@ -0,0 +1,352 @@
name: Main Release
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: release-main
cancel-in-progress: false
env:
CI_GIT_EMAIL: 'git-ci@hiabuto.net'
CI_GIT_NAME: 'Git-CI'
GITEA_API_BASE: 'https://git.hiabuto.net/api/v1'
GITEA_REPO: ${{ github.repository }}
jobs:
compute:
runs-on: linux-amd64
if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }}
outputs:
program_version: ${{ steps.ver.outputs.program_version }}
did_release: ${{ steps.ver.outputs.did_release }}
release_tag: ${{ steps.ver.outputs.release_tag }}
release_kind: ${{ steps.ver.outputs.release_kind }}
head_sha: ${{ steps.meta.outputs.head_sha }}
head_msg: ${{ steps.meta.outputs.head_msg }}
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
else
echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
fi
git fetch --depth=50 origin "${{ github.ref_name }}"
git checkout --force "${{ github.sha }}"
- name: Load central CI templates
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
git submodule sync --recursive
git submodule update --init --remote ci-templates
git -C ci-templates rev-parse --short HEAD
- id: meta
shell: bash
run: |
set -euo pipefail
echo "head_sha=${{ github.sha }}" >> "$GITHUB_OUTPUT"
echo "head_msg=$(git log -1 --pretty=format:%s)" >> "$GITHUB_OUTPUT"
- id: ver
name: Compute version
uses: ./ci-templates/.gitea/actions/actions-versioning
with:
config_file: ci-config.yaml
ref_name: ${{ github.ref_name }}
package:
needs: [compute]
if: ${{ needs.compute.outputs.did_release == 'true' && !contains(needs.compute.outputs.head_msg, '[nobuild]') }}
strategy:
fail-fast: false
matrix:
include:
- os_label: linux-amd64
os: linux
arch: amd64
- os_label: linux-arm64
os: linux
arch: arm64
- os_label: windows-amd64
os: windows
arch: amd64
runs-on: ${{ matrix.os_label }}
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
else
echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
fi
git fetch --depth=50 origin "${{ github.ref_name }}"
git checkout --force "${{ needs.compute.outputs.head_sha }}"
- name: Load central CI templates
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
git submodule sync --recursive
git submodule update --init --remote ci-templates
git -C ci-templates rev-parse --short HEAD
- name: Package release via central CI templates
uses: ./ci-templates/actions/ci-runner
env:
CI_ARCH: ${{ matrix.arch }}
with:
command: package-release
config: ci-config.yaml
version: ${{ needs.compute.outputs.program_version }}
- name: Upload dist
uses: actions/upload-artifact@v3
with:
name: dist-${{ matrix.os }}-${{ matrix.arch }}
path: dist/
finalize_and_publish:
needs: [compute, package]
if: ${{ needs.compute.outputs.did_release == 'true' && needs.package.result == 'success' }}
runs-on: linux-amd64
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
else
echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
fi
git fetch --depth=50 origin "${{ github.ref_name }}"
git checkout --force "${{ needs.compute.outputs.head_sha }}"
- name: Download artifacts
uses: actions/download-artifact@v3
with:
path: release-artifacts
- name: Prepare upload dir
shell: bash
run: |
set -euo pipefail
mkdir -p upload
find release-artifacts -maxdepth 4 -type f -print -exec cp -f {} upload/ \;
ls -la upload
- name: Commit VERSION + tag + push (only now)
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
version="${{ needs.compute.outputs.program_version }}"
tag="${{ needs.compute.outputs.release_tag }}"
version_file=$(python3 - <<'PY'
import re
p='VERSION'
for line in open('ci-config.yaml', encoding='utf-8'):
if re.match(r'^\s*file\s*:', line):
p=line.split(':',1)[1].strip().strip('"\'')
break
print(p)
PY
)
git config user.email "${CI_GIT_EMAIL}"
git config user.name "${CI_GIT_NAME}"
echo "$version" > "$version_file"
git add "$version_file"
if git diff --cached --quiet; then
echo "VERSION already set in repo; continuing"
else
git commit -m "ci: release version ${version} [skip ci]"
fi
git config --local --unset-all http.https://git.hiabuto.net/.extraheader || true
git config --global --unset-all http.https://git.hiabuto.net/.extraheader || true
git remote set-url origin "https://matcha:${CI_MATCHA_GITEA_TOKEN}@git.hiabuto.net/${GITEA_REPO}.git"
git fetch --tags origin
git push origin "HEAD:main"
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
echo "Tag already exists on origin: ${tag} (will reuse)"
else
git tag "${tag}"
git push origin "${tag}"
fi
- name: Publish release + upload assets
shell: bash
env:
GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
TAG: ${{ needs.compute.outputs.release_tag }}
run: |
set -euo pipefail
if [ -z "${GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
python3 - <<'PY'
import json, os, pathlib, urllib.parse, urllib.request, urllib.error
api_base = os.environ['GITEA_API_BASE'].rstrip('/')
repo = os.environ['GITEA_REPO']
token = os.environ['GITEA_TOKEN'].strip()
tag = os.environ['TAG'].strip()
artifacts = sorted(p for p in pathlib.Path('upload').glob('*') if p.is_file())
headers = {'Authorization': f'token {token}', 'Accept': 'application/json'}
def request_json(method, url, data=None):
payload=None
h=dict(headers)
if data is not None:
payload=json.dumps(data).encode('utf-8'); h['Content-Type']='application/json'
req=urllib.request.Request(url, data=payload, method=method, headers=h)
try:
with urllib.request.urlopen(req) as resp:
txt=resp.read().decode('utf-8'); return resp.getcode(), json.loads(txt) if txt else None
except urllib.error.HTTPError as exc:
return exc.code, {'error': exc.read().decode('utf-8', errors='replace')}
def request_binary_post(url, payload, content_type):
h=dict(headers); h['Content-Type']=content_type
req=urllib.request.Request(url, data=payload, method='POST', headers=h)
with urllib.request.urlopen(req) as resp:
txt=resp.read().decode('utf-8'); return resp.getcode(), json.loads(txt) if txt else None
tag_url=f"{api_base}/repos/{repo}/releases/tags/{urllib.parse.quote(tag, safe='')}"
status, release = request_json('GET', tag_url)
if status==200 and isinstance(release, dict):
release_id=release.get('id')
else:
status, release = request_json('POST', f"{api_base}/repos/{repo}/releases", {
'tag_name': tag, 'name': tag, 'body': f'Automated release for {tag}', 'draft': False, 'prerelease': False,
})
if status not in (200,201):
raise SystemExit(f"create release failed {status} {release}")
release_id=release.get('id')
assets_url=f"{api_base}/repos/{repo}/releases/{release_id}/assets"
status, existing = request_json('GET', assets_url)
existing = existing if isinstance(existing, list) else []
by_name={e.get('name'):e for e in existing if isinstance(e, dict) and e.get('name')}
for a in artifacts:
name=a.name
prev=by_name.get(name)
if prev and prev.get('id'):
ds,_=request_json('DELETE', f"{assets_url}/{prev['id']}")
if ds!=204: raise SystemExit(f"delete asset failed {name} {ds}")
code,_=request_binary_post(f"{assets_url}?name={urllib.parse.quote(name, safe='')}", a.read_bytes(), 'application/octet-stream')
if code not in (200,201): raise SystemExit(f"upload failed {name} {code}")
print('Uploaded', name)
print('Release done', tag)
PY
sync_main_to_dev:
needs: [finalize_and_publish]
if: ${{ needs.finalize_and_publish.result == 'success' }}
runs-on: linux-amd64
steps:
- name: Checkout repository
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
git init .
git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
else
echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
fi
git fetch --depth=50 origin "${{ github.ref_name }}"
git checkout --force "${{ github.sha }}"
- name: Merge main into dev + bump dev0
shell: bash
env:
CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
exit 1
fi
git config user.email "${CI_GIT_EMAIL}"
git config user.name "${CI_GIT_NAME}"
git config --local --unset-all http.https://git.hiabuto.net/.extraheader || true
git config --global --unset-all http.https://git.hiabuto.net/.extraheader || true
git remote set-url origin "https://matcha:${CI_MATCHA_GITEA_TOKEN}@git.hiabuto.net/${GITEA_REPO}.git"
git fetch origin main dev
git checkout -B dev origin/dev
git merge origin/main -m "ci: merge main into dev [skip ci]"
version_file=$(python3 - <<'PY'
import re
p='VERSION'
for line in open('ci-config.yaml', encoding='utf-8'):
if re.match(r'^\s*file\s*:', line):
p=line.split(':',1)[1].strip().strip('"\'')
break
print(p)
PY
)
main_version=$(git show origin/main:"$version_file" | head -n1 | tr -d '\r\n' | xargs)
python3 -c "import re,sys; v=sys.argv[1].strip(); m=re.search(r'(\\d+)\\.(\\d+)\\.(\\d+)', v); (m is not None) or (_ for _ in ()).throw(SystemExit(f'Bad VERSION on main: {v!r}')); print(f'{m.group(1)}.{m.group(2)}.{m.group(3)}-dev0')" "$main_version" > "$version_file"
git add "$version_file"
if git diff --cached --quiet; then
echo "No VERSION changes after sync.";
else
git commit -m "ci: bump dev version to $(cat "$version_file") [skip ci]"
fi
git push origin HEAD:dev