Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
129 changes: 129 additions & 0 deletions .github/workflows/build-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Build Preview

on:
pull_request:
branches:
- main
- develop
types:
- opened
- synchronize
- reopened

permissions:
contents: read

concurrency:
group: build-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
build-preview:
name: Build Web Preview
runs-on: ubuntu-latest
env:
EMSDK_VERSION: 3.1.51
steps:
- name: Checkout PR commit
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
persist-credentials: false

- name: Cache Emscripten SDK & ports
uses: actions/cache@v5
id: emsdk-cache
with:
path: |
emsdk
~/.emscripten_cache
key: emsdk-${{ env.EMSDK_VERSION }}-${{ runner.os }}-${{ hashFiles('CMakeLists.txt') }}
restore-keys: |
emsdk-${{ env.EMSDK_VERSION }}-${{ runner.os }}-

- name: Setup Emscripten
if: steps.emsdk-cache.outputs.cache-hit != 'true'
run: |
if [ -d emsdk ]; then
cd emsdk && git pull
else
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
fi
./emsdk install $EMSDK_VERSION
./emsdk activate $EMSDK_VERSION

- name: Activate Emscripten
run: |
cd emsdk
./emsdk activate $EMSDK_VERSION
echo "${{ github.workspace }}/emsdk" >> "$GITHUB_PATH"
echo "${{ github.workspace }}/emsdk/upstream/emscripten" >> "$GITHUB_PATH"

- name: Setup External Dependencies
run: |
git clone --depth 1 --branch v1.90.1 https://github.com/ocornut/imgui.git external/imgui &
curl -sL -o external/nanosvg.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvg.h &
curl -sL -o external/nanosvgrast.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvgrast.h &
curl -sL -o external/dr_wav.h https://raw.githubusercontent.com/mackron/dr_libs/master/dr_wav.h &
mkdir -p external/kiss_fft
curl -sL -o external/kiss_fft/kiss_fft.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.h &
curl -sL -o external/kiss_fft/kiss_fft.c https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.c &
curl -sL -o external/kiss_fft/_kiss_fft_guts.h https://raw.githubusercontent.com/mborgerding/kissfft/master/_kiss_fft_guts.h &
curl -sL -o external/kiss_fft/kiss_fft_log.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft_log.h &
wait

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the preview workflow file
find . -name "preview.yml" -type f

Repository: sudip-mondal-2002/Amplitron

Length of output: 103


🏁 Script executed:

# Read the relevant section of the workflow file
cat -n .github/workflows/preview.yml | sed -n '60,80p'

Repository: sudip-mondal-2002/Amplitron

Length of output: 1609


🌐 Web query:

curl -sL vs -fsSL flags difference error handling HTTP

💡 Result:

The primary difference between the curl flag combinations -sL and -fsSL lies in how they handle HTTP errors and error reporting [1][2]. -sL (Silent, Location) - -s (--silent): Disables the progress meter and error messages [3][4]. - -L (--location): Tells curl to follow HTTP 3xx redirects [5][6]. - Error Handling: Because -s is used without -S, curl will suppress error messages if the request fails (e.g., DNS issues, connection refused, or SSL errors) [1]. This can make debugging difficult in scripts, as the command may fail silently without providing feedback [1]. -fsSL (Fail, Silent, Show-error, Location) - -f (--fail): Tells curl to fail silently (no output) on server errors (HTTP 4xx or 5xx) [7][6]. Without this flag, curl treats HTTP error responses as successful transfers and will output the error page content [2]. - -s (--silent): Disables the progress meter [3][4]. - -S (--show-error): When used with -s, this ensures that if curl fails, it will still output the error message to stderr [1][3]. - -L (--location): Follows HTTP 3xx redirects [5][6]. - Error Handling: This combination is generally preferred for scripts [1]. It ensures that HTTP server errors cause the command to exit with a non-zero status (error 22) [7][2], while still providing diagnostic error messages if a network or connection failure occurs [1]. Summary of Key Flags - -f (--fail): Prevents curl from outputting the body of an HTTP error response and forces a non-zero exit code [7][2]. - -s (--silent): Suppresses progress bars and other output [3][4]. - -S (--show-error): Ensures error messages are printed even when -s is active [1][3]. - -L (--location): Enables automatic following of redirects [5][6]. For robust scripting, -fsSL is recommended over -sL because it provides better error visibility and forces the command to fail explicitly on HTTP errors [1][2].

