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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.git
.github
dist
docs
*.md
140 changes: 140 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: CI

# The Go code here is a synced copy of hivecommons/hive src/crux (see
# .hive-sync). This CI proves the published, module-path-rewritten tree
# builds, vets, tests and serves on its own; hive's CI is where the code is
# actually gated. Fix failures in hive, never here.

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build:
name: build+vet+test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Module is standalone
run: |
set -euo pipefail
test -f .hive-sync && cat .hive-sync
grep -qx 'module github.com/hivecommons/crux' go.mod
if grep -rn --include='*.go' '"github.com/hivecommons/hive' . ; then
echo "::error::tree still imports the hive module path; the sync rewrite is incomplete" >&2
exit 1
fi
test -z "${GOWORK:-}" || { echo "::error::GOWORK must be unset" >&2; exit 1; }
go mod verify
- run: go build ./...
- run: go vet ./...
- name: go test -short -race (all but agent)
# Same flags as hive's v2-tests lanes (-short -race -count=1). The
# tmux-bound tests in hive skip themselves via internal/testutil
# (SkipUnlessRequired) unless HIVE_TEST_REQUIRE_BEHAVIOURAL=1, which is
# deliberately NOT set here: this lane proves the published module, not
# the tmux integration hive already gates. ./agent is its own job below
# because it alone takes ~7 minutes of test time.
run: |
# shellcheck disable=SC2046
go test -short -race -count=1 -timeout 20m $(go list ./... | grep -v '/agent$')

test-agent:
name: go test ./agent (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Install tmux
run: sudo apt-get update -q && sudo apt-get install -y -q tmux
- run: go test -short -race -count=1 -timeout 35m ./agent/...

lint:
name: golangci-lint
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: latest
args: --timeout=10m

smoke:
name: smoke crux serve (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Build crux
run: go build -trimpath -ldflags "-X main.version=ci-${GITHUB_SHA::12}" -o crux ./cmd/crux
- name: Version
run: ./crux --version
- name: Install tmux
if: runner.os == 'Linux'
run: sudo apt-get update -q && sudo apt-get install -y -q tmux
- name: Smoke (synced scripts/smoke.sh, same as hive's make smoke)
run: CRUX_BIN="$PWD/crux" scripts/smoke.sh

goreleaser-check:
name: goreleaser check + snapshot
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
version: "~> v2"
args: check
- name: Snapshot build (no publish, no docker, no sign)
uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
version: "~> v2"
args: release --snapshot --clean --skip=publish,docker,sign,sbom
78 changes: 78 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Release

# Runs on tags vX.Y.Z, which hive's crux-sync workflow pushes when hive is
# tagged crux/vX.Y.Z (a tag may also be pushed here directly). goreleaser
# builds darwin/linux × amd64/arm64 archives + checksums (cosign keyless
# signed), the multi-arch ghcr.io/hivecommons/crux image, and the GitHub
# release with generated notes. The Homebrew formula lives in
# hivecommons/homebrew-hive (Formula/crux.rb) and is bumped by PR.

on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
tag:
description: 'Existing tag to (re)release, e.g. v0.1.0'
type: string
required: true

permissions:
contents: read

jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 40
permissions:
contents: write
packages: write
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.inputs.tag || github.ref }}
fetch-depth: 0
persist-credentials: false
- name: Tag sanity
run: |
set -euo pipefail
tag="$(git describe --tags --exact-match HEAD)"
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-+].+)?$ ]] || { echo "::error::HEAD tag '$tag' is not vX.Y.Z" >&2; exit 1; }
test -f cmd/crux/main.go || { echo "::error::cmd/crux is not in this tree; nothing to release" >&2; exit 1; }
echo "Releasing $tag from $(grep '^hive_sha=' .hive-sync || echo 'unknown hive sha')"
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pre-release smoke
run: |
set -euo pipefail
sudo apt-get update -q && sudo apt-get install -y -q tmux
go build -trimpath -ldflags "-X main.version=$(git describe --tags --exact-match HEAD)" -o crux ./cmd/crux
./crux --version
CRUX_BIN="$PWD/crux" scripts/smoke.sh
rm -f crux
- uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Summary
run: |
{
echo "## crux ${GITHUB_REF_NAME}"
echo
echo "- Release: https://github.com/${GITHUB_REPOSITORY}/releases/tag/${GITHUB_REF_NAME}"
echo "- Image: \`ghcr.io/hivecommons/crux:${GITHUB_REF_NAME#v}\`"
echo "- \`go install github.com/hivecommons/crux/cmd/crux@${GITHUB_REF_NAME}\`"
echo "- Hive source: $(grep '^source=' .hive-sync | cut -d= -f2-)"
} >> "$GITHUB_STEP_SUMMARY"
63 changes: 63 additions & 0 deletions .github/workflows/sync-guard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Sync guard

