name: Build & publish Docker image description: >- Build a Docker image and push it to this Forgejo instance's container registry. Reimplements docker/login-action + docker/metadata-action + docker/build-push-action in plain shell using the docker CLI — no marketplace actions are fetched or run. inputs: context: description: Docker build context. default: "." dockerfile: description: Path to the Dockerfile (relative to the workspace). Empty = /Dockerfile. default: "" image-suffix: description: Appended to the derived image name //, e.g. "-server". default: "" build-args: description: Newline-separated KEY=VALUE pairs passed as --build-arg. default: "" push: description: Whether to log in and push ("true"/"false"). Set false for pull-request builds. default: "true" token: description: Registry password/token (e.g. secrets.FORGEJO_PACKAGE_TOKEN). required: true registry-host: description: Override the registry host. Defaults to github.server_url (vars.CONTAINER_REGISTRY_HOST is honoured if set in the env). default: "" runs: using: composite steps: - name: Build and publish shell: bash env: INPUT_CONTEXT: ${{ inputs.context }} INPUT_DOCKERFILE: ${{ inputs.dockerfile }} INPUT_IMAGE_SUFFIX: ${{ inputs.image-suffix }} INPUT_BUILD_ARGS: ${{ inputs.build-args }} INPUT_PUSH: ${{ inputs.push }} INPUT_TOKEN: ${{ inputs.token }} INPUT_REGISTRY_HOST: ${{ inputs.registry-host }} REPO: ${{ github.repository }} OWNER: ${{ github.repository_owner }} SERVER_URL: ${{ github.server_url }} SHA: ${{ github.sha }} REF: ${{ github.ref }} REF_TYPE: ${{ github.ref_type }} REF_NAME: ${{ github.ref_name }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} run: | set -euo pipefail # --- Ensure the docker CLI exists (idempotent; the node:* runner image may lack it) --- if ! command -v docker >/dev/null 2>&1; then ARCH="$(uname -m)" curl -fsSL --retry 3 --retry-connrefused \ "https://download.docker.com/linux/static/stable/${ARCH}/docker-27.5.1.tgz" \ | tar xz --strip-components=1 -C /usr/local/bin docker/docker fi docker --version # --- Resolve the registry host (canonical form of the block copy-pasted across repos) --- host="${INPUT_REGISTRY_HOST:-${CONTAINER_REGISTRY_HOST:-$SERVER_URL}}" host="${host#https://}"; host="${host#http://}"; host="${host%/}" # The job's docker daemon reaches the registry via the host-published port, not the # internal service name; this is the same remap the old inline scripts performed. [ "$host" = "forgejo:3000" ] && host="127.0.0.1:13000" repo="$(printf '%s' "$REPO" | tr '[:upper:]' '[:lower:]')" image="${host}/${repo}${INPUT_IMAGE_SUFFIX}" echo "Target image: ${image}" # --- Compute tags from the git ref (replaces docker/metadata-action) --- tags=( -t "${image}:sha-$(printf '%s' "$SHA" | cut -c1-12)" ) if [ "$REF" = "refs/heads/${DEFAULT_BRANCH}" ]; then tags+=( -t "${image}:latest" ) fi if [ "$REF_TYPE" = "tag" ]; then tags+=( -t "${image}:${REF_NAME}" ) if printf '%s' "$REF_NAME" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then v="${REF_NAME#v}" tags+=( -t "${image}:${v}" -t "${image}:${v%.*}" -t "${image}:${v%%.*}" ) fi fi # --- Assemble extra build flags --- extra=() [ -n "${INPUT_DOCKERFILE}" ] && extra+=( -f "${INPUT_DOCKERFILE}" ) while IFS= read -r a; do [ -n "$a" ] && extra+=( --build-arg "$a" ) done <<< "${INPUT_BUILD_ARGS}" # --- Build --- docker build "${extra[@]}" \ --label "org.opencontainers.image.source=${SERVER_URL}/${REPO}" \ --label "org.opencontainers.image.revision=${SHA}" \ --label "org.opencontainers.image.created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ "${tags[@]}" \ "${INPUT_CONTEXT}" # --- Push (skipped on pull requests by passing push: false) --- if [ "${INPUT_PUSH}" = "true" ]; then printf '%s' "${INPUT_TOKEN}" | docker login "$host" -u "$OWNER" --password-stdin docker push --all-tags "$image" fi