diff --git a/.github/actions/license/action.yml b/.github/actions/license/action.yml index 1afd1699..339776ca 100644 --- a/.github/actions/license/action.yml +++ b/.github/actions/license/action.yml @@ -12,7 +12,7 @@ runs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: 18 + node-version: 20 cache: 'pnpm' - name: Install dependencies diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 549481e5..3a90460b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,6 +2,12 @@ # Security PRs also require: Settings → Code security → Dependabot security updates. version: 2 updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 2 + - package-ecosystem: npm directory: "/" schedule: diff --git a/.github/workflows/pr-artifact-publisher.yml b/.github/workflows/pr-artifact-publisher.yml new file mode 100644 index 00000000..83a63da8 --- /dev/null +++ b/.github/workflows/pr-artifact-publisher.yml @@ -0,0 +1,195 @@ +name: PR Artifact Publisher + +on: + workflow_run: + workflows: ["PR"] + types: [completed] + +permissions: + contents: write + actions: read + issues: write + +jobs: + publish: + if: > + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Prepare metadata + id: metadata + env: + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }} + REPOSITORY: ${{ github.repository }} + run: | + if [ -z "$PR_NUMBER" ]; then + echo "Unable to resolve pull request number from workflow_run payload." >&2 + exit 1 + fi + + SHORT_SHA="$(echo "$HEAD_SHA" | cut -c1-7)" + + echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT" + echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" + echo "repository=$REPOSITORY" >> "$GITHUB_OUTPUT" + echo "chrome_artifact=cloudhood-chrome-$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "firefox_artifact=cloudhood-firefox-$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "firefox_sources_artifact=cloudhood-firefox-sources-$HEAD_SHA" >> "$GITHUB_OUTPUT" + + - name: Download Chrome build artifact + uses: actions/download-artifact@v8 + with: + name: ${{ steps.metadata.outputs.chrome_artifact }} + path: downloaded/chrome + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Download Firefox build artifact + uses: actions/download-artifact@v8 + with: + name: ${{ steps.metadata.outputs.firefox_artifact }} + path: downloaded/firefox + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Download Firefox sources artifact + uses: actions/download-artifact@v8 + with: + name: ${{ steps.metadata.outputs.firefox_sources_artifact }} + path: downloaded/firefox-sources + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Validate downloaded artifacts + env: + SHORT_SHA: ${{ steps.metadata.outputs.short_sha }} + run: | + set -euo pipefail + + CHROME_ZIP="downloaded/chrome/cloudhood-chrome-$SHORT_SHA.zip" + FIREFOX_ZIP="downloaded/firefox/cloudhood-firefox-$SHORT_SHA.zip" + FIREFOX_SOURCES_ZIP="downloaded/firefox-sources/cloudhood-firefox-sources-$SHORT_SHA.zip" + + for artifact in "$CHROME_ZIP" "$FIREFOX_ZIP" "$FIREFOX_SOURCES_ZIP"; do + test -f "$artifact" + test -s "$artifact" + test "$(stat -c '%s' "$artifact")" -le 104857600 + done + + unzip -l "$CHROME_ZIP" | grep -q 'manifest.json' + unzip -l "$CHROME_ZIP" | grep -q 'background.bundle.js' + unzip -l "$FIREFOX_ZIP" | grep -q 'manifest.json' + unzip -l "$FIREFOX_ZIP" | grep -q 'background.bundle.js' + unzip -t "$CHROME_ZIP" + unzip -t "$FIREFOX_ZIP" + unzip -t "$FIREFOX_SOURCES_ZIP" + + - name: Prepare tester artifact bundle + env: + HEAD_SHA: ${{ steps.metadata.outputs.head_sha }} + SHORT_SHA: ${{ steps.metadata.outputs.short_sha }} + PR_NUMBER: ${{ steps.metadata.outputs.pr_number }} + REPOSITORY: ${{ steps.metadata.outputs.repository }} + RUN_ID: ${{ github.event.workflow_run.id }} + run: | + set -euo pipefail + + mkdir -p "publish/pull-requests/$PR_NUMBER" + + cp "downloaded/chrome/cloudhood-chrome-$SHORT_SHA.zip" "publish/pull-requests/$PR_NUMBER/chrome.zip" + cp "downloaded/firefox/cloudhood-firefox-$SHORT_SHA.zip" "publish/pull-requests/$PR_NUMBER/firefox.zip" + cp "downloaded/firefox-sources/cloudhood-firefox-sources-$SHORT_SHA.zip" "publish/pull-requests/$PR_NUMBER/firefox-sources.zip" + + cd "publish/pull-requests/$PR_NUMBER" + sha256sum chrome.zip firefox.zip firefox-sources.zip > SHA256SUMS + cat > metadata.json < comment.md <> $GITHUB_OUTPUT + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + SHORT_SHA="$(echo "$HEAD_SHA" | cut -c1-7)" + + echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT" + echo "chrome_artifact=cloudhood-chrome-$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "firefox_artifact=cloudhood-firefox-$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "firefox_sources_artifact=cloudhood-firefox-sources-$HEAD_SHA" >> "$GITHUB_OUTPUT" - name: Build Chrome extension run: pnpm build:chromium @@ -145,60 +155,52 @@ jobs: - name: Pack Chrome build folder to ZIP-file run: | cd build/chrome - zip -r ../../cloudhood-chrome-${{ steps.set_short_sha.outputs.short_sha }}.zip . + zip -r ../../cloudhood-chrome-${{ steps.set_build_metadata.outputs.short_sha }}.zip . - name: Build Firefox extension env: - FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} + FIREFOX_EXTENSION_ID: ${{ vars.FIREFOX_EXTENSION_ID }} run: pnpm build:firefox shell: bash - name: Check Firefox build env: - FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} + FIREFOX_EXTENSION_ID: ${{ vars.FIREFOX_EXTENSION_ID }} run: pnpm check:firefox-build shell: bash - name: Pack Firefox build folder to ZIP-file run: | cd build/firefox - zip -r ../../cloudhood-firefox-${{ steps.set_short_sha.outputs.short_sha }}.zip . + zip -r ../../cloudhood-firefox-${{ steps.set_build_metadata.outputs.short_sha }}.zip . - name: Build Firefox sources ZIP-file run: pnpm run build:firefox-sources shell: bash - name: Rename Firefox sources ZIP-file - run: mv cloudhood-firefox-sources.zip cloudhood-firefox-sources-${{ steps.set_short_sha.outputs.short_sha }}.zip - - - name: Pull request artifacts - uses: gavv/pull-request-artifacts@v1.1.0 - with: - commit: ${{ steps.set_short_sha.outputs.short_sha }} - repo-token: ${{ secrets.GITHUB_TOKEN }} - artifacts-branch: artifacts - artifacts: | - cloudhood-chrome-${{ steps.set_short_sha.outputs.short_sha }}.zip - cloudhood-firefox-${{ steps.set_short_sha.outputs.short_sha }}.zip - cloudhood-firefox-sources-${{ steps.set_short_sha.outputs.short_sha }}.zip + run: mv cloudhood-firefox-sources.zip cloudhood-firefox-sources-${{ steps.set_build_metadata.outputs.short_sha }}.zip - name: Upload Chrome build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: cloudhood-chrome-${{ steps.set_short_sha.outputs.short_sha }} - path: cloudhood-chrome-${{ steps.set_short_sha.outputs.short_sha }}.zip + name: ${{ steps.set_build_metadata.outputs.chrome_artifact }} + path: cloudhood-chrome-${{ steps.set_build_metadata.outputs.short_sha }}.zip + retention-days: 14 - name: Upload Firefox build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: cloudhood-firefox-${{ steps.set_short_sha.outputs.short_sha }} - path: cloudhood-firefox-${{ steps.set_short_sha.outputs.short_sha }}.zip + name: ${{ steps.set_build_metadata.outputs.firefox_artifact }} + path: cloudhood-firefox-${{ steps.set_build_metadata.outputs.short_sha }}.zip + retention-days: 14 - name: Upload Firefox sources artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: cloudhood-firefox-sources-${{ steps.set_short_sha.outputs.short_sha }} - path: cloudhood-firefox-sources-${{ steps.set_short_sha.outputs.short_sha }}.zip + name: ${{ steps.set_build_metadata.outputs.firefox_sources_artifact }} + path: cloudhood-firefox-sources-${{ steps.set_build_metadata.outputs.short_sha }}.zip + retention-days: 14 e2e-test: runs-on: ubuntu-latest @@ -227,11 +229,6 @@ jobs: if: steps.e2e_changes.outputs.run_e2e != 'true' run: echo "Skipping extension E2E tests because this PR does not change extension runtime, E2E, or screenshot inputs." - - name: Set short SHA - if: steps.e2e_changes.outputs.run_e2e == 'true' - id: set_short_sha - run: echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT - - name: Setup pnpm if: steps.e2e_changes.outputs.run_e2e == 'true' uses: pnpm/action-setup@v2 @@ -251,9 +248,9 @@ jobs: - name: Download Chrome build artifact if: steps.e2e_changes.outputs.run_e2e == 'true' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: - name: cloudhood-chrome-${{ needs.pr-build.outputs.short_sha }} + name: ${{ needs.pr-build.outputs.chrome_artifact }} - name: Extract Chrome extension if: steps.e2e_changes.outputs.run_e2e == 'true' @@ -263,9 +260,9 @@ jobs: - name: Download Firefox build artifact if: steps.e2e_changes.outputs.run_e2e == 'true' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: - name: cloudhood-firefox-${{ needs.pr-build.outputs.short_sha }} + name: ${{ needs.pr-build.outputs.firefox_artifact }} - name: Extract Firefox extension if: steps.e2e_changes.outputs.run_e2e == 'true' @@ -289,7 +286,7 @@ jobs: if: steps.e2e_changes.outputs.run_e2e == 'true' run: docker compose -f docker-compose.screenshots.yml run --rm screenshots sh -lc "pnpm install --frozen-lockfile && pnpm build && pnpm test:e2e:screenshots" - pre-publish: + validate-build-artifacts: needs: [pr-build, e2e-test] runs-on: ubuntu-latest steps: @@ -297,21 +294,21 @@ jobs: uses: actions/checkout@v3 - name: Download Chrome build artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: - name: cloudhood-chrome-${{ needs.pr-build.outputs.short_sha }} + name: ${{ needs.pr-build.outputs.chrome_artifact }} path: dist/chrome - name: Download Firefox build artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: - name: cloudhood-firefox-${{ needs.pr-build.outputs.short_sha }} + name: ${{ needs.pr-build.outputs.firefox_artifact }} path: dist/firefox - name: Download Firefox sources artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: - name: cloudhood-firefox-sources-${{ needs.pr-build.outputs.short_sha }} + name: ${{ needs.pr-build.outputs.firefox_sources_artifact }} path: dist/firefox-sources - name: Extract builds for release checks @@ -322,36 +319,5 @@ jobs: - name: Check release builds env: - FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} + FIREFOX_EXTENSION_ID: ${{ vars.FIREFOX_EXTENSION_ID }} run: node scripts/check-extension-builds.mjs - - - name: Publish Chrome Extension (Dry Run) - env: - CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} - CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }} - CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }} - CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }} - CHROME_PUBLISH_TARGET: ${{ secrets.CHROME_PUBLISH_TARGET }} - run: | - npx --yes publish-browser-extension@4.0.4 \ - --dry-run \ - --chrome-zip dist/chrome/cloudhood-chrome-${{ needs.pr-build.outputs.short_sha }}.zip \ - --chrome-extension-id ${{ env.CHROME_EXTENSION_ID }} \ - --chrome-client-id ${{ env.CHROME_CLIENT_ID }} \ - --chrome-client-secret ${{ env.CHROME_CLIENT_SECRET }} \ - --chrome-refresh-token ${{ env.CHROME_REFRESH_TOKEN }} \ - --chrome-publish-target ${{ env.CHROME_PUBLISH_TARGET }} - - - name: Publish Firefox Extension (Dry Run) - env: - FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} - FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }} - FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }} - run: | - npx --yes publish-browser-extension@4.0.4 \ - --dry-run \ - --firefox-zip dist/firefox/cloudhood-firefox-${{ needs.pr-build.outputs.short_sha }}.zip \ - --firefox-sources-zip dist/firefox-sources/cloudhood-firefox-sources-${{ needs.pr-build.outputs.short_sha }}.zip \ - --firefox-extension-id ${{ env.FIREFOX_EXTENSION_ID }} \ - --firefox-jwt-issuer ${{ env.FIREFOX_JWT_ISSUER }} \ - --firefox-jwt-secret ${{ env.FIREFOX_JWT_SECRET }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c21bcff..6dd38840 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -83,7 +83,7 @@ jobs: git push origin "$TAG" - name: Upload release artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: cloudhood-${{ steps.release.outputs.tag }} path: | @@ -99,7 +99,7 @@ jobs: contents: write steps: - name: Download release artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: cloudhood-${{ needs.build.outputs.tag }} @@ -119,7 +119,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download release artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: cloudhood-${{ needs.build.outputs.tag }} @@ -144,7 +144,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download release artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: cloudhood-${{ needs.build.outputs.tag }}