mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-02 04:29:55 -06:00
318 lines
8.7 KiB
JavaScript
318 lines
8.7 KiB
JavaScript
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 R = require('ramda')
|
|
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 = {
|
|
appVeyor: {
|
|
main: 'cypress-io/cypress',
|
|
win32: [
|
|
'cypress-io/cypress-test-tiny',
|
|
'cypress-io/cypress-test-example-repos',
|
|
],
|
|
},
|
|
|
|
circle: {
|
|
main: 'cypress-io/cypress',
|
|
linux: [
|
|
'cypress-io/cypress-test-tiny',
|
|
'cypress-io/cypress-test-module-api',
|
|
'cypress-io/cypress-test-node-versions',
|
|
'cypress-io/cypress-test-nested-projects',
|
|
'cypress-io/cypress-test-ci-environments',
|
|
'cypress-io/cypress-test-example-repos',
|
|
],
|
|
darwin: [
|
|
'cypress-io/cypress-test-tiny',
|
|
'cypress-io/cypress-test-example-repos',
|
|
],
|
|
},
|
|
}
|
|
|
|
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 = R.identity) {
|
|
const creds = getCiConfig()
|
|
|
|
// configure a new Bumpercar
|
|
const providers = {}
|
|
|
|
if (check.unemptyString(creds.githubToken)) {
|
|
providers.travis = {
|
|
githubToken: creds.githubToken,
|
|
}
|
|
}
|
|
|
|
if (check.unemptyString(creds.circleToken)) {
|
|
providers.circle = {
|
|
circleToken: creds.circleToken,
|
|
}
|
|
}
|
|
|
|
if (check.unemptyString(creds.appVeyorToken)) {
|
|
providers.appVeyor = {
|
|
appVeyorToken: creds.appVeyorToken,
|
|
}
|
|
}
|
|
|
|
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 = R.filter(filter, projects)
|
|
|
|
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
|
|
// for example appVeyor should be used for Windows testing
|
|
const getFilterByProvider = function (providerName, platformName) {
|
|
let platformFilter; let providerFilter
|
|
|
|
if (providerName) {
|
|
console.log('only allow projects for provider', providerName)
|
|
providerFilter = R.propEq('provider', providerName)
|
|
} else {
|
|
providerFilter = R.identity
|
|
}
|
|
|
|
if (platformName) {
|
|
console.log('only allow projects for platform', platformName)
|
|
platformFilter = R.propEq('platform', platformName)
|
|
} else {
|
|
platformFilter = R.identity
|
|
}
|
|
|
|
// combined filter is when both filters pass
|
|
const projectFilter = R.allPass([providerFilter, platformFilter])
|
|
|
|
return projectFilter
|
|
}
|
|
|
|
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(R.always(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))
|
|
|
|
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}`
|
|
}
|
|
|
|
if (process.env.APPVEYOR) {
|
|
const slug = process.env.APPVEYOR_PROJECT_SLUG
|
|
const build = process.env.APPVEYOR_BUILD_ID
|
|
|
|
message += '\n'
|
|
message += `AppVeyor CI ${slug} ${build}`
|
|
}
|
|
}
|
|
|
|
const defaultOptions = {
|
|
owner,
|
|
repo,
|
|
message,
|
|
token: creds.githubToken,
|
|
}
|
|
|
|
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
|
|
const specificBranchOptions = {
|
|
owner,
|
|
repo,
|
|
token: creds.githubToken,
|
|
message,
|
|
branch: version,
|
|
}
|
|
|
|
return makeEmptyGithubCommit(specificBranchOptions)
|
|
.catch(() => {
|
|
// maybe there is no branch for next version
|
|
// try default branch
|
|
return makeEmptyGithubCommit(defaultOptions)
|
|
}).then(createGithubCommitStatusCheck)
|
|
}
|
|
|
|
return awaitEachProjectAndProvider(PROJECTS, makeCommit, projectFilter)
|
|
},
|
|
}
|