Skip to content

Commit

Permalink
fix(circleci-orb): properly pass through revision parameters
Browse files Browse the repository at this point in the history
The actual pipeline variables cannot be accessed directly from our
Orb and we would need to pass them through explicitly.

Also this cuts the first 0.0.1 version of the Orb for us in other
repositories.
  • Loading branch information
devversion committed Sep 20, 2022
1 parent 5b747aa commit 0f3a67f
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 184 deletions.
4 changes: 2 additions & 2 deletions circleci-orb/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
ORB_NAME = "angular/dev-infra"

ORB_VERSION = "dev:0.0.1"
ORB_VERSION = "0.0.7"

filegroup(
name = "orb_generated_files",
srcs = [
"//circleci-orb/scripts/rebase-on-target-branch:script",
"//circleci-orb/scripts/rebase-pr-on-target-branch:script",
],
)

Expand Down
16 changes: 0 additions & 16 deletions circleci-orb/commands/rebase-on-target-branch.yml

This file was deleted.

29 changes: 29 additions & 0 deletions circleci-orb/commands/rebase-pr-on-target-branch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
description: Rebase PR on the target branch

parameters:
head_revision:
type: string
description: The `pipeline.git.revision` pipeline value.
base_revision:
type: string
description: The `pipeline.git.base_revision` pipeline value.
primary_branch_name:
type: string
description: The primary branch for the repository.
default: 'main'
shell:
type: string
default: ""
description: |
Shell to use for executing the command. Useful for Windows where a
non-bash shell is the default.
steps:
- run:
environment:
MAIN_BRANCH_NAME: << parameters.primary_branch_name >>
CIRCLE_GIT_BASE_REVISION: << parameters.base_revision >>
CIRCLE_GIT_HEAD_REVISION: << parameters.head_revision >>
name: Rebasing PR on the target branch
shell: << parameters.shell >>
command: << include(../dist/bin/circleci-orb/scripts/rebase-pr-on-target-branch/script.sh) >>
163 changes: 0 additions & 163 deletions circleci-orb/scripts/rebase-on-target-branch/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ load("//circleci-orb:index.bzl", "nodejs_script_to_sh_script")
package(default_visibility = ["//circleci-orb:__subpackages__"])

ts_library(
name = "rebase-on-target-branch",
srcs = ["index.ts"],
name = "rebase-pr-on-target-branch",
srcs = glob(["*.ts"]),
deps = ["@npm//@types/node"],
)

Expand All @@ -14,7 +14,7 @@ esbuild(
entry_point = "index.ts",
format = "iife",
sourcemap = "inline",
deps = [":rebase-on-target-branch"],
deps = [":rebase-pr-on-target-branch"],
)

nodejs_script_to_sh_script(
Expand Down
62 changes: 62 additions & 0 deletions circleci-orb/scripts/rebase-pr-on-target-branch/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {execSync as execSync_} from 'child_process';
import {getRefFromBranchList} from './ref-branch-list';

/** Synchronously executes the command, suppressing errors as empty string outputs. */
export function exec(command: string): string {
try {
return execSync_(command, {stdio: 'pipe', encoding: 'utf8'}).trim();
} catch (err: unknown) {
return '';
}
}

/**
* Get the list of branches which contain the provided sha, sorted in descending
* order by committerdate.
*
* example:
* upstream/main
* upstream/9.0.x
* upstream/test
* upstream/1.1.x
*/
export function getBranchListForSha(sha: string, remote: string) {
return exec(`git branch -r '${remote}/*' --sort=-committerdate --contains ${sha}`);
}

/** Get the common ancestor sha of the two provided shas. */
export function getCommonAncestorSha(sha1: string, sha2: string) {
return exec(`git merge-base ${sha1} ${sha2}`);
}

/** * Adds the remote to git, if it doesn't already exist. */
export function addAndFetchRemote(owner: string, name: string) {
const remoteName = `${owner}_${name}`;
exec(`git remote add ${remoteName} https://github.com/${owner}/${name}.git`);
exec(`git fetch ${remoteName}`);
return remoteName;
}

/** Get the full sha of the ref provided. */
export function getShaFromRef(ref: string) {
return exec(`git rev-parse ${ref}`);
}

/** Get the ref and latest shas for the provided sha on a specific remote. */
export function lookupSha(sha: string, owner: string, name: string, primaryBranchName: string) {
const remote = addAndFetchRemote(owner, name);
// Get the ref on the remote for the sha provided.
const ref = getRefFromBranchList(getBranchListForSha(sha, remote), primaryBranchName);
// Get the latest sha on the discovered remote ref.
const latestSha = getShaFromRef(`${remote}/${ref}`);

return {remote, ref, latestSha, sha};
}
83 changes: 83 additions & 0 deletions circleci-orb/scripts/rebase-pr-on-target-branch/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {exec, getCommonAncestorSha, lookupSha} from './helpers';

// Parameter variables.
const baseRevision = process.env.CIRCLE_GIT_BASE_REVISION!;
const headRevision = process.env.CIRCLE_GIT_HEAD_REVISION!;

// CircleCI environment variables.
const baseRepoOwner = process.env.CIRCLE_PROJECT_USERNAME!;
const baseRepoName = process.env.CIRCLE_PROJECT_REPONAME!;
const headRepoOwner = process.env.CIRCLE_PR_USERNAME!;
const headRepoName = process.env.CIRCLE_PR_REPONAME!;
const prNumber = process.env.CIRCLE_PR_NUMBER!;
const primaryBranchName = process.env.MAIN_BRANCH_NAME!;

if (!process.env.CIRCLE_PR_NUMBER) {
console.info('Skipping rebase as the CircleCI run is not for a pull request.');
process.exit(0);
}

/** Rebase on the latest commit for the targeted branch. */
(async () => {
const base = lookupSha(baseRevision, baseRepoOwner, baseRepoName, primaryBranchName);
const target = lookupSha(headRevision, headRepoOwner, headRepoName, primaryBranchName);
const commonAncestorSha = getCommonAncestorSha(base.sha, target.sha);

// Log known refs and shas
console.log(`--------------------------------`);
console.log(` Target Branch: ${base.ref}`);
console.log(` Latest Commit for Target Branch: ${target.latestSha}`);
console.log(` Latest Commit for PR: ${base.latestSha}`);
console.log(` First Common Ancestor SHA: ${commonAncestorSha}`);
console.log(`--------------------------------`);
console.log();

// Get the count of commits between the latest commit from origin and the common ancestor SHA.
const commitCount = exec(`git rev-list --count origin/${base.ref}...${commonAncestorSha}`);
console.log(`Checking ${commitCount} commits for changes in the CircleCI config file.`);

// Check if the files changed between the latest commit from origin and the common ancestor SHA
// includes the CircleCI config.
const circleCIConfigChanged = exec(
`git diff --name-only origin/${base.ref} ${commonAncestorSha} -- .circleci/config.yml`,
);
if (!!circleCIConfigChanged) {
throw Error(`
CircleCI config on ${base.ref} has been modified since commit
${commonAncestorSha.slice(0, 7)}, which this PR is based on.
Please rebase the PR on ${base.ref} after fetching from upstream.
Rebase instructions for PR Author, please run the following commands:
git fetch upstream ${base.ref};
git checkout ${target.ref};
git rebase upstream/${base.ref};
git push --force-with-lease;
Angular team members can rebase this PR with the following command:
yarn ng-dev pr rebase ${prNumber}
`);
} else {
console.log('No change found in the CircleCI config file, continuing.');
}
console.log();

// Rebase the PR.
exec(`git rebase origin/${base.ref}`);
console.log(`Rebased current branch onto ${base.ref}.`);
})().catch((err: unknown) => {
console.error('Failed to rebase on top of target branch.');
console.error(err);
process.exitCode = 1;
});
Loading

0 comments on commit 0f3a67f

Please sign in to comment.