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
36 changes: 34 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,40 @@ jobs:

- name: Validate module builds
run: |
cd ${{ needs.detect.outputs.module_path }}
go build ./...
set -euo pipefail

MODULE_PATH="${{ needs.detect.outputs.module_path }}"

# cmd/forge and extensions/database pin the last PUBLISHED
# github.com/xraph/forge, because cmd/forge/go.mod has to stay free of
# replace directives for `go install ...@latest` to accept it. Built
# standalone they therefore compile against the released root module
# rather than this tree, and any root API this tag adds but has not
# published yet fails here as "undefined" -- a dry run reporting a
# break the real release does not have, since .goreleaser.yml's first
# before-hook sets up the same workspace for the build itself.
#
# The workfile lives OUTSIDE the repo on purpose: a go.work at the root
# would apply to every module, and the ones it does not list would fail
# with "directory prefix ... does not contain modules listed in
# go.work". Everything else is built with GOWORK=off so each module is
# still checked standalone.
case "$MODULE_PATH" in
cmd/forge|extensions/database)
WORKFILE="${RUNNER_TEMP:-/tmp}/forge-release.work"
rm -f "$WORKFILE"
GOWORK="$WORKFILE" go work init \
"$GITHUB_WORKSPACE" \
"$GITHUB_WORKSPACE/cmd/forge" \
"$GITHUB_WORKSPACE/extensions/database"
cd "$MODULE_PATH"
GOWORK="$WORKFILE" go build ./...
;;
*)
cd "$MODULE_PATH"
GOWORK=off go build ./...
;;
esac

- name: GoReleaser dry run (main/cli only)
if: needs.detect.outputs.module_type == 'main' || needs.detect.outputs.module_type == 'cli'
Expand Down
38 changes: 38 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,32 @@ version: 2

project_name: forge


# Pre-build hooks (run in root module context)
before:
hooks:
# MUST be first: every hook below, and the build itself, resolves modules.
#
# `builds.dir` is ./cmd/forge, which is a separate module pinning the last
# PUBLISHED github.com/xraph/forge -- its go.mod has to stay free of replace
# directives for `go install ...@latest` to accept it (see the comment at the
# top of that file). Without a workspace the build therefore compiles the CLI
# against the *released* root module rather than this tree, so any root API a
# tag adds but has not published yet fails as "undefined". That is not
# hypothetical: it is how the release broke, with `client.DiffSpecs` and
# `client.PathFilter` undefined against a root module pinned several versions
# back.
#
# This is the same throwaway workspace the "Build CLI" job in go.yml creates,
# moved to where the *release* can see it -- that job builds the CLI
# correctly and the release did not, which is the whole reason the two
# disagreed. go.work is gitignored, so it never escapes the runner.
#
# GOWORK is pinned to this directory because a bare `go work init` searches
# upward and refuses with "go.work already exists" if the checkout happens to
# sit inside another workspace -- which a git worktree under the main clone
# does. Pinning it keeps the hook working wherever the tree is checked out.
- sh -c 'rm -f go.work go.work.sum && GOWORK="$PWD/go.work" go work init . ./cmd/forge ./extensions/database'
- go mod tidy
- go mod verify
- sh -c "cd cmd/forge && go mod tidy"
Expand Down Expand Up @@ -294,6 +317,21 @@ docker_manifests:
git:
tag_sort: -version:refname

# This repository tags far more than the CLI: every extension gets its own
# `extensions/<name>/vX.Y.Z`, and the editor plugin gets `vscode-forge/vX.Y.Z`.
# Without this, GoReleaser takes the newest tag in the whole repo as "the
# release", picks up whichever extension was tagged last, and refuses with
#
# git tag extensions/ai/v1.9.3 was not made against commit <sha>
#
# because that tag belongs to a different commit than the one being released.
# Snapshot builds hide it -- tag validation is disabled there -- so it only
# ever surfaces during a real release. Restricting the search to the CLI's own
# `vX.Y.Z` tags is what makes a snapshot and a release agree.
ignore_tags:
- 'extensions/*'
- 'vscode-forge/*'

# Metadata
metadata:
mod_timestamp: '{{ .CommitTimestamp }}'
Loading