From 4b32484c253c6f6b7e4d5f525d4e54e51db4ceb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:53:47 +0000 Subject: [PATCH 01/18] feat: add Chromium pipeline with deep file scan, Docker build, and artifacts on master --- .github/workflows/chromium-pipeline.yml | 211 ++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 .github/workflows/chromium-pipeline.yml diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml new file mode 100644 index 0000000..100cffb --- /dev/null +++ b/.github/workflows/chromium-pipeline.yml @@ -0,0 +1,211 @@ +name: Chromium Pipeline – Docker Build & Artifacts + +on: + push: + branches: ["master"] + paths: + - "src/**" + - "webapp/**" + - "webapp/frontend/src/**" + - "webapp/frontend/src/components/**" + - "webapp/frontend/src/pages/**" + - "marketing-site/**" + - "marketing-site/app/**" + - "marketing-site/Dockerfile" + - ".github/workflows/chromium-pipeline.yml" + pull_request: + branches: ["master"] + paths: + - "src/**" + - "webapp/**" + - "webapp/frontend/src/**" + - "webapp/frontend/src/components/**" + - "webapp/frontend/src/pages/**" + - "marketing-site/**" + - "marketing-site/app/**" + - "marketing-site/Dockerfile" + - ".github/workflows/chromium-pipeline.yml" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/pinkflow-app + +permissions: + contents: read + packages: write + +concurrency: + group: chromium-pipeline-${{ github.ref }} + cancel-in-progress: true + +jobs: + # ──────────────────────────────────────────────── + # 1. Chromium headless smoke-test + # ──────────────────────────────────────────────── + chromium-check: + name: Chromium Headless Check + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Chromium + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends chromium-browser + + - name: Verify Chromium version + run: chromium-browser --version + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install Puppeteer (headless Chromium driver) + run: | + npm install puppeteer-core + + - name: Run headless Chromium smoke test + run: | + node - <<'EOF' + const puppeteer = require('puppeteer-core'); + (async () => { + const browser = await puppeteer.launch({ + executablePath: '/usr/bin/chromium-browser', + args: ['--no-sandbox', '--disable-setuid-sandbox', '--headless=new'], + }); + const page = await browser.newPage(); + await page.goto('about:blank'); + const title = await page.title(); + console.log('Chromium smoke test OK – page title:', title); + await browser.close(); + })(); + EOF + + - name: Upload Chromium test log + if: always() + uses: actions/upload-artifact@v4 + with: + name: chromium-smoke-log-${{ github.run_id }} + path: /tmp/chromium-*.log + if-no-files-found: ignore + retention-days: 7 + + # ──────────────────────────────────────────────── + # 2. Discover deeply nested source artifacts + # ──────────────────────────────────────────────── + discover-artifacts: + name: Discover Deep Nested Source Files + runs-on: ubuntu-latest + outputs: + file-list: ${{ steps.scan.outputs.file_list }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Scan for deeply nested files (depth ≥ 5) + id: scan + run: | + echo "=== Deeply nested files (depth >= 5) ===" + FILES=$(find . -mindepth 5 -type f \ + ! -path './.git/*' \ + ! -path './node_modules/*' \ + ! -path './.next/*' \ + | sort) + echo "$FILES" + # Write summary + COUNT=$(echo "$FILES" | grep -c . || true) + echo "Total: $COUNT files at depth >= 5" + echo "file_list=$FILES" >> $GITHUB_OUTPUT + # Also write to a report file + echo "$FILES" > /tmp/deep-nested-files.txt + + - name: Upload deep-file discovery report + uses: actions/upload-artifact@v4 + with: + name: deep-nested-files-${{ github.run_id }} + path: /tmp/deep-nested-files.txt + retention-days: 14 + + # ──────────────────────────────────────────────── + # 3. Docker image build + # ──────────────────────────────────────────────── + docker-build: + name: Docker Image Build + runs-on: ubuntu-latest + needs: [chromium-check] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=sha,prefix=sha- + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: marketing-site/Dockerfile + push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Export image as tar artifact (PRs only) + if: github.event_name == 'pull_request' + run: | + docker save ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$(echo ${{ github.sha }} | head -c 7) \ + -o /tmp/pinkflow-image.tar || \ + docker save $(docker images -q | head -1) -o /tmp/pinkflow-image.tar + + - name: Upload image artifact (PRs only) + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: docker-image-${{ github.run_id }} + path: /tmp/pinkflow-image.tar + retention-days: 3 + + # ──────────────────────────────────────────────── + # 4. Pipeline summary + # ──────────────────────────────────────────────── + pipeline-summary: + name: Pipeline Summary + runs-on: ubuntu-latest + needs: [chromium-check, discover-artifacts, docker-build] + if: always() + steps: + - name: Write job summary + run: | + echo "## Chromium Pipeline Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY + echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Chromium Headless Check | ${{ needs.chromium-check.result }} |" >> $GITHUB_STEP_SUMMARY + echo "| Discover Deep Nested Files | ${{ needs.discover-artifacts.result }} |" >> $GITHUB_STEP_SUMMARY + echo "| Docker Image Build | ${{ needs.docker-build.result }} |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Branch: \`${{ github.ref_name }}\` · SHA: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY From fe3066fea777eaafbc19556aa0a1d9b75023058b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:54:49 +0000 Subject: [PATCH 02/18] fix: clean up redundant path filters, fix multiline output, safer Docker export --- .github/workflows/chromium-pipeline.yml | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index 100cffb..60ed24f 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -6,24 +6,14 @@ on: paths: - "src/**" - "webapp/**" - - "webapp/frontend/src/**" - - "webapp/frontend/src/components/**" - - "webapp/frontend/src/pages/**" - "marketing-site/**" - - "marketing-site/app/**" - - "marketing-site/Dockerfile" - ".github/workflows/chromium-pipeline.yml" pull_request: branches: ["master"] paths: - "src/**" - "webapp/**" - - "webapp/frontend/src/**" - - "webapp/frontend/src/components/**" - - "webapp/frontend/src/pages/**" - "marketing-site/**" - - "marketing-site/app/**" - - "marketing-site/Dockerfile" - ".github/workflows/chromium-pipeline.yml" workflow_dispatch: @@ -113,13 +103,19 @@ jobs: ! -path './.git/*' \ ! -path './node_modules/*' \ ! -path './.next/*' \ + ! -path './dist/*' \ + ! -path './build/*' \ + ! -path './target/*' \ + ! -path './.cache/*' \ | sort) echo "$FILES" - # Write summary COUNT=$(echo "$FILES" | grep -c . || true) echo "Total: $COUNT files at depth >= 5" - echo "file_list=$FILES" >> $GITHUB_OUTPUT - # Also write to a report file + { + echo "file_list<> $GITHUB_OUTPUT echo "$FILES" > /tmp/deep-nested-files.txt - name: Upload deep-file discovery report @@ -177,9 +173,13 @@ jobs: - name: Export image as tar artifact (PRs only) if: github.event_name == 'pull_request' run: | - docker save ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$(echo ${{ github.sha }} | head -c 7) \ - -o /tmp/pinkflow-image.tar || \ - docker save $(docker images -q | head -1) -o /tmp/pinkflow-image.tar + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-$(echo ${{ github.sha }} | head -c 7)" + if docker image inspect "$IMAGE_TAG" > /dev/null 2>&1; then + docker save "$IMAGE_TAG" -o /tmp/pinkflow-image.tar + else + echo "Expected image $IMAGE_TAG not found; skipping export." + exit 1 + fi - name: Upload image artifact (PRs only) if: github.event_name == 'pull_request' From 0a0d35bb747817322737b74163caf200e4e71507 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:55:32 +0000 Subject: [PATCH 03/18] fix: use load:true for PR Docker builds, compute short SHA via shell --- .github/workflows/chromium-pipeline.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index 60ed24f..544c2d7 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -160,20 +160,27 @@ jobs: type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} - name: Build Docker image + id: docker-build uses: docker/build-push-action@v6 with: context: . file: marketing-site/Dockerfile push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + load: ${{ github.event_name == 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + - name: Compute short SHA + if: github.event_name == 'pull_request' + id: short-sha + run: echo "value=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT + - name: Export image as tar artifact (PRs only) if: github.event_name == 'pull_request' run: | - IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-$(echo ${{ github.sha }} | head -c 7)" + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ steps.short-sha.outputs.value }}" if docker image inspect "$IMAGE_TAG" > /dev/null 2>&1; then docker save "$IMAGE_TAG" -o /tmp/pinkflow-image.tar else From 915a4bb168e5667de4d4195478da3ddae1392eb3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:04:20 +0000 Subject: [PATCH 04/18] fix: add missing labeler configuration file --- .github/labeler.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/labeler.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..315cab5 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,25 @@ +dependencies: + - changed-files: + - any-glob-to-any-file: + - "**/package.json" + - "**/package-lock.json" + - "**/pnpm-lock.yaml" + - "**/yarn.lock" + - "**/requirements*.txt" + - "**/poetry.lock" + - "**/go.mod" + - "**/go.sum" + +javascript: + - changed-files: + - any-glob-to-any-file: + - "**/*.js" + - "**/*.jsx" + - "**/*.ts" + - "**/*.tsx" + +documentation: + - changed-files: + - any-glob-to-any-file: + - "**/*.md" + - "docs/**" From 93b507b88fcea954799159d706729a1fa5d915c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:06:44 +0000 Subject: [PATCH 05/18] fix(ci): add npm cache path and install dir for security review workflow --- .github/workflows/pr-security.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr-security.yml b/.github/workflows/pr-security.yml index fee2d59..7667c42 100644 --- a/.github/workflows/pr-security.yml +++ b/.github/workflows/pr-security.yml @@ -22,6 +22,7 @@ jobs: with: node-version: '20' cache: 'npm' + cache-dependency-path: marketing-site/package-lock.json - name: Check for new dependencies id: deps @@ -40,6 +41,7 @@ jobs: fi - name: Install dependencies + working-directory: marketing-site run: npm ci - name: Run dependency audit From 3294cb6cbb1777f70a020ea508cf6efc4c245797 Mon Sep 17 00:00:00 2001 From: Pmaster-dev <8pinkycollie8@gmail.com> Date: Thu, 2 Jul 2026 09:26:40 -0500 Subject: [PATCH 06/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/chromium-pipeline.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index 544c2d7..2631b3b 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -59,11 +59,23 @@ jobs: - name: Run headless Chromium smoke test run: | - node - <<'EOF' + node - <<'EOF' 2>&1 | tee /tmp/chromium-smoke.log + const fs = require('fs'); const puppeteer = require('puppeteer-core'); + const candidates = [ + process.env.CHROME_BIN, + '/usr/bin/chromium-browser', + '/usr/bin/chromium', + '/usr/bin/google-chrome', + '/usr/bin/google-chrome-stable', + ].filter(Boolean); + const executablePath = candidates.find((p) => fs.existsSync(p)); + if (!executablePath) { + throw new Error(`Chromium executable not found. Tried: ${candidates.join(', ')}`); + } (async () => { const browser = await puppeteer.launch({ - executablePath: '/usr/bin/chromium-browser', + executablePath, args: ['--no-sandbox', '--disable-setuid-sandbox', '--headless=new'], }); const page = await browser.newPage(); From 6da6da5e6476963c202a0680bd159a25f1a81ed2 Mon Sep 17 00:00:00 2001 From: Pmaster-dev <8pinkycollie8@gmail.com> Date: Thu, 2 Jul 2026 09:27:26 -0500 Subject: [PATCH 07/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/chromium-pipeline.yml | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index 2631b3b..9589a52 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -111,24 +111,18 @@ jobs: id: scan run: | echo "=== Deeply nested files (depth >= 5) ===" - FILES=$(find . -mindepth 5 -type f \ - ! -path './.git/*' \ - ! -path './node_modules/*' \ - ! -path './.next/*' \ - ! -path './dist/*' \ - ! -path './build/*' \ - ! -path './target/*' \ - ! -path './.cache/*' \ - | sort) - echo "$FILES" - COUNT=$(echo "$FILES" | grep -c . || true) + find . -mindepth 5 \ + \( -path '*/.git' -o -path '*/node_modules' -o -path '*/.next' -o -path '*/dist' -o -path '*/build' -o -path '*/target' -o -path '*/.cache' \) -prune -o \ + -type f -print \ + | sort > /tmp/deep-nested-files.txt + cat /tmp/deep-nested-files.txt + COUNT=$(wc -l < /tmp/deep-nested-files.txt | tr -d ' ') echo "Total: $COUNT files at depth >= 5" { echo "file_list<> $GITHUB_OUTPUT - echo "$FILES" > /tmp/deep-nested-files.txt + } >> "$GITHUB_OUTPUT" - name: Upload deep-file discovery report uses: actions/upload-artifact@v4 From 4340972ebf985197d599f4f1766dd4712e7c97ab Mon Sep 17 00:00:00 2001 From: Pmaster-dev <8pinkycollie8@gmail.com> Date: Thu, 2 Jul 2026 09:27:58 -0500 Subject: [PATCH 08/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/chromium-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index 9589a52..b46e637 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -162,7 +162,7 @@ jobs: type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} - type=sha,prefix=sha- + type=sha,format=short,prefix=sha- type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} - name: Build Docker image From 6db718b2fd477301e5be031597f8a8f8b3abef3e Mon Sep 17 00:00:00 2001 From: Pmaster-dev <8pinkycollie8@gmail.com> Date: Thu, 2 Jul 2026 09:30:48 -0500 Subject: [PATCH 09/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/chromium-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromium-pipeline.yml b/.github/workflows/chromium-pipeline.yml index b46e637..ec9516d 100644 --- a/.github/workflows/chromium-pipeline.yml +++ b/.github/workflows/chromium-pipeline.yml @@ -102,7 +102,7 @@ jobs: name: Discover Deep Nested Source Files runs-on: ubuntu-latest outputs: - file-list: ${{ steps.scan.outputs.file_list }} + file_list: ${{ steps.scan.outputs.file_list }} steps: - name: Checkout uses: actions/checkout@v4 From 651b1ba2243b95719679c0c8e6370b3b9284011d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:59:52 +0000 Subject: [PATCH 10/18] fix: load labeler config from PR head --- .github/workflows/label.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 4613569..ae02d85 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -17,6 +17,26 @@ jobs: pull-requests: write steps: + - name: Fetch labeler config from pull request + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + const configPath = '.github/labeler.yml'; + const pullRequest = context.payload.pull_request; + + const response = await github.rest.repos.getContent({ + owner: pullRequest.head.repo.owner.login, + repo: pullRequest.head.repo.name, + path: configPath, + ref: pullRequest.head.sha, + }); + + const content = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + fs.mkdirSync(path.dirname(configPath), { recursive: true }); + fs.writeFileSync(configPath, content); + - uses: actions/labeler@v4 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" From 3868cee1d9de185f9ac377ede19d5da34908b57a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:00:43 +0000 Subject: [PATCH 11/18] fix: harden labeler config loading --- .github/workflows/label.yml | 50 +++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index ae02d85..0f6d4f5 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -21,21 +21,55 @@ jobs: uses: actions/github-script@v7 with: script: | + const core = require('@actions/core'); const fs = require('fs'); const path = require('path'); const configPath = '.github/labeler.yml'; const pullRequest = context.payload.pull_request; + const sources = [ + { + owner: pullRequest.head.repo?.owner?.login, + repo: pullRequest.head.repo?.name, + ref: pullRequest.head.sha, + }, + { + owner: context.repo.owner, + repo: context.repo.repo, + ref: pullRequest.base.sha, + }, + ].filter((source) => source.owner && source.repo && source.ref); - const response = await github.rest.repos.getContent({ - owner: pullRequest.head.repo.owner.login, - repo: pullRequest.head.repo.name, - path: configPath, - ref: pullRequest.head.sha, - }); + let configContent; + + for (const source of sources) { + try { + const response = await github.rest.repos.getContent({ + owner: source.owner, + repo: source.repo, + path: configPath, + ref: source.ref, + }); + + if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { + throw new Error(`Unsupported response for ${configPath} at ${source.owner}/${source.repo}@${source.ref}`); + } + + configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + break; + } catch (error) { + if (error.status !== 404) { + throw error; + } + } + } + + if (!configContent) { + core.setFailed(`Unable to load ${configPath} from the pull request head or base branch.`); + return; + } - const content = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); fs.mkdirSync(path.dirname(configPath), { recursive: true }); - fs.writeFileSync(configPath, content); + fs.writeFileSync(configPath, configContent); - uses: actions/labeler@v4 with: From bba14db0e941c8c64301416b084fc322bb83bc64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:01:38 +0000 Subject: [PATCH 12/18] fix: tidy labeler workflow indentation --- .github/workflows/label.yml | 96 ++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 0f6d4f5..2aa1462 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -17,60 +17,60 @@ jobs: pull-requests: write steps: - - name: Fetch labeler config from pull request - uses: actions/github-script@v7 - with: - script: | - const core = require('@actions/core'); - const fs = require('fs'); - const path = require('path'); - const configPath = '.github/labeler.yml'; - const pullRequest = context.payload.pull_request; - const sources = [ - { - owner: pullRequest.head.repo?.owner?.login, - repo: pullRequest.head.repo?.name, - ref: pullRequest.head.sha, - }, - { - owner: context.repo.owner, - repo: context.repo.repo, - ref: pullRequest.base.sha, - }, - ].filter((source) => source.owner && source.repo && source.ref); + - name: Fetch labeler config from pull request + uses: actions/github-script@v7 + with: + script: | + const core = require('@actions/core'); + const fs = require('fs'); + const path = require('path'); + const configPath = '.github/labeler.yml'; + const pullRequest = context.payload.pull_request; + const sources = [ + { + owner: pullRequest.head.repo?.owner?.login, + repo: pullRequest.head.repo?.name, + ref: pullRequest.head.sha, + }, + { + owner: context.repo.owner, + repo: context.repo.repo, + ref: pullRequest.base.sha, + }, + ].filter((source) => source.owner && source.repo && source.ref); - let configContent; + let configContent; - for (const source of sources) { - try { - const response = await github.rest.repos.getContent({ - owner: source.owner, - repo: source.repo, - path: configPath, - ref: source.ref, - }); + for (const source of sources) { + try { + const response = await github.rest.repos.getContent({ + owner: source.owner, + repo: source.repo, + path: configPath, + ref: source.ref, + }); - if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { - throw new Error(`Unsupported response for ${configPath} at ${source.owner}/${source.repo}@${source.ref}`); - } + if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { + throw new Error(`Unsupported response for ${configPath} at ${source.owner}/${source.repo}@${source.ref}`); + } - configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); - break; - } catch (error) { - if (error.status !== 404) { - throw error; + configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + break; + } catch (error) { + if (error.status !== 404) { + throw error; + } } } - } - if (!configContent) { - core.setFailed(`Unable to load ${configPath} from the pull request head or base branch.`); - return; - } + if (!configContent) { + core.setFailed(`Unable to load ${configPath} from the pull request head or base branch.`); + return; + } - fs.mkdirSync(path.dirname(configPath), { recursive: true }); - fs.writeFileSync(configPath, configContent); + fs.mkdirSync(path.dirname(configPath), { recursive: true }); + fs.writeFileSync(configPath, configContent); - - uses: actions/labeler@v4 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" From 96d249c782ac0f9fe0a856ed37facece289a5b9b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:02:22 +0000 Subject: [PATCH 13/18] fix: guard labeler config fallback --- .github/workflows/label.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 2aa1462..fd49cc9 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -26,10 +26,11 @@ jobs: const path = require('path'); const configPath = '.github/labeler.yml'; const pullRequest = context.payload.pull_request; + const headRepo = pullRequest.head.repo; const sources = [ { - owner: pullRequest.head.repo?.owner?.login, - repo: pullRequest.head.repo?.name, + owner: headRepo ? headRepo.owner.login : undefined, + repo: headRepo ? headRepo.name : undefined, ref: pullRequest.head.sha, }, { From 2ddc1fd6053cb52e649d7d778f5d406c97fc0959 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:03:17 +0000 Subject: [PATCH 14/18] fix: tighten labeler config fetch logic --- .github/workflows/label.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index fd49cc9..ec85c89 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -28,17 +28,17 @@ jobs: const pullRequest = context.payload.pull_request; const headRepo = pullRequest.head.repo; const sources = [ - { - owner: headRepo ? headRepo.owner.login : undefined, - repo: headRepo ? headRepo.name : undefined, + ...(headRepo ? [{ + owner: headRepo.owner.login, + repo: headRepo.name, ref: pullRequest.head.sha, - }, + }] : []), { owner: context.repo.owner, repo: context.repo.repo, ref: pullRequest.base.sha, }, - ].filter((source) => source.owner && source.repo && source.ref); + ]; let configContent; @@ -52,7 +52,12 @@ jobs: }); if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { - throw new Error(`Unsupported response for ${configPath} at ${source.owner}/${source.repo}@${source.ref}`); + const reason = Array.isArray(response.data) + ? 'received a directory listing' + : response.data.type !== 'file' + ? `received type "${response.data.type}"` + : 'received empty file content'; + throw new Error(`Unable to read ${configPath} at ${source.owner}/${source.repo}@${source.ref}: ${reason}.`); } configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); From 63b9c15d3025cab85791013f3c8d7610279612f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:03:59 +0000 Subject: [PATCH 15/18] fix: improve labeler fetch errors --- .github/workflows/label.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index ec85c89..9fe5a92 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -52,11 +52,14 @@ jobs: }); if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { - const reason = Array.isArray(response.data) - ? 'received a directory listing' - : response.data.type !== 'file' - ? `received type "${response.data.type}"` - : 'received empty file content'; + let reason = 'received empty file content'; + + if (Array.isArray(response.data)) { + reason = 'received a directory listing'; + } else if (response.data.type !== 'file') { + reason = `received type "${response.data.type}"`; + } + throw new Error(`Unable to read ${configPath} at ${source.owner}/${source.repo}@${source.ref}: ${reason}.`); } @@ -64,7 +67,7 @@ jobs: break; } catch (error) { if (error.status !== 404) { - throw error; + throw new Error(`Failed to load ${configPath} from ${source.owner}/${source.repo}@${source.ref}: ${error.message}`); } } } From 522df16dec2c336f501b2626bd7efc09fd19cbd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:04:48 +0000 Subject: [PATCH 16/18] fix: separate labeler fetch validation --- .github/workflows/label.yml | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 9fe5a92..fe11fbd 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -43,33 +43,39 @@ jobs: let configContent; for (const source of sources) { + let response; + try { - const response = await github.rest.repos.getContent({ + response = await github.rest.repos.getContent({ owner: source.owner, repo: source.repo, path: configPath, ref: source.ref, }); + } catch (error) { + if (error.status === 404) { + continue; + } - if (Array.isArray(response.data) || response.data.type !== 'file' || !response.data.content) { - let reason = 'received empty file content'; + throw new Error(`Failed to load ${configPath} from ${source.owner}/${source.repo}@${source.ref}: ${error.message}`); + } - if (Array.isArray(response.data)) { - reason = 'received a directory listing'; - } else if (response.data.type !== 'file') { - reason = `received type "${response.data.type}"`; - } + let reason; - throw new Error(`Unable to read ${configPath} at ${source.owner}/${source.repo}@${source.ref}: ${reason}.`); - } + if (Array.isArray(response.data)) { + reason = 'received a directory listing'; + } else if (response.data.type !== 'file') { + reason = `received type "${response.data.type}"`; + } else if (response.data.content === undefined) { + reason = 'received no file content'; + } - configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); - break; - } catch (error) { - if (error.status !== 404) { - throw new Error(`Failed to load ${configPath} from ${source.owner}/${source.repo}@${source.ref}: ${error.message}`); - } + if (reason) { + throw new Error(`Unable to read ${configPath} at ${source.owner}/${source.repo}@${source.ref}: ${reason}.`); } + + configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + break; } if (!configContent) { From 6f7f96c767df04a2cdf6e2598032f2480318f236 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:05:35 +0000 Subject: [PATCH 17/18] fix: restrict labeler head config fetch --- .github/workflows/label.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index fe11fbd..825dc8e 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -27,8 +27,9 @@ jobs: const configPath = '.github/labeler.yml'; const pullRequest = context.payload.pull_request; const headRepo = pullRequest.head.repo; + const isSameRepositoryPullRequest = headRepo && headRepo.full_name === `${context.repo.owner}/${context.repo.repo}`; const sources = [ - ...(headRepo ? [{ + ...(isSameRepositoryPullRequest ? [{ owner: headRepo.owner.login, repo: headRepo.name, ref: pullRequest.head.sha, From 9b8121473c28be11964d6bde192b36135cf369fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:06:16 +0000 Subject: [PATCH 18/18] fix: clarify labeler decode failures --- .github/workflows/label.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 825dc8e..323a315 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -75,7 +75,12 @@ jobs: throw new Error(`Unable to read ${configPath} at ${source.owner}/${source.repo}@${source.ref}: ${reason}.`); } - configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + try { + configContent = Buffer.from(response.data.content, response.data.encoding).toString('utf8'); + } catch (error) { + throw new Error(`Unable to decode ${configPath} at ${source.owner}/${source.repo}@${source.ref} using ${response.data.encoding}: ${error.message}`); + } + break; }