From eec2bf882b939aa081b80c64a5104a3e8ab88c16 Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Fri, 13 May 2022 14:15:12 +0200 Subject: [PATCH] chore: set up daily jobs for latest Chromium builds (#8344) --- .github/workflows/tot.yml | 75 ++++++++++++++++++++++++ src/node/BrowserFetcher.ts | 22 +++++--- utils/check_availability.js | 110 +++++++++++++++++++++++------------- 3 files changed, 161 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/tot.yml diff --git a/.github/workflows/tot.yml b/.github/workflows/tot.yml new file mode 100644 index 00000000..d4f51b03 --- /dev/null +++ b/.github/workflows/tot.yml @@ -0,0 +1,75 @@ +name: run-tot-checks +# Checks Puppeteer against the latest ToT build of Chromium. +# Declare default permissions as read only. +permissions: read-all + +on: + schedule: + # * is a special character in YAML so you have to quote this string + # Supposed to be every day at 8 am (UTC). + - cron: '0 8 * * *' + +jobs: + linux-tot-checks: + # https://github.com/actions/virtual-environments#available-environments + runs-on: ubuntu-latest + strategy: + matrix: + node: [16] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Set up Node.js + uses: actions/setup-node@v3.1.1 + with: + node-version: ${{ matrix.node }} + + - name: Install dependencies and build + run: | + sudo apt-get install xvfb + # Ensure both a Chromium and a Firefox binary are available. + PUPPETEER_PRODUCT=firefox npm install + npm install + ls .local-chromium .local-firefox + REV=$(node utils/check_availability.js -p linux) + echo "Installing revision $REV" + cat src/revisions.ts | sed "s/[0-9]\{6,\}/$REV/" > src/revisions.ts.replaced + mv src/revisions.ts.replaced src/revisions.ts + npm run build + npm install + + - name: Run unit tests in headless + uses: nick-invision/retry@v2 + env: + CHROMIUM: true + HEADLESS: true + with: + max_attempts: 1 + command: xvfb-run --auto-servernum npm run unit + timeout_minutes: 10 + + - name: Run unit tests in headful + uses: nick-invision/retry@v2 + if: always() + needs: [job1, job2, job3] + env: + CHROMIUM: true + HEADLESS: false + with: + max_attempts: 1 + command: xvfb-run --auto-servernum npm run unit + timeout_minutes: 10 + + - name: Run unit tests in chrome headless + uses: nick-invision/retry@v2 + if: always() + needs: [job1, job2, job3] + env: + CHROMIUM: true + with: + max_attempts: 1 + command: xvfb-run --auto-servernum npm run chrome-headless-unit + timeout_minutes: 10 diff --git a/src/node/BrowserFetcher.ts b/src/node/BrowserFetcher.ts index fdd89da0..2ee64372 100644 --- a/src/node/BrowserFetcher.ts +++ b/src/node/BrowserFetcher.ts @@ -277,9 +277,14 @@ export class BrowserFetcher { revision ); return new Promise((resolve) => { - const request = httpRequest(url, 'HEAD', (response) => { - resolve(response.statusCode === 200); - }); + const request = httpRequest( + url, + 'HEAD', + (response) => { + resolve(response.statusCode === 200); + }, + false + ); request.on('error', (error) => { console.error(error); resolve(false); @@ -575,7 +580,8 @@ function installDMG(dmgPath: string, folderPath: string): Promise { function httpRequest( url: string, method: string, - response: (x: http.IncomingMessage) => void + response: (x: http.IncomingMessage) => void, + keepAlive = true ): http.ClientRequest { const urlParsed = URL.parse(url); @@ -589,9 +595,11 @@ function httpRequest( let options: Options = { ...urlParsed, method, - headers: { - Connection: 'keep-alive', - }, + headers: keepAlive + ? { + Connection: 'keep-alive', + } + : undefined, }; const proxyURL = getProxyForUrl(url); diff --git a/utils/check_availability.js b/utils/check_availability.js index f9cf0226..e848eadd 100755 --- a/utils/check_availability.js +++ b/utils/check_availability.js @@ -22,9 +22,6 @@ const BrowserFetcher = require('../lib/cjs/puppeteer/node/BrowserFetcher.js').BrowserFetcher; const SUPPORTED_PLATFORMS = ['linux', 'mac', 'mac_arm', 'win32', 'win64']; -const fetchers = SUPPORTED_PLATFORMS.map( - (platform) => new BrowserFetcher('', { platform }) -); const colors = { reset: '\x1b[0m', @@ -59,10 +56,13 @@ This script checks availability of prebuilt Chromium snapshots. Usage: node check_availability.js [] [] options - -f full mode checks availability of all the platforms, default mode - -r roll mode checks for the most recent stable Chromium roll candidate - -rb roll mode checks for the most recent beta Chromium roll candidate - -rd roll mode checks for the most recent dev Chromium roll candidate + -f full mode checks availability of all the platforms, default mode + -r roll mode checks for the most recent stable Chromium roll candidate + -rb roll mode checks for the most recent beta Chromium roll candidate + -rd roll mode checks for the most recent dev Chromium roll candidate + -p $platform print the latest revision for the given platform (${SUPPORTED_PLATFORMS.join( + ',' + )}). -h show this help browser version(s) @@ -108,6 +108,9 @@ function main() { case 'rd': checkRollCandidate('dev'); return; + case 'p': + printLatestRevisionForPlatform(args[1]); + return; default: console.log(helpMessage); return; @@ -154,12 +157,43 @@ async function checkOmahaProxyAvailability() { ]) ).map((s) => parseInt(s, 10)); const from = Math.max(...latestRevisions); - checkRangeAvailability({ + await checkRangeAvailability({ fromRevision: from, toRevision: 0, stopWhenAllAvailable: false, }); } + +async function printLatestRevisionForPlatform(platform) { + const latestRevisions = ( + await Promise.all([ + fetch( + 'https://storage.googleapis.com/chromium-browser-snapshots/Mac/LAST_CHANGE' + ), + fetch( + 'https://storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/LAST_CHANGE' + ), + fetch( + 'https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/LAST_CHANGE' + ), + fetch( + 'https://storage.googleapis.com/chromium-browser-snapshots/Win/LAST_CHANGE' + ), + fetch( + 'https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/LAST_CHANGE' + ), + ]) + ).map((s) => parseInt(s, 10)); + const from = Math.max(...latestRevisions); + await checkRangeAvailability({ + fromRevision: from, + toRevision: 0, + stopWhenAllAvailable: true, + printAsTable: false, + platforms: [platform], + }); +} + async function checkRollCandidate(channel) { const omahaResponse = await fetch( `https://omahaproxy.appspot.com/all.json?channel=${channel}&os=linux` @@ -193,9 +227,19 @@ async function checkRangeAvailability({ fromRevision, toRevision, stopWhenAllAvailable, + platforms, + printAsTable = true, }) { - const table = new Table([10, 7, 7, 7, 7, 7]); - table.drawRow([''].concat(SUPPORTED_PLATFORMS)); + platforms = platforms || SUPPORTED_PLATFORMS; + let table; + if (printAsTable) { + table = new Table([10, ...platforms.map(() => 7)]); + table.drawRow([''].concat(platforms)); + } + + const fetchers = platforms.map( + (platform) => new BrowserFetcher('', { platform }) + ); const inc = fromRevision < toRevision ? 1 : -1; const revisionToStop = toRevision + inc; // +inc so the range is fully inclusive @@ -204,39 +248,27 @@ async function checkRangeAvailability({ revision !== revisionToStop; revision += inc ) { - const allAvailable = await checkAndDrawRevisionAvailability( - table, - '', - revision - ); + const promises = fetchers.map((fetcher) => fetcher.canDownload(revision)); + const availability = await Promise.all(promises); + const allAvailable = availability.every((e) => !!e); + if (table) { + const values = [ + ' ' + + (allAvailable ? colors.green + revision + colors.reset : revision), + ]; + for (let i = 0; i < availability.length; ++i) { + const decoration = availability[i] ? '+' : '-'; + const color = availability[i] ? colors.green : colors.red; + values.push(color + decoration + colors.reset); + } + table.drawRow(values); + } else { + if (allAvailable) console.log(revision); + } if (allAvailable && stopWhenAllAvailable) break; } } -/** - * @param {!Table} table - * @param {string} name - * @param {number} revision - * @returns {boolean} - */ -async function checkAndDrawRevisionAvailability(table, name, revision) { - const promises = fetchers.map((fetcher) => fetcher.canDownload(revision)); - const availability = await Promise.all(promises); - const allAvailable = availability.every((e) => !!e); - const values = [ - name + - ' ' + - (allAvailable ? colors.green + revision + colors.reset : revision), - ]; - for (let i = 0; i < availability.length; ++i) { - const decoration = availability[i] ? '+' : '-'; - const color = availability[i] ? colors.green : colors.red; - values.push(color + decoration + colors.reset); - } - table.drawRow(values); - return allAvailable; -} - /** * @param {string} url * @returns {!Promise}