diff options
author | Jason Wray <friedbunny@users.noreply.github.com> | 2019-08-08 15:35:56 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-08 15:35:56 -0700 |
commit | a3a661e84649b78575237a2ab935a2d2584970c4 (patch) | |
tree | becd992b40ff5d164dfbc8caac39f60d063c1b15 /scripts/check-ci-job-skippability.js | |
parent | 56e7bbc0b74840701a513c709cac94b4d4d34e26 (diff) | |
download | qtlocation-mapboxgl-a3a661e84649b78575237a2ab935a2d2584970c4.tar.gz |
[build] Skip CI jobs if there are no relevant changed files
Diffstat (limited to 'scripts/check-ci-job-skippability.js')
-rwxr-xr-x | scripts/check-ci-job-skippability.js | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/scripts/check-ci-job-skippability.js b/scripts/check-ci-job-skippability.js new file mode 100755 index 0000000000..55f940db31 --- /dev/null +++ b/scripts/check-ci-job-skippability.js @@ -0,0 +1,121 @@ +#!/usr/bin/env node + +/* +This script takes two parameters or three environment variables: + + {CI job name|$CIRCLE_JOB} {SHA1...SHA1|$CIRCLE_MERGE_BASE...$CIRCLE_SHA1} + +The flow of this script: + + - List of files changed in PR: `git diff --name-only start...end` + - Extract list into array. + - Remove items from array if they match: + - Global ignore list. + - Other platform ignore lists. + - If array still contains items, do not authorize skipping CI job. + - Else if array is empty, skip CI job. + +To add support for a new platform: + + - Add a new PLATFORM_FILES array with a list of unique paths for the + files belonging to the platform. + - Add a case to `skippableFilePatternsForCIJob()` with: + - The prefix for the platform's CI job names. + - A concatenated array of other platform paths that are safe to ignore + for the new platform. These should be files that can change without + having any effect on the output of the new platform. + - Update other cases in `skippableFilePatternsForCIJob()` to include the + paths for the new platform. +*/ + +const execSync = require('child_process').execSync; +const _ = require('lodash'); +const minimatch = require("minimatch"); + +console.step = _.partial(console.log, '\n\033[1m\033[36m*', _, '\033[0m'); + +// BUILD PARAMETERS +const CI_JOB_NAME = process.argv[2] || process.env.CIRCLE_JOB; +if (!CI_JOB_NAME) { console.error('You must specify the name of a CI job as a parameter or environment variable.'); process.exit(1); } + +const COMMIT_RANGE = process.argv[3] || `${process.env.CIRCLE_MERGE_BASE}...${process.env.CIRCLE_SHA1}`; +if (!COMMIT_RANGE || COMMIT_RANGE.includes('undefined')) { console.error('You must specify a range of commits to check for changed files in as a parameter or environment variable.'); process.exit(1); } + +// FILE SKIPPING PATTERNS +const ALWAYS_SKIPPABLE_FILES = [ + '**/CHANGELOG.md', + '**/README.md', + '**/CONTRIBUTING.md', + '**/DEVELOPING.md', + '**/INSTALL.md', + '**/*.podspec' +] + +const ANDROID_FILES = [ + 'platform/android/**' +] + +const DARWIN_FILES = [ + 'platform/darwin/**' +] + +const IOS_FILES = [ + 'platform/ios/**' +] + +const MACOS_FILES = [ + 'platform/macos/**' +] + +const OTHER_PLATFORMS = [ + 'platform/glfw/**', + 'platform/linux/**', + 'platform/node/**', + 'platform/qt/**', + 'benchmark/**', + 'test/**' +] + +function skippableFilePatternsForCIJob(job) { + if (job.includes('render-tests')) { + // Render tests run on specific platforms are effectively unskippable core jobs, not platform jobs. + return ALWAYS_SKIPPABLE_FILES; + } else if (job.startsWith('ios')) { + return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, MACOS_FILES, OTHER_PLATFORMS); + } else if (job.startsWith('android')) { + return _.concat(ALWAYS_SKIPPABLE_FILES, DARWIN_FILES, IOS_FILES, MACOS_FILES, OTHER_PLATFORMS); + } else if (job.startsWith('macos')) { + return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, IOS_FILES, OTHER_PLATFORMS); + } else { + return ALWAYS_SKIPPABLE_FILES; + } +} + +console.step(`Getting list of files changed between ${COMMIT_RANGE}`); + +let changedFiles = execSync(`git diff --name-only ${COMMIT_RANGE}`).toString().split('\n'); +changedFiles = _.compact(changedFiles); + +console.log(`${changedFiles.length} total files changed.`); + +console.step(`Checking changed files for paths relevant to ${CI_JOB_NAME} job`); + +// Filter the changed files array to remove files that are irrelevant to the specified CI job. +_.remove(changedFiles, function(changedFile) { + for (const skippableFilePattern of skippableFilePatternsForCIJob(CI_JOB_NAME)) { + if (minimatch(changedFile, skippableFilePattern, { dot: true, nocase: true })) { + return true; + } + } + return false; +}); + +if (changedFiles.length) { + console.log(`Found ${changedFiles.length} unskippable changed file${changedFiles.length > 1 ? 's':''}:\n`, changedFiles); +} else { + console.log(`Found no relevant changed files, so it's safe to skip the remainder of this CI job.`) + if (process.env.CIRCLECI) { + console.step('Aborting CI job'); + execSync(`circleci step halt`, {stdio: 'inherit'}); + } +} |