From b983e601e8760772767f2065c54d5709f6085b03 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Tue, 26 May 2026 14:27:40 -0500 Subject: [PATCH 1/2] updated docs and the release workflow --- .github/workflows/release.yml | 77 ++++++++++++++++------------------- README.md | 12 ++++-- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad48b8c..bdffe61 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,62 +19,49 @@ env: RELEASE_TAG: ${{ github.event.inputs.tag_name || github.ref_name }} jobs: - build-debian: - name: Build Debian 13 + build-linux-amd64: + name: Build Linux amd64 runs-on: ubuntu-latest - container: - image: debian:13-slim steps: - - name: Install dependencies - run: | - apt-get update && apt-get install -y git golang-go ca-certificates - name: Checkout Code uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.26.3' - name: Build - run: go build -v -o gh-repo-bootstrap-linux-debian13-amd64 main.go + env: + CGO_ENABLED: '0' + GOOS: linux + GOARCH: amd64 + run: go build -v -o gh-repo-bootstrap-linux-amd64 main.go - name: Upload Artifact uses: actions/upload-artifact@v4 with: - name: gh-repo-bootstrap-linux-debian13-amd64 - path: gh-repo-bootstrap-linux-debian13-amd64 + name: gh-repo-bootstrap-linux-amd64 + path: gh-repo-bootstrap-linux-amd64 - build-arch: - name: Build Arch Linux - runs-on: ubuntu-latest - container: - image: archlinux:latest + build-linux-arm64: + name: Build Linux arm64 + runs-on: ubuntu-24.04-arm steps: - - name: Install dependencies - run: | - pacman -Syu --noconfirm git go ca-certificates - name: Checkout Code uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.26.3' - name: Build - run: go build -v -o gh-repo-bootstrap-linux-arch-amd64 main.go + env: + CGO_ENABLED: '0' + GOOS: linux + GOARCH: arm64 + run: go build -v -o gh-repo-bootstrap-linux-arm64 main.go - name: Upload Artifact uses: actions/upload-artifact@v4 with: - name: gh-repo-bootstrap-linux-arch-amd64 - path: gh-repo-bootstrap-linux-arch-amd64 - - build-fedora: - name: Build Fedora 44 - runs-on: ubuntu-latest - container: - image: fedora:44 - steps: - - name: Install dependencies - run: | - dnf install -y git golang ca-certificates - - name: Checkout Code - uses: actions/checkout@v4 - - name: Build - run: go build -v -o gh-repo-bootstrap-linux-fedora44-amd64 main.go - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: gh-repo-bootstrap-linux-fedora44-amd64 - path: gh-repo-bootstrap-linux-fedora44-amd64 + name: gh-repo-bootstrap-linux-arm64 + path: gh-repo-bootstrap-linux-arm64 build-windows: name: Build Windows @@ -114,7 +101,11 @@ jobs: release: name: Create Release - needs: [build-debian, build-arch, build-fedora, build-windows, build-macos] + needs: + - build-linux-amd64 + - build-linux-arm64 + - build-windows + - build-macos runs-on: ubuntu-latest permissions: contents: write @@ -131,7 +122,7 @@ jobs: run: | mkdir release-assets find bin-artifacts -type f -exec cp {} release-assets/ \; - + cd release-assets echo "## SHA256 Checksums" > ../release_notes.txt echo "" >> ../release_notes.txt @@ -141,7 +132,7 @@ jobs: sha=$(sha256sum "$file" | cut -d' ' -f1) echo "| \`$file\` | \`$sha\` |" >> ../release_notes.txt done - + cat ../release_notes.txt - name: Create GitHub Release diff --git a/README.md b/README.md index 94765ed..f4c3f56 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ gh extension install JMR-dev/gh-repo-bootstrap release. You also need: - [`pulumi`](https://www.pulumi.com/docs/iac/download-install/) on `PATH` -- `gh` already authenticated (`gh auth login`) +- `gh` already authenticated (`gh auth login`), or a `GITHUB_TOKEN` + exported in the environment — the extension uses `GITHUB_TOKEN` + when it is set and otherwise falls back to `gh auth token` ## Use @@ -112,9 +114,11 @@ A single `--config FILE` can describe everything. When `--config` is used, **no other flags are allowed**: ```toml -owner = "JMR-dev" -name = "my-new-app" -mode = "create" # or "manage", or "data" (default) +owner = "JMR-dev" +name = "my-new-app" +mode = "create" # or "manage", or "data" (default) +action = "apply" # or "plan", or "destroy" (default: apply) +state_dir = "./state" # optional; overrides the default per-repo state dir [repo] visibility = "private" -- 2.47.3 From 47f0290652de02d2bcb8bd565c717ef276167a7c Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Tue, 26 May 2026 17:02:47 -0500 Subject: [PATCH 2/2] fix state path bug --- internal/runner/runner.go | 5 +++ internal/runner/runner_test.go | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 74682c8..94a3935 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -82,6 +82,11 @@ func Run(ctx context.Context, opts *cli.Options) error { if err := os.MkdirAll(stateDir, 0o700); err != nil { return fmt.Errorf("creating state dir: %w", err) } + absStateDir, err := filepath.Abs(stateDir) + if err != nil { + return fmt.Errorf("resolving state dir: %w", err) + } + stateDir = absStateDir // --- Auth: prefer caller-supplied GITHUB_TOKEN, else borrow from gh --- if os.Getenv("GITHUB_TOKEN") == "" { diff --git a/internal/runner/runner_test.go b/internal/runner/runner_test.go index cabbe51..c78f9d7 100644 --- a/internal/runner/runner_test.go +++ b/internal/runner/runner_test.go @@ -117,6 +117,63 @@ func (m *mockStack) Destroy(ctx context.Context, opts ...optdestroy.Option) (aut return auto.DestroyResult{}, nil } +// TestRun_RelativeStateDir verifies that a relative state_dir (e.g. "./state" +// from a TOML config) does not cause a "state/state" double-path in the +// file:// backend URL. Before the fix, upsertStack was called with a relative +// file:// URL that Pulumi resolved against its WorkDir, producing the wrong path. +func TestRun_RelativeStateDir(t *testing.T) { + oldExec := execCommand + oldGithubExec := githubapi.ExecCommand + oldUpsert := upsertStack + execCommand = mockExec + githubapi.ExecCommand = mockExec + defer func() { + execCommand = oldExec + githubapi.ExecCommand = oldGithubExec + upsertStack = oldUpsert + }() + + // Capture the PULUMI_BACKEND_URL env var passed to upsertStack. + var capturedBackendURL string + mStack := &mockStack{setConfigCalls: make(map[string]string)} + upsertStack = func(ctx context.Context, stackName, projectName string, program pulumi.RunFunc, opts ...auto.LocalWorkspaceOption) (stackInterface, error) { + // Apply options to a scratch workspace to extract env vars. + ws, err := auto.NewLocalWorkspace(ctx, opts...) + if err == nil { + env := ws.GetEnvVars() + capturedBackendURL = env["PULUMI_BACKEND_URL"] + } + return mStack, nil + } + + parent := t.TempDir() + oldWd, _ := os.Getwd() + _ = os.Chdir(parent) + defer os.Chdir(oldWd) + + opts := &cli.Options{ + Owner: "JMR-dev", + Repo: "test-repo", + Branch: "main", + Action: cli.ActionApply, + StateDir: "./state", + Environments: []*cli.EnvSpec{{Name: "production"}}, + } + + oldToken := os.Getenv("GITHUB_TOKEN") + os.Setenv("GITHUB_TOKEN", "test-token") + defer os.Setenv("GITHUB_TOKEN", oldToken) + + if err := Run(context.Background(), opts); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + want := "file://" + filepath.Join(parent, "state") + if capturedBackendURL != want { + t.Errorf("PULUMI_BACKEND_URL = %q, want %q", capturedBackendURL, want) + } +} + func TestRun_Apply(t *testing.T) { oldExec := execCommand oldGithubExec := githubapi.ExecCommand -- 2.47.3