# The Go code in this repository is produced by hivecommons/hive's
# crux-sync workflow from src/crux there. A pull request here that edits Go
# code would be overwritten by the next sync, so it is refused with a pointer
# to the source of truth. Scaffolding (.github/, .goreleaser.yaml, Dockerfile,
# README.md, LICENSE) is maintained here and passes.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

permissions:
contents: read
pull-requests: write

jobs:
guard:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Refuse Go edits from non-sync actors
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
ACTOR: ${{ github.actor }}
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
run: |
set -euo pipefail
# The sync pushes straight to main (no PR), so any PR here is by
# definition not the sync. Keep an allowlist anyway for a future
# PR-based sync actor.
case "$ACTOR" in
hive-release[bot]|hivecommons-hive[bot]) echo "sync actor $ACTOR; skipping"; exit 0 ;;
esac
files="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR}/files" --paginate --jq '.[].filename')"
go_files="$(printf '%s\n' "$files" | grep -E '(\.go|^go\.mod|^go\.sum|^\.hive-sync)$' || true)"
if [ -z "$go_files" ]; then
echo "No Go/module files touched; scaffolding-only change is fine here."
exit 0
fi
marker="<!-- crux-sync-guard -->"
# shellcheck disable=SC2016
list="$(printf '%s\n' "$go_files" | sed 's/^/- `/; s/$/`/')"
body="$marker
### This repository is a synced copy

The Go code here is generated from [\`hivecommons/hive\` \`src/crux\`](https://github.com/hivecommons/hive/tree/v5/src/crux) by hive's \`crux-sync\` workflow and would be overwritten by the next sync. Please open this change as a pull request against **hivecommons/hive** (base \`v5\`, under \`src/crux/\`); it will be published here automatically once it merges.

Files this PR touches that are owned by the sync:
$list

Only scaffolding is maintained in this repository: \`.github/\`, \`.goreleaser.yaml\`, \`Dockerfile\`, \`README.md\`, \`LICENSE\`."
# Strip the YAML indentation the lines above carry.
body="$(printf '%s\n' "$body" | sed 's/^ //')"
existing="$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" --paginate --jq ".[] | select(.body | startswith(\"$marker\")) | .id" | head -1)"
if [ -n "$existing" ]; then
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${existing}" -f body="$body" >/dev/null
else
gh pr comment "$PR" --body "$body"
fi
echo "::error::PR touches sync-owned files ($(printf '%s' "$go_files" | tr '\n' ' ')). Source of truth is hivecommons/hive src/crux."
exit 1
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/crux
/dist/
*.test
*.out
# Test-run scratch: crux/agent tests create stub CLI binaries under a
# per-run directory (mirrors hive's .gitignore).
.hive-agent-stubs-*/
/bin/
/.smoke/
27 changes: 27 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Lint config for the published copy of hivecommons/hive src/crux. Mirrors the
# enabled set and staticcheck scope of hive's src/.golangci.yml (minus hive's
# depguard rules, which name root-module packages) so the rewritten tree is
# held to exactly the gate it already passes in hive. Tighten there, not here.
version: "2"

run:
timeout: 10m
tests: true

linters:
default: none
enable:
- govet
- misspell
- ineffassign
- unused
- staticcheck
settings:
staticcheck:
checks: ["SA*", "-SA1019"]
exclusions:
generated: lax

issues:
max-issues-per-linter: 0
max-same-issues: 0
Loading
Loading