Build Release Branch #1779
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Release Branch | |
| on: | |
| push: | |
| branches-ignore: | |
| - main | |
| - releases | |
| - 'pr-releases/**' | |
| delete: | |
| permissions: write-all | |
| jobs: | |
| build: | |
| # Only run on push events (not delete) | |
| if: github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'npm' | |
| - name: Cache node_modules | |
| id: cache-node-modules | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| node_modules | |
| injected/node_modules | |
| special-pages/node_modules | |
| messaging/node_modules | |
| types-generator/node_modules | |
| key: ${{ runner.os }}-node-modules-${{ hashFiles('.nvmrc') }}-${{ hashFiles('**/package-lock.json') }} | |
| - name: Install dependencies | |
| if: steps.cache-node-modules.outputs.cache-hit != 'true' | |
| run: npm ci | |
| - name: Run build | |
| run: npm run build | |
| - name: Build docs preview | |
| run: npm run docs-preview | |
| - name: Create and push build branch | |
| id: create_branch | |
| env: | |
| SOURCE_BRANCH: ${{ github.ref_name }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| git config --global user.name "github-actions[bot]" | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| # Build branch uses the pr-releases/ prefix to avoid ref conflicts. | |
| # A branch named "foo" prevents creating "foo/bar" (and vice-versa) | |
| # because git refs are a filesystem hierarchy. pr-releases/ is a | |
| # separate namespace that can never collide with the source branch. | |
| BUILD_BRANCH="pr-releases/${SOURCE_BRANCH}" | |
| git checkout -b "${BUILD_BRANCH}" | |
| git add -f build Sources/ContentScopeScripts/dist docs | |
| git commit -m "Build artifacts for ${SOURCE_BRANCH}" | |
| git push -u origin "${BUILD_BRANCH}" --force | |
| echo "BUILD_BRANCH=${BUILD_BRANCH}" >> $GITHUB_ENV | |
| echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV | |
| - name: Comment on associated PR | |
| uses: actions/github-script@v8 | |
| env: | |
| BUILD_BRANCH: ${{ env.BUILD_BRANCH }} | |
| COMMIT_HASH: ${{ env.COMMIT_HASH }} | |
| SOURCE_BRANCH: ${{ github.ref_name }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const buildBranch = process.env.BUILD_BRANCH; | |
| const commitHash = process.env.COMMIT_HASH; | |
| const sourceBranch = process.env.SOURCE_BRANCH; | |
| const repoUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}`; | |
| const branchUrl = `${repoUrl}/tree/${buildBranch}`; | |
| const commitUrl = `${repoUrl}/commit/${commitHash}`; | |
| const previewBaseUrl = `https://rawcdn.githack.com/${context.repo.owner}/${context.repo.repo}/${commitHash}`; | |
| const docsIndexUrl = `${previewBaseUrl}/docs/index.html`; | |
| const staticPagesIndexUrl = `${previewBaseUrl}/build/integration/pages/index.html`; | |
| const integrationPagesIndexUrl = `${previewBaseUrl}/injected/integration-test/test-pages/index.html`; | |
| const qrUrl = (targetUrl) => `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${encodeURIComponent(targetUrl)}`; | |
| const docsQrUrl = qrUrl(docsIndexUrl); | |
| const staticPagesQrUrl = qrUrl(staticPagesIndexUrl); | |
| const integrationPagesQrUrl = qrUrl(integrationPagesIndexUrl); | |
| const lastUpdated = (new Date()).toLocaleString('en-US', { | |
| dateStyle: 'long', | |
| timeStyle: 'long' | |
| }); | |
| const marker = '<!-- BUILD_BRANCH_COMMENT -->'; | |
| const commentBody = [ | |
| marker, | |
| `### Build Branch`, | |
| ``, | |
| `| | |`, | |
| `|---|---|`, | |
| `| **Branch** | [\`${buildBranch}\`](${branchUrl}) |`, | |
| `| **Commit** | [\`${commitHash.slice(0, 10)}\`](${commitUrl}) |`, | |
| `| **Updated** | ${lastUpdated} |`, | |
| ``, | |
| `#### Static preview entry points`, | |
| ``, | |
| `- Docs: [docs/index.html](${docsIndexUrl})`, | |
| `- Static pages: [build/integration/pages/index.html](${staticPagesIndexUrl})`, | |
| `- Integration pages: [injected/integration-test/test-pages/index.html](${integrationPagesIndexUrl})`, | |
| ``, | |
| `<details>`, | |
| `<summary>QR codes (mobile preview)</summary>`, | |
| ``, | |
| `| Entry point | QR code |`, | |
| `|---|---|`, | |
| `| [Docs](${docsIndexUrl}) |  |`, | |
| `| [Static pages](${staticPagesIndexUrl}) |  |`, | |
| `| [Integration pages](${integrationPagesIndexUrl}) |  |`, | |
| ``, | |
| `</details>`, | |
| ``, | |
| `#### Integration commands`, | |
| ``, | |
| `**npm** (Android / Extension):`, | |
| '```', | |
| `npm i github:duckduckgo/content-scope-scripts#${buildBranch}`, | |
| '```', | |
| ``, | |
| `**Swift Package Manager** (Apple):`, | |
| '```swift', | |
| `.package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "${buildBranch}")`, | |
| '```', | |
| ``, | |
| `**git submodule** (Windows):`, | |
| '```sh', | |
| `git -C submodules/content-scope-scripts fetch origin ${buildBranch}`, | |
| `git -C submodules/content-scope-scripts checkout origin/${buildBranch}`, | |
| '```', | |
| ``, | |
| `<details>`, | |
| `<summary>Pin to exact commit</summary>`, | |
| ``, | |
| `**npm** (Android / Extension):`, | |
| '```', | |
| `npm i github:duckduckgo/content-scope-scripts#${commitHash}`, | |
| '```', | |
| ``, | |
| `**Swift Package Manager** (Apple):`, | |
| '```swift', | |
| `.package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "${commitHash}")`, | |
| '```', | |
| ``, | |
| `**git submodule** (Windows):`, | |
| '```sh', | |
| `git -C submodules/content-scope-scripts fetch origin ${buildBranch}`, | |
| `git -C submodules/content-scope-scripts checkout ${commitHash}`, | |
| '```', | |
| ``, | |
| `</details>`, | |
| ].join('\n'); | |
| // Find open PRs for this branch | |
| const { data: prs } = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| head: `${context.repo.owner}:${sourceBranch}`, | |
| state: 'open', | |
| }); | |
| for (const pr of prs) { | |
| // Find existing bot comment by marker | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| }); | |
| const botComment = comments.find( | |
| c => c.user.login === 'github-actions[bot]' && c.body.includes(marker) | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: commentBody, | |
| }); | |
| console.log(`Updated comment on PR #${pr.number}`); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| body: commentBody, | |
| }); | |
| console.log(`Created comment on PR #${pr.number}`); | |
| } | |
| } | |
| if (prs.length === 0) { | |
| console.log(`No open PR found for branch ${sourceBranch} — build branch pushed but no PR to annotate.`); | |
| } | |
| clean_up: | |
| # Only run when a branch is deleted, and only for non-pr-releases branches | |
| if: github.event_name == 'delete' && github.event.ref_type == 'branch' && !startsWith(github.event.ref, 'pr-releases/') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Delete build branch | |
| env: | |
| DELETED_BRANCH: ${{ github.event.ref }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| git push origin --delete "pr-releases/${DELETED_BRANCH}" || echo "Build branch pr-releases/${DELETED_BRANCH} not found (may already be deleted)" |