Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -11,7 +11,9 @@ on:
|
||||
required: true
|
||||
AUR_KEY:
|
||||
required: true
|
||||
CLOUDSMITH_API_KEY:
|
||||
PACKAGES_GPG_KEY:
|
||||
required: true
|
||||
PACKAGES_RSA_KEY:
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -34,6 +36,8 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
outputs:
|
||||
latest: ${{ steps.latest.outputs.latest }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
@@ -54,8 +58,8 @@ jobs:
|
||||
with:
|
||||
go-version: ${{ steps.go.outputs.version }}
|
||||
cache: false
|
||||
# The tap, the bucket, the AUR and the image's latest tag each hold one version, so
|
||||
# only the latest release updates them.
|
||||
# The tap, the bucket, the AUR, the image's latest tag and the Linux repositories each
|
||||
# hold one version, so only the latest release updates them.
|
||||
- name: Channels holding one version
|
||||
id: latest
|
||||
env:
|
||||
@@ -63,9 +67,10 @@ jobs:
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
if [ "$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq .tagName)" = "$TAG" ]; then
|
||||
echo "skip=" >> "$GITHUB_OUTPUT"
|
||||
echo "latest=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "skip=--skip=homebrew,scoop,aur,docker" >> "$GITHUB_OUTPUT"
|
||||
echo "skip=--skip=homebrew,scoop,aur" >> "$GITHUB_OUTPUT"
|
||||
echo "OLDER_TAG=1" >> "$GITHUB_ENV"
|
||||
fi
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- uses: docker/login-action@v4
|
||||
@@ -82,20 +87,48 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
|
||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||
- name: Upload to the Cloudsmith repositories
|
||||
env:
|
||||
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
||||
run: |
|
||||
pip install --quiet cloudsmith-cli==1.27.0
|
||||
for f in dist/*.deb; do cloudsmith push deb --republish larvit/fejkdata/any-distro/any-version "$f"; done
|
||||
for f in dist/*.rpm; do cloudsmith push rpm --republish larvit/fejkdata/any-distro/any-version "$f"; done
|
||||
for f in dist/*.apk; do cloudsmith push alpine --republish larvit/fejkdata/alpine/any-version "$f"; done
|
||||
- name: The built binary and the published image print the tag
|
||||
env:
|
||||
TAG: ${{ inputs.tag }}
|
||||
IMAGE: ${{ steps.latest.outputs.skip == '' }}
|
||||
run: |
|
||||
test "$(dist/fejkdata_linux_amd64_v1/fejkdata --version)" = "fejkdata $TAG"
|
||||
if [ "$IMAGE" = true ]; then
|
||||
test "$(docker run --rm "ghcr.io/larvit/fejkdata:${TAG#v}" --version)" = "fejkdata $TAG"
|
||||
fi
|
||||
test "$(docker run --rm "ghcr.io/larvit/fejkdata:${TAG#v}" --version)" = "fejkdata $TAG"
|
||||
|
||||
repos:
|
||||
name: apt, dnf and apk repositories for ${{ inputs.tag }}
|
||||
needs: packages
|
||||
if: needs.packages.outputs.latest == 'true'
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deploy.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: The release's Linux packages
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir packages --pattern '*.deb' --pattern '*.rpm' --pattern '*.apk'
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- name: Install fejkdata from each repository, then export them
|
||||
env:
|
||||
PACKAGES_GPG_KEY: ${{ secrets.PACKAGES_GPG_KEY }}
|
||||
PACKAGES_RSA_KEY: ${{ secrets.PACKAGES_RSA_KEY }}
|
||||
run: |
|
||||
build() {
|
||||
docker buildx build -f release-tooling/package-repos.Dockerfile \
|
||||
--secret id=gpg,env=PACKAGES_GPG_KEY --secret id=rsa,env=PACKAGES_RSA_KEY "$@" packages
|
||||
}
|
||||
build --target checks --output type=local,dest=checks
|
||||
build --target site --output type=local,dest=site
|
||||
- uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: site
|
||||
- id: deploy
|
||||
uses: actions/deploy-pages@v5
|
||||
|
||||
@@ -78,10 +78,13 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
pages: write
|
||||
id-token: write
|
||||
uses: ./.github/workflows/packages.yml
|
||||
with:
|
||||
tag: ${{ needs.release.outputs.tag }}
|
||||
secrets:
|
||||
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
|
||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
||||
PACKAGES_GPG_KEY: ${{ secrets.PACKAGES_GPG_KEY }}
|
||||
PACKAGES_RSA_KEY: ${{ secrets.PACKAGES_RSA_KEY }}
|
||||
|
||||
@@ -122,7 +122,7 @@ In [docs/decisions.md](docs/decisions.md):
|
||||
- Goal 7.2 holds while a first template can be written with no escape; a literal brace still takes `{{` or `}}`
|
||||
- The locales are Ethnologue 2026's ten most-spoken languages, each in the country with the most speakers of it, the Nordic countries and Germany
|
||||
- A country with no open address register covering it whole ships its places and postal codes without streets
|
||||
- The deb, rpm and apk repositories live on Cloudsmith, and the image on GHCR
|
||||
- The apt, dnf and apk repositories are static files on GitHub Pages, holding the latest release only
|
||||
|
||||
# Scoring run
|
||||
|
||||
|
||||
@@ -43,13 +43,23 @@ docker run --rm -i ghcr.io/larvit/fejkdata < template.json # any OS with
|
||||
go install github.com/larvit/fejkdata/cmd/fejkdata@latest # any OS with Go
|
||||
```
|
||||
|
||||
Debian, Ubuntu, Fedora, RHEL and Alpine install from fejkdata's Cloudsmith repository,
|
||||
after one setup script adds it and its signing key:
|
||||
Debian, Ubuntu, Fedora, RHEL and Alpine install from fejkdata's signed repositories, which
|
||||
hold the latest release:
|
||||
|
||||
```sh
|
||||
curl -1sLf https://dl.cloudsmith.io/public/larvit/fejkdata/cfg/setup/bash.deb.sh | sudo -E bash && sudo apt install fejkdata
|
||||
curl -1sLf https://dl.cloudsmith.io/public/larvit/fejkdata/cfg/setup/bash.rpm.sh | sudo -E bash && sudo dnf install fejkdata
|
||||
curl -1sLf https://dl.cloudsmith.io/public/larvit/fejkdata/cfg/setup/bash.alpine.sh | sudo -E bash && sudo apk add fejkdata
|
||||
# Debian, Ubuntu
|
||||
sudo curl -fsSLo /etc/apt/keyrings/fejkdata.asc https://larvit.github.io/fejkdata/fejkdata.asc
|
||||
echo 'deb [signed-by=/etc/apt/keyrings/fejkdata.asc] https://larvit.github.io/fejkdata/deb stable main' | sudo tee /etc/apt/sources.list.d/fejkdata.list
|
||||
sudo apt update && sudo apt install fejkdata
|
||||
|
||||
# Fedora, RHEL
|
||||
sudo curl -fsSLo /etc/yum.repos.d/fejkdata.repo https://larvit.github.io/fejkdata/rpm/fejkdata.repo
|
||||
sudo dnf install fejkdata
|
||||
|
||||
# Alpine, as root
|
||||
wget -qO /etc/apk/keys/fejkdata.rsa.pub https://larvit.github.io/fejkdata/apk/fejkdata.rsa.pub
|
||||
echo https://larvit.github.io/fejkdata/apk >> /etc/apk/repositories
|
||||
apk add fejkdata
|
||||
```
|
||||
|
||||
Each [release](https://github.com/larvit/fejkdata/releases) also carries the binaries for
|
||||
@@ -1156,7 +1166,7 @@ internal/rows/ a table's rows: the TSV, the options proved over it, the links b
|
||||
data/ the shipped modules, each a Go package embedding its categories (JSON, and a TSV per table) and its manifest; and Modules, which lists them
|
||||
data-import/ the scripts that rebuild each sourced table (see DATA-LICENSES.md), and the modules they share
|
||||
docs/ the decision log, the register research behind the shipped data, the survey of other libraries, panels' scores and rulings on how readable the code is, and what each chunk cost an agent to read
|
||||
release-tooling/ the release CI publishes from the changelog heading, and the binaries, packages and image built for it
|
||||
release-tooling/ the release CI publishes from the changelog heading, and the binaries, packages, image and package repositories built for it
|
||||
testdata/ the pinned shipped shape (see Versioning)
|
||||
```
|
||||
|
||||
@@ -1253,14 +1263,15 @@ To release, head `CHANGELOG.md` with the version's section in place of `Unreleas
|
||||
and merge: once `main` passes the gate, CI tags that commit `vX.Y.Z` and publishes
|
||||
the GitHub release with the section as its body. A top heading of `[Unreleased]`
|
||||
publishes nothing. The new release then runs the Packages workflow, which attaches the
|
||||
binaries and packages, pushes the image, uploads to Cloudsmith and updates the Homebrew
|
||||
tap, the Scoop bucket and the AUR. It reads the repository secrets `TAP_GITHUB_TOKEN`,
|
||||
a token that can push to `larvit/homebrew-tap` and `larvit/scoop-bucket`, `AUR_KEY`,
|
||||
the AUR account's SSH key, and `CLOUDSMITH_API_KEY`; the image's GHCR package must be
|
||||
public. To package a release again, run the workflow by hand with its tag; it replaces
|
||||
what it uploaded before. For a tag older than the latest release it updates only that
|
||||
release's assets and Cloudsmith, since the tap, the bucket, the AUR and the image's
|
||||
`latest` each hold one version.
|
||||
binaries and packages, pushes the image, updates the Homebrew tap, the Scoop bucket and
|
||||
the AUR, and deploys the apt, dnf and apk repositories to GitHub Pages. It reads the
|
||||
repository secrets `TAP_GITHUB_TOKEN`, a token that can push to `larvit/homebrew-tap` and
|
||||
`larvit/scoop-bucket`; `AUR_KEY`, the AUR account's SSH key; and `PACKAGES_GPG_KEY` and
|
||||
`PACKAGES_RSA_KEY`, the private keys that sign the repositories. The image's GHCR package
|
||||
must be public, and Pages must deploy from GitHub Actions. To package a release again, run the workflow by hand with its tag; it replaces
|
||||
what it uploaded before. For a tag older than the latest release it leaves the tap, the
|
||||
bucket, the AUR, the image's `latest` and the repositories alone, since each holds one
|
||||
version.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+10
-10
@@ -963,15 +963,15 @@ section says why beside each such country. This works against goal 2.1 until
|
||||
`todo.md` item 218 gives those countries streets. Valid until the maintainer accepts ODbL
|
||||
data, or the country opens a register.
|
||||
|
||||
## The deb, rpm and apk repositories live on Cloudsmith, and the image on GHCR
|
||||
## The apt, dnf and apk repositories are static files on GitHub Pages, holding the latest release only
|
||||
|
||||
2026-10-13, decided by the maintainer. Serves goal 1.1; technical principle: prefer the
|
||||
vendor-neutral option, sidestepped deliberately (`~/.claude/principles/technical-principles.md`).
|
||||
A repository apt, dnf or apk can upgrade from needs signed indexes for three formats.
|
||||
Self-hosting them on GitHub Pages would put two signing keys and the tooling that rebuilds
|
||||
every index into this repository. Cloudsmith signs and indexes all three, for free to open
|
||||
source, so the tie buys that tooling, not a capability only Cloudsmith has. Leaving it costs
|
||||
each Linux user one new setup line. Every release's assets carry the same packages, so
|
||||
nothing is lost in a move. GHCR sits beside the code and takes CI's own token; the image is
|
||||
OCI, so leaving it changes only the image path. Valid while Cloudsmith's open-source plan
|
||||
stays free.
|
||||
vendor-neutral option (`~/.claude/principles/technical-principles.md`). A hosted package
|
||||
service would sign and index the packages for us, but only saves tooling, so the repositories
|
||||
are built here: `release-tooling/package-repos.Dockerfile` signs them with a GPG key (apt,
|
||||
dnf) and an RSA key (apk), and any static host can serve the result. GitHub already hosts the
|
||||
code (see "GitHub is canonical"), so Pages adds no new vendor; the image sits on GHCR for the
|
||||
same reason, and as OCI it moves by changing its path. A Pages site holds at most 1 GB and a
|
||||
release's packages take about 35 MB, so the repositories hold the latest release only; every
|
||||
release keeps its own packages, and the image keeps a tag per version. Valid while GitHub
|
||||
hosts the code.
|
||||
|
||||
@@ -58,7 +58,7 @@ dockers_v2:
|
||||
- ghcr.io/larvit/fejkdata
|
||||
tags:
|
||||
- "{{ .Version }}"
|
||||
- latest
|
||||
- '{{ if not (isEnvSet "OLDER_TAG") }}latest{{ end }}'
|
||||
dockerfile: ../tooling/release-tooling/image.Dockerfile
|
||||
labels:
|
||||
org.opencontainers.image.source: *homepage
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# The apt, dnf and apk repositories GitHub Pages serves, signed, from the .deb, .rpm and
|
||||
# .apk files in the build context. The checks target installs fejkdata from each:
|
||||
#
|
||||
# docker build -f package-repos.Dockerfile --secret id=gpg,env=PACKAGES_GPG_KEY \
|
||||
# --secret id=rsa,env=PACKAGES_RSA_KEY --target checks <dir>
|
||||
# docker build ... --target site --output <site dir> <dir>
|
||||
ARG BASE_URL=https://larvit.github.io/fejkdata
|
||||
|
||||
FROM debian:trixie-20260918-slim AS deb-rpm
|
||||
ARG BASE_URL
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends apt-utils createrepo-c dpkg-dev gnupg \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY *.deb /site/deb/pool/
|
||||
COPY *.rpm /site/rpm/
|
||||
WORKDIR /site
|
||||
RUN --mount=type=secret,id=gpg,required=true \
|
||||
gpg --batch --quiet --import /run/secrets/gpg \
|
||||
&& gpg --armor --export > fejkdata.asc \
|
||||
&& cd deb \
|
||||
&& for arch in amd64 arm64; do \
|
||||
mkdir -p dists/stable/main/binary-$arch \
|
||||
&& dpkg-scanpackages --arch $arch pool > dists/stable/main/binary-$arch/Packages \
|
||||
&& gzip -9k dists/stable/main/binary-$arch/Packages; \
|
||||
done \
|
||||
&& apt-ftparchive -o APT::FTPArchive::Release::Origin=fejkdata \
|
||||
-o APT::FTPArchive::Release::Suite=stable -o APT::FTPArchive::Release::Codename=stable \
|
||||
-o APT::FTPArchive::Release::Components=main \
|
||||
-o "APT::FTPArchive::Release::Architectures=amd64 arm64" \
|
||||
release dists/stable > dists/stable/Release \
|
||||
&& gpg --batch --yes --clearsign -o dists/stable/InRelease dists/stable/Release \
|
||||
&& gpg --batch --yes --armor --detach-sign -o dists/stable/Release.gpg dists/stable/Release \
|
||||
&& cd ../rpm \
|
||||
&& createrepo_c --quiet . \
|
||||
&& gpg --batch --yes --armor --detach-sign repodata/repomd.xml \
|
||||
&& printf '[fejkdata]\nname=fejkdata\nbaseurl=%s/rpm\nrepo_gpgcheck=1\ngpgcheck=0\ngpgkey=%s/fejkdata.asc\n' \
|
||||
"$BASE_URL" "$BASE_URL" > fejkdata.repo
|
||||
|
||||
FROM alpine:3.22.2 AS apk
|
||||
RUN apk add --no-cache abuild openssl
|
||||
COPY *.apk /packages/
|
||||
RUN --mount=type=secret,id=rsa,required=true \
|
||||
mkdir -p /keys /site/apk/x86_64 /site/apk/aarch64 \
|
||||
&& cp /run/secrets/rsa /keys/fejkdata.rsa \
|
||||
&& openssl rsa -in /keys/fejkdata.rsa -pubout -out /keys/fejkdata.rsa.pub 2>/dev/null \
|
||||
&& cp /keys/fejkdata.rsa.pub /site/apk/ \
|
||||
&& cp /packages/*_linux_amd64.apk /site/apk/x86_64/ \
|
||||
&& cp /packages/*_linux_arm64.apk /site/apk/aarch64/ \
|
||||
&& for arch in x86_64 aarch64; do \
|
||||
cd /site/apk/$arch \
|
||||
&& apk index --quiet --allow-untrusted -o APKINDEX.tar.gz *.apk \
|
||||
&& mv *.apk "fejkdata-$(tar -xzOf APKINDEX.tar.gz APKINDEX | sed -n 's/^V://p').apk" \
|
||||
&& abuild-sign -q -k /keys/fejkdata.rsa APKINDEX.tar.gz; \
|
||||
done
|
||||
|
||||
FROM scratch AS site
|
||||
COPY --from=deb-rpm /site /
|
||||
COPY --from=apk /site /
|
||||
|
||||
FROM debian:trixie-20260918-slim AS check-deb
|
||||
COPY --from=site / /site
|
||||
RUN echo 'deb [signed-by=/site/fejkdata.asc] file:/site/deb stable main' > /etc/apt/sources.list.d/fejkdata.list \
|
||||
&& apt-get update -o Dir::Etc::SourceList=/etc/apt/sources.list.d/fejkdata.list -o Dir::Etc::SourceParts=- \
|
||||
&& apt-get install -y fejkdata \
|
||||
&& fejkdata --version > /checked
|
||||
|
||||
FROM fedora:43@sha256:a651ddf48ea28a06ed4e1e6519f51c9f47e7a5a138722ade87369b8fbb7e5b42 AS check-rpm
|
||||
COPY --from=site / /site
|
||||
RUN sed -e 's#^baseurl=.*#baseurl=file:///site/rpm#' -e 's#^gpgkey=.*#gpgkey=file:///site/fejkdata.asc#' \
|
||||
/site/rpm/fejkdata.repo > /etc/yum.repos.d/fejkdata.repo \
|
||||
&& dnf install -y --repo fejkdata fejkdata \
|
||||
&& fejkdata --version > /checked
|
||||
|
||||
FROM alpine:3.22.2 AS check-apk
|
||||
COPY --from=site / /site
|
||||
RUN cp /site/apk/fejkdata.rsa.pub /etc/apk/keys/ \
|
||||
&& apk add --no-cache --repositories-file /dev/null -X /site/apk fejkdata \
|
||||
&& fejkdata --version > /checked
|
||||
|
||||
FROM scratch AS checks
|
||||
COPY --from=check-deb /checked /deb
|
||||
COPY --from=check-rpm /checked /rpm
|
||||
COPY --from=check-apk /checked /apk
|
||||
@@ -23,18 +23,6 @@
|
||||
"matchStrings": [
|
||||
"goreleaser/goreleaser-action@\\S+\\s+with:\\s+version: (?<currentValue>\\S+)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"datasourceTemplate": "pypi",
|
||||
"depNameTemplate": "cloudsmith-cli",
|
||||
"description": "the Cloudsmith CLI the Packages workflow installs",
|
||||
"managerFilePatterns": [
|
||||
"/^\\.github/workflows/packages\\.yml$/"
|
||||
],
|
||||
"matchStrings": [
|
||||
"cloudsmith-cli==(?<currentValue>\\S+)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"extends": [
|
||||
|
||||
Reference in New Issue
Block a user