Citations:


Create external/ before starting background operations and use -fsSL for robust curl error handling.

Lines 66-69 are backgrounded before the external/ directory is created on line 70, so this step has a race condition that can fail intermittently with "No such file or directory" on git clone and curl operations. Additionally, curl -sL silently outputs HTTP error pages (404/500) as file content instead of failing the build. Switch to -fsSL to fail explicitly on upstream errors.

Suggested fix
       - name: Setup External Dependencies
         run: |
+          mkdir -p external external/kiss_fft
           git clone --depth 1 --branch v1.90.1 https://github.com/ocornut/imgui.git external/imgui &
-          curl -sL -o external/nanosvg.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvg.h &
-          curl -sL -o external/nanosvgrast.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvgrast.h &
-          curl -sL -o external/dr_wav.h https://raw.githubusercontent.com/mackron/dr_libs/master/dr_wav.h &
-          mkdir -p external/kiss_fft
-          curl -sL -o external/kiss_fft/kiss_fft.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.h &
-          curl -sL -o external/kiss_fft/kiss_fft.c https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.c &
-          curl -sL -o external/kiss_fft/_kiss_fft_guts.h https://raw.githubusercontent.com/mborgerding/kissfft/master/_kiss_fft_guts.h &
-          curl -sL -o external/kiss_fft/kiss_fft_log.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft_log.h &
+          curl -fsSL -o external/nanosvg.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvg.h &
+          curl -fsSL -o external/nanosvgrast.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvgrast.h &
+          curl -fsSL -o external/dr_wav.h https://raw.githubusercontent.com/mackron/dr_libs/master/dr_wav.h &
+          curl -fsSL -o external/kiss_fft/kiss_fft.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.h &
+          curl -fsSL -o external/kiss_fft/kiss_fft.c https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.c &
+          curl -fsSL -o external/kiss_fft/_kiss_fft_guts.h https://raw.githubusercontent.com/mborgerding/kissfft/master/_kiss_fft_guts.h &
+          curl -fsSL -o external/kiss_fft/kiss_fft_log.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft_log.h &
           wait
📝 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: Setup External Dependencies
run: |
git clone --depth 1 --branch v1.90.1 https://github.com/ocornut/imgui.git external/imgui &
curl -sL -o external/nanosvg.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvg.h &
curl -sL -o external/nanosvgrast.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvgrast.h &
curl -sL -o external/dr_wav.h https://raw.githubusercontent.com/mackron/dr_libs/master/dr_wav.h &
mkdir -p external/kiss_fft
curl -sL -o external/kiss_fft/kiss_fft.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.h &
curl -sL -o external/kiss_fft/kiss_fft.c https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.c &
curl -sL -o external/kiss_fft/_kiss_fft_guts.h https://raw.githubusercontent.com/mborgerding/kissfft/master/_kiss_fft_guts.h &
curl -sL -o external/kiss_fft/kiss_fft_log.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft_log.h &
wait
- name: Setup External Dependencies
run: |
mkdir -p external external/kiss_fft
git clone --depth 1 --branch v1.90.1 https://github.com/ocornut/imgui.git external/imgui &
curl -fsSL -o external/nanosvg.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvg.h &
curl -fsSL -o external/nanosvgrast.h https://raw.githubusercontent.com/memononen/nanosvg/master/src/nanosvgrast.h &
curl -fsSL -o external/dr_wav.h https://raw.githubusercontent.com/mackron/dr_libs/master/dr_wav.h &
curl -fsSL -o external/kiss_fft/kiss_fft.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.h &
curl -fsSL -o external/kiss_fft/kiss_fft.c https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft.c &
curl -fsSL -o external/kiss_fft/_kiss_fft_guts.h https://raw.githubusercontent.com/mborgerding/kissfft/master/_kiss_fft_guts.h &
curl -fsSL -o external/kiss_fft/kiss_fft_log.h https://raw.githubusercontent.com/mborgerding/kissfft/master/kiss_fft_log.h &
wait
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/preview.yml around lines 64 - 75, In the "Setup External
Dependencies" step, create the external directory before launching any
backgrounded fetches and make curl fail on HTTP errors: move or add a mkdir -p
external (and keep mkdir -p external/kiss_fft) before the git clone and curl ...
& lines, and replace all occurrences of curl -sL with curl -fsSL so broken
downloads fail the job; keep the backgrounding (&) and final wait if you want
parallel fetches.


