diff --git a/.github/workflows/tagged-release.yml b/.github/workflows/tagged-release.yml index e0d1de2b9..f7ae4bfb2 100644 --- a/.github/workflows/tagged-release.yml +++ b/.github/workflows/tagged-release.yml @@ -23,7 +23,6 @@ on: - "v*" permissions: - id-token: "write" contents: "write" env: GH_TOKEN: ${{ github.token }} @@ -94,6 +93,15 @@ jobs: - run: npm run release:firefox-sources + - name: Upload Chrome package artifact + if: github.event_name == 'push' || inputs.submit_stores == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: chrome-extension + path: build/chromium.zip + if-no-files-found: error + retention-days: 30 + - if: github.event_name == 'push' run: | gh release upload ${{github.ref_name}} build/chromium.zip @@ -115,13 +123,7 @@ jobs: fi npm run release:submit -- "${args[@]}" 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 }} - CHROME_DEPLOY_PERCENTAGE: ${{ secrets.CHROME_DEPLOY_PERCENTAGE }} - CHROME_REVIEW_EXEMPTION: ${{ secrets.CHROME_REVIEW_EXEMPTION }} + CHROME_PUBLISH_VIA_ACTION: "true" FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }} FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }} @@ -134,3 +136,38 @@ jobs: - if: github.event_name == 'push' run: | gh release edit ${{github.ref_name}} --draft=false + + publish_chrome: + if: github.event_name == 'push' || inputs.submit_stores == 'true' + needs: build_and_release + runs-on: ubuntu-latest + environment: chrome-web-store + permissions: + id-token: "write" + concurrency: + group: chrome-web-store + cancel-in-progress: false + queue: max + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: chrome-extension + - id: auth + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3 + with: + workload_identity_provider: ${{ vars.CWS_WIF_PROVIDER }} + service_account: ${{ vars.CWS_SERVICE_ACCOUNT }} + token_format: access_token + access_token_scopes: https://www.googleapis.com/auth/chromewebstore + access_token_lifetime: 1800s + create_credentials_file: false + export_environment_variables: false + - uses: hamzahamidi/publish-to-chrome-web-store@c8919147f8de0d6f1129bec36345e4a9aa638af9 # v1 + with: + access-token: ${{ steps.auth.outputs.access_token }} + publisher-id: ${{ vars.CWS_PUBLISHER_ID }} + item-id: ${{ secrets.CHROME_EXTENSION_ID }} + zip: chromium.zip + deploy-percentage: ${{ secrets.CHROME_DEPLOY_PERCENTAGE }} + skip-review: ${{ secrets.CHROME_REVIEW_EXEMPTION }} + dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == 'true' }} diff --git a/scripts/submit-stores.mjs b/scripts/submit-stores.mjs index 1a64f1722..3552b5f14 100644 --- a/scripts/submit-stores.mjs +++ b/scripts/submit-stores.mjs @@ -32,6 +32,12 @@ const REQUIRED_ENV = [ 'EDGE_CLIENT_ID', 'EDGE_API_KEY', ] +const CHROME_ENV = [ + 'CHROME_EXTENSION_ID', + 'CHROME_CLIENT_ID', + 'CHROME_CLIENT_SECRET', + 'CHROME_REFRESH_TOKEN', +] export function parseArgs(args) { return { @@ -40,7 +46,12 @@ export function parseArgs(args) { } export function findMissingEnv(env = process.env) { - return REQUIRED_ENV.filter((name) => { + const requiredEnv = + env.CHROME_PUBLISH_VIA_ACTION === 'true' + ? REQUIRED_ENV.filter((name) => !CHROME_ENV.includes(name)) + : REQUIRED_ENV + + return requiredEnv.filter((name) => { const value = env[name] return typeof value !== 'string' || value.trim().length === 0 }) @@ -58,11 +69,10 @@ export async function findMissingArtifacts({ exists = fs.pathExists } = {}) { return missing } -export function buildPublishExtensionArgs({ dryRun }) { +export function buildPublishExtensionArgs({ dryRun, skipChrome = false }) { return [ ...(dryRun ? ['--dry-run'] : []), - '--chrome-zip', - 'build/chromium.zip', + ...(!skipChrome ? ['--chrome-zip', 'build/chromium.zip'] : []), '--firefox-zip', 'build/firefox.zip', '--firefox-sources-zip', @@ -199,10 +209,12 @@ export async function submitStores({ argv = process.argv.slice(2), env = process } const manifest = await fs.readJson('build/firefox/manifest.json') - const args = buildPublishExtensionArgs({ dryRun }) + const skipChrome = env.CHROME_PUBLISH_VIA_ACTION === 'true' + const args = buildPublishExtensionArgs({ dryRun, skipChrome }) const firefoxReleaseNotes = buildFirefoxReleaseNotes(manifest.version) + const stores = skipChrome ? 'Firefox and Edge' : 'Chrome, Firefox, and Edge' - console.log(`Submitting ChatGPTBox ${manifest.version} to Chrome, Firefox, and Edge`) + console.log(`Submitting ChatGPTBox ${manifest.version} to ${stores}`) console.log(`Mode: ${dryRun ? 'dry-run' : 'submit'}`) console.log(`Artifacts: ${REQUIRED_ARTIFACTS.join(', ')}`) console.log(`Firefox version notes: ${firefoxReleaseNotes}`) diff --git a/tests/unit/release/submit-stores.test.mjs b/tests/unit/release/submit-stores.test.mjs index dddfcb3d1..331770ae3 100644 --- a/tests/unit/release/submit-stores.test.mjs +++ b/tests/unit/release/submit-stores.test.mjs @@ -68,6 +68,47 @@ test('findMissingEnv accepts required secrets', () => { assert.deepEqual(findMissingEnv(env), []) }) +test('findMissingEnv does not require Chrome credentials when publishing through the action', () => { + const env = { + CHROME_PUBLISH_VIA_ACTION: 'true', + FIREFOX_EXTENSION_ID: 'chatgptbox', + FIREFOX_JWT_ISSUER: 'firefox-issuer', + FIREFOX_JWT_SECRET: 'firefox-secret', + EDGE_PRODUCT_ID: 'edge-product', + EDGE_CLIENT_ID: 'edge-client', + EDGE_API_KEY: 'edge-key', + } + + assert.deepEqual(findMissingEnv(env), []) +}) + +test('findMissingEnv still requires Firefox and Edge credentials when publishing Chrome through the action', () => { + const requiredStoreEnv = [ + 'FIREFOX_EXTENSION_ID', + 'FIREFOX_JWT_ISSUER', + 'FIREFOX_JWT_SECRET', + 'EDGE_PRODUCT_ID', + 'EDGE_CLIENT_ID', + 'EDGE_API_KEY', + ] + const env = { + CHROME_PUBLISH_VIA_ACTION: 'true', + FIREFOX_EXTENSION_ID: 'chatgptbox', + FIREFOX_JWT_ISSUER: 'firefox-issuer', + FIREFOX_JWT_SECRET: 'firefox-secret', + EDGE_PRODUCT_ID: 'edge-product', + EDGE_CLIENT_ID: 'edge-client', + EDGE_API_KEY: 'edge-key', + } + + for (const name of requiredStoreEnv) { + const envWithoutStoreValue = { ...env } + delete envWithoutStoreValue[name] + + assert.deepEqual(findMissingEnv(envWithoutStoreValue), [name]) + } +}) + test('findMissingEnv treats whitespace-only secrets as missing', () => { const env = { CHROME_EXTENSION_ID: 'chrome-id', @@ -108,6 +149,19 @@ test('buildPublishExtensionArgs includes all stores and dry run', () => { ]) }) +test('buildPublishExtensionArgs skips Chrome when it is published through the action', () => { + const args = buildPublishExtensionArgs({ dryRun: false, skipChrome: true }) + + assert.deepEqual(args, [ + '--firefox-zip', + 'build/firefox.zip', + '--firefox-sources-zip', + 'build/firefox-sources.zip', + '--edge-zip', + 'build/chromium.zip', + ]) +}) + test('buildFirefoxReleaseNotes returns the fixed GitHub release URL', () => { assert.equal( buildFirefoxReleaseNotes('2.6.1'),