Skip to content

Commit 97dafef

Browse files
committed
feat: add cross-platform installers with shell integration
Add `wt init` command for automatic shell configuration: - Auto-detects shell (bash, zsh, PowerShell) - Idempotent: uses markers to update existing config - Supports --dry-run, --uninstall, --no-prompt flags Add GoReleaser configuration for unified release process: - Builds for Linux, macOS, Windows (amd64, arm64) - Creates .deb and .rpm packages via nfpm - Generates Arch Linux packages - Updates Homebrew tap automatically - Configures Scoop bucket for Windows Add installer scripts: - postinstall.sh: Configures shell integration on install - preremove.sh: Removes shell integration on uninstall Add e2e tests for init command: - Tests dry-run, config creation, idempotency, uninstall - Tests preservation of existing shell config
1 parent 0459d50 commit 97dafef

File tree

6 files changed

+566
-241
lines changed

6 files changed

+566
-241
lines changed

.github/workflows/release.yml

Lines changed: 14 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -9,166 +9,8 @@ permissions:
99
contents: write
1010

1111
jobs:
12-
build:
13-
name: Build Binaries
14-
runs-on: ubuntu-latest
15-
strategy:
16-
matrix:
17-
include:
18-
- goos: linux
19-
goarch: amd64
20-
output: wt-linux-amd64
21-
bottle: x86_64_linux
22-
- goos: linux
23-
goarch: arm64
24-
output: wt-linux-arm64
25-
bottle: aarch64_linux
26-
- goos: darwin
27-
goarch: amd64
28-
output: wt-darwin-amd64
29-
bottle: ventura
30-
- goos: darwin
31-
goarch: arm64
32-
output: wt-darwin-arm64
33-
bottle: arm64_sonoma
34-
- goos: windows
35-
goarch: amd64
36-
output: wt-windows-amd64.exe
37-
bottle: null
38-
39-
steps:
40-
- name: Generate GitHub App token
41-
id: generate-token
42-
continue-on-error: true
43-
uses: actions/create-github-app-token@v1
44-
with:
45-
app-id: ${{ secrets.BOT_APP_ID }}
46-
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
47-
48-
- name: Checkout code
49-
uses: actions/checkout@v4
50-
with:
51-
token: ${{ steps.generate-token.outputs.token || github.token }}
52-
53-
- name: Set up Go
54-
uses: actions/setup-go@v5
55-
with:
56-
go-version: '1.25'
57-
cache: true
58-
59-
- name: Extract version from tag
60-
id: version
61-
run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
62-
63-
- name: Build binary
64-
env:
65-
GOOS: ${{ matrix.goos }}
66-
GOARCH: ${{ matrix.goarch }}
67-
run: |
68-
mkdir -p dist
69-
go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" -o dist/wt .
70-
71-
- name: Create Homebrew bottle
72-
if: matrix.bottle != 'null'
73-
run: |
74-
# Create bottle directory structure: wt/VERSION/bin/wt
75-
mkdir -p wt/${{ steps.version.outputs.VERSION }}/bin
76-
cp dist/wt wt/${{ steps.version.outputs.VERSION }}/bin/
77-
78-
# Create tarball with proper naming: wt-VERSION.PLATFORM.bottle.tar.gz
79-
tar czf wt-${{ steps.version.outputs.VERSION }}.${{ matrix.bottle }}.bottle.tar.gz wt
80-
81-
# Also keep the raw binary for non-Homebrew users
82-
mv dist/wt dist/${{ matrix.output }}
83-
84-
- name: Skip bottle creation for Windows
85-
if: matrix.bottle == 'null'
86-
run: |
87-
# Just rename the binary for Windows (no bottle needed)
88-
mv dist/wt dist/${{ matrix.output }}
89-
90-
- name: Upload bottle artifact
91-
if: matrix.bottle != 'null'
92-
uses: actions/upload-artifact@v4
93-
with:
94-
name: bottle-${{ matrix.bottle }}
95-
path: wt-${{ steps.version.outputs.VERSION }}.${{ matrix.bottle }}.bottle.tar.gz
96-
if-no-files-found: error
97-
98-
- name: Upload binary artifact
99-
uses: actions/upload-artifact@v4
100-
with:
101-
name: binary-${{ matrix.output }}
102-
path: dist/${{ matrix.output }}
103-
if-no-files-found: error
104-
105-
release:
106-
name: Create Release
107-
needs: build
108-
runs-on: ubuntu-latest
109-
110-
steps:
111-
- name: Generate GitHub App token
112-
id: generate-token
113-
continue-on-error: true
114-
uses: actions/create-github-app-token@v1
115-
with:
116-
app-id: ${{ secrets.BOT_APP_ID }}
117-
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
118-
119-
- name: Checkout code
120-
uses: actions/checkout@v4
121-
with:
122-
token: ${{ steps.generate-token.outputs.token || github.token }}
123-
124-
- name: Set up Go
125-
uses: actions/setup-go@v5
126-
with:
127-
go-version: '1.25'
128-
cache: true
129-
130-
- name: Download all artifacts
131-
uses: actions/download-artifact@v4
132-
with:
133-
path: artifacts/
134-
135-
- name: Organize release files
136-
run: |
137-
mkdir -p release
138-
139-
# Move bottles to release directory
140-
find artifacts/bottle-* -name "*.bottle.tar.gz" -exec mv {} release/ \;
141-
142-
# Move binaries to release directory
143-
find artifacts/binary-* -type f -exec mv {} release/ \;
144-
145-
ls -la release/
146-
147-
- name: Generate checksums
148-
run: |
149-
cd release
150-
shasum -a 256 * > checksums.txt
151-
cat checksums.txt
152-
153-
- name: Upload checksums artifact
154-
uses: actions/upload-artifact@v4
155-
with:
156-
name: checksums
157-
path: release/checksums.txt
158-
if-no-files-found: error
159-
160-
- name: Create GitHub Release
161-
env:
162-
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
163-
run: |
164-
gh release create ${{ github.ref_name }} \
165-
--title "Release ${{ github.ref_name }}" \
166-
--generate-notes \
167-
release/*
168-
169-
update-formula:
170-
name: Update Homebrew Formula
171-
needs: release
12+
goreleaser:
13+
name: Release with GoReleaser
17214
runs-on: ubuntu-latest
17315

17416
steps:
@@ -182,10 +24,12 @@ jobs:
18224
repositories: |
18325
wt
18426
homebrew-tap
27+
scoop-bucket
18528
18629
- name: Checkout code
18730
uses: actions/checkout@v4
18831
with:
32+
fetch-depth: 0
18933
token: ${{ steps.generate-token.outputs.token || github.token }}
19034

19135
- name: Set up Go
@@ -194,85 +38,14 @@ jobs:
19438
go-version: '1.25'
19539
cache: true
19640

197-
- name: Download checksums artifact
198-
uses: actions/download-artifact@v4
41+
- name: Run GoReleaser
42+
uses: goreleaser/goreleaser-action@v6
19943
with:
200-
path: artifacts/
201-
202-
- name: Extract version and checksums
203-
id: version
204-
run: |
205-
VERSION=${GITHUB_REF_NAME#v}
206-
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
207-
208-
# Find checksums.txt in artifacts
209-
CHECKSUMS_FILE=$(find artifacts -name "checksums.txt" -type f | head -1)
210-
211-
# Extract bottle SHA256s from checksums
212-
AARCH64_LINUX=$(grep "wt-${VERSION}.aarch64_linux.bottle.tar.gz" "$CHECKSUMS_FILE" | awk '{print $1}')
213-
ARM64_SONOMA=$(grep "wt-${VERSION}.arm64_sonoma.bottle.tar.gz" "$CHECKSUMS_FILE" | awk '{print $1}')
214-
VENTURA=$(grep "wt-${VERSION}.ventura.bottle.tar.gz" "$CHECKSUMS_FILE" | awk '{print $1}')
215-
X86_64_LINUX=$(grep "wt-${VERSION}.x86_64_linux.bottle.tar.gz" "$CHECKSUMS_FILE" | awk '{print $1}')
216-
217-
echo "AARCH64_LINUX=$AARCH64_LINUX" >> $GITHUB_OUTPUT
218-
echo "ARM64_SONOMA=$ARM64_SONOMA" >> $GITHUB_OUTPUT
219-
echo "VENTURA=$VENTURA" >> $GITHUB_OUTPUT
220-
echo "X86_64_LINUX=$X86_64_LINUX" >> $GITHUB_OUTPUT
221-
222-
- name: Download source tarball and calculate SHA256
223-
id: source
224-
run: |
225-
VERSION=${{ steps.version.outputs.VERSION }}
226-
wget "https://github.com/timvw/wt/archive/refs/tags/v${VERSION}.tar.gz" -O source.tar.gz
227-
SOURCE_SHA256=$(shasum -a 256 source.tar.gz | awk '{print $1}')
228-
echo "SHA256=$SOURCE_SHA256" >> $GITHUB_OUTPUT
229-
230-
- name: Clone homebrew-tap repository
231-
run: |
232-
git clone https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com/timvw/homebrew-tap.git
233-
234-
- name: Update formula
235-
run: |
236-
cd homebrew-tap
237-
VERSION=${{ steps.version.outputs.VERSION }}
238-
239-
# Update the formula file
240-
cat > Formula/wt.rb << 'EOF'
241-
class Wt < Formula
242-
desc "Git worktree helper"
243-
homepage "https://github.com/timvw/wt"
244-
url "https://github.com/timvw/wt/archive/refs/tags/v${{ steps.version.outputs.VERSION }}.tar.gz"
245-
sha256 "${{ steps.source.outputs.SHA256 }}"
246-
license "MIT"
247-
head "https://github.com/timvw/wt.git", branch: "main"
248-
249-
bottle do
250-
root_url "https://github.com/timvw/wt/releases/download/v${{ steps.version.outputs.VERSION }}"
251-
sha256 cellar: :any_skip_relocation, arm64_sonoma: "${{ steps.version.outputs.ARM64_SONOMA }}"
252-
sha256 cellar: :any_skip_relocation, ventura: "${{ steps.version.outputs.VENTURA }}"
253-
sha256 cellar: :any_skip_relocation, x86_64_linux: "${{ steps.version.outputs.X86_64_LINUX }}"
254-
sha256 cellar: :any_skip_relocation, aarch64_linux: "${{ steps.version.outputs.AARCH64_LINUX }}"
255-
end
256-
257-
def install
258-
bin.install "wt"
259-
end
260-
261-
test do
262-
assert_match "wt version", shell_output("#{bin}/wt version")
263-
end
264-
end
265-
EOF
266-
267-
- name: Commit and push changes
268-
run: |
269-
cd homebrew-tap
270-
git config user.name "timvw-ci-bot[bot]"
271-
git config user.email "timvw-ci-bot[bot]@users.noreply.github.com"
272-
git add Formula/wt.rb
273-
git commit -m "chore: update wt formula to v${{ steps.version.outputs.VERSION }}
274-
275-
🤖 Generated with [Claude Code](https://claude.com/claude-code)
276-
277-
Co-Authored-By: Claude <noreply@anthropic.com>"
278-
git push
44+
distribution: goreleaser
45+
version: latest
46+
args: release --clean
47+
env:
48+
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token || github.token }}
49+
HOMEBREW_TAP_TOKEN: ${{ steps.generate-token.outputs.token || github.token }}
50+
SCOOP_BUCKET_TOKEN: ${{ steps.generate-token.outputs.token || github.token }}
51+
AUR_KEY: ${{ secrets.AUR_KEY }}

0 commit comments

Comments
 (0)