Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 36 additions & 126 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,140 +1,50 @@
name: Release

# Every release is tag-driven and publishes BOTH the source code and the
# binaries: GoReleaser cross-compiles the full matrix, builds the archives,
# packages, and a reproducible source tarball, generates SBOMs and checksums,
# creates the GitHub Release (body from the tagged CHANGELOG section), and
# updates the Homebrew/Scoop/Winget manifests. A build-provenance attestation is
# then signed for every artifact via the checksums file.
# Release: build vigil's binaries and publish them on its GitHub release, and nowhere else (no
# `go install` path, Homebrew, Scoop, Winget, image or any other channel; owner, 2026-11-13).
# The pipeline is simtabi/.github's shared go-release.yml; this file only says when, and where.
#
# Go releases are git only until the owner says otherwise for this project, so
# nothing here starts on a tag push: pushing a vX.Y.Z tag records a version and
# publishes nothing. A release is dispatched by hand against the tag, with an
# explicit confirmation, and refuses to run without both:
# git push origin vX.Y.Z builds and publishes vX.Y.Z
# gh workflow run release.yml --repo simtabi/vigil -f tag=vX.Y.Z the same, for a tag already pushed
#
# gh workflow run release.yml --repo simtabi/vigil --ref vX.Y.Z -f confirm=release-go
# Push a version tag only for final code: tags are final, and a pushed tag publishes. The shared
# workflow reads src/.goreleaser.yaml (dist: .cache/goreleaser, never build/), takes the notes from
# the tag's CHANGELOG.md section and reads the published body back, and pushes the src/vX.Y.Z
# module tag, which matches no trigger here.
#
# It stays tag-driven: GoReleaser reads the version from the ref it is run
# against, and the first step refuses a ref that is not a v[0-9]* tag.
# src/cmd/vigil's TestReleaseRunsOnlyOnAConfirmedDispatch fails if an automatic
# trigger comes back or the refusal stops being the first step.
#
# The Go module lives in src/ (github.com/simtabi/vigil/src), so GoReleaser runs
# from the repository root with --config src/.goreleaser.yaml and writes its
# scratch dist to .cache/goreleaser/, never into build/.
# macOS, not Linux: vigil's input engine (src/internal/activity/input_darwin.go) links
# CoreGraphics/IOKit via cgo, so the darwin targets need the macOS SDK and can't be cross-compiled
# CGO-free. The arm64 runner builds darwin natively and cross-builds the CGO-free
# linux/windows/bsd matrix in one job. The job runs under the `release` environment, as before.
# src/cmd/vigil's TestReleaseRunsOnAVersionTagOrOnRequest and src/internal/release's
# TestReleaseInputsMatchTheRepository fail if a trigger is added or an input drifts.
name: Release

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
confirm:
description: Type release-go to publish binaries for the tag this run is dispatched on
tag:
description: 'An existing vX.Y.Z tag to build and publish'
required: true
type: string

# Releases must never be cancelled mid-publish by a newer tag.
permissions: {}

# One run per tag, never cancelled: two runs must not publish the same release.
concurrency:
group: release-${{ github.ref }}
group: release-${{ inputs.tag || github.ref_name }}
cancel-in-progress: false

permissions:
contents: read

# Our own modules are fetched from git, never through proxy.golang.org or
# sum.golang.org, so the build itself is not what feeds the public proxy a tag.
env:
GOPRIVATE: github.com/simtabi/*
GONOSUMDB: github.com/simtabi/*

jobs:
goreleaser:
# macOS, not Linux: vigil's input engine (src/internal/activity/input_darwin.go)
# links CoreGraphics/IOKit via cgo, so the darwin targets need the macOS SDK
# and can't be cross-compiled CGO-free. The arm64 runner builds darwin
# natively and cross-builds the CGO-free linux/windows/bsd matrix in one job.
runs-on: macos-latest
environment: release
timeout-minutes: 60
release:
permissions:
contents: write # create the release and upload assets
id-token: write # keyless signing for the provenance attestation
attestations: write # write the build-provenance attestation
steps:
- name: Refuse without confirmation or a release tag
env:
CONFIRM: ${{ inputs.confirm }}
run: |
if [ "${CONFIRM}" != "release-go" ]; then
echo "::error::confirm must be release-go; nothing was published"
exit 1
fi
case "${GITHUB_REF}" in
refs/tags/v[0-9]*) ;;
*) echo "::error::dispatch this on a vX.Y.Z tag (--ref vX.Y.Z), not ${GITHUB_REF}"; exit 1 ;;
esac

- uses: actions/checkout@v7
with:
fetch-depth: 0 # full history + tags for GoReleaser

- uses: actions/setup-go@v7
with:
go-version-file: src/go.mod
cache: true
cache-dependency-path: src/go.sum

# syft powers GoReleaser's SBOM generation.
- uses: anchore/sbom-action/download-syft@66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c # v0.24.3

# `go install` needs a tag named after the module's subdirectory: the
# module is github.com/simtabi/vigil/src, so Go resolves src/vX.Y.Z and
# ignores vX.Y.Z. OSS GoReleaser rejects the prefixed tag as non-semver,
# so the release runs off vX.Y.Z and mirrors src/vX.Y.Z onto the same
# commit here, where it cannot be forgotten. This workflow starts on no
# tag push, so pushing src/... starts no second run. A re-run finds the
# tag already there and leaves it alone: a public tag is never moved.
- name: Mirror the tag Go resolves the module through
run: |
alias_tag="src/${GITHUB_REF_NAME}"
if git rev-parse -q --verify "refs/tags/${alias_tag}" >/dev/null; then
echo "${alias_tag} already exists"
else
git tag "${alias_tag}" "${GITHUB_REF_NAME}^{commit}"
git push origin "refs/tags/${alias_tag}"
echo "pushed ${alias_tag}"
fi

- name: Extract CHANGELOG section for this tag
run: ./src/scripts/extract-changelog.sh "${GITHUB_REF_NAME}" > release_notes.md

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
version: latest
args: release --clean --config src/.goreleaser.yaml --release-notes=release_notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
# Write deploy keys on simtabi/homebrew-tap and simtabi/scoop-bucket. When set, GoReleaser
# pushes with them and the token is not used for those two.
HOMEBREW_TAP_DEPLOY_KEY: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }}
SCOOP_BUCKET_DEPLOY_KEY: ${{ secrets.SCOOP_BUCKET_DEPLOY_KEY }}
# Scoop/Winget publishing is skipped until the bucket/fork exist. Set
# repo variable SKIP_WINDOWS_PKGS to "false" to enable it.
SKIP_WINDOWS_PKGS: ${{ vars.SKIP_WINDOWS_PKGS || 'true' }}
# Scoop's own switch; empty falls back to SKIP_WINDOWS_PKGS (see the GoReleaser config).
SKIP_SCOOP: ${{ vars.SKIP_SCOOP }}

# Set the body again from the same CHANGELOG section, so the release
# carries its notes even if a GoReleaser change stops honouring
# --release-notes, which is how ssh-manager v3.2.0 and v3.4.0 went out empty.
- name: Set the release body from CHANGELOG.md
env:
GH_TOKEN: ${{ github.token }}
run: gh release edit "${GITHUB_REF_NAME}" --repo "${GITHUB_REPOSITORY}" --notes-file release_notes.md

# Sign a build-provenance attestation for every released artifact. The
# checksums file lists them all, so `gh attestation verify <file>
# --repo <owner>/<repo>` works for any downloaded binary or archive.
- name: Attest build provenance
uses: actions/attest-build-provenance@v4
with:
subject-checksums: .cache/goreleaser/checksums.txt
contents: write
id-token: write
attestations: write
uses: simtabi/.github/.github/workflows/go-release.yml@941f7b7ecce5dc8af6daedfc7496dd4367c70877 # simtabi/.github#28
with:
tag: ${{ inputs.tag || github.ref_name }}
runs-on: macos-latest
environment: release
55 changes: 34 additions & 21 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,25 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
release download fails.

### Changed
- **The `Release` workflow is disabled in Actions while binary releases are on
hold.** The tags `v0.1.0` through `v0.7.0` carry an older `release.yml` that a
manual dispatch would run with no confirmation step, and a disabled workflow
runs on no ref. `docs/release.md` gives the enable, dispatch and disable
commands for an approved release.
- **Binary releases are on hold; the release workflow runs only on a confirmed
manual dispatch.** A tag push no longer starts GoReleaser. A release is
dispatched on a `v[0-9]*` tag with `-f confirm=release-go`
(`gh workflow run release.yml --repo simtabi/vigil --ref vX.Y.Z -f confirm=release-go`),
and the first step refuses anything else before a single artifact is built.
`TestReleaseRunsOnlyOnAConfirmedDispatch` fails if `release.yml` regains an
automatic trigger or loses the confirmation, or if the refusal stops being the
first step.
- **Binaries ship on the GitHub release only, built on a version tag or on
request.** A pushed `vX.Y.Z` tag (or `vX.Y.Z-rc.N` pre-release) builds and
publishes the release, and
`gh workflow run release.yml --repo simtabi/vigil -f tag=vX.Y.Z` does the same
for a tag already pushed. `release.yml` is now a thin caller of simtabi/.github's
shared `go-release.yml`, run on `macos-latest` (the darwin targets need cgo) under
the `release` environment; the shared workflow checks the tag, takes the notes
from this file and reads the published body back, mirrors `src/vX.Y.Z`, runs
GoReleaser and attests provenance. This replaces the dispatch-only,
`-f confirm=release-go` workflow of this cycle, which never shipped, and its own
`gh release edit --notes-file` step. `TestReleaseRunsOnAVersionTagOrOnRequest`
and `TestReleaseInputsMatchTheRepository` fail if a trigger is added, the job
stops calling the shared workflow, or the runner, environment, alias tag, config
or changelog input drifts.
- **The `Release` workflow stays disabled in Actions until the owner enables it.**
It was disabled on 2026-11-08 because a dispatch with `--ref` runs the workflow a
tag carries. The only version tag on GitHub now, `v0.1.0`, carries a dispatch-only
workflow that refuses to run without `-f confirm=release-go`; `docs/release.md`
gives the enable command.
- **The Go module lives in `src/`.** `go.mod`, `go.sum`, `cmd/`, `internal/`,
`tui/`, `tools/iconz`, `scripts/`, `.goreleaser.yaml` and `.golangci.yml` moved
under `src/`, and the module path is now `github.com/simtabi/vigil/src`, as the
Expand Down Expand Up @@ -66,14 +72,21 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
`brand.md` and `cli.md` give the new paths. They still say binary releases are
on hold and build from source; `updating.md` no longer offers re-running
`go install` and says that channel is frozen at 0.7.0.
- **Building from source is the only documented install path.** The README and
`installation.md` no longer offer the install scripts, Homebrew, Scoop, deb/rpm,
release downloads or `go install`; they give a clone, `make build`,
`vigil self install`, how to pin a tag and update, and say the 0.1.0-0.7.0
release archives stay where they are but no new release is published.
`updating.md` says `vigil upgrade` finds nothing newer than 0.7.0 while
releases are on hold, and that it refuses to replace a source build with an
older release unless `--force` is given.
- **Two install paths, in order: the GitHub release, then a build from source.**
The README and `installation.md` give the release download checked against
`checksums.txt` (and `gh attestation verify`), then a clone, `make build`,
`vigil self install`, how to pin a tag and update. No Homebrew, Scoop, Winget or
`go install` path is offered. `updating.md` says `vigil upgrade` reads the latest
GitHub release, and that it refuses to replace a source build with an older
release unless `--force` is given.

### Removed
- **Homebrew cask, Scoop and Winget publishing.** `src/.goreleaser.yaml` loses its
`homebrew_casks`, `scoops` and `winget` blocks, and `release.yml` the tap and
bucket deploy keys, `TAP_GITHUB_TOKEN` and the `SKIP_SCOOP` /
`SKIP_WINDOWS_PKGS` switches that fed them. `simtabi/homebrew-tap` and
`simtabi/scoop-bucket` hold no vigil entry, so nothing there is affected.
`TestGoReleaserPublishesNowhereElse` fails if a publishing block returns.

### Fixed
- **`vigil upgrade` no longer replaces a newer build with an older release.**
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# as macos and .exe on Windows. `make check-build` (TestBuildLayout) fails on
# anything else.
#
# Nothing here publishes. Releases are dispatched by hand (docs/release.md).
# Nothing here publishes. A release builds on a pushed vX.Y.Z tag or on request (docs/release.md).

SHELL := /usr/bin/env bash
# `make` alone builds, as it did before the help target existed.
Expand Down
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,25 @@ schedule, keeps the session non-idle with one of two **engines**:

## Install

vigil is built from source: binary releases are on hold, so there is no
download, install-script, package-manager or `go install` channel to use. You
need Go (the version `src/go.mod` names), `git` and `make`; macOS also needs the
Xcode Command Line Tools, because the input backend uses cgo.
Download the binary for your platform from the
[GitHub releases](https://github.com/simtabi/vigil/releases) (`vigil_<os>_<arch>`,
e.g. `vigil_macos_universal`, `vigil_linux_amd64`), check it against the release's
`checksums.txt`, and let it install itself:

```bash
gh release download --repo simtabi/vigil --pattern vigil_macos_universal --pattern checksums.txt
shasum -a 256 -c checksums.txt --ignore-missing
chmod +x vigil_macos_universal && ./vigil_macos_universal self install
vigil doctor
```

The GitHub release is the only channel: there is no package-manager or
`go install` path. GitHub lists no vigil release yet (checked 2026-11-13); until
the first one under the current release workflow is published, build from source.

To build from source you need Go (the version `src/go.mod` names), `git` and
`make`; macOS also needs the Xcode Command Line Tools, because the input backend
uses cgo.

```bash
git clone https://github.com/simtabi/vigil ~/src/vigil
Expand All @@ -72,8 +87,8 @@ vigil doctor
```

Then run `vigil config wizard` (or `vigil config init`) and `vigil install`.
Windows, pinning a version, updating, and the archives published for 0.1.0 to
0.7.0 are in [docs/installation.md](docs/installation.md).
Windows, verifying the attestation, pinning a version, updating, and the release
asset names are in [docs/installation.md](docs/installation.md).

The **input** engine must be installed with `--scope user` (default, GUI
session); a system-wide service (`--scope system`) is intended for the `graph`
Expand Down Expand Up @@ -109,8 +124,8 @@ The full configuration walkthrough is in [docs/configuration.md](docs/configurat

## Updating

No new releases are published while binary releases are on hold, so update a
source build from git:
A release install updates with `vigil upgrade` ([docs/updating.md](docs/updating.md)).
Update a source build from git:

```bash
git -C ~/src/vigil pull --ff-only
Expand Down
48 changes: 35 additions & 13 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,36 @@

## Install

vigil is built from source. Binary releases are on hold until the maintainer
decides otherwise, so this page offers no download, install-script,
package-manager or `go install` path. You need Go (the version `src/go.mod`
names), `git` and `make`.
Two ways, in this order: download the binary from the GitHub release, or build
from source. This page offers no package-manager or `go install` path.

### Download a release

Download the binary for your platform from the
[GitHub releases](https://github.com/simtabi/vigil/releases) (`vigil_<os>_<arch>`,
e.g. `vigil_macos_universal`, `vigil_linux_amd64`), check it against the release's
`checksums.txt`, and let it install itself:

```bash
gh release download --repo simtabi/vigil --pattern vigil_macos_universal --pattern checksums.txt
shasum -a 256 -c checksums.txt --ignore-missing
chmod +x vigil_macos_universal && ./vigil_macos_universal self install
vigil doctor
```

The GitHub release is the only channel: there is no package-manager or
`go install` path. GitHub lists no vigil release yet (checked 2026-11-13); until
the first one under the current release workflow is published, build from source.

Every asset in `checksums.txt` carries a build-provenance attestation:

```bash
gh attestation verify vigil_macos_universal --repo simtabi/vigil
```

### Build from source

You need Go (the version `src/go.mod` names), `git` and `make`.

```bash
git clone https://github.com/simtabi/vigil ~/src/vigil
Expand Down Expand Up @@ -46,16 +72,12 @@ Do not use `vigil upgrade` on a source build; see [updating.md](updating.md).
`vigil version` reports the version `git describe` gave the build, so a build
from a branch is still identifiable.

### Earlier binary releases
### Release assets

0.1.0 to 0.7.0 were published as archives on
[GitHub Releases](https://github.com/simtabi/vigil/releases). Those stay where
they are and an existing install keeps working, but no new release is published
while binary releases are on hold: build from source to get anything newer. The
install scripts in `src/scripts/` remain in the tree, but they download the latest
published release, so they cannot install anything newer than 0.7.0. For
reference, those archives are named `vigil_<os>_<arch>` (macOS uses the
`macos` token):
Releases are published on [GitHub Releases](https://github.com/simtabi/vigil/releases)
only; no Homebrew, Scoop or Winget manifest is published. The install scripts in
`src/scripts/` download the latest published release. The archives are named
`vigil_<os>_<arch>` (macOS uses the `macos` token):

| Machine | Archive |
|---------|---------|
Expand Down
Loading
Loading