diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml new file mode 100644 index 0000000..54eed91 --- /dev/null +++ b/.github/workflows/packages.yml @@ -0,0 +1,61 @@ +name: Packages + +on: + workflow_call: + inputs: + tag: + type: string + required: true + workflow_dispatch: + inputs: + tag: + description: The released tag to package, such as v0.1.0 + type: string + required: true + +permissions: + contents: read + +jobs: + packages: + name: Binaries, packages and image for ${{ inputs.tag }} + runs-on: ubuntu-26.04 + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ inputs.tag }} + path: src + fetch-depth: 0 + persist-credentials: false + # The packaging config comes from the workflow's commit, so a tag cut before it + # existed can still be packaged. + - uses: actions/checkout@v7 + with: + path: tooling + persist-credentials: false + - uses: docker/setup-buildx-action@v4 + - uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: goreleaser/goreleaser-action@v7 + with: + version: v2.18.3 + workdir: src + args: release --clean --config ../tooling/release-tooling/goreleaser.yaml + env: + 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 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0523889..3a7fefa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,13 +58,27 @@ jobs: runs-on: ubuntu-26.04 permissions: contents: write + outputs: + tag: ${{ steps.publish.outputs.tag }} steps: - uses: actions/checkout@v7 with: persist-credentials: false - - run: python3 release-tooling/publish_release.py + - id: publish + run: python3 release-tooling/publish_release.py env: FORGE_API_URL: ${{ github.api_url }} FORGE_REPOSITORY: ${{ github.repository }} FORGE_TOKEN: ${{ secrets.GITHUB_TOKEN }} SHA: ${{ github.sha }} + + packages: + needs: release + if: needs.release.outputs.tag != '' + permissions: + contents: write + packages: write + uses: ./.github/workflows/packages.yml + with: + tag: ${{ needs.release.outputs.tag }} + secrets: inherit diff --git a/CHANGELOG.md b/CHANGELOG.md index 09d16e7..c4493e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). A release's `Breaking` section comes first and names each rejected spelling with its replacement, and each removed path, column or flag. +## [Unreleased] + +### Added + +- Prebuilt binaries for Linux, macOS and Windows on amd64 and arm64, packages for apt, + dnf, apk, Homebrew, Scoop and the AUR, and the image `ghcr.io/larvit/fejkdata`, so + the CLI installs without Go. 0.1.0 ships them too; the README's + [Install](https://github.com/larvit/fejkdata#install) lists each command. + ## [0.1.0] - 2026-10-13 The first release: a Go library and a CLI that render locale-aware fake data from JSON diff --git a/Dockerfile b/Dockerfile index d37075d..ed4d0b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,8 +16,9 @@ COPY release-tooling/ /release-tooling/ RUN python3 -m unittest discover -s /release-tooling -p '*_test.py' && touch /tested FROM goreleaser/goreleaser:v2.18.3 AS packaging -COPY release-tooling/goreleaser.yaml /goreleaser.yaml -RUN goreleaser check --config /goreleaser.yaml && touch /tested +WORKDIR /check +COPY release-tooling/goreleaser.yaml ./ +RUN git init -q && goreleaser check --config goreleaser.yaml && touch /tested FROM portable # BuildKit skips a stage nothing copies from. diff --git a/README.md b/README.md index eed549b..0ae68bc 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,32 @@ echo '{/sv_SE.person}' | fejkdata # Sara Eriksson - **Reproducible:** the same seed, version and data give the same output, when one goroutine draws it. -[CLI](#cli) · [Library](#library) · [Data](#data) · [Data format (templates)](#data-format) · +[Install](#install) · [CLI](#cli) · [Library](#library) · [Data](#data) · [Data format (templates)](#data-format) · [Functions](#functions) · [Versioning](#versioning) · [Audience](#audience) · [Goals](#goals) · [Development](#development) · [License](#license) +## Install + +```sh +brew install larvit/tap/fejkdata # macOS, Linux +scoop bucket add larvit https://github.com/larvit/scoop-bucket && scoop install fejkdata # Windows +yay -S fejkdata-bin # Arch, from the AUR +docker run --rm -i ghcr.io/larvit/fejkdata < template.json # any OS with Docker +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: + +```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 +``` + +Each [release](https://github.com/larvit/fejkdata/releases) also carries the binaries for +Linux, macOS and Windows on amd64 and arm64, and the `.deb`, `.rpm` and `.apk` packages. + ## CLI ```sh @@ -1133,7 +1155,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 +release-tooling/ the release CI publishes from the changelog heading, and the binaries, packages and image built for it testdata/ the pinned shipped shape (see Versioning) ``` @@ -1229,7 +1251,12 @@ docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/usera To release, head `CHANGELOG.md` with the version's section in place of `Unreleased` 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. +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`. To package a release again, run +the workflow by hand with its tag; it replaces what it uploaded before. ## License diff --git a/docs/decisions.md b/docs/decisions.md index e60919c..a1fc3d8 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -903,6 +903,8 @@ By the maintainer's decision of 2026-10-09, every 0.1.0 chunk ships under the fl Shipped under that decision: item 89, the last of 0.1.0, at 52e0304. Its paired ruling against 90ffcff was better. The release's scoring run read Navigation 7.00, Locality 5.75, Shape 6.38, Self-sufficiency 6.50 and overall 6.25; its seats named places items 170 to 172 and 178 hold, and `isPath`, filed as item 251. +Shipped under the floor by the maintainer's decision of 2026-10-13: item 58, prebuilt binaries and packages, as the distribution of 0.1.0 rather than a 0.2.0 item. It changes no Go code. + Shipped by the maintainer's decision of 2026-10-11 with its ratchet waived: item 182, the shipped data as Go packages, at a632a92. Its last paired ruling against bf1becb was same overall, Mid A better and Junior A worse, with Shape fallen, three seats against the namespace mount in `internal/datafiles/mount.go` and the `at` field of `datafiles.Source`; the scoring run that would rule it worse under the floor was not run. `todo.md` item 197 replaces that mount. Shipped under the floor before that by the maintainer's decisions of 2026-10-07, each with the scoring run and its ratchet waived: the CLI reading its template from stdin; and goal 5.7 loading whatever is well-formed and means one thing, dropping every refusal that guessed at a mistake. diff --git a/release-tooling/goreleaser.yaml b/release-tooling/goreleaser.yaml new file mode 100644 index 0000000..5a80e4d --- /dev/null +++ b/release-tooling/goreleaser.yaml @@ -0,0 +1,109 @@ +# The packages workflow runs this from a checkout of the release's tag, in src/, beside +# this repository's tooling/ checkout: the paths below are relative to src/. A dist/ +# inside src/ would make Go stamp the binaries' version +dirty. +version: 2 + +project_name: fejkdata +dist: ../dist + +builds: + - main: ./cmd/fejkdata + binary: fejkdata + env: + - CGO_ENABLED=0 + flags: + - -trimpath + ldflags: + - -s -w + goos: [linux, darwin, windows] + goarch: [amd64, arm64] + +archives: + - formats: [tar.gz] + format_overrides: + - goos: windows + formats: [zip] + files: + - LICENSE + - DATA-LICENSES.md + - README.md + - CHANGELOG.md + +checksum: + name_template: checksums.txt + +changelog: + disable: true + +release: + github: + owner: larvit + name: fejkdata + mode: keep-existing + replace_existing_artifacts: true + +nfpms: + - package_name: fejkdata + vendor: Larvit + homepage: https://github.com/larvit/fejkdata + maintainer: Lilleman auf Larv + description: Render locale-aware fake data from JSON templates. + license: MIT + formats: [deb, rpm, apk] + contents: + - src: LICENSE + dst: /usr/share/doc/fejkdata/LICENSE + - src: DATA-LICENSES.md + dst: /usr/share/doc/fejkdata/DATA-LICENSES.md + +dockers_v2: + - images: + - ghcr.io/larvit/fejkdata + tags: + - "{{ .Version }}" + - latest + dockerfile: ../tooling/release-tooling/image.Dockerfile + labels: + org.opencontainers.image.source: https://github.com/larvit/fejkdata + org.opencontainers.image.version: "{{ .Version }}" + org.opencontainers.image.licenses: MIT + +homebrew_casks: + - name: fejkdata + binaries: [fejkdata] + homepage: https://github.com/larvit/fejkdata + description: Render locale-aware fake data from JSON templates + license: MIT + repository: + owner: larvit + name: homebrew-tap + token: "{{ .Env.TAP_GITHUB_TOKEN }}" + hooks: + post: + install: | + if OS.mac? + system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/fejkdata"] + end + +scoops: + - name: fejkdata + homepage: https://github.com/larvit/fejkdata + description: Render locale-aware fake data from JSON templates. + license: MIT + repository: + owner: larvit + name: scoop-bucket + token: "{{ .Env.TAP_GITHUB_TOKEN }}" + +aurs: + - name: fejkdata-bin + homepage: https://github.com/larvit/fejkdata + description: Render locale-aware fake data from JSON templates + license: MIT + maintainers: + - Lilleman auf Larv + private_key: "{{ .Env.AUR_KEY }}" + git_url: ssh://aur@aur.archlinux.org/fejkdata-bin.git + commit_author: + name: Lilleman auf Larv + email: lilleman@larvit.se diff --git a/release-tooling/image.Dockerfile b/release-tooling/image.Dockerfile new file mode 100644 index 0000000..19455bc --- /dev/null +++ b/release-tooling/image.Dockerfile @@ -0,0 +1,4 @@ +FROM scratch +ARG TARGETPLATFORM +COPY $TARGETPLATFORM/fejkdata /fejkdata +ENTRYPOINT ["/fejkdata"] diff --git a/release-tooling/publish_release.py b/release-tooling/publish_release.py index 07105dd..63af191 100644 --- a/release-tooling/publish_release.py +++ b/release-tooling/publish_release.py @@ -2,7 +2,8 @@ """Publish the release that CHANGELOG.md's top heading names, tagging SHA. A top heading of `[Unreleased]`, or a version already released, publishes nothing. -Env: FORGE_API_URL, FORGE_REPOSITORY (owner/repo), FORGE_TOKEN, SHA. +Env: FORGE_API_URL, FORGE_REPOSITORY (owner/repo), FORGE_TOKEN, SHA, and GITHUB_OUTPUT, +where a published release writes `tag=vX.Y.Z`. """ import json @@ -58,6 +59,8 @@ def main() -> int: raise release = request("releases", {"body": body, "name": tag, "tag_name": tag, "target_commitish": sha}) print(release["html_url"]) + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: + f.write(f"tag={tag}\n") return 0 diff --git a/todo.md b/todo.md index 6f3e32e..c4d82e0 100644 --- a/todo.md +++ b/todo.md @@ -65,7 +65,6 @@ | ID | Release | Exempt | Item | R | S | A | G | Goals | Score | |---|---|---|---|---|---|---|---|---|---| -| 58 | 0.2.0 | | **Ship prebuilt binaries, a container image, and packages for Homebrew, Scoop and the biggest Linux package managers, so the CLI needs no Go.** | 3 | 7 | 8 | 9 | 1.1, 7 | 29.2 | | 243 | 0.2.0 | | **Add `en_US.ein`, drawing only the prefixes the IRS assigns.** | 2 | 2 | 7 | 8 | 2.1, 4 | 26.7 | | 230 | 0.2.0 | | **Add `sv_SE.organisationsnummer`, whose first digit is its legal form's group digit and whose last is a Luhn check digit, and `sv_SE.vat`, `SE` + the number + `01`.** | 2 | 3 | 7 | 8 | 2.1, 4 | 26.4 | | 210 | 0.2.0 | | **Add `fr_FR` with its `geo/FR` tree.** | 3 | 8 | 8 | 8 | 2 | 26.2 | @@ -215,10 +214,6 @@ ## Details -### 58. Ship prebuilt binaries, a container image, and packages for Homebrew, Scoop and the biggest Linux package managers, so the CLI needs no Go. - -GoReleaser attaches the binaries to the release the tag workflow publishes, and builds deb and rpm packages, an Alpine APK and an AUR package beside Homebrew and Scoop. The binaries carry the stamped tag, which `--version` prints. v0.1.0 ships first, so it can be tested before it is packaged. - ### 243. Add `en_US.ein`, drawing only the prefixes the IRS assigns. The IRS's prefix list is facts. [Source research](docs/research/research-sources-world.md).