feat(infra): implement tag-based release pipeline#7
Conversation
- Add unified release script (script/release.ts) - Add weekly changeset version workflow - Add tag-triggered release workflows for core and app - Add curl installer with checksum verification - Remove auto-publish on push behavior
🚀 Preview DeploymentYour changes have been deployed to: 📖 Docs: https://docs-pr-7.t-req.io This preview will be automatically removed when the PR is closed. |
Greptile SummaryImplements a tag-based release pipeline that separates version management from publishing, replacing the previous auto-publish-on-push behavior. The new workflow uses changesets for weekly version PRs, then manual tag creation triggers GitHub Actions to build, test, and publish both core and app packages. Key Changes:
Issues Found:
The architecture is solid with good separation of concerns (version management → tagging → publishing), proper version verification, and dry-run support throughout. Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant Local as Local Git
participant Script as release.ts
participant Remote as GitHub Remote
participant GHA as GitHub Actions
participant NPM as NPM Registry
participant User as End User
Note over Dev,GHA: Weekly Version Preparation
Dev->>Remote: Merge changesets to main
GHA->>GHA: changeset-version.yml (weekly/manual)
GHA->>Remote: Create "Version Packages" PR
Dev->>Remote: Review and merge version PR
Note over Dev,NPM: Tag-Based Release Flow
Dev->>Script: bun run release:core/app
Script->>Local: Validate clean working dir
Script->>Local: Verify on main branch
Script->>Local: Read version from package.json
Script->>Local: Check tag doesn't exist
Script->>Remote: Push tag (core-v* or app-v*)
Note over GHA,NPM: Core Package Release
Remote->>GHA: Trigger release-core.yml
GHA->>GHA: Extract version from tag
GHA->>GHA: Verify version matches package.json
GHA->>GHA: Build and test
GHA->>NPM: Publish @t-req/core
Note over GHA,User: App Package Release
Remote->>GHA: Trigger release-app.yml
GHA->>GHA: Extract version from tag
GHA->>GHA: Verify version matches package.json
GHA->>GHA: Build all platform binaries
GHA->>GHA: Create archives with checksums
GHA->>Remote: Create draft GitHub release
GHA->>Remote: Upload binary archives
GHA->>NPM: Publish platform packages
GHA->>NPM: Publish wrapper package
GHA->>Remote: Finalize GitHub release
Note over User: Installation
User->>Remote: curl install script
User->>Remote: Download binary + checksums
User->>User: Verify checksum
User->>User: Install to ~/.treq/bin
|
.github/workflows/release-app.yml
Outdated
|
|
||
| - name: Publish to npm | ||
| if: ${{ github.event_name == 'push' || !inputs.dry-run }} | ||
| run: bun run script/publish.ts |
There was a problem hiding this comment.
style: Publishing script is called but may already build binaries again. The packages/app/script/publish.ts runs bun run build:all on line 32, which duplicates the build from line 69-70. This wastes CI time and resources.
| run: bun run script/publish.ts | |
| run: bun run script/publish.ts --skip-build |
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release-app.yml
Line: 181:181
Comment:
**style:** Publishing script is called but may already build binaries again. The `packages/app/script/publish.ts` runs `bun run build:all` on line 32, which duplicates the build from line 69-70. This wastes CI time and resources.
```suggestion
run: bun run script/publish.ts --skip-build
```
How can I resolve this? If you propose a fix, please make it concise.| local response | ||
|
|
||
| # Find latest app release (tag starting with app-v) | ||
| response=$(curl -fsSL "$api_url" 2>/dev/null) || die "Failed to fetch releases from GitHub" |
There was a problem hiding this comment.
logic: Response is not sanitized before using grep and sed. If GitHub API returns unexpected data with malicious content, the shell command injection could occur through crafted tag names in the response.
Consider using jq for safe JSON parsing:
| response=$(curl -fsSL "$api_url" 2>/dev/null) || die "Failed to fetch releases from GitHub" | |
| response=$(curl -fsSL "$api_url" 2>/dev/null) || die "Failed to fetch releases from GitHub" | |
| version=$(echo "$response" | jq -r '[.[] | select(.tag_name | startswith("app-v")) | .tag_name] | first | sub("^app-v"; "")') |
Prompt To Fix With AI
This is a comment left during a code review.
Path: install
Line: 128:128
Comment:
**logic:** Response is not sanitized before using `grep` and `sed`. If GitHub API returns unexpected data with malicious content, the shell command injection could occur through crafted tag names in the response.
Consider using `jq` for safe JSON parsing:
```suggestion
response=$(curl -fsSL "$api_url" 2>/dev/null) || die "Failed to fetch releases from GitHub"
version=$(echo "$response" | jq -r '[.[] | select(.tag_name | startswith("app-v")) | .tag_name] | first | sub("^app-v"; "")')
```
How can I resolve this? If you propose a fix, please make it concise.| if [[ "$expected" != "$actual" ]]; then | ||
| die "Checksum verification failed!\nExpected: $expected\nActual: $actual" | ||
| fi |
There was a problem hiding this comment.
style: Error message uses \n which may not render as newlines in all shells. The die function uses echo -e which should handle it, but some shells might not expand the escape sequence correctly. Have you tested this on different shells (bash, zsh, dash) to ensure the newline renders correctly?
Prompt To Fix With AI
This is a comment left during a code review.
Path: install
Line: 167:169
Comment:
**style:** Error message uses `\n` which may not render as newlines in all shells. The `die` function uses `echo -e` which should handle it, but some shells might not expand the escape sequence correctly. Have you tested this on different shells (bash, zsh, dash) to ensure the newline renders correctly?
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| // Ensure we have the latest | ||
| console.log('\nFetching latest from origin...'); | ||
| await $`git fetch origin --tags`.quiet(); |
There was a problem hiding this comment.
logic: Fetching tags but not checking if local branch is behind remote. If someone runs this with an outdated local main, they'll create a tag from old code.
Add after this line:
const behindResult = await $`git rev-list --count HEAD..origin/main`.quiet();
const behindCount = parseInt(behindResult.text().trim());
if (behindCount > 0) {
console.error('Error: Local main branch is behind origin/main');
console.error(`Please pull the latest changes first (${behindCount} commits behind).`);
process.exit(1);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: script/release.ts
Line: 192:192
Comment:
**logic:** Fetching tags but not checking if local branch is behind remote. If someone runs this with an outdated local `main`, they'll create a tag from old code.
Add after this line:
```
const behindResult = await $`git rev-list --count HEAD..origin/main`.quiet();
const behindCount = parseInt(behindResult.text().trim());
if (behindCount > 0) {
console.error('Error: Local main branch is behind origin/main');
console.error(`Please pull the latest changes first (${behindCount} commits behind).`);
process.exit(1);
}
```
How can I resolve this? If you propose a fix, please make it concise.
Summary
Type of Change
How Has This Been Tested?
Checklist