From 7a765e9fab53c99503a4450988ff3b007f78c7a2 Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com> Date: Thu, 1 Jun 2023 10:13:42 +0200 Subject: [PATCH] ci: automate PR for Chrome roll (#10287) --- .github/workflows/update-browser-pins.yml | 46 ++++++++++ tools/update_chrome_revision.mjs | 103 ++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 .github/workflows/update-browser-pins.yml create mode 100644 tools/update_chrome_revision.mjs diff --git a/.github/workflows/update-browser-pins.yml b/.github/workflows/update-browser-pins.yml new file mode 100644 index 00000000000..b6148111d8a --- /dev/null +++ b/.github/workflows/update-browser-pins.yml @@ -0,0 +1,46 @@ +# This workflow will update the pinned browsers + +name: 'Update the pinned browsers' + +on: + schedule: + # Run everyday at: https://crontab.guru/#0_6_*_*_*. + - cron: '0 6 * * *' + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v3.3.0 + - name: Set up Node.js + uses: actions/setup-node@v3.5.1 + with: + cache: npm + node-version: lts/* + - uses: google/wireit@setup-github-actions-caching/v1 + - name: Install npm dependencies + run: npm ci + - name: Build Puppeteer + run: npm run build -w puppeteer + - name: Update Chrome to latest stable version + id: update + run: | + node --experimental-fetch tools/update_chrome_revision.mjs + - name: Format files if needed + run: npm run format + - name: Update package-lock.json + run: npm install --ignore-scripts + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.BROWSER_AUTOMATION_BOT_TOKEN }} + branch: browser-automation-bot/update-browser-version + delete-branch: true + committer: Browser Automation Bot + author: Browser Automation Bot + commit-message: 'feat(chrome): roll to Chrome ${{ steps.update.outputs.version }} (r${{ steps.update.outputs.revision }} )' + title: 'feat(chrome): roll to Chrome ${{ steps.update.outputs.version }} (r${{ steps.update.outputs.revision }} )' + body: 'Automatically generated by https://github.com/puppeteer/puppeteer/blob/main/.github/workflows/update-browser-pins.yml' + labels: dependencies diff --git a/tools/update_chrome_revision.mjs b/tools/update_chrome_revision.mjs new file mode 100644 index 00000000000..2e48b55da3e --- /dev/null +++ b/tools/update_chrome_revision.mjs @@ -0,0 +1,103 @@ +/** + * Copyright 2023 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {execSync} from 'child_process'; +import {writeFile, readFile} from 'fs/promises'; + +import actions from '@actions/core'; +import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; + +import packageJson from '../packages/puppeteer-core/package.json' assert {type: 'json'}; +import {versionsPerRelease, lastMaintainedChromeVersion} from '../versions.js'; + +const CHROME_CURRENT_VERSION = PUPPETEER_REVISIONS.chrome; +const VERSIONS_PER_RELEASE_COMMENT = + '// In Chrome roll patches, use `NEXT` for the Puppeteer version.'; + +async function replaceInFile(filePath, search, replace) { + const buffer = await readFile(filePath); + const update = buffer.toString().replace(search, replace); + + await writeFile(filePath, update); +} + +async function getVersionAndRevisionForStable() { + const result = await fetch( + 'https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions.json' + ).then(response => { + return response.json(); + }); + + const {version, revision} = result.channels['Stable']; + + return { + version, + revision, + }; +} + +async function updateDevToolsProtocolVersion(revision) { + const currentProtocol = packageJson.dependencies['devtools-protocol']; + const command = `npm view "devtools-protocol@<=0.0.${revision}" version | tail -1`; + + const bestNewProtocol = execSync(command, { + encoding: 'utf8', + }) + .split(' ')[1] + .replace(/'|\n/g, ''); + + await replaceInFile( + './packages/puppeteer-core/package.json', + `"devtools-protocol": "${currentProtocol}"`, + `"devtools-protocol": "${bestNewProtocol}"` + ); +} + +async function updateVersionFileLastMaintained(updateVersion) { + const versions = [...versionsPerRelease.keys()]; + if (version.indexOf(updateVersion) !== -1) { + return; + } + + await replaceInFile( + './versions.js', + VERSIONS_PER_RELEASE_COMMENT, + `${VERSIONS_PER_RELEASE_COMMENT}\n ['${version}', 'NEXT'],` + ); + + const lastMaintainedIndex = versions.indexOf(lastMaintainedChromeVersion); + const nextMaintainedVersion = versions[lastMaintainedIndex - 1]; + + await replaceInFile( + './versions.js', + `const lastMaintainedChromeVersion = '${lastMaintainedChromeVersion}';`, + `const lastMaintainedChromeVersion = '${nextMaintainedVersion}';` + ); +} + +const {version, revision} = await getVersionAndRevisionForStable(); + +await replaceInFile( + './packages/puppeteer-core/src/revisions.ts', + CHROME_CURRENT_VERSION, + version +); + +await updateVersionFileLastMaintained(version); +await updateDevToolsProtocolVersion(revision); + +actions.setOutput('version', version); +actions.setOutput('revision', revision);