diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a45c1da --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +# The image is a toolchain only -- the dockerfile COPYs nothing, and the +# scripts arrive via actions/checkout at run time. Keep the build context empty. +* +!dockerfile diff --git a/.gitea/workflows/build-image.yaml b/.gitea/workflows/build-image.yaml new file mode 100644 index 0000000..89c7100 --- /dev/null +++ b/.gitea/workflows/build-image.yaml @@ -0,0 +1,67 @@ +--- +name: Build Autoupdater Image + +concurrency: + group: build-image + cancel-in-progress: false + +on: + schedule: + # Monthly. fedora:latest moves to a new release twice a year and gets + # updates in between; :latest is overwritten each time. + - cron: "0 3 1 * *" + push: + branches: + - main + paths: + - dockerfile + - .dockerignore + - .gitea/workflows/build-image.yaml + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + build: + # No Fedora needed here -- this only drives docker. The *image* is Fedora. + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Log in to the Gitea container registry + env: + GIT_HOST: ${{ vars.GIT_HOST || 'git.bjphoster.com' }} + REGISTRY_USER: ${{ vars.REGISTRY_USER }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + run: | + set -euo pipefail + # NB: this is the Gitea *username*, not vars.GIT_NAME -- that one is + # the display name used for git commit authorship and contains spaces. + printf '%s' "${GIT_TOKEN}" \ + | docker login "${GIT_HOST}" \ + --username "${REGISTRY_USER}" \ + --password-stdin + + - name: Build and push + env: + GIT_HOST: ${{ vars.GIT_HOST || 'git.bjphoster.com' }} + run: | + set -euo pipefail + # The repo is `.autoupdate`, but OCI names cannot start with a dot. + image="${GIT_HOST}/rpm/autoupdate" + + # --pull so a monthly rebuild actually picks up a new base image + # rather than reusing a cached one. + docker build --pull --tag "${image}:latest" . + docker push "${image}:latest" + + echo "pushed ${image}:latest" + + - name: Log out + if: always() + env: + GIT_HOST: ${{ vars.GIT_HOST || 'git.bjphoster.com' }} + run: docker logout "${GIT_HOST}" || true diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..f943aa2 --- /dev/null +++ b/dockerfile @@ -0,0 +1,46 @@ +# Build environment for the RPM autoupdater. +# +# Rebuilt monthly by .gitea/workflows/build-image.yaml and pushed as :latest, so +# the nightly package jobs start with the toolchain already in place instead +# of each running a full dnf transaction first. +# +# Fedora specifically: rpmbuild, rpmspec and rpmlint are native there and +# current. Packages are built with `dist` undefined, so the noarch result is not +# tied to the Fedora release that built it and installs on EL and openSUSE too. +FROM fedora:latest + +LABEL org.opencontainers.image.title="rpm-autoupdate" +LABEL org.opencontainers.image.description="Fedora build environment for the RPM package autoupdater" +LABEL org.opencontainers.image.source="https://git.bjphoster.com/rpm/.autoupdate" + +# nodejs actions/checkout is a JavaScript action; the runner executes it +# with `node` from inside this image, and fedora ships none. +# rpm-build rpmbuild and rpmspec +# rpmdevtools spectool, to resolve Source0's file name +# rpmlint advisory lint of the spec and the built package +# util-linux runuser, to drop from root to the build user +# make the usual BuildRequires of a script package +RUN dnf -y install --setopt=install_weak_deps=False \ + nodejs \ + git \ + curl \ + jq \ + rpm-build \ + rpmdevtools \ + rpmlint \ + util-linux \ + shadow-utils \ + make \ + tar \ + gzip \ + findutils \ + diffutils \ + && dnf clean all + +# The nightly job drops to this user rather than building as root (CI +# containers are root by default). Baked in here rather than created per run. +RUN useradd --create-home --shell /bin/bash builder + +# Sanity check: fail the image build rather than the nightly job if the +# toolchain ever stops working in this environment. +RUN runuser -u builder -- bash -c 'rpmbuild --version && rpmspec --version && command -v spectool rpmlint node'