name: Build and publish runner image description: Build, verify, and publish a runner image to a private Gitea registry. inputs: registry: description: Registry hostname, for example mahgit.ir. required: true image: description: Fully qualified image name without a tag. required: true base-image: description: Base image used by the default Dockerfile. required: false default: mahgit.ir/meghdadfadaee/build-runner-image-base:node-20-bookworm context: description: Docker build context relative to the checked-out repository. required: false default: . requirements-file: description: Requirements lock path relative to the Docker build context. required: false default: requirements.lock dockerfile: description: Optional caller Dockerfile path; defaults to the action Dockerfile. required: false default: "" source-url: description: Repository URL stored in the OCI source label. required: true registry-username: description: Registry username. required: true registry-token: description: Registry token with package Read and Write permission. required: true verify-commands: description: Shell commands that verify the candidate image using IMAGE_REF. required: false default: "" outputs: image: description: Fully qualified image name without a tag. value: ${{ steps.publish.outputs.image }} revision: description: Twelve-character Git revision used as the immutable tag. value: ${{ steps.publish.outputs.revision }} revision_tag: description: Fully qualified immutable image reference. value: ${{ steps.publish.outputs.revision_tag }} latest_tag: description: Fully qualified latest image reference. value: ${{ steps.publish.outputs.latest_tag }} runs: using: composite steps: - name: Install Docker client shell: sh run: | set -eu if command -v docker >/dev/null 2>&1; then docker version --format 'Docker client {{.Client.Version}}, server {{.Server.Version}}' exit 0 fi if ! command -v apt-get >/dev/null 2>&1; then echo "Docker is unavailable and this job image does not provide apt-get" exit 1 fi for attempt in 1 2 3; do if apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ --no-install-recommends docker.io; then break fi if [ "$attempt" -eq 3 ]; then echo "Unable to install the Docker client after 3 attempts" exit 1 fi sleep "$((attempt * 5))" done rm -rf /var/lib/apt/lists/* docker version --format 'Docker client {{.Client.Version}}, server {{.Server.Version}}' - name: Build, verify, and publish image id: publish shell: sh env: INPUT_REGISTRY: ${{ inputs.registry }} INPUT_IMAGE: ${{ inputs.image }} INPUT_BASE_IMAGE: ${{ inputs.base-image }} INPUT_CONTEXT: ${{ inputs.context }} INPUT_REQUIREMENTS_FILE: ${{ inputs.requirements-file }} INPUT_DOCKERFILE: ${{ inputs.dockerfile }} INPUT_SOURCE_URL: ${{ inputs.source-url }} INPUT_REGISTRY_USERNAME: ${{ inputs.registry-username }} INPUT_REGISTRY_TOKEN: ${{ inputs.registry-token }} INPUT_VERIFY_COMMANDS: ${{ inputs.verify-commands }} ACTION_PATH: ${{ gitea.action_path }} run: | set -eu : "${INPUT_REGISTRY:?registry is required}" : "${INPUT_IMAGE:?image is required}" : "${INPUT_BASE_IMAGE:?base-image is required}" : "${INPUT_CONTEXT:?context is required}" : "${INPUT_REQUIREMENTS_FILE:?requirements-file is required}" : "${INPUT_SOURCE_URL:?source-url is required}" : "${INPUT_REGISTRY_USERNAME:?registry-username is required}" : "${INPUT_REGISTRY_TOKEN:?registry-token is required}" revision="$(git rev-parse --short=12 HEAD)" candidate="$INPUT_IMAGE:$revision" latest="$INPUT_IMAGE:latest" dockerfile="$INPUT_DOCKERFILE" if [ -z "$dockerfile" ]; then dockerfile="$ACTION_PATH/runner-image/Dockerfile" fi if [ ! -f "$dockerfile" ]; then echo "Dockerfile does not exist: $dockerfile" exit 1 fi cleanup() { docker logout "$INPUT_REGISTRY" >/dev/null 2>&1 || true } trap cleanup EXIT printf '%s' "$INPUT_REGISTRY_TOKEN" | docker login "$INPUT_REGISTRY" \ --username "$INPUT_REGISTRY_USERNAME" \ --password-stdin docker build \ --pull \ --label "org.opencontainers.image.revision=$revision" \ --label "org.opencontainers.image.source=$INPUT_SOURCE_URL" \ --build-arg "BASE_IMAGE=$INPUT_BASE_IMAGE" \ --build-arg "REQUIREMENTS_FILE=$INPUT_REQUIREMENTS_FILE" \ --file "$dockerfile" \ --tag "$candidate" \ "$INPUT_CONTEXT" if [ -n "$INPUT_VERIFY_COMMANDS" ]; then export IMAGE_REF="$candidate" sh -eu -c "$INPUT_VERIFY_COMMANDS" fi docker push "$candidate" docker tag "$candidate" "$latest" docker push "$latest" if [ -n "${GITHUB_OUTPUT:-}" ]; then { echo "image=$INPUT_IMAGE" echo "revision=$revision" echo "revision_tag=$candidate" echo "latest_tag=$latest" } >> "$GITHUB_OUTPUT" fi