forked from cloud/ovgate
build image / image (push) Canceled after 0s
Gitea reads .gitea/workflows in preference to .github/workflows, so this supersedes the ghcr.io workflow here without deleting it: that one stays correct for github.com, and the two cannot race. Registry cache rather than type=gha -- a self-hosted act_runner supplies ACTIONS_CACHE_URL/ACTIONS_RUNTIME_TOKEN inconsistently, and without a cache every run recompiles the openvpn3 core from scratch. Attestations are off because they turn the push into a multi-manifest index that Gitea's package view renders as junk entries.
164 lines
7.0 KiB
YAML
164 lines
7.0 KiB
YAML
# Build the container image and publish it to the Gitea container registry.
|
|
#
|
|
# Why this lives in .gitea/workflows and not .github/workflows: Gitea looks for
|
|
# .gitea/workflows first and only falls back to .github/workflows when that
|
|
# directory does not exist. So the presence of this file makes Gitea ignore
|
|
# .github/workflows/publish-image.yml entirely. That file is still correct for
|
|
# github.com/ghcr.io and is deliberately left in place -- the two cannot race,
|
|
# and neither is dead code. Deleting this directory silently re-activates the
|
|
# ghcr.io workflow, which will fail here for want of a GitHub PAT.
|
|
#
|
|
# The unit suite runs *inside* the image build (the Dockerfile's builder stage
|
|
# ends with ./build/tests/ovg_tests), so a failing test fails the publish. There
|
|
# is deliberately no separate test job duplicating that -- see the note in
|
|
# .github/workflows/publish-image.yml, which makes the same choice.
|
|
#
|
|
# Tags produced:
|
|
# push to master -> master, sha-<short>
|
|
# push tag v1.2.3 -> 1.2.3, 1.2, latest, sha-<short>
|
|
# pull request -> built and smoke-tested, never pushed
|
|
#
|
|
# `latest` follows the newest release tag, not the branch head. Until the first
|
|
# v* tag exists, the tag to pull is `master`.
|
|
name: build image
|
|
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
tags: ["v*"]
|
|
pull_request:
|
|
branches: [master]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
# Superseding a PR build is free; killing a release build half way through is
|
|
# not.
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
|
|
jobs:
|
|
image:
|
|
runs-on: ubuntu-latest
|
|
# A cold build compiles the openvpn3 core and lwIP from source. Configure +
|
|
# compile alone measured 1m39s on 4 cores; on top of that the image build
|
|
# also does an apt install, two git clones, and the test suite. The ceiling
|
|
# is set well above any of that because the failure mode it guards against
|
|
# -- a cache miss on a runner that is also being slow -- is the one where a
|
|
# tight limit turns a slow build into a red one.
|
|
timeout-minutes: 60
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# Registry paths must be lowercase and github.repository is not guaranteed
|
|
# to be. Both halves are overridable: REGISTRY for a different Gitea host,
|
|
# IMAGE for an owner/name that differs from this repository's.
|
|
- name: Resolve image reference
|
|
id: img
|
|
env:
|
|
REGISTRY: ${{ vars.REGISTRY || 'git.sfclub.cc' }}
|
|
IMAGE: ${{ vars.IMAGE || github.repository }}
|
|
run: |
|
|
set -eu
|
|
printf 'ref=%s\n' \
|
|
"$(printf '%s/%s' "$REGISTRY" "$IMAGE" | tr '[:upper:]' '[:lower:]')" \
|
|
>> "$GITHUB_OUTPUT"
|
|
printf 'registry=%s\n' "$REGISTRY" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
# Skipped on pull requests: nothing is pushed from a PR, and a PR from a
|
|
# fork has no access to secrets anyway.
|
|
#
|
|
# REGISTRY_USER/REGISTRY_TOKEN match the naming in cloud/workspace-image.
|
|
# The fallback is Gitea's own per-job token, which can push to this
|
|
# instance's registry under the actor's namespace -- enough for the common
|
|
# case, so the workflow is not dead on arrival before secrets are set.
|
|
- name: Log in to the Gitea registry
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ steps.img.outputs.registry }}
|
|
username: ${{ secrets.REGISTRY_USER || github.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN || secrets.GITEA_TOKEN }}
|
|
|
|
- name: Derive tags and labels
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ steps.img.outputs.ref }}
|
|
tags: |
|
|
type=ref,event=branch
|
|
type=ref,event=pr
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=sha
|
|
# The default flavor (latest=auto) adds `latest` on a semver tag push
|
|
# and nowhere else, which is the intent stated at the top of the file.
|
|
|
|
- name: Build and push
|
|
id: build
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: ${{ github.event_name != 'pull_request' }}
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
# amd64 only, matching the project's stated target. arm64 is not known
|
|
# to be broken -- it is untested, and cross-building the openvpn3 core
|
|
# under QEMU costs the better part of an hour per run. Enabling it
|
|
# means adding docker/setup-qemu-action above and verifying lwIP's
|
|
# unaligned-access assumptions, not just editing this line.
|
|
platforms: linux/amd64
|
|
build-args: |
|
|
OVG_WITH_TUNNEL=ON
|
|
OVG_RUN_TESTS=1
|
|
# Registry-backed cache rather than type=gha: the GitHub Actions cache
|
|
# backend needs ACTIONS_CACHE_URL/ACTIONS_RUNTIME_TOKEN, which a
|
|
# self-hosted act_runner supplies inconsistently. A registry cache
|
|
# needs only the login two steps up. Without one of the two, every run
|
|
# recompiles openvpn3 from scratch.
|
|
cache-from: type=registry,ref=${{ steps.img.outputs.ref }}:buildcache
|
|
cache-to: ${{ github.event_name != 'pull_request' && format('type=registry,ref={0}:buildcache,mode=max', steps.img.outputs.ref) || '' }}
|
|
# Off on purpose. Attestations turn the push into a multi-manifest
|
|
# index with unknown/unknown platform entries, which Gitea's registry
|
|
# renders as junk "images" in the package view and which some pull
|
|
# paths mishandle. ghcr.io copes; this does not need to.
|
|
provenance: false
|
|
|
|
# Verifies the artifact that was actually published, by digest rather than
|
|
# by tag. Cheap, and it covers the two things a green build still would
|
|
# not: that the runtime stage carries the shared libraries the binary
|
|
# needs, and that the config baked into the image parses.
|
|
#
|
|
# --check needs the credentials file, which is deliberately not in the
|
|
# image; a throwaway one is enough to get the config validated.
|
|
- name: Smoke test the published image
|
|
if: github.event_name != 'pull_request'
|
|
env:
|
|
IMAGE: ${{ steps.img.outputs.ref }}@${{ steps.build.outputs.digest }}
|
|
run: |
|
|
set -eux
|
|
docker run --rm "$IMAGE" --version
|
|
printf 'ci:changeme\n' > "$RUNNER_TEMP/socks5.auth"
|
|
docker run --rm \
|
|
-v "$RUNNER_TEMP/socks5.auth:/etc/openvpngate/socks5.auth:ro" \
|
|
"$IMAGE" -c /etc/openvpngate/openvpngate.conf --check
|
|
|
|
- name: Summary
|
|
if: github.event_name != 'pull_request'
|
|
run: |
|
|
{
|
|
echo "### Published"
|
|
echo
|
|
echo '```'
|
|
echo "${{ steps.meta.outputs.tags }}"
|
|
echo '```'
|
|
echo
|
|
echo "digest: \`${{ steps.build.outputs.digest }}\`"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|