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
79 changes: 79 additions & 0 deletions .github/workflows/check-go-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Check Go Version

on:
schedule:
# Run every Monday at 9 AM UTC
- cron: '0 9 * * 1'
workflow_dispatch: # Allow manual triggering

permissions:
issues: write

jobs:
check-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Get current Go version from go.mod
id: current
run: |
# go.mod is the canonical and only source of truth for the repository's
# Go version. Workflows derive their version from it via
# `go-version-file: go.mod`, so there is nothing else to update.
CURRENT_VERSION=$(grep -E '^go [0-9]' go.mod | awk '{print $2}')
echo "Current Go version in go.mod: $CURRENT_VERSION"
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"

- name: Get latest stable Go version
id: latest
run: |
# Fetch the latest stable Go version from the official releases page.
LATEST_VERSION=$(curl -s https://go.dev/VERSION?m=text | head -n 1 | sed 's/go//')
echo "Latest stable Go version: $LATEST_VERSION"
echo "version=$LATEST_VERSION" >> "$GITHUB_OUTPUT"

- name: Open an issue if outdated
env:
GH_TOKEN: ${{ github.token }}
CURRENT_VERSION: ${{ steps.current.outputs.version }}
LATEST_VERSION: ${{ steps.latest.outputs.version }}
run: |
echo "Current: $CURRENT_VERSION"
echo "Latest: $LATEST_VERSION"

if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo "Go version is up to date!"
exit 0
fi

echo "Go version is outdated."
TITLE="Update Go version from $CURRENT_VERSION to $LATEST_VERSION"

# Skip if an open issue for this exact bump already exists. Opening an
# issue (rather than building the PR here) keeps this workflow simple and
# lets the autonomous Claude agent produce the bump PR.
EXISTING_ISSUE=$(gh issue list --search "$TITLE in:title" --state open --label claude --json number,title --jq "map(select(.title == \"$TITLE\")) | .[0].number // empty")
if [ -n "$EXISTING_ISSUE" ]; then
echo "Issue #$EXISTING_ISSUE already open for this bump, skipping."
exit 0
fi

gh issue create \
--title "$TITLE" \
--label "claude" \
--body "$(cat <<EOF
A new stable Go version is available. Bump the canonical Go version in
\`go.mod\` from \`$CURRENT_VERSION\` to \`$LATEST_VERSION\`.

\`go.mod\` is the only place a Go version lives in this repository:
update the \`go\` directive (and the \`toolchain\` line, if present).
Workflows derive their Go version from \`go.mod\` via
\`go-version-file: go.mod\`, so no other files need to change.

See the [Go release notes](https://go.dev/doc/devel/release) for details about this version.

---
✨ Content generated by automated workflow.
EOF
)"
16 changes: 14 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,21 @@ This repository is a small, standalone Entity Component System (ECS) library in
* Every Go source file in the package is named `ecs_<subsystem>.go` (for example `ecs_world.go`, `ecs_store.go`), with matching tests `ecs_<subsystem>_test.go`. The package doc lives in `ecs/ecs_doc.go`.
* Keep files small and single-responsibility; split by responsibility, not by technical layer.

### Go version and dependencies
### Go Version Consistency

`go.mod` is the single source of truth for this repository's Go version — it is the only place a Go version is written, and the workflows already derive their version from it via `go-version-file: go.mod`:

```yaml
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true
```

Never hardcode a `go-version:` literal in a workflow. The scheduled `check-go-version.yml` workflow compares `go.mod`'s declared version against the latest stable Go release and, when it falls behind, opens a `claude`-labelled issue requesting the bump; the autonomous Claude agent then makes the one-line change to the single `go` directive. Because nothing else carries the version, a bump is a one-line change.

### Dependencies

* Go 1.26 (see `go.mod`). The code relies on range-over-func and the `iter` package.
* No third-party dependencies, and that is a deliberate property of a foundational library. A new dependency is a significant decision; if one is ever genuinely needed, call it out prominently in the PR description (name, version, purpose, justification, and whether it is test-only).

### Verification before pushing
Expand Down
Loading