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
2 changes: 1 addition & 1 deletion .github/github.xdocs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
subject: buda-github
description: GitHub repository automation and workflow configuration for Buda.
parent: null
parent: buda-package
children:
- buda-github-workflows
files: {}
Expand Down
459 changes: 255 additions & 204 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

273 changes: 39 additions & 234 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,272 +1,77 @@
name: Publish Go Release
name: Publish Buda Release

on:
workflow_dispatch:
push:
tags:
- 'buda/v*'
tags: ['buda/v*']

permissions:
contents: write

jobs:
release-ref:
name: Verify current canonical tag target
runs-on: ubuntu-latest
outputs:
current: ${{ steps.target.outputs.current }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- id: target
name: Ignore a superseded tag event
shell: bash
run: |
set -euo pipefail
current="$(git ls-remote origin "refs/tags/${GITHUB_REF_NAME}^{}" | cut -f1)"
if [[ "$current" != "$GITHUB_SHA" ]]; then
echo "::notice::Ignoring stale ${GITHUB_REF_NAME} event for ${GITHUB_SHA}; current target is ${current:-missing}."
echo 'current=false' >> "$GITHUB_OUTPUT"
exit 0
fi
echo 'current=true' >> "$GITHUB_OUTPUT"

windows-installer-preflight:
name: Preflight Windows installer before publication
needs: release-ref
if: needs.release-ref.outputs.current == 'true'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- name: Build local release assets and upgrade from 0.0.1
shell: pwsh
run: |
$tag = '${{ github.ref_name }}'
if ($tag -notmatch '^buda/v(?<Version>[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)$') { throw "Invalid Buda tag: $tag" }
$version = $Matches.Version
$buildDate = (git show -s --format=%cI HEAD | Out-String).Trim()
go run .\devops\build-binaries.go --version $version --commit '${{ github.sha }}' --build-date $buildDate
if ((Get-ChildItem -LiteralPath dist -File).Count -ne 11) { throw 'Release must contain exactly 11 assets.' }

$root = Join-Path $env:RUNNER_TEMP 'buda-preflight'
$homeDirectory = Join-Path $root 'home'
$installDirectory = Join-Path $root 'bin'
$fakeBin = Join-Path $root 'fake-bin'
New-Item -ItemType Directory -Force -Path $homeDirectory, $installDirectory, $fakeBin | Out-Null
go build -trimpath -ldflags '-X main.version=0.0.1' -o (Join-Path $installDirectory 'buda.exe') .
Set-Content -LiteralPath (Join-Path $fakeBin 'qmd.cmd') -Value '@echo qmd 2.5.3' -Encoding ASCII
$env:HOME = $homeDirectory
$env:USERPROFILE = $homeDirectory
$env:PATH = "$fakeBin;$env:PATH"
$env:BUDA_RELEASE_ASSET_DIR = (Resolve-Path 'dist').Path
& .\devops\install.ps1 -Version $tag -InstallDir $installDirectory
$actual = (& (Join-Path $installDirectory 'buda.exe') --version | Out-String).Trim()
if ($actual -ne "buda v$version") { throw "Unexpected installed version: $actual" }

publish:
needs:
- release-ref
- windows-installer-preflight
if: needs.release-ref.outputs.current == 'true'
runs-on: ubuntu-latest
outputs:
version: ${{ steps.release.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

with: { fetch-depth: 0 }
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install the tested external qmd runtime
run: npm install --global @tobilu/qmd@2.5.3

- name: Resolve canonical release metadata
with: { go-version-file: go.mod, cache: true }
- name: Install repository tooling
env:
GOBIN: ${{ github.workspace }}/.bin
run: |
mkdir -p "$GOBIN"
# These projects use repository-prefixed release tags (for example
# mirror/v4.0.1), which Go does not interpret as module versions.
# Pin the corresponding release commits with immutable pseudo-versions.
go install github.com/CGuiho/mirror@v0.0.0-20260802221718-766730ccf4b6
go install github.com/CGuiho/runx@v0.0.0-20260811091523-2c96e8aec105
go install github.com/CGuiho/xdocs@v0.0.0-20260802225907-1d353b79b73e
- name: Resolve and validate canonical version
id: release
shell: bash
run: |
if [[ "${GITHUB_REF_NAME}" != buda/v* ]]; then
echo "Non-canonical Buda tag: ${GITHUB_REF_NAME}" >&2
exit 1
fi
version="${GITHUB_REF_NAME#buda/v}"
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "Invalid Buda semantic version: $version" >&2
exit 1
fi
[[ "$GITHUB_REF_NAME" == buda/v* ]] || { echo 'non-canonical tag' >&2; exit 1; }
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]] || { echo 'invalid SemVer' >&2; exit 1; }
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "build_date=$(git show -s --format=%cI HEAD)" >> "$GITHUB_OUTPUT"

- name: Verify source
echo "date=$(git show -s --format=%cI HEAD)" >> "$GITHUB_OUTPUT"
- name: Required quality and tooling gates
run: |
./.bin/mirror config check
./.bin/runx check --format json
./.bin/xdocs meta . --documents --strict
./.bin/xdocs doctor . --warnings-as-errors
test -z "$(gofmt -l .)"
go mod tidy
git diff --exit-code -- go.mod go.sum
go test -count=1 ./...
go vet ./...

- name: Build and verify exact 11 assets
- name: Build complete release unit
run: |
go run ./devops/build-binaries.go \
--version '${{ steps.release.outputs.version }}' \
--commit "${GITHUB_SHA}" \
--build-date '${{ steps.release.outputs.build_date }}'
test "$(find dist -maxdepth 1 -type f | wc -l)" -eq 11
go run ./devops/build-binaries.go --version '${{ steps.release.outputs.version }}' --commit "$GITHUB_SHA" --build-date '${{ steps.release.outputs.date }}'
(cd dist && sha256sum --check checksums.txt)
test "$(dist/buda-linux-amd64 --version)" = 'buda v${{ steps.release.outputs.version }}'

- name: Extract exact-version release notes
shell: bash
run: |
version='${{ steps.release.outputs.version }}'
awk -v heading="## [$version]" '
index($0, heading " - ") == 1 || $0 == heading { found = 1; next }
found && /^## / { exit }
found { print }
END { if (!found) exit 1 }
' CHANGELOG.md > "${RUNNER_TEMP}/buda-release-notes.md"
test -s "${RUNNER_TEMP}/buda-release-notes.md"

- name: Preflight Bash installer before publication
shell: bash
run: |
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT
mkdir -p "$root/home" "$root/install" "$root/fake-bin"
go build -trimpath -ldflags '-X main.version=0.0.1' -o "$root/install/buda" .
printf '#!/usr/bin/env sh\nprintf "qmd 2.5.3\\n"\n' > "$root/fake-bin/qmd"
chmod +x "$root/fake-bin/qmd"
export HOME="$root/home"
export PATH="$root/fake-bin:$PATH"
export GUIHO_INSTALL_DIR="$root/install"
export BUDA_RELEASE_ASSET_DIR="$PWD/dist"
sh devops/install.sh "${GITHUB_REF_NAME}"
test "$("$root/install/buda" --version)" = 'buda v${{ steps.release.outputs.version }}'

- name: Preflight real qmd project-local retrieval before publication
shell: bash
run: |
set -euo pipefail
wiki="${RUNNER_TEMP}/release-wiki"
export HOME="${RUNNER_TEMP}/release-home"
mkdir -p "$HOME"
dist/buda-linux-amd64 init --wiki "$wiki" --wiki-id release-smoke
dist/buda-linux-amd64 capture --wiki "$wiki" \
--target concepts/release.md \
--title 'Release evidence' \
--description 'Evidence for the Buda release qmd preflight.' \
--actor agent:release \
--text 'Buda release retrieval is delegated to qmd.'
dist/buda-linux-amd64 query --wiki "$wiki" --mode lexical \
--text 'release retrieval' --json > "${RUNNER_TEMP}/release-query.json"
jq -e '.results[0].path == "concepts/release.md"' "${RUNNER_TEMP}/release-query.json"

- name: Create or repair GitHub release
test "$(dist/buda-linux-amd64 --version)" = '${{ steps.release.outputs.version }}'
- name: Create or repair GitHub Release from manifest-derived assets
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
mapfile -t assets < <(find dist -maxdepth 1 -type f -printf '%f\n' | sort)
test "${#assets[@]}" -eq 11
asset_paths=()
for asset in "${assets[@]}"; do asset_paths+=("dist/$asset"); done
release_flags=(--latest)
if [[ '${{ steps.release.outputs.version }}' == *-* ]]; then
release_flags=(--prerelease)
fi
if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
while IFS= read -r current; do
if [[ -n "$current" && ! -f "dist/$current" ]]; then
gh release delete-asset "${GITHUB_REF_NAME}" "$current" --yes
fi
done < <(gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets[].name')
gh release upload "${GITHUB_REF_NAME}" "${asset_paths[@]}" --clobber
gh release edit "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
--notes-file "${RUNNER_TEMP}/buda-release-notes.md" \
"${release_flags[@]}"
paths=(); for asset in "${assets[@]}"; do paths+=("dist/$asset"); done
notes="${RUNNER_TEMP}/release-notes.md"
awk -v h="## [${{ steps.release.outputs.version }}]" 'index($0,h)==1{found=1;next} found&&/^## /{exit} found{print} END{if(!found)exit 1}' CHANGELOG.md > "$notes"
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
gh release upload "$GITHUB_REF_NAME" "${paths[@]}" --clobber
gh release edit "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file "$notes"
else
gh release create "${GITHUB_REF_NAME}" "${asset_paths[@]}" \
--verify-tag \
--title "${GITHUB_REF_NAME}" \
--notes-file "${RUNNER_TEMP}/buda-release-notes.md" \
"${release_flags[@]}"
gh release create "$GITHUB_REF_NAME" "${paths[@]}" --verify-tag --title "$GITHUB_REF_NAME" --notes-file "$notes"
fi

- name: Verify exact public asset set
- name: Verify public asset set and checksums
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
find dist -maxdepth 1 -type f -printf '%f\n' | sort > "${RUNNER_TEMP}/expected-assets.txt"
gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets[].name' | sort > "${RUNNER_TEMP}/actual-assets.txt"
test "$(wc -l < "${RUNNER_TEMP}/actual-assets.txt" | tr -d '[:space:]')" -eq 11
cmp "${RUNNER_TEMP}/expected-assets.txt" "${RUNNER_TEMP}/actual-assets.txt"

- name: Verify tag-pinned public Bash installer
shell: bash
run: |
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT
mkdir -p "$root/home" "$root/project" "$root/install" "$root/fake-bin"
printf '#!/usr/bin/env sh\nprintf "qmd 2.5.3\\n"\n' > "$root/fake-bin/qmd"
chmod +x "$root/fake-bin/qmd"
export HOME="$root/home"
export PATH="$root/fake-bin:$PATH"
export GUIHO_INSTALL_DIR="$root/install"
cd "$root/project"
curl -fsSL "https://raw.githubusercontent.com/CGuiho/buda/${GITHUB_SHA}/devops/install.sh" |
sh -s -- "${GITHUB_REF_NAME}"
test "$("$root/install/buda" --version)" = 'buda v${{ steps.release.outputs.version }}'
test -s "$HOME/.agents/skills/guiho-s-0002-buda/SKILL.md"
test -s "$HOME/.claude/skills/guiho-s-0002-buda/SKILL.md"

windows-installer:
name: Verify tag-pinned public Windows installer
needs:
- release-ref
- publish
if: needs.release-ref.outputs.current == 'true'
runs-on: windows-latest
steps:
- name: Install the exact tagged Buda release
shell: pwsh
env:
BUDA_VERSION: ${{ needs.publish.outputs.version }}
run: |
$root = Join-Path $env:RUNNER_TEMP 'buda-public'
$homeDirectory = Join-Path $root 'home'
$installDirectory = Join-Path $root 'bin'
$fakeBin = Join-Path $root 'fake-bin'
New-Item -ItemType Directory -Force -Path $homeDirectory, $installDirectory, $fakeBin | Out-Null
Set-Content -LiteralPath (Join-Path $fakeBin 'qmd.cmd') -Value '@echo qmd 2.5.3' -Encoding ASCII
$env:HOME = $homeDirectory
$env:USERPROFILE = $homeDirectory
$env:PATH = "$fakeBin;$env:PATH"
$source = Invoke-RestMethod "https://raw.githubusercontent.com/CGuiho/buda/${{ github.sha }}/devops/install.ps1"
& ([scriptblock]::Create($source)) -Version "buda/v$env:BUDA_VERSION" -InstallDir $installDirectory
$actual = (& "$installDirectory\buda.exe" --version | Out-String).Trim()
if ($actual -ne "buda v$env:BUDA_VERSION") { throw "Unexpected installed version: $actual" }
if (-not (Test-Path -LiteralPath "$homeDirectory\.agents\skills\guiho-s-0002-buda\SKILL.md")) {
throw 'Missing .agents Buda skill installation.'
}
if (-not (Test-Path -LiteralPath "$homeDirectory\.claude\skills\guiho-s-0002-buda\SKILL.md")) {
throw 'Missing .claude Buda skill installation.'
}
find dist -maxdepth 1 -type f -printf '%f\n' | sort > "${RUNNER_TEMP}/expected"
gh release view "$GITHUB_REF_NAME" --json assets --jq '.assets[].name' | sort > "${RUNNER_TEMP}/actual"
cmp "${RUNNER_TEMP}/expected" "${RUNNER_TEMP}/actual"
40 changes: 23 additions & 17 deletions .github/workflows/workflows.xdocs.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
---
subject: buda-github-workflows
description: Go CI, native smoke coverage, canonical-tag or manual GitHub Release publication, stale-tag event filtering, exact-asset reconciliation, and public installer acceptance.
description: Go quality, native launcher and payload smoke, complete manifest-derived GitHub Release publication, and public lifecycle acceptance.
parent: buda-github
children: []
files:
ci.yml: Go formatting, module, test, vet, exact eleven-artifact build, checksum, installer syntax, hosted native-platform smoke, and real qmd 2.5.3 project-local lexical integration validation.
publish.yml: Canonical buda/v* GitHub Release publication with manual recovery dispatch, stale-tag event filtering, exact-version notes, exactly eleven assets, checksum verification, pre-publication Linux and Windows upgrade-installer gates, real qmd lexical retrieval, and post-publication installer acceptance.
ci.yml: Go formatting, module, test, vet, RunX, Mirror, strict XDocs, manifest build, checksums, installer syntax, hosted native launcher/payload smoke, POSIX and Windows lifecycle acceptance, legacy 0.1.1 migration, and foreign build-only targets.
publish.yml: Canonical buda/v* GitHub Release publication with manifest-derived assets and public checksum reconciliation.
documents: {}
tags:
- github-actions
- ci
- release
keywords:
- buda/vX.Y.Z
- eleven artifacts
- artifacts.json
- public installers
- GitHub Release
- no package publication
flags: []
status: stable
---

CI builds all eight pure-Go release targets and executes compatible artifacts
on hosted Linux, macOS, and Windows AMD64 and ARM64 runners. ARMv6 and ARMv7
remain cross-build-only because GitHub does not provide matching hosted runners.
It also installs the separate tested qmd 2.5.3 runtime and exercises Buda init,
capture, project-local indexing, lexical query, get, status, and doctor on
Linux, plus the npm `qmd.cmd` launcher path on Windows, without downloading
models or adding a Buda package-manager publication.
CI builds the manifest-derived complete release unit and validates checksums.
Hosted Linux, macOS, and Windows AMD64 and ARM64 runners execute native
payload smokes and launcher smokes through a disposable pointer fixture.
ARMv6 and ARMv7 remain cross-build-only because GitHub does not provide
matching hosted runners. RunX, Mirror, strict XDocs, Go quality, lifecycle
transaction and interruption acceptance, and both installer-language syntax
checks are required.

Publication runs for canonical `buda/v*` tags or a manual recovery dispatch
against one. It ignores delayed events whose commit no longer matches the
current tag target. For a current tag, it reconciles one GitHub Release to the
exact eleven checked artifacts and verifies the tag-pinned Bash and PowerShell
installers before publication, then repeats public installer acceptance after
publication, without publishing to a package manager or registry.
Native lifecycle jobs on Linux and Windows install the release from a local
asset directory into a disposable home with a qmd process stub, verify the
stable launcher, prove same-version reinstall repair, migrate a synthetic
0.1.1 direct-binary layout through the launcher transaction (carrying the
legacy wiki_id into the newly selected wiki), and run a synchronous default
uninstall while asserting that canonical OKF content and shared GUIHO
sentinels survive.

Publication runs for canonical `buda/v*` tags or a manual recovery dispatch.
It reconciles one GitHub Release to every manifest-declared asset, verifies
the public asset names against the generated release directory, and never
publishes to a package manager or registry.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
/buda.exe
*.test
*.out
/.tmp/
/.tmp/
/.gocache/
/.gomodcache/
/.tmp-buda.exe
Loading
Loading