- name: Generate Preview Version
id: version
run: |
COUNT=$(git rev-list --count HEAD)
echo "version=0.1.${COUNT}-pr.${{ github.event.pull_request.number }}.${{ github.run_number }}" >> "$GITHUB_OUTPUT"

- name: Build WASM
run: |
source emsdk/emsdk_env.sh
mkdir -p build-web && cd build-web
emcmake cmake -DCMAKE_BUILD_TYPE=Release -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" ..
emmake make -j"$(nproc)"

- name: Stage preview artifact
run: |
mkdir -p preview .preview-meta

for file in \
build-web/index.html \
build-web/index.js \
build-web/index.wasm \
build-web/index.data \
build-web/*.worker.js \
build-web/coi-serviceworker.js
do
[ -e "$file" ] && cp "$file" preview/
done

test -f preview/index.html
test -f preview/index.js
test -f preview/index.wasm
touch preview/.nojekyll

cat > .preview-meta/preview.env <<EOF
PR_NUMBER=${{ github.event.pull_request.number }}
HEAD_SHA=${{ github.event.pull_request.head.sha }}
PREVIEW_PATH=pr-previews/pr-${{ github.event.pull_request.number }}
PREVIEW_URL=https://amplitron.sudipmondal.co.in/pr-previews/pr-${{ github.event.pull_request.number }}/
EOF

- name: Upload preview artifact
uses: actions/upload-artifact@v7
with:
name: pr-preview
path: preview/
retention-days: 3

- name: Upload preview metadata
uses: actions/upload-artifact@v7
with:
name: pr-preview-metadata
path: .preview-meta/
retention-days: 3
199 changes: 199 additions & 0 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
name: Deploy Preview

on:
workflow_run:
workflows:
- Build Preview
types:
- completed
pull_request_target:
types:
- closed

permissions:
contents: write
pull-requests: write

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
concurrency:
group: deploy-preview-${{ github.event.workflow_run.id || github.event.pull_request.number }}
cancel-in-progress: false

jobs:
deploy-preview:
name: Deploy PR Preview
if: >
github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Download preview artifact
uses: actions/download-artifact@v8
with:
name: pr-preview
path: preview
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Download preview metadata
uses: actions/download-artifact@v8
with:
name: pr-preview-metadata
path: .preview-meta
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Load preview metadata
id: preview-meta
run: |
set -a
. .preview-meta/preview.env
set +a

echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
echo "preview_path=$PREVIEW_PATH" >> "$GITHUB_OUTPUT"
echo "preview_url=$PREVIEW_URL" >> "$GITHUB_OUTPUT"
echo "short_sha=${HEAD_SHA:0:7}" >> "$GITHUB_OUTPUT"

- name: Check pull request state
id: pr-state
uses: actions/github-script@v8
with:
script: |
const { owner, repo } = context.repo;
const pull_number = Number('${{ steps.preview-meta.outputs.pr_number }}');
const { data: pull } = await github.rest.pulls.get({
owner,
repo,
pull_number,
});
core.setOutput('state', pull.state);

- name: Publish preview to GitHub Pages
if: steps.pr-state.outputs.state == 'open'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./preview
publish_branch: gh-pages
destination_dir: ${{ steps.preview-meta.outputs.preview_path }}
keep_files: true
enable_jekyll: false

- name: Comment preview URL on PR
if: steps.pr-state.outputs.state == 'open'
uses: actions/github-script@v8
env:
PR_NUMBER: ${{ steps.preview-meta.outputs.pr_number }}
PREVIEW_URL: ${{ steps.preview-meta.outputs.preview_url }}
PREVIEW_PATH: ${{ steps.preview-meta.outputs.preview_path }}
SHORT_SHA: ${{ steps.preview-meta.outputs.short_sha }}
with:
script: |
const marker = '<!-- amplitron-pr-preview -->';
const { owner, repo } = context.repo;
const issue_number = Number(process.env.PR_NUMBER);
const body = [
marker,
'### PR Preview Ready',
'',
`Preview URL: ${process.env.PREVIEW_URL}`,
'',
`Built from commit \`${process.env.SHORT_SHA}\` and deployed to \`${process.env.PREVIEW_PATH}\`.`,
'This preview updates automatically when the PR branch changes and is removed when the PR closes.',
].join('\n');

const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
per_page: 100,
});
const previous = comments.find((comment) =>
comment.user?.type === 'Bot' && comment.body?.includes(marker)
);

if (previous) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: previous.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}

cleanup-preview:
name: Remove Closed PR Preview
if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
steps:
- name: Checkout GitHub Pages branch
id: pages-checkout
uses: actions/checkout@v6
continue-on-error: true
with:
ref: gh-pages
path: pages
token: ${{ secrets.GITHUB_TOKEN }}

- name: Remove preview directory
if: steps.pages-checkout.outcome == 'success'
working-directory: pages
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
target="pr-previews/pr-${PR_NUMBER}"

if [ ! -d "$target" ]; then
echo "No preview directory found at $target"
exit 0
fi

rm -rf "$target"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A "$target"
git commit -m "Remove preview for PR #${PR_NUMBER}"
git push

- name: Comment cleanup on PR
if: steps.pages-checkout.outcome == 'success'
uses: actions/github-script@v8
with:
script: |
const marker = '<!-- amplitron-pr-preview -->';
const { owner, repo } = context.repo;
const issue_number = context.payload.pull_request.number;
const body = [
marker,
'### PR Preview Removed',
'',
'The GitHub Pages preview for this PR has been removed because the PR was closed.',
].join('\n');

const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
per_page: 100,
});
const previous = comments.find((comment) =>
comment.user?.type === 'Bot' && comment.body?.includes(marker)
);

if (previous) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: previous.id,
body,
});
}
21 changes: 20 additions & 1 deletion DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ This document explains the CI/CD pipeline and how to create releases.
4. Uploads installers to the release
5. Deploys web demo and download page to GitHub Pages

### 3. PR Preview Workflows (`.github/workflows/build-preview.yml`, `.github/workflows/deploy-preview.yml`)

**Triggers**: Pull Requests to `main` or `develop`, and completed PR preview builds

**What they do**:
1. Build the Emscripten web target for each open Pull Request
2. Upload only the static preview files (`index.html`, JavaScript, WebAssembly, data, worker, and service worker files)
3. Deploy the preview to GitHub Pages under `pr-previews/pr-<number>/`
4. Post or update a PR comment with the live preview URL
5. Remove the preview directory automatically when the PR is closed

Preview URLs follow this format:

```text
https://amplitron.sudipmondal.co.in/pr-previews/pr-<number>/
```

Comment on lines +54 to +58

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Please use https://amplitron.sudipmondal.co.in/

The build and deploy steps are intentionally split across two workflows. Pull Request code is built with read-only permissions, while the Pages deployment workflow only publishes the generated artifact. This keeps preview deployments available for review without giving PR build scripts write access to the repository.

## Creating a Release

### Step 1: Prepare the Release
Expand Down Expand Up @@ -97,7 +116,7 @@ To trigger a release manually, push to `main` and let CI complete. The release w
3. Branch: `gh-pages` / `root`
4. Click Save

The website will be available at: https://sudip-mondal-2002.github.io/Amplitron/
The website will be available at: https://amplitron.sudipmondal.co.in/

### Update the Download Page

Expand Down
Loading