Merge remote-tracking branch 'origin/develop' into merge-develop-2-28-22

This commit is contained in:
Zach Bloomquist
2022-02-28 10:54:03 -05:00
58 changed files with 2375 additions and 1691 deletions
-268
View File
@@ -1,268 +0,0 @@
const _ = require('lodash')
const Promise = require('bluebird')
const bumpercar = require('@cypress/bumpercar')
const path = require('path')
const la = require('lazy-ass')
const check = require('check-more-types')
const { configFromEnvOrJsonFile, filenameToShellVariable } = require('@cypress/env-or-json-file')
const makeEmptyGithubCommit = require('make-empty-github-commit')
const parse = require('parse-github-repo-url')
const { setCommitStatus } = require('@cypress/github-commit-status-check')
let car = null
// all the projects to trigger / run / change environment variables for
const _PROVIDERS = {
circle: {
main: 'cypress-io/cypress',
linux: [
'cypress-io/cypress-test-module-api',
],
},
}
const remapProjects = function (projectsByProvider) {
const list = []
_.mapValues(projectsByProvider, (provider, name) => {
const remapPlatform = (platform, repos) => {
return repos.forEach((repo) => {
return list.push({
repo,
provider: name,
platform,
})
})
}
if (provider.win32) {
remapPlatform('win32', provider.win32)
}
if (provider.linux) {
remapPlatform('linux', provider.linux)
}
if (provider.darwin) {
return remapPlatform('darwin', provider.darwin)
}
})
return list
}
// make flat list of objects
// {repo, provider, platform}
const PROJECTS = remapProjects(_PROVIDERS)
const getCiConfig = function () {
const key = path.join('scripts', 'support', 'ci.json')
const config = configFromEnvOrJsonFile(key)
if (!config) {
console.error('⛔️ Cannot find CI credentials')
console.error('Using @cypress/env-or-json-file module')
console.error('and filename', key)
console.error('which is environment variable', filenameToShellVariable(key))
throw new Error('CI config not found')
}
return config
}
const awaitEachProjectAndProvider = function (projects, fn, filter = (val) => val) {
const creds = getCiConfig()
// configure a new Bumpercar
const providers = {}
if (check.unemptyString(creds.githubToken)) {
providers.travis = {
githubToken: process.env.GH_TOKEN,
}
}
if (check.unemptyString(creds.circleToken)) {
providers.circle = {
circleToken: creds.circleToken,
}
}
const providerNames = Object.keys(providers)
console.log('configured providers', providerNames)
la(check.not.empty(providerNames), 'empty list of providers')
car = bumpercar.create({ providers })
const filteredProjects = projects.filter(filter)
if (check.empty(filteredProjects)) {
console.log('⚠️ zero filtered projects left after filtering')
}
console.log('filtered projects:')
console.table(filteredProjects)
return Promise.mapSeries(filteredProjects, (project) => {
return fn(project.repo, project.provider, creds)
})
}
// do not trigger all projects if there is specific provider
const getFilterByProvider = function (providerName, platformName) {
return (val) => {
if (providerName && val.provider !== providerName) {
return false
}
if (platformName && val.platform !== platformName) {
return false
}
return val
}
}
module.exports = {
_PROVIDERS,
remapProjects,
getFilterByProvider,
// in each project, set a couple of environment variables
version (nameOrUrl, binaryVersionOrUrl, platform, providerName) {
console.log('All possible projects:')
console.table(PROJECTS)
la(check.unemptyString(nameOrUrl),
'missing cypress name or url to set', nameOrUrl)
if (check.semver(nameOrUrl)) {
console.log('for version', nameOrUrl)
nameOrUrl = `cypress@${nameOrUrl}`
console.log('full NPM install name is', nameOrUrl)
}
la(check.unemptyString(binaryVersionOrUrl),
'missing binary version or url', binaryVersionOrUrl)
const result = {
versionName: nameOrUrl,
binary: binaryVersionOrUrl,
}
const projectFilter = getFilterByProvider(providerName)
const updateProject = function (project, provider) {
console.log('setting environment variables in', project)
return car.updateProjectEnv(project, provider, {
CYPRESS_NPM_PACKAGE_NAME: nameOrUrl,
CYPRESS_INSTALL_BINARY: binaryVersionOrUrl,
})
}
return awaitEachProjectAndProvider(PROJECTS, updateProject, projectFilter)
.then(() => result)
},
// triggers test projects on multiple CIs
// the test projects will exercise the new version of
// the Cypress test runner we just built
runTestProjects (getStatusAndMessage, providerName, version, platform) {
const projectFilter = getFilterByProvider(providerName, platform)
const makeCommit = function (project, provider, creds) {
// make empty commit to trigger CIs
// project is owner/repo string like cypress-io/cypress-test-tiny
console.log('making commit to project', project)
// print if we have a few github variables present
console.log('do we have GH_APP_ID?', Boolean(process.env.GH_APP_ID))
console.log('do we have GH_INSTALLATION_ID?', Boolean(process.env.GH_INSTALLATION_ID))
console.log('do we have GH_PRIVATE_KEY?', Boolean(process.env.GH_PRIVATE_KEY))
console.log('do we have GH_TOKEN?', Boolean(process.env.GH_TOKEN))
const parsedRepo = parse(project)
const owner = parsedRepo[0]
const repo = parsedRepo[1]
let { status, message } = getStatusAndMessage(repo)
if (!message) {
message =
`\
Testing new Cypress version ${version}
\
`
if (process.env.CIRCLE_BUILD_URL) {
message += '\n'
message += `Circle CI build url ${process.env.CIRCLE_BUILD_URL}`
}
}
const defaultOptions = {
owner,
repo,
message,
token: process.env.GH_TOKEN,
}
const createGithubCommitStatusCheck = function ({ sha }) {
if (!status) {
return
}
// status is {owner, repo, sha} and maybe a few other properties
const isStatus = check.schema({
owner: check.unemptyString,
repo: check.unemptyString,
sha: check.commitId,
context: check.unemptyString,
platform: check.unemptyString,
arch: check.unemptyString,
})
if (!isStatus(status)) {
console.error('Invalid status object %o', status)
}
const targetUrl = `https://github.com/${owner}/${repo}/commit/${sha}`
const commitStatusOptions = {
targetUrl,
owner: status.owner,
repo: status.repo,
sha: status.sha,
context: status.context,
state: 'pending',
description: `${owner}/${repo}`,
}
console.log(
'creating commit status check',
commitStatusOptions.description,
commitStatusOptions.context,
)
return setCommitStatus(commitStatusOptions)
}
if (!version) {
return makeEmptyGithubCommit(defaultOptions).then(createGithubCommitStatusCheck)
}
// first try to commit to branch for next upcoming version
return makeEmptyGithubCommit({ ...defaultOptions, branch: version })
.catch(() => {
// maybe there is no branch for next version
// try default branch
return makeEmptyGithubCommit(defaultOptions)
}).then(createGithubCommitStatusCheck)
}
return awaitEachProjectAndProvider(PROJECTS, makeCommit, projectFilter)
},
}
-18
View File
@@ -16,7 +16,6 @@ const rp = require('@cypress/request-promise')
const zip = require('./zip')
const ask = require('./ask')
const bump = require('./bump')
const meta = require('./meta')
const build = require('./build')
const upload = require('./upload')
@@ -104,23 +103,6 @@ const deploy = {
return opts
},
bump () {
return ask.whichBumpTask()
.then((task) => {
switch (task) {
case 'run':
return bump.runTestProjects()
case 'version':
return ask.whichVersion(meta.distDir(''))
.then((v) => {
return bump.version(v)
})
default:
throw new Error('unknown task')
}
})
},
release () {
// read off the argv
const options = this.parseOptions(process.argv)
+13 -9
View File
@@ -2,13 +2,14 @@
// See ../guides/next-version.md for documentation.
const path = require('path')
const semver = require('semver')
const Bluebird = require('bluebird')
const bumpCb = require('conventional-recommended-bump')
const { promisify } = require('util')
const currentVersion = require('../package.json').version
const bump = Bluebird.promisify(bumpCb)
const bump = promisify(bumpCb)
const paths = ['packages', 'cli']
let nextVersion
@@ -30,14 +31,17 @@ if (require.main !== module) {
return
}
Bluebird.mapSeries(paths, async (path) => {
const pathNextVersion = await getNextVersionForPath(path)
(async () => {
process.chdir(path.join(__dirname, '..'))
if (!nextVersion || semver.gt(pathNextVersion, nextVersion)) {
nextVersion = pathNextVersion
for (const path of paths) {
const pathNextVersion = await getNextVersionForPath(path)
if (!nextVersion || semver.gt(pathNextVersion, nextVersion)) {
nextVersion = pathNextVersion
}
}
})
.then(() => {
if (!nextVersion) {
throw new Error('Unable to determine next version.')
}
@@ -51,4 +55,4 @@ Bluebird.mapSeries(paths, async (path) => {
}
console.log(nextVersion)
})
})()
-139
View File
@@ -1,139 +0,0 @@
const la = require('lazy-ass')
const is = require('check-more-types')
const { getNameAndBinary, getJustVersion, getShortCommit } = require('./utils')
const bump = require('./binary/bump')
const { stripIndent } = require('common-tags')
const os = require('os')
const minimist = require('minimist')
const { getInstallJson } = require('@cypress/commit-message-install')
/* eslint-disable no-console */
// See ../guides/testing-other-projects.md for documentation.
const { npm, binary } = getNameAndBinary(process.argv)
la(is.unemptyString(npm), 'missing npm url')
la(is.unemptyString(binary), 'missing binary url')
const platform = os.platform()
const arch = os.arch()
console.log('bumping versions for other projects')
console.log(' npm:', npm)
console.log(' binary:', binary)
console.log(' platform:', platform)
console.log(' arch:', arch)
const cliOptions = minimist(process.argv, {
string: 'provider',
alias: {
provider: 'p',
},
})
/**
* Returns given string surrounded by ```json + ``` quotes
* @param {string} s
*/
const toJsonCodeBlock = (s) => {
const start = '```json'
const finish = '```'
return `${start}\n${s}\n${finish}\n`
}
/**
* Converts given JSON object into markdown text block
* @param {object} object
*/
const toMarkdownJsonBlock = (object) => {
la(object, 'expected an object to convert to JSON', object)
const str = JSON.stringify(object, null, 2)
return toJsonCodeBlock(str)
}
console.log('starting each test projects')
const shortNpmVersion = getJustVersion(npm)
console.log('short NPM version', shortNpmVersion)
let subject = `Testing new ${platform} ${arch} Cypress version ${shortNpmVersion}`
const commitInfo = getShortCommit()
if (commitInfo) {
subject += ` ${commitInfo.short}`
}
// instructions for installing this binary,
// see "@cypress/commit-message-install"
const env = {
CYPRESS_INSTALL_BINARY: binary,
}
const getStatusAndMessage = (projectRepoName) => {
// also pass "status" object that points back at this repo and this commit
// so that other projects can report their test success as GitHub commit status check
let status = null
const commit = commitInfo && commitInfo.sha
if (commit && is.commitId(commit)) {
// commit is full 40 character hex string
const platform = os.platform()
const arch = os.arch()
status = {
owner: 'cypress-io',
repo: 'cypress',
sha: commit,
platform,
arch,
context: `[${platform}-${arch}] ${projectRepoName}`,
}
}
const commitMessageInstructions = getInstallJson({
packages: npm,
env,
platform,
arch,
branch: shortNpmVersion, // use as version as branch name on test projects
commit,
status,
})
const jsonBlock = toMarkdownJsonBlock(commitMessageInstructions)
const footer =
'Use tool `@cypress/commit-message-install` to install from above block'
let message = `${subject}\n\n${jsonBlock}\n${footer}\n`
if (process.env.CIRCLE_BUILD_URL) {
message += '\n'
message += stripIndent`
CircleCI job url: ${process.env.CIRCLE_BUILD_URL}
`
}
console.log('commit message:')
console.log(message)
return {
status,
message,
}
}
const onError = (e) => {
console.error('could not bump test projects')
console.error(e)
process.exit(1)
}
bump
.runTestProjects(
getStatusAndMessage,
cliOptions.provider,
shortNpmVersion,
platform,
)
.catch(onError)
-48
View File
@@ -1,48 +0,0 @@
const la = require('lazy-ass')
const snapshot = require('snap-shot-it')
const _ = require('lodash')
const bump = require('../../binary/bump')
/* eslint-env mocha */
describe('bump', () => {
context('remapProjects', () => {
it('returns flat list of projects', () => {
la(bump._PROVIDERS, 'has _PROVIDERS', bump)
const list = bump.remapProjects(bump._PROVIDERS)
snapshot('list of all projects', list)
})
})
context('getFilterByProvider', () => {
it('returns a filter function without provider name', () => {
const projects = bump.remapProjects(bump._PROVIDERS)
const filter = bump.getFilterByProvider()
// should return ALL projects
const filtered = projects.filter(filter)
la(
_.isEqual(filtered, projects),
'should have kept all projects',
filtered,
)
})
it('returns a filter function for circle and linux', () => {
const projects = bump.remapProjects(bump._PROVIDERS)
la(
projects.length,
'there should be at least a few projects in the list of projects',
projects,
)
const filter = bump.getFilterByProvider('circle', 'linux')
const filtered = projects.filter(filter)
la(filtered.length, 'there should be at least a few projects', filtered)
snapshot('should have just circle and linux projects', filtered)
})
})
})