The publish job had never run. It is the part that produces the apt and dnf repositories, which is to say it is the whole update mechanism, and finding out whether it works when a tag is already pushed is the wrong time. A dry run now builds both repositories with a key generated on the spot, verifies the three signatures it wrote, and then installs the packages back out of them - apt on the runner, dnf in a Fedora container - so the thing being tested is the thing that runs. Nothing is pushed and no release is created.
257 lines
8.8 KiB
YAML
257 lines
8.8 KiB
YAML
name: release
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: >-
|
|
Build the repositories with a throwaway key and install from them,
|
|
without publishing anything. This is how the release path gets
|
|
exercised without cutting a tag.
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
deb:
|
|
name: Debian package
|
|
runs-on: ubuntu-latest
|
|
container: debian:stable
|
|
steps:
|
|
- name: Install the build tools
|
|
run: |
|
|
apt-get update -qq
|
|
apt-get install -y --no-install-recommends \
|
|
ca-certificates git make gettext scdoc dpkg-dev
|
|
|
|
- uses: actions/checkout@v7
|
|
|
|
- name: Check the tag against the Makefile
|
|
run: packaging/check-version.sh "${{ github.ref_name }}"
|
|
|
|
- run: packaging/build-deb.sh
|
|
|
|
- name: Look inside what was built
|
|
run: |
|
|
dpkg-deb --info dist/*.deb
|
|
dpkg-deb --contents dist/*.deb
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: deb
|
|
path: dist/*.deb
|
|
if-no-files-found: error
|
|
|
|
rpm:
|
|
name: RPM package
|
|
runs-on: ubuntu-latest
|
|
container: fedora:latest
|
|
steps:
|
|
- name: Install the build tools
|
|
run: |
|
|
dnf install -y --setopt=install_weak_deps=False \
|
|
git make gettext scdoc tar rpm-build rpm-sign systemd-rpm-macros
|
|
|
|
- uses: actions/checkout@v7
|
|
|
|
- name: Check the tag against the Makefile
|
|
run: packaging/check-version.sh "${{ github.ref_name }}"
|
|
|
|
- run: packaging/build-rpm.sh
|
|
|
|
# Signed here rather than alongside the APT repository, because this is
|
|
# the one place with a native rpm-sign. A dry run signs with a key it
|
|
# makes on the spot, so the command itself is still exercised.
|
|
- name: Sign the package
|
|
env:
|
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
DRY_RUN: ${{ inputs.dry_run }}
|
|
run: |
|
|
if [ "$DRY_RUN" = "true" ]; then
|
|
gpg --batch --passphrase '' --quick-generate-key \
|
|
'dry run <dry-run@example.invalid>' rsa2048 sign never
|
|
elif [ -n "${GPG_PRIVATE_KEY:-}" ]; then
|
|
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
|
else
|
|
echo "No GPG_PRIVATE_KEY secret; leaving the package unsigned."
|
|
exit 0
|
|
fi
|
|
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
|
rpmsign --define "_gpg_name $keyid" --addsign dist/*.rpm
|
|
gpg --armor --export "$keyid" > dist/rpm-signer.asc
|
|
rpm --import dist/rpm-signer.asc
|
|
rpm --checksig dist/*.rpm
|
|
|
|
- name: Look inside what was built
|
|
run: |
|
|
rpm -qip dist/*.rpm
|
|
rpm -qlp dist/*.rpm
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: rpm
|
|
path: |
|
|
dist/*.rpm
|
|
dist/rpm-signer.asc
|
|
if-no-files-found: error
|
|
|
|
publish:
|
|
name: Release and repositories
|
|
needs: [deb, rpm]
|
|
if: startsWith(github.ref, 'refs/tags/v') || inputs.dry_run
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
path: incoming
|
|
merge-multiple: true
|
|
|
|
- name: Attach the packages to the release
|
|
if: ${{ !inputs.dry_run }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh release create "${{ github.ref_name }}" \
|
|
--title "${{ github.ref_name }}" \
|
|
--generate-notes \
|
|
incoming/*.deb incoming/*.rpm \
|
|
|| gh release upload "${{ github.ref_name }}" \
|
|
incoming/*.deb incoming/*.rpm --clobber
|
|
|
|
- name: Install the repository tools
|
|
run: |
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y --no-install-recommends \
|
|
dpkg-dev apt-utils createrepo-c
|
|
|
|
- name: Get a signing key
|
|
id: key
|
|
env:
|
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
DRY_RUN: ${{ inputs.dry_run }}
|
|
run: |
|
|
if [ "$DRY_RUN" = "true" ]; then
|
|
gpg --batch --passphrase '' --quick-generate-key \
|
|
'dry run <dry-run@example.invalid>' rsa2048 sign never
|
|
elif [ -n "${GPG_PRIVATE_KEY:-}" ]; then
|
|
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
|
else
|
|
echo "present=no" >> "$GITHUB_OUTPUT"
|
|
echo "::warning::No GPG_PRIVATE_KEY secret - the apt and dnf repositories were not updated. The packages are on the release."
|
|
exit 0
|
|
fi
|
|
echo "present=yes" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Check out the published repositories
|
|
if: steps.key.outputs.present == 'yes' && !inputs.dry_run
|
|
uses: actions/checkout@v7
|
|
with:
|
|
ref: gh-pages
|
|
path: pages
|
|
continue-on-error: true
|
|
|
|
- name: Update the repositories
|
|
if: steps.key.outputs.present == 'yes'
|
|
run: |
|
|
# First release, or a dry run: there is no branch to start from.
|
|
if [ ! -d pages/.git ]; then
|
|
rm -rf pages && mkdir pages
|
|
git -C pages init -q -b gh-pages
|
|
git -C pages remote add origin "https://github.com/${{ github.repository }}.git"
|
|
fi
|
|
rm -f incoming/rpm-signer.asc
|
|
packaging/publish-repos.sh pages incoming
|
|
|
|
- name: Check that what was written can be verified
|
|
if: steps.key.outputs.present == 'yes'
|
|
run: |
|
|
find pages -type f -not -path '*/.git/*' | sort
|
|
echo '--- Release ---'; cat pages/deb/Release
|
|
echo '--- Packages ---'; cat pages/deb/Packages
|
|
gpg --verify pages/deb/InRelease
|
|
gpg --verify pages/deb/Release.gpg pages/deb/Release
|
|
gpg --verify pages/rpm/repodata/repomd.xml.asc pages/rpm/repodata/repomd.xml
|
|
|
|
# The proof that the repository works is apt reading it: the signature,
|
|
# the index, the dependencies and the program that comes out the far end.
|
|
- name: Install from the repository that was just built
|
|
if: inputs.dry_run
|
|
run: |
|
|
sudo install -d -m 0755 /etc/apt/keyrings
|
|
sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg < pages/KEY.gpg
|
|
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] file://$PWD/pages/deb ./" \
|
|
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
|
sudo apt-get update
|
|
sudo apt-get install -y middleclick-autoscroll
|
|
middleclick-autoscroll --version
|
|
middleclick-autoscroll list
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
if: inputs.dry_run
|
|
with:
|
|
name: pages
|
|
path: pages
|
|
include-hidden-files: true
|
|
|
|
- name: Push them
|
|
if: steps.key.outputs.present == 'yes' && !inputs.dry_run
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
cd pages
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
git add -A
|
|
git diff --quiet --cached && { echo "nothing changed"; exit 0; }
|
|
git commit -q -m "Publish ${{ github.ref_name }}"
|
|
git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:gh-pages
|
|
|
|
verify-dnf:
|
|
name: Install from the RPM repository
|
|
needs: publish
|
|
if: inputs.dry_run
|
|
runs-on: ubuntu-latest
|
|
container: fedora:latest
|
|
steps:
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: pages
|
|
path: pages
|
|
|
|
# A real run signs the package and the repository metadata with the one
|
|
# key from the secret. A dry run has no secret, so each job made a key of
|
|
# its own and both public halves are needed to check both signatures.
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: rpm
|
|
path: signer
|
|
|
|
- name: Install from the repository that was just built
|
|
run: |
|
|
rpm --import pages/KEY.gpg
|
|
rpm --import signer/rpm-signer.asc
|
|
cat > /etc/yum.repos.d/middleclick-autoscroll.repo <<EOF
|
|
[middleclick-autoscroll]
|
|
name=middleclick-autoscroll
|
|
baseurl=file://$PWD/pages/rpm
|
|
enabled=1
|
|
gpgcheck=1
|
|
repo_gpgcheck=1
|
|
gpgkey=file://$PWD/pages/KEY.gpg
|
|
EOF
|
|
# util-linux is for runuser below; the base image does not carry it,
|
|
# and util-linux-core is not the half that has it.
|
|
dnf install -y middleclick-autoscroll util-linux
|
|
|
|
# As somebody, not as root: running it as root is refused, which is
|
|
# the point of it, and a container is root by default.
|
|
useradd -m tester
|
|
runuser -u tester -- middleclick-autoscroll --version
|
|
runuser -u tester -- middleclick-autoscroll list
|