Skip to content

Commit

Permalink
fix(circleci-orb): rebase script not working on windows
Browse files Browse the repository at this point in the history
Fixes that the rebase script is not working on Windows by
using `spawnSync` with `shell: true`. Like we do in the ng-dev
git client (which we cannot use here).

Also fixes that the rebease command fails if there is no user
configured. We always set a user as part of rebasing. The user
may be overriden later by other scripts- like the publish snapshots
script.
  • Loading branch information
devversion committed Sep 20, 2022
1 parent 3846e48 commit 87ac315
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 22 deletions.
2 changes: 1 addition & 1 deletion circleci-orb/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")

ORB_NAME = "angular/dev-infra"

ORB_VERSION = "1.0.0"
ORB_VERSION = "1.0.1"

nodejs_binary(
name = "pack_orb_script",
Expand Down
44 changes: 30 additions & 14 deletions circleci-orb/scripts/rebase-pr-on-target-branch/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,37 @@
* found in the LICENSE file at https://angular.io/license
*/

import {execSync as execSync_} from 'child_process';
import {spawnSync} 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 '';
/**
* Synchronously executes the Git command.
*
* @throws {Error} Errors will be thrown on non-successful commands.
*/
export function execGit(args: string[]): string {
const cmd = `git ${args.join(' ')}`;
const proc = spawnSync('git', args, {shell: true, stdio: 'pipe', encoding: 'utf8'});

if (proc.error !== undefined) {
console.error(proc.error);
throw new Error(`Unexpected error while executing: ${cmd}`);
}

if (proc.status !== 0) {
console.error(`Failed executing: ${cmd}.`);
console.error(`Status Code: ${proc.status}`);
console.error(`Stdout: ${proc.stdout}`);
console.error(`Stderr: ${proc.stdout}`);
throw new Error(`Unexpected error while executing: ${cmd}`);
}

return proc.stdout.trim();
}

/**
* Get the list of branches which contain the provided sha, sorted in descending
* order by committerdate.
* Get the list of branches which contain the provided sha, sorted in
* descending order by committerdate.
*
* example:
* upstream/main
Expand All @@ -29,25 +45,25 @@ export function exec(command: string): string {
* upstream/1.1.x
*/
export function getBranchListForSha(sha: string, remote: string) {
return exec(`git branch -r '${remote}/*' --sort=-committerdate --contains ${sha}`);
return execGit(['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}`);
return execGit(['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}`);
execGit(['remote', 'add', remoteName, `https://github.com/${owner}/${name}.git`]);
execGit(['fetch', remoteName]);
return remoteName;
}

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

/** Get the ref and latest shas for the provided sha on a specific remote. */
Expand Down
22 changes: 16 additions & 6 deletions circleci-orb/scripts/rebase-pr-on-target-branch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* found in the LICENSE file at https://angular.io/license
*/

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

// Parameter variables.
const baseRevision = process.env.CIRCLE_GIT_BASE_REVISION!;
Expand All @@ -32,6 +32,10 @@ if (!process.env.CIRCLE_PR_NUMBER) {

/** Rebase on the latest commit for the targeted branch. */
(async () => {
// Rebasing requires a Git user set.
execGit(['config', 'user.email', '[email protected]']);
execGit(['config', 'user.name', 'Angular Robot']);

const base = lookupSha(baseRevision, baseRepoOwner, baseRepoName, primaryBranchName);
const head = lookupSha(headRevision, headRepoOwner, headRepoName, primaryBranchName);
const commonAncestorSha = getCommonAncestorSha(base.sha, head.sha);
Expand All @@ -46,14 +50,20 @@ if (!process.env.CIRCLE_PR_NUMBER) {
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}`);
const commitCount = execGit(['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`,
);
const circleCIConfigChanged = execGit([
'diff',
'--name-only',
`origin/${base.ref}`,
commonAncestorSha,
'--',
'.circleci/config.yml',
]);

if (!!circleCIConfigChanged) {
throw Error(`
CircleCI config on ${base.ref} has been modified since commit
Expand All @@ -77,7 +87,7 @@ if (!process.env.CIRCLE_PR_NUMBER) {
console.log();

// Rebase the PR.
exec(`git rebase origin/${base.ref}`);
execGit(['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.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const semverRegex = /^(\d+)\.(\d+)\.x$/;
* likely correct branch will be the first one encountered in the list.
*/
export function getRefFromBranchList(gitOutput: string, primaryBranchName: string): string {
const branches = gitOutput.split('\n').map((b) => b.split('/').slice(1).join('').trim());
const branches = gitOutput.split(/\r?\n/g).map((b) => b.split('/').slice(1).join('').trim());

return branches.sort((a: string, b: string) => {
if (a === primaryBranchName) {
Expand Down

0 comments on commit 87ac315

Please sign in to comment.