From 6c3e8af7eaf634040e351345d10644806a7d4987 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Tue, 25 Aug 2026 04:54:57 +0200 Subject: [PATCH] docs(releasing): full gh auth login section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gh's credential is separate from git's: SSH keys let you push but not call the API, so a machine that pushes can still fail to release - the five interactive prompts and what to answer, with SSH as the protocol to match this repo's existing remote - headless path: PAT scopes (classic repo/read:org/gist, fine-grained Contents: read and write), --with-token from a 600 file, GH_TOKEN for automation - verify with `gh repo view shoneyJ/writeonce` — proves the token reaches THIS repo, not just that it is valid Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/releasing.md | 74 ++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/docs/guides/releasing.md b/docs/guides/releasing.md index 9c8078d..d747f20 100644 --- a/docs/guides/releasing.md +++ b/docs/guides/releasing.md @@ -16,17 +16,69 @@ tag must be `v0.1.0` and the asset must be named exactly `writeonce-0.1.0-linux-amd64.tar.gz` — which is what `just dist` already produces. -## 0. Before you start +## 0. Authenticate `gh` (once per machine) -`gh` must be authenticated. It is an interactive browser/device flow, so -run it yourself: +`gh` keeps its own credential, separate from git's. SSH keys let you +`git push`; they do **not** let `gh` call the API, so a machine that +pushes fine can still fail to create a release. + +Check first — if this names your account, skip the rest of this section: + +``` +gh auth status +``` + +### The interactive flow (what to pick) ``` gh auth login ``` -In a Claude Code session, type it with a leading `!` so the output lands -in the conversation: `! gh auth login`. +It asks five things: + +| prompt | answer | +| --- | --- | +| What account do you want to log into? | **GitHub.com** | +| Preferred protocol for Git operations? | **SSH** — this repo's remote is already `git@github.com:shoneyJ/writeonce.git`, and answering HTTPS here rewrites how git talks to GitHub for every repo on the host | +| Upload your SSH public key? | pick `~/.ssh/id_ed25519.pub`, or **Skip** if that key is already on your account | +| How would you like to authenticate? | **Login with a web browser** | +| One-time code | gh prints something like `ABCD-1234`; press Enter, paste it at , authorise | + +The token lands in the system credential store, or in a plain file if +there is no store (`gh auth status` prints the location; `--insecure-storage` +forces the file). `-w`/`--web` skips straight to the browser step. + +**In a Claude Code session, prefix it with `!`** — `! gh auth login` — so +the prompts are yours to answer and the output lands in the conversation. +An agent cannot complete a device flow on your behalf. + +### No browser on that machine (server, container, CI) + +Create a personal access token at . +Classic tokens need the scopes `repo`, `read:org` and `gist`; +a fine-grained token needs **Contents: read and write** on the repo, +which is what release assets are written through. Then: + +``` +printf '%s' "$TOKEN" | gh auth login --with-token +``` + +Read it from a `chmod 600` file rather than typing it inline — an +argument on the command line lands in shell history and in `ps`. For +automation, skip login entirely and export `GH_TOKEN`; gh picks it up and +stores nothing. + +### Verify before you rely on it + +``` +gh auth status +gh repo view shoneyJ/writeonce --json name,visibility +``` + +The second call is the real check: it proves the token can reach *this* +repo, which a valid-but-wrong-account token would not. + +## 1. Before you build Check the tree is clean and the version is what you mean to ship — `VERSION` is the single source, and `mkdist.sh` refuses to build if @@ -37,7 +89,7 @@ git status --porcelain # expect empty cat VERSION # e.g. 0.1.0 ``` -## 1. Build the artifact +## 2. Build the artifact ``` just dist @@ -51,7 +103,7 @@ dist/writeonce--linux-amd64.tar.gz dist/writeonce--linux-amd64.tar.gz.sha256 ``` -## 2. Verify it before anyone else can +## 3. Verify it before anyone else can Two checks, both cheap, both worth it. First the digest: @@ -76,7 +128,7 @@ woc . && ./target/hello If that prints `hello, writeonce`, the release is sound. -## 3. Tag the commit +## 4. Tag the commit The tag is what the download URL points at, so tag the exact commit the binaries were built from: @@ -86,7 +138,7 @@ git tag -a v0.1.0 -m "writeonce 0.1.0" git push origin v0.1.0 ``` -## 4. Publish and upload +## 5. Publish and upload One command creates the release and attaches both files: @@ -120,7 +172,7 @@ page → *Draft a new release* → choose tag `v0.1.0` → drag both files into the attachment box → *Publish release*. Uploading by hand is where the filename usually drifts, so paste it rather than retyping it. -## 5. Check the link the site actually uses +## 6. Check the link the site actually uses ``` curl -sIL -o /dev/null -w '%{http_code} %{url_effective}\n' \ @@ -131,7 +183,7 @@ A `200` means `/install`'s download button works for a stranger. Anything else means the tag, the asset name, or the repo path disagrees with the link in `docs/examples/site/install/view.wo`. -## 6. Refresh the site's mirror +## 7. Refresh the site's mirror `/install` offers this site as a mirror beside the GitHub link, served by the framework's `StaticFiles` out of `$WO_DIST` (default `./dist`). Copy