From a6aa35e5985ff5a256680db116479926b0b3c4cc Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Tue, 11 Feb 2020 14:56:25 -0800 Subject: [PATCH] ci: use pipeline values to define the CI_COMMIT_RANGE (#35348) PR Close #35348 --- .circleci/config.yml | 7 +- .circleci/env.sh | 6 +- .circleci/get-commit-range.js | 166 ---------------------------------- 3 files changed, 7 insertions(+), 172 deletions(-) delete mode 100644 .circleci/get-commit-range.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e10584f81..79d45a1486 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -140,7 +140,12 @@ commands: init_environment: description: Initializing environment (setting up variables) steps: - - run: ./.circleci/env.sh + - run: + name: Set up environment + environment: + CIRCLE_GIT_BASE_REVISION: << pipeline.git.base_revision >> + CIRCLE_GIT_REVISION: << pipeline.git.revision >> + command: ./.circleci/env.sh - run: # Configure git as the CircleCI `checkout` command does. # This is needed because we only checkout on the setup job. diff --git a/.circleci/env.sh b/.circleci/env.sh index d7613eb123..1b66e6412c 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -27,11 +27,7 @@ setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 79.0.3945.130"; setPublicVar CI_COMMIT "$CIRCLE_SHA1"; # `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun # workflows of such builds). -# NOTE: With [CircleCI Pipelines](https://circleci.com/docs/2.0/build-processing) enabled, -# `CIRCLE_COMPARE_URL` is no longer available and the commit range cannot be reliably -# detected. Fall back to only considering the last commit (which is accurate in the majority -# of cases for push builds). -setPublicVar CI_COMMIT_RANGE "`[[ ${CIRCLE_PR_NUMBER:-false} != false ]] && echo "" || echo "$CIRCLE_SHA1~1...$CIRCLE_SHA1"`"; +setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION"; setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}"; setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME"; setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME"; diff --git a/.circleci/get-commit-range.js b/.circleci/get-commit-range.js deleted file mode 100644 index c5f569c6f6..0000000000 --- a/.circleci/get-commit-range.js +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env node - -/** - * **Usage:** - * ``` - * node get-commit-range [ []] - * ``` - * - * Returns the commit range, either extracting it from `compare-url` (if defined), which is of the - * format of the `CIRCLE_COMPARE_URL` environment variable, or by retrieving the equivalent of - * `CIRCLE_COMPARE_URL` for jobs that are part of a rerun workflow and extracting it from there. - * - * > !!! WARNING !!! - * > !! - * > !! When [CircleCI Pipelines](https://circleci.com/docs/2.0/build-processing) is enabled, the - * > !! `CIRCLE_COMPARE_URL` environment variable is not available at all and this script does not - * > !! work. - * > !!!!!!!!!!!!!!! - * - * **Context:** - * CircleCI sets the `CIRCLE_COMPARE_URL` environment variable (from which we can extract the commit - * range) on push builds (a.k.a. non-PR, non-scheduled builds). Yet, when a workflow is rerun - * (either from the beginning or from failed jobs) - e.g. when a job flakes - CircleCI does not set - * the `CIRCLE_COMPARE_URL`. - * - * **Implementation details:** - * This script relies on the fact that all rerun workflows share the same CircleCI workspace and the - * (undocumented) fact that the workspace ID happens to be the same as the workflow ID that first - * created it. - * - * For example, for a job on push build workflows, the CircleCI API will return data that look like: - * ```js - * { - * compare: 'THE_COMPARE_URL_WE_ARE_LOOKING_FOR', - * //... - * previous: { - * // ... - * build_num: 12345, - * }, - * //... - * workflows: { - * //... - * workflow_id: 'SOME_ID_A', - * workspace_id: 'SOME_ID_A', // Same as `workflow_id`. - * } - * } - * ``` - * - * If the workflow is rerun, the data for jobs on the new workflow will look like: - * ```js - * { - * compare: null, // ¯\_(ツ)_/¯ - * //... - * previous: { - * // ... - * build_num: 23456, - * }, - * //... - * workflows: { - * //... - * workflow_id: 'SOME_ID_B', - * workspace_id: 'SOME_ID_A', // Different from current `workflow_id`. - * // Same as original `workflow_id`. \o/ - * } - * } - * ``` - * - * This script uses the `previous.build_num` (which points to the previous build number on the same - * branch) to traverse the jobs backwards, until it finds a job from the original workflow. Such a - * job (if found) should also contain the compare URL. - * - * **NOTE 1:** - * This is only useful on workflows which are created by rerunning a workflow for which - * `CIRCLE_COMPARE_URL` was defined. - * - * **NOTE 2:** - * The `circleToken` will be used for CircleCI API requests if provided, but it is not needed for - * accessing the read-only endpoints that we need (as long as the current project is FOSS and the - * corresponding setting is turned on in "Advanced Settings" in the project dashboard). - * - * --- - * Inspired by https://circleci.com/orbs/registry/orb/iynere/compare-url - * (source code: https://github.com/iynere/compare-url-orb). - * - * We are not using the `compare-url` orb for the following reasons: - * 1. (By looking at the code) it would only work if the rerun workflow is the latest workflow on - * the branch (which is not guaranteed to be true). - * 2. It is less efficient (e.g. makes unnecessary CircleCI API requests for builds on different - * branches, installs extra dependencies, persists files to the workspace (as a means of passing - * the result to the calling job), etc.). - * 3. It is slightly more complicated to setup and consume than our own script. - * 4. Its implementation is more complicated than needed for our usecase (e.g. handles different git - * providers, handles newly created branches, etc.). - */ - -// Imports -const {get: httpsGet} = require('https'); - -// Constants -const API_URL_BASE = 'https://circleci.com/api/v1.1/project/github/angular/angular'; -const COMPARE_URL_RE = /^.*\/([0-9a-f]+\.\.\.[0-9a-f]+)$/i; - -// Run -_main(process.argv.slice(2)); - -// Helpers -async function _main([buildNumber, compareUrl = '', circleToken = '']) { - try { - if (!buildNumber || isNaN(buildNumber)) { - throw new Error( - 'Missing or invalid arguments.\n' + - 'Expected: buildNumber (number), compareUrl? (string), circleToken? (string)'); - } - - if (!compareUrl) { - compareUrl = await getCompareUrl(buildNumber, circleToken); - } - - const commitRangeMatch = COMPARE_URL_RE.exec(compareUrl) - const commitRange = commitRangeMatch ? commitRangeMatch[1] : ''; - - console.log(commitRange); - } catch (err) { - console.error(err); - process.exit(1); - } -} - -function getBuildInfo(buildNumber, circleToken) { - console.error(`BUILD ${buildNumber}`); - const url = `${API_URL_BASE}/${buildNumber}?circle-token=${circleToken}`; - return getJson(url); -} - -async function getCompareUrl(buildNumber, circleToken) { - let info = await getBuildInfo(buildNumber, circleToken); - const targetWorkflowId = info.workflows.workspace_id; - - while (info.workflows.workflow_id !== targetWorkflowId) { - info = await getBuildInfo(info.previous.build_num, circleToken); - } - - return info.compare || ''; -} - -function getJson(url) { - return new Promise((resolve, reject) => { - const opts = {headers: {Accept: 'application/json'}}; - const onResponse = res => { - const statusCode = res.statusCode || -1; - const isSuccess = (200 <= statusCode) && (statusCode < 400); - let responseText = ''; - - res. - on('error', reject). - on('data', d => responseText += d). - on('end', () => isSuccess ? - resolve(JSON.parse(responseText)) : - reject(`Error getting '${url}' (status ${statusCode}):\n${responseText}`)); - }; - - httpsGet(url, opts, onResponse). - on('error', reject). - end(); - }); -}