feat: packages and a signed repository for Debian and Fedora

The code works on those distributions now; there was still nothing to
install. This adds the two packages and, more to the point, somewhere for
them to live that hands out updates - a package a user has to notice a new
version of and download again is not much better than a checkout.

Both are built from `make install` and nothing else. A packaging script that
lists the installed files a second time is a second description of the
layout, and the two drift the first time a file moves; here the Makefile
stays the only place that says where anything goes. The .deb is staged and
wrapped with dpkg-deb, the .rpm goes through a spec whose %install is the
same make invocation. Both are architecture-independent, so one file each
covers Debian, Ubuntu and their derivatives on one side and Fedora, RHEL and
openSUSE on the other.

The version is not written down twice either. The Makefile has it, the
control file and the spec take it as a placeholder, and check-version.sh
refuses a tag that disagrees - otherwise a v1.0.4 release quietly ships a
program that reports 1.0.3.

The release workflow builds both in a Debian and a Fedora container, signs
the RPM where there is a native rpm-sign, attaches both to the GitHub
release, and then adds them to an APT and a DNF repository on gh-pages,
regenerating the indexes over every version ever published so that pinning
and going back to one still work. Missing the signing key is not an error:
it builds, it says in the log that the repositories were left alone, and the
packages are still on the release.

There is also a check workflow, which is the first time shellcheck actually
runs on this.

Neither package carries a maintainer script. The units are enabled per user
by the program itself, so there is nothing for a package to do as root - and
nothing it could do about the changes in a user's home either, which is why
both descriptions say to run `disable` before removing.

packaging/README.md has the two things that cannot be automated: making the
signing key, and pointing Pages at the branch.
This commit is contained in:
Felitendo committed 2026-08-24 10:40:15 +02:00
1 parent 36498f2acf
commit a053b4e555
15 files changed
+764 -4

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
# Packaging and releases
The Makefile installs everything; these only wrap what it produced. That is
deliberate — a packaging script that lists the files again is a second
description of the layout, and two descriptions drift.
| | |
|---|---|
| `deb/control`, `deb/copyright` | metadata for the Debian binary package |
| `rpm/middleclick-autoscroll.spec` | the RPM spec |
| `build-deb.sh`, `build-rpm.sh` | build one package into `dist/` |
| `check-version.sh` | refuses a tag that disagrees with the Makefile |
| `publish-repos.sh` | regenerates the APT and RPM repositories |
| `pages/` | the landing page and the `.repo` file served from GitHub Pages |
Neither package carries a maintainer script. The units are enabled per user by
the program itself, and there is nothing to do as root at install time.
## Building one by hand
```bash
packaging/build-deb.sh # needs dpkg-dev, gettext, scdoc
packaging/build-rpm.sh # needs rpm-build, gettext, scdoc, systemd-rpm-macros
```
Both take the version from `make version` unless one is passed as the first
argument.
## Making a release
1. Bump `VERSION` in the Makefile.
2. Commit, then `git tag vX.Y.Z && git push --tags`.
The `release` workflow builds both packages in a Debian and a Fedora container,
refuses the tag if it disagrees with the Makefile, attaches the packages to a
GitHub release, and adds them to the APT and RPM repositories on the `gh-pages`
branch. Nothing else has to be done by hand.
## Setting up the signing, once
The repositories are signed, so this needs a key. Make one that exists for
nothing else — not a personal key — and give it no passphrase: it lives as an
encrypted repository secret, and `rpmsign` cannot be handed a passphrase
unattended.
```bash
gpg --batch --passphrase '' --quick-generate-key \
'middleclick-autoscroll repository <felitendoyt@gmail.com>' rsa4096 sign never
gpg --armor --export-secret-keys 'middleclick-autoscroll repository' \
| gh secret set GPG_PRIVATE_KEY
```
Then, in the repository settings, set **Pages** to deploy from a branch and
pick `gh-pages` at the root. The branch is created by the first release that
runs with the key in place.
Without the secret the workflow still builds both packages and attaches them to
the release; it says so in the log and leaves the repositories alone.
## What users end up with
The public key is published as `KEY.gpg` beside the repositories, and the
landing page carries the setup lines for each distribution. After that, a new
version arrives with `apt upgrade`, `dnf upgrade` or `zypper up` like anything
else.