chore: Check for and update tested-against Chrome versions (#16549)

This commit is contained in:
Chris Breiding
2021-05-19 11:13:54 -04:00
committed by GitHub
parent fca9b9aeb0
commit d20cb93b4d
5 changed files with 639 additions and 3 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
# Each line is a file pattern followed by one or more owners.
# Test Runner team are owners of code within root packages and cli
/browser-versions.json @cypress-io/test-runner
/cli/ @cypress-io/test-runner
/packages/coffee/ @cypress-io/test-runner
/packages/datetime-utils/ @cypress-io/test-runner
@@ -23,4 +24,4 @@
/packages/static/ @cypress-io/test-runner
/packages/ts/ @cypress-io/test-runner
/packages/ui-components/ @cypress-io/test-runner
/packages/web-config/ @cypress-io/test-runner
/packages/web-config/ @cypress-io/test-runner
@@ -0,0 +1,119 @@
name: Update Browser Versions
on:
schedule:
- cron: '0 8 * * *' # every day at 8am UTC (3/4am EST/EDT)
jobs:
update-browser-versions:
runs-on: ubuntu-latest
env:
CYPRESS_BOT_APP_ID: ${{ secrets.CYPRESS_BOT_APP_ID }}
BASE_BRANCH: develop
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.DEVELOP_PUSH_TOKEN }}
- name: Set committer info
## attribute the commit to cypress-bot: https://github.community/t/logging-into-git-as-a-github-app/115916
run: |
git config --local user.email "${{ env.CYPRESS_BOT_APP_ID }}+cypress-bot[bot]@users.noreply.github.com"
git config --local user.name "cypress-bot[bot]"
- name: Checkout base branch
run: |
git fetch origin
git checkout ${{ env.BASE_BRANCH }}
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 14
- name: Check for new Chrome versions
id: get-versions
uses: actions/github-script@v4
with:
script: |
const { getVersions } = require('./scripts/github-actions/update-browser-versions.js')
getVersions({ core })
- name: Determine name of new branch and if it already exists
id: check-branch
env:
BRANCH_NAME: update-chrome-stable-from-${{ steps.get-versions.outputs.current_stable_version }}-beta-from-${{ steps.get-versions.outputs.current_beta_version }}
run: |
echo "::set-output name=branch_name::${{ env.BRANCH_NAME }}"
echo "::set-output name=branch_exists::$(git show-ref --verify --quiet refs/remotes/origin/${{ env.BRANCH_NAME }} && echo 'true')"
- name: Check need for PR or branch update
id: check-need-for-pr
run: |
echo "::set-output name=needs_pr::${{ steps.get-versions.outputs.has_update == 'true' && steps.check-branch.outputs.branch_exists != 'true' }}"
echo "::set-output name=needs_branch_update::${{ steps.get-versions.outputs.has_update == 'true' && steps.check-branch.outputs.branch_exists == 'true' }}"
## Update available and a branch/PR already exists
- name: Checkout existing branch
if: ${{ steps.check-need-for-pr.outputs.needs_branch_update == 'true' }}
run: git checkout ${{ steps.check-branch.outputs.branch_name }}
- name: Check need for update on existing branch
if: ${{ steps.check-need-for-pr.outputs.needs_branch_update == 'true' }}
id: check-need-for-branch-update
uses: actions/github-script@v4
with:
script: |
const { checkNeedForBranchUpdate } = require('./scripts/github-actions/update-browser-versions.js')
checkNeedForBranchUpdate({
core,
latestStableVersion: '${{ steps.get-versions.outputs.latest_stable_version }}',
latestBetaVersion: '${{ steps.get-versions.outputs.latest_beta_version }}',
})
## Update available and a PR doesn't already exist
- name: Checkout new branch
if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' }}
run: git checkout -b ${{ steps.check-branch.outputs.branch_name }} ${{ env.BASE_BRANCH }}
## Both
- name: Update Browser Versions File
if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' || steps.check-need-for-branch-update.outputs.has_newer_update == 'true' }}
uses: actions/github-script@v4
with:
script: |
const { updateBrowserVersionsFile } = require('./scripts/github-actions/update-browser-versions.js')
updateBrowserVersionsFile({
latestStableVersion: '${{ steps.get-versions.outputs.latest_stable_version }}',
latestBetaVersion: '${{ steps.get-versions.outputs.latest_beta_version }}',
})
- name: Commit the changes
if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' || steps.check-need-for-branch-update.outputs.has_newer_update == 'true' }}
run: |
git commit -am "chore: ${{ steps.get-versions.outputs.description }}"
- name: Push branch to remote
if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' || steps.check-need-for-branch-update.outputs.has_newer_update == 'true' }}
run: git push origin ${{ steps.check-branch.outputs.branch_name }}
## Update available and a branch/PR already exists
- name: Update PR Title
if: ${{ steps.check-need-for-pr.outputs.needs_branch_update == 'true' }}
uses: actions/github-script@v4
with:
script: |
const { updatePRTitle } = require('./scripts/github-actions/update-browser-versions.js')
await updatePRTitle({
context,
github,
baseBranch: '${{ env.BASE_BRANCH }}',
branchName: '${{ steps.check-branch.outputs.branch_name }}',
description: '${{ steps.get-versions.outputs.description }}',
})
# Update available and a PR doesn't already exist
- name: Create Pull Request
if: ${{ steps.check-need-for-pr.outputs.needs_pr == 'true' }}
uses: actions/github-script@v4
with:
script: |
const { createPullRequest } = require('./scripts/github-actions/update-browser-versions.js')
await createPullRequest({
context,
github,
baseBranch: '${{ env.BASE_BRANCH }}',
branchName: '${{ steps.check-branch.outputs.branch_name }}',
description: '${{ steps.get-versions.outputs.description }}',
})
+2 -2
View File
@@ -1,4 +1,4 @@
{
"chrome:stable": "90.0.4430.212",
"chrome:beta": "91.0.4472.57"
"chrome:beta": "91.0.4472.57",
"chrome:stable": "90.0.4430.212"
}
@@ -0,0 +1,130 @@
const https = require('https')
const fs = require('fs')
const getLatestVersionData = () => {
const options = {
hostname: 'omahaproxy.appspot.com',
port: 443,
path: '/all.json',
method: 'GET',
}
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let response = ''
res.on('data', (d) => {
response += d.toString()
})
res.on('end', () => {
resolve(response)
})
})
req.on('error', (err) => {
reject(err)
})
req.end()
})
}
const getVersions = async ({ core }) => {
try {
// file path is relative to repo root
const currentBrowserVersions = JSON.parse(fs.readFileSync('./browser-versions.json'))
const data = JSON.parse(await getLatestVersionData())
const linuxData = data.find((item) => item.os === 'linux')
const stableData = linuxData.versions.find((version) => version.channel === 'stable')
const betaData = linuxData.versions.find((version) => version.channel === 'beta')
const hasStableUpdate = currentBrowserVersions['chrome:stable'] !== stableData.version
const hasBetaUpdate = currentBrowserVersions['chrome:beta'] !== betaData.version
let description = 'Update '
if (hasStableUpdate) {
description += `Chrome (stable) to ${stableData.version}`
if (hasBetaUpdate) {
description += ' and '
}
}
if (hasBetaUpdate) {
description += `Chrome (beta) to ${betaData.version}`
}
core.setOutput('has_update', (hasStableUpdate || hasBetaUpdate) ? 'true' : 'false')
core.setOutput('current_stable_version', currentBrowserVersions['chrome:stable'])
core.setOutput('latest_stable_version', stableData.version)
core.setOutput('current_beta_version', currentBrowserVersions['chrome:beta'])
core.setOutput('latest_beta_version', betaData.version)
core.setOutput('description', description)
} catch (err) {
// eslint-disable-next-line no-console
console.log('Errored checking for new Chrome versions:', err.stack)
core.setOutput('has_update', 'false')
}
}
const checkNeedForBranchUpdate = ({ core, latestStableVersion, latestBetaVersion }) => {
// file path is relative to repo root
const branchBrowserVersions = JSON.parse(fs.readFileSync('./browser-versions.json'))
const hasNewerStableVersion = branchBrowserVersions['chrome:stable'] !== latestStableVersion
const hasNewerBetaVersion = branchBrowserVersions['chrome:beta'] !== latestBetaVersion
core.setOutput('has_newer_update', (hasNewerStableVersion || hasNewerBetaVersion) ? 'true' : 'false')
}
const updateBrowserVersionsFile = ({ latestBetaVersion, latestStableVersion }) => {
const versions = {
'chrome:beta': latestBetaVersion,
'chrome:stable': latestStableVersion,
}
// file path is relative to repo root
fs.writeFileSync('./browser-versions.json', `${JSON.stringify(versions, null, 2) }\n`)
}
const updatePRTitle = async ({ context, github, baseBranch, branchName, description }) => {
const { data } = await github.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
base: baseBranch,
head: `${context.repo.owner}:${branchName}`,
})
if (!data.length) {
// eslint-disable-next-line no-console
console.log('Could not find PR for branch:', branchName)
return
}
await github.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: data[0].number,
title: `chore: ${description}`,
})
}
const createPullRequest = async ({ context, github, baseBranch, branchName, description }) => {
await github.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
base: baseBranch,
head: branchName,
title: `chore: ${description}`,
body: 'This PR was auto-generated to update the version(s) of Chrome for driver tests',
maintainer_can_modify: true,
})
}
module.exports = {
getVersions,
checkNeedForBranchUpdate,
updateBrowserVersionsFile,
updatePRTitle,
createPullRequest,
}
@@ -0,0 +1,386 @@
const chai = require('chai')
const fs = require('fs')
const mockfs = require('mock-fs')
const nock = require('nock')
const sinon = require('sinon')
chai.use(require('sinon-chai'))
const { expect } = chai
const {
getVersions,
checkNeedForBranchUpdate,
updateBrowserVersionsFile,
updatePRTitle,
createPullRequest,
} = require('../../github-actions/update-browser-versions')
const coreStub = () => {
return {
setOutput: sinon.stub(),
}
}
const stubOmahaResult = (result) => {
nock('https://omahaproxy.appspot.com')
.get('/all.json')
.reply(200, result)
}
const stubRepoVersions = ({ betaVersion, stableVersion }) => {
mockfs({
'./browser-versions.json': JSON.stringify({
'chrome:beta': betaVersion,
'chrome:stable': stableVersion,
}),
})
}
const stubOmahaVersions = ({ betaVersion, stableVersion }) => {
stubOmahaResult([
{
os: 'linux',
versions: [
{
channel: 'stable',
version: stableVersion,
},
{
channel: 'beta',
version: betaVersion,
},
],
},
])
}
describe('update browser version github action', () => {
beforeEach(() => {
sinon.restore()
mockfs.restore()
nock.cleanAll()
})
context('.getVersions', () => {
beforeEach(() => {
stubRepoVersions({
betaVersion: '1.1',
stableVersion: '1.0',
})
})
it('sets has_update: true when there is a stable update', async () => {
stubOmahaVersions({
betaVersion: '1.1',
stableVersion: '2.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('has_update', 'true')
})
it('sets has_update: true when there is a beta update', async () => {
stubOmahaVersions({
betaVersion: '1.2',
stableVersion: '1.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('has_update', 'true')
})
it('sets has_update: true when there is a stable update and a beta update', async () => {
stubOmahaVersions({
betaVersion: '2.1',
stableVersion: '2.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('has_update', 'true')
})
it('sets has_update: false when there is not a stable update or a beta update', async () => {
stubOmahaVersions({
betaVersion: '1.1',
stableVersion: '1.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('has_update', 'false')
})
it('sets has_update: false if there is a failure', async () => {
stubOmahaResult({})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('has_update', 'false')
})
it('sets versions', async () => {
stubOmahaVersions({
betaVersion: '2.1',
stableVersion: '2.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('current_stable_version', '1.0')
expect(core.setOutput).to.be.calledWith('latest_stable_version', '2.0')
expect(core.setOutput).to.be.calledWith('current_beta_version', '1.1')
expect(core.setOutput).to.be.calledWith('latest_beta_version', '2.1')
})
it('sets description correctly when there is a stable update', async () => {
stubOmahaVersions({
betaVersion: '1.1',
stableVersion: '2.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('description', 'Update Chrome (stable) to 2.0')
})
it('sets description correctly when there is a beta update', async () => {
stubOmahaVersions({
betaVersion: '1.2',
stableVersion: '1.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('description', 'Update Chrome (beta) to 1.2')
})
it('sets description correctly when there is a stable update and a beta update', async () => {
stubOmahaVersions({
betaVersion: '2.1',
stableVersion: '2.0',
})
const core = coreStub()
await getVersions({ core })
expect(core.setOutput).to.be.calledWith('description', 'Update Chrome (stable) to 2.0 and Chrome (beta) to 2.1')
})
})
context('.checkNeedForBranchUpdate', () => {
beforeEach(() => {
stubRepoVersions({
betaVersion: '1.1',
stableVersion: '1.0',
})
})
it('sets has_newer_update: true when there is a stable update', () => {
const core = coreStub()
checkNeedForBranchUpdate({
core,
latestBetaVersion: '1.1',
latestStableVersion: '2.0',
})
expect(core.setOutput).to.be.calledWith('has_newer_update', 'true')
})
it('sets has_newer_update: true when there is a beta update', () => {
const core = coreStub()
checkNeedForBranchUpdate({
core,
latestBetaVersion: '1.2',
latestStableVersion: '1.0',
})
expect(core.setOutput).to.be.calledWith('has_newer_update', 'true')
})
it('sets has_newer_update: true when there is a stable update and a beta update', () => {
const core = coreStub()
checkNeedForBranchUpdate({
core,
latestBetaVersion: '2.1',
latestStableVersion: '2.0',
})
expect(core.setOutput).to.be.calledWith('has_newer_update', 'true')
})
it('sets has_newer_update: false when there is not a stable update or a beta update', () => {
const core = coreStub()
checkNeedForBranchUpdate({
core,
latestBetaVersion: '1.1',
latestStableVersion: '1.0',
})
expect(core.setOutput).to.be.calledWith('has_newer_update', 'false')
})
})
context('.updateBrowserVersionsFile', () => {
it('updates browser-versions.json with specified versions', () => {
sinon.stub(fs, 'writeFileSync')
updateBrowserVersionsFile({
latestBetaVersion: '2.1',
latestStableVersion: '2.0',
})
expect(fs.writeFileSync).to.be.calledWith('./browser-versions.json', `{
"chrome:beta": "2.1",
"chrome:stable": "2.0"
}
`)
})
})
context('.updatePRTitle', () => {
it('updates pull request title', async () => {
const github = {
pulls: {
list: sinon.stub().returns(Promise.resolve(
{
data: [
{ number: '123' },
],
},
)),
update: sinon.stub(),
},
}
const context = {
repo: {
owner: 'cypress-io',
repo: 'cypress',
},
}
await updatePRTitle({
context,
github,
baseBranch: 'develop',
branchName: 'some-branch-name',
description: 'Update Chrome to newer version',
})
expect(github.pulls.list).to.be.calledWith({
owner: 'cypress-io',
repo: 'cypress',
base: 'develop',
head: 'cypress-io:some-branch-name',
})
expect(github.pulls.update).to.be.calledWith({
owner: 'cypress-io',
repo: 'cypress',
pull_number: '123',
title: 'chore: Update Chrome to newer version',
})
})
it('logs and does not attempt to update pull request title if PR cannot be found', async () => {
const github = {
pulls: {
list: sinon.stub().returns(Promise.resolve(
{
data: [],
},
)),
update: sinon.stub(),
},
}
const context = {
repo: {
owner: 'cypress-io',
repo: 'cypress',
},
}
sinon.spy(console, 'log')
await updatePRTitle({
context,
github,
baseBranch: 'develop',
branchName: 'some-branch-name',
description: 'Update Chrome to newer version',
})
expect(github.pulls.list).to.be.calledWith({
owner: 'cypress-io',
repo: 'cypress',
base: 'develop',
head: 'cypress-io:some-branch-name',
})
expect(github.pulls.update).not.to.be.called
// eslint-disable-next-line no-console
expect(console.log).to.be.calledWith('Could not find PR for branch:', 'some-branch-name')
})
})
context('.createPullRequest', () => {
it('creates pull request with correct properties', async () => {
const github = {
pulls: {
create: sinon.stub().returns(Promise.resolve()),
},
}
const context = {
repo: {
owner: 'cypress-io',
repo: 'cypress',
},
}
await createPullRequest({
context,
github,
baseBranch: 'develop',
branchName: 'some-branch-name',
description: 'Update Chrome',
})
expect(github.pulls.create).to.be.calledWith({
owner: 'cypress-io',
repo: 'cypress',
base: 'develop',
head: 'some-branch-name',
title: 'chore: Update Chrome',
body: 'This PR was auto-generated to update the version(s) of Chrome for driver tests',
maintainer_can_modify: true,
})
})
})
})