Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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
131 changes: 131 additions & 0 deletions .github/workflows/pr-preview-push.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: PR Preview (Push)

on:
push:
branches:
- "**"
paths:
- "apps/cli/**"
- "packages/types/**"
- ".github/workflows/pr-preview-push.yaml"
Comment on lines +3 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Add fork protection to prevent secret exposure.

This workflow triggers on pushes from any branch, including forks. Fork contributors would gain access to NPM_TOKEN, creating a severe security risk. Add a condition to prevent execution on forks.

🔎 Proposed fix
 on:
   push:
     branches:
       - "**"
     paths:
       - "apps/cli/**"
       - "packages/types/**"
       - ".github/workflows/pr-preview-push.yaml"

Then add a fork check to the job condition:

   publish-preview:
     name: Publish Preview
     runs-on: ubuntu-latest
-    if: github.ref != 'refs/heads/main'
+    if: github.ref != 'refs/heads/main' && github.event.repository.fork == false
     timeout-minutes: 30

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
.github/workflows/pr-preview-push.yaml around lines 3 to 10: the workflow
currently triggers on pushes from any branch/paths and can run for events
originating from forked repos, risking exposure of secrets like NPM_TOKEN; add a
job-level condition that prevents execution for events originating from forks
(e.g., only run when the event repository matches the base repository or when
the pull_request head repo equals the base repo), by adding an if check to the
workflow jobs so the pipeline only runs for non-forked events.


permissions:
contents: read
pull-requests: write
id-token: write
Comment on lines +12 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused permissions following least-privilege principle.

The id-token: write and pull-requests: write permissions are not used in this workflow. The workflow writes to GITHUB_STEP_SUMMARY (a workflow-level summary), not PR comments, and doesn't use OIDC authentication.

🔎 Proposed fix
 permissions:
   contents: read
-  pull-requests: write
-  id-token: write
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
contents: read
pull-requests: write
id-token: write
permissions:
contents: read
🤖 Prompt for AI Agents
.github/workflows/pr-preview-push.yaml around lines 12 to 15: the workflow
currently grants unnecessary permissions; remove the unused id-token: write and
pull-requests: write entries and keep only the minimal permissions required
(e.g., contents: read) so the workflow follows the least-privilege principle.


concurrency:
group: pr-preview-push-${{ github.ref }}
cancel-in-progress: true

jobs:
publish-preview:
name: Publish Preview
runs-on: ubuntu-latest
if: github.ref != 'refs/heads/main'
timeout-minutes: 30
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install Dependencies
run: bun install --frozen-lockfile
env:
BTS_TELEMETRY: 0

- name: Generate Preview Version
id: version
run: |
BRANCH_NAME="${GITHUB_REF#refs/heads/}"
SAFE_BRANCH=$(echo "$BRANCH_NAME" | tr '/' '-' | tr '_' '-' | cut -c1-20)
COMMIT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7)
BASE_VERSION=$(jq -r '.version' apps/cli/package.json | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
PREVIEW_VERSION="${BASE_VERSION}-${SAFE_BRANCH}.${COMMIT_SHA}"
NPM_TAG="dev"
echo "version=$PREVIEW_VERSION" >> $GITHUB_OUTPUT
echo "tag=$NPM_TAG" >> $GITHUB_OUTPUT
echo "commit=$COMMIT_SHA" >> $GITHUB_OUTPUT
echo "Preview version: $PREVIEW_VERSION"
echo "NPM tag: $NPM_TAG"
- name: Update types package version
run: |
cd packages/types
jq --arg v "${{ steps.version.outputs.version }}" '.version = $v' package.json > tmp.json && mv tmp.json package.json
- name: Build types package
run: cd packages/types && bun run build

- name: Publish types to NPM
run: cd packages/types && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Update CLI package version and dependencies
run: |
cd apps/cli
VERSION="${{ steps.version.outputs.version }}"
jq --arg v "$VERSION" '
.version = $v |
.dependencies["@better-t-stack/types"] = $v |
.optionalDependencies["@better-t-stack/cli-darwin-arm64"] = $v |
.optionalDependencies["@better-t-stack/cli-darwin-x64"] = $v |
.optionalDependencies["@better-t-stack/cli-linux-arm64"] = $v |
.optionalDependencies["@better-t-stack/cli-linux-x64"] = $v |
.optionalDependencies["@better-t-stack/cli-windows-x64"] = $v
' package.json > tmp.json && mv tmp.json package.json
- name: Update create-bts alias package version
run: |
cd packages/create-bts
jq --arg v "${{ steps.version.outputs.version }}" '.version = $v | .dependencies["create-better-t-stack"] = $v' package.json > tmp.json && mv tmp.json package.json
- name: Build CLI binaries
run: cd apps/cli && bun run build
env:
BTS_TELEMETRY: 0

- name: Publish CLI platform packages to NPM
run: |
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir"
bun publish --access public --tag ${{ steps.version.outputs.tag }}
cd ..
fi
done
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

Comment on lines +97 to +111
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add error handling in the platform package publishing loop.

The loop publishes each platform package but doesn't handle failures. If one package fails to publish, the workflow continues, resulting in an incomplete preview release.

🔎 Proposed fix
       - name: Publish CLI platform packages to NPM
         run: |
+          set -e
           cd apps/cli/dist
           ls -la
           for dir in */; do
             if [ -f "$dir/package.json" ]; then
               echo "Publishing $dir..."
-              cd "$dir"
+              cd "$dir" || exit 1
               bun publish --access public --tag ${{ steps.version.outputs.tag }}
-              cd ..
+              PUBLISH_EXIT=$?
+              cd .. || exit 1
+              if [ $PUBLISH_EXIT -ne 0 ]; then
+                echo "Failed to publish $dir"
+                exit 1
+              fi
+              echo "Successfully published $dir"
             fi
           done
         env:
           NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Publish CLI platform packages to NPM
run: |
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir"
bun publish --access public --tag ${{ steps.version.outputs.tag }}
cd ..
fi
done
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish CLI platform packages to NPM
run: |
set -e
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir" || exit 1
bun publish --access public --tag ${{ steps.version.outputs.tag }}
PUBLISH_EXIT=$?
cd .. || exit 1
if [ $PUBLISH_EXIT -ne 0 ]; then
echo "Failed to publish $dir"
exit 1
fi
echo "Successfully published $dir"
fi
done
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
🤖 Prompt for AI Agents
In .github/workflows/pr-preview-push.yaml around lines 97 to 111, the publish
loop runs bun publish for each platform package but does not handle failures, so
a single failing publish can be silently ignored and produce an incomplete
preview release; update the script to detect publish failures and fail the job
(or collect and report failures) by checking bun publish's exit code after each
publish, echoing a clear error with package name and exit status, and exiting
with a non-zero status if any publish fails (alternatively accumulate failed
package names and exit non-zero after the loop with a summary).

- name: Publish CLI to NPM
run: cd apps/cli && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Publish create-bts to NPM
run: cd packages/create-bts && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Summary
run: |
echo "## Preview Release Published!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** \`${{ steps.version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Install" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "npx create-better-t-stack@${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
67 changes: 51 additions & 16 deletions .github/workflows/pr-preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,37 @@ name: PR Preview
on:
pull_request_target:
types: [labeled]
workflow_dispatch:
inputs:
pr_number:
description: "PR number to build preview for"
required: true
type: string
ref:
description: "Git ref to checkout (commit SHA or branch)"
required: true
type: string

permissions:
contents: read
pull-requests: write
id-token: write

concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
group: pr-preview-${{ github.event.pull_request.number || inputs.pr_number }}
cancel-in-progress: true

jobs:
publish-preview:
name: Publish Preview
runs-on: ubuntu-latest
if: github.event.label.name == 'preview'
if: github.event.label.name == 'preview' || github.event_name == 'workflow_dispatch'
timeout-minutes: 30
steps:
- name: Checkout PR Code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ github.event.pull_request.head.sha || inputs.ref }}
fetch-depth: 0

- name: Setup Bun
Expand All @@ -38,8 +49,9 @@ jobs:
- name: Generate Preview Version
id: version
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
COMMIT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7)
PR_NUMBER=${{ github.event.pull_request.number || inputs.pr_number }}
REF="${{ github.event.pull_request.head.sha || inputs.ref }}"
COMMIT_SHA=$(echo "$REF" | cut -c1-7)
BASE_VERSION=$(jq -r '.version' apps/cli/package.json | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
PREVIEW_VERSION="${BASE_VERSION}-pr${PR_NUMBER}.${COMMIT_SHA}"
NPM_TAG="pr${PR_NUMBER}"
Expand All @@ -64,48 +76,69 @@ jobs:
run: cd packages/types && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
BTS_TELEMETRY: 0

- name: Update CLI package version and types dependency
- name: Update CLI package version and dependencies
run: |
cd apps/cli
jq --arg v "${{ steps.version.outputs.version }}" '.version = $v | .dependencies["@better-t-stack/types"] = $v' package.json > tmp.json && mv tmp.json package.json
VERSION="${{ steps.version.outputs.version }}"
jq --arg v "$VERSION" '
.version = $v |
.dependencies["@better-t-stack/types"] = $v |
.optionalDependencies["@better-t-stack/cli-darwin-arm64"] = $v |
.optionalDependencies["@better-t-stack/cli-darwin-x64"] = $v |
.optionalDependencies["@better-t-stack/cli-linux-arm64"] = $v |
.optionalDependencies["@better-t-stack/cli-linux-x64"] = $v |
.optionalDependencies["@better-t-stack/cli-windows-x64"] = $v
' package.json > tmp.json && mv tmp.json package.json
- name: Update create-bts alias package version
run: |
cd packages/create-bts
jq --arg v "${{ steps.version.outputs.version }}" '.version = $v | .dependencies["create-better-t-stack"] = $v' package.json > tmp.json && mv tmp.json package.json
- name: Build CLI
- name: Build CLI binaries
run: cd apps/cli && bun run build
env:
BTS_TELEMETRY: 0

- name: Publish CLI platform packages to NPM
run: |
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir"
bun publish --access public --tag ${{ steps.version.outputs.tag }}
cd ..
fi
done
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
Comment on lines +104 to +117
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Working directory not restored, breaking subsequent steps.

After this step completes, the working directory remains apps/cli/dist instead of the repository root. This will cause the next two publish steps (lines 120 and 125) to fail because they use relative paths (cd apps/cli and cd packages/create-bts) that expect to be run from the root directory.

🔎 Proposed fix
      - name: Publish CLI platform packages to NPM
        run: |
          cd apps/cli/dist
          ls -la
          for dir in */; do
            if [ -f "$dir/package.json" ]; then
              echo "Publishing $dir..."
              cd "$dir"
              bun publish --access public --tag ${{ steps.version.outputs.tag }}
              cd ..
            fi
          done
+         cd ../../..
        env:
          NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}

Alternatively, use a subshell to avoid changing the working directory of the step:

      - name: Publish CLI platform packages to NPM
        run: |
-         cd apps/cli/dist
-         ls -la
-         for dir in */; do
-           if [ -f "$dir/package.json" ]; then
-             echo "Publishing $dir..."
-             cd "$dir"
-             bun publish --access public --tag ${{ steps.version.outputs.tag }}
-             cd ..
-           fi
-         done
+         (
+           cd apps/cli/dist
+           ls -la
+           for dir in */; do
+             if [ -f "$dir/package.json" ]; then
+               echo "Publishing $dir..."
+               cd "$dir"
+               bun publish --access public --tag ${{ steps.version.outputs.tag }}
+               cd ..
+             fi
+           done
+         )
        env:
          NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Publish CLI platform packages to NPM
run: |
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir"
bun publish --access public --tag ${{ steps.version.outputs.tag }}
cd ..
fi
done
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish CLI platform packages to NPM
run: |
cd apps/cli/dist
ls -la
for dir in */; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir..."
cd "$dir"
bun publish --access public --tag ${{ steps.version.outputs.tag }}
cd ..
fi
done
cd ../../..
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
🤖 Prompt for AI Agents
.github/workflows/pr-preview.yaml around lines 104 to 117: the step changes the
working directory to apps/cli/dist and does not restore it, so subsequent steps
using relative paths fail; to fix, run the publish loop in a subshell or
explicitly restore the original directory (e.g., wrap the cd and loop in
parentheses or use pushd/popd and popd at the end) so the workflow's working
directory remains the repository root before the next steps run.

⚠️ Potential issue | 🟠 Major

Add error handling to fail on first publish error.

The loop continues even if a platform package fails to publish. Without explicit error handling, the step might succeed despite some platforms failing to publish, leading to incomplete preview releases.

🔎 Proposed fix

Add set -e at the beginning of the script to fail immediately on any error:

      - name: Publish CLI platform packages to NPM
        run: |
+         set -e
          cd apps/cli/dist
          ls -la
          for dir in */; do
            if [ -f "$dir/package.json" ]; then
              echo "Publishing $dir..."
              cd "$dir"
              bun publish --access public --tag ${{ steps.version.outputs.tag }}
              cd ..
            fi
          done
        env:
          NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
🤖 Prompt for AI Agents
.github/workflows/pr-preview.yaml around lines 104 to 117: the publish loop
continues on errors so a failed bun publish can be silently ignored; modify the
shell script to fail fast by enabling errexit (e.g., add `set -e` or `set -o
errexit` at the start of the run block) so the step exits immediately on any
publish error (alternatively ensure each publish command is checked and exits
non‑zero on failure).


- name: Publish CLI to NPM
run: cd apps/cli && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
BTS_TELEMETRY: 0

- name: Publish create-bts to NPM
run: cd packages/create-bts && bun publish --access public --tag ${{ steps.version.outputs.tag }}
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
BTS_TELEMETRY: 0

- name: Find existing preview comment
uses: peter-evans/find-comment@v3
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
issue-number: ${{ github.event.pull_request.number || inputs.pr_number }}
comment-author: "github-actions[bot]"
body-includes: "PR Preview Release"

- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
issue-number: ${{ github.event.pull_request.number || inputs.pr_number }}
edit-mode: replace
body: |
## PR Preview Release
Expand All @@ -117,22 +150,24 @@ jobs:
| `create-better-t-stack` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `create-bts` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/types` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/cli-darwin-arm64` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/cli-darwin-x64` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/cli-linux-arm64` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/cli-linux-x64` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
| `@better-t-stack/cli-windows-x64` | `${{ steps.version.outputs.version }}` | `pr${{ steps.version.outputs.pr }}` |
**Commit:** `${{ steps.version.outputs.commit }}`
### Install
```bash
# Using the PR tag (always gets latest for this PR)
bunx create-better-t-stack@pr${{ steps.version.outputs.pr }}
npx create-better-t-stack@pr${{ steps.version.outputs.pr }}
# Using exact version
bunx create-better-t-stack@${{ steps.version.outputs.version }}
npx create-better-t-stack@${{ steps.version.outputs.version }}
# Using the alias
bunx create-bts@pr${{ steps.version.outputs.pr }}
npx create-bts@pr${{ steps.version.outputs.pr }}
```
Expand Down
Loading
Loading