From 4433509cd60e86936217f63bf854e9879bbf9126 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 25 Mar 2021 14:35:56 +0100 Subject: [PATCH 1/2] Don't use last build on branch as baseline if for the same commit; assume a rebuild --- bin/git/git.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/git/git.js b/bin/git/git.js index f0eca6320..2ec5a9ee6 100644 --- a/bin/git/git.js +++ b/bin/git/git.js @@ -259,6 +259,7 @@ export async function getBaselineCommits( // Add the most recent build on the branch as a (potential) baseline build, unless: // - the user opts out with `--ignore-last-build-on-branch` + // - the commit is equal (and by definition on the same branch), in which case we're dealing with a rebuild // - the commit is newer than the build we are running, in which case we doing this build out // of order and that could lead to problems. // - the current branch is `HEAD`; this is fairly meaningless @@ -268,6 +269,7 @@ export async function getBaselineCommits( branch !== 'HEAD' && !ignoreLastBuildOnBranch && lastBuild && + lastBuild.commit !== commit && lastBuild.committedAt <= committedAt ) { if (await commitExists(lastBuild.commit)) { @@ -281,7 +283,7 @@ export async function getBaselineCommits( } } - // Add the most recent build on a (merged) branch if as a (potential) baseline if we think + // Add the most recent build on a (merged) branch as a (potential) baseline if we think // this commit was the commit that merged the PR. // @see https://www.chromatic.com/docs/branching-and-baselines#squash-and-rebase-merging if (pullRequest && pullRequest.lastHeadBuild) { From 592d1c571639656f11fee9a44c4e4f6ddd800d71 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Tue, 30 Mar 2021 16:56:27 +0200 Subject: [PATCH 2/2] Check baseline status to decide on skipping the build --- bin/git/git.js | 2 -- bin/tasks/gitInfo.js | 27 ++++++++++++++++++++++++++- bin/ui/tasks/gitInfo.js | 6 ++++++ bin/ui/tasks/gitInfo.stories.js | 11 ++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/bin/git/git.js b/bin/git/git.js index 2ec5a9ee6..78635f2bd 100644 --- a/bin/git/git.js +++ b/bin/git/git.js @@ -259,7 +259,6 @@ export async function getBaselineCommits( // Add the most recent build on the branch as a (potential) baseline build, unless: // - the user opts out with `--ignore-last-build-on-branch` - // - the commit is equal (and by definition on the same branch), in which case we're dealing with a rebuild // - the commit is newer than the build we are running, in which case we doing this build out // of order and that could lead to problems. // - the current branch is `HEAD`; this is fairly meaningless @@ -269,7 +268,6 @@ export async function getBaselineCommits( branch !== 'HEAD' && !ignoreLastBuildOnBranch && lastBuild && - lastBuild.commit !== commit && lastBuild.committedAt <= committedAt ) { if (await commitExists(lastBuild.commit)) { diff --git a/bin/tasks/gitInfo.js b/bin/tasks/gitInfo.js index 6d9bfa6cf..bf1ac75ef 100644 --- a/bin/tasks/gitInfo.js +++ b/bin/tasks/gitInfo.js @@ -7,8 +7,9 @@ import { initial, pending, skipFailed, - skippedForCommit, skippingBuild, + skippedForCommit, + skippedRebuild, success, } from '../ui/tasks/gitInfo'; @@ -18,6 +19,17 @@ const TesterSkipBuildMutation = ` } `; +const TesterLastBuildQuery = ` + query TesterLastBuildQuery($commit: String!, $branch: String!) { + app { + lastBuild(ref: $commit, branch: $branch) { + id + status(legacy: false) + } + } + } +`; + export const setGitInfo = async (ctx, task) => { const { branchName, patchBaseRef, fromCI: ci } = ctx.options; ctx.git = await getCommitAndBranch({ branchName, patchBaseRef, ci, log: ctx.log }); @@ -37,6 +49,7 @@ export const setGitInfo = async (ctx, task) => { if (matchesBranch(ctx.options.skip)) { transitionTo(skippingBuild)(ctx, task); + // The SkipBuildMutation ensures the commit is tagged properly. if (await ctx.client.runQuery(TesterSkipBuildMutation, { commit })) { ctx.skip = true; return transitionTo(skippedForCommit, true)(ctx, task); @@ -51,6 +64,18 @@ export const setGitInfo = async (ctx, task) => { ctx.git.baselineCommits = baselineCommits; ctx.log.debug(`Found baselineCommits: ${baselineCommits}`); + // If the sole baseline is the most recent ancestor, then this is likely a rebuild (rerun of CI job). + // If the MRA is all green, there's no need to rerun the build, we just want the CLI to exit 0 so the CI job succeeds. + // This is especially relevant for (unlinked) projects that don't use --exit-zero-on-changes. + // There's no need for a SkipBuildMutation because we don't have to tag the commit again. + if (baselineCommits.length === 1 && baselineCommits[0] === commit) { + const mostRecentAncestor = await ctx.client.runQuery(TesterLastBuildQuery, { commit, branch }); + if (mostRecentAncestor && ['PASSED', 'ACCEPTED'].includes(mostRecentAncestor.status)) { + ctx.skip = true; + return transitionTo(skippedRebuild, true)(ctx, task); + } + } + return transitionTo(success, true)(ctx, task); }; diff --git a/bin/ui/tasks/gitInfo.js b/bin/ui/tasks/gitInfo.js index a51a67df8..3645b11f8 100644 --- a/bin/ui/tasks/gitInfo.js +++ b/bin/ui/tasks/gitInfo.js @@ -30,6 +30,12 @@ export const skippedForCommit = (ctx) => ({ output: `Skipped build for commit ${ctx.git.commit.substr(0, 7)} due to --skip`, }); +export const skippedRebuild = (ctx) => ({ + status: 'success', + title: 'Skipping build', + output: `Skipped rebuild of an already fully passed/accepted build`, +}); + export const skipFailed = (ctx) => ({ status: 'error', title: 'Skipping build', diff --git a/bin/ui/tasks/gitInfo.stories.js b/bin/ui/tasks/gitInfo.stories.js index d3a9326dd..e15328b4e 100644 --- a/bin/ui/tasks/gitInfo.stories.js +++ b/bin/ui/tasks/gitInfo.stories.js @@ -1,5 +1,13 @@ import task from '../components/task'; -import { initial, pending, skipFailed, skippedForCommit, skippingBuild, success } from './gitInfo'; +import { + initial, + pending, + skipFailed, + skippedForCommit, + skippedRebuild, + skippingBuild, + success, +} from './gitInfo'; export default { title: 'CLI/Tasks/GitInfo', @@ -15,4 +23,5 @@ export const Success = () => success({ git, options }); export const NoBaselines = () => success({ git: { ...git, baselineCommits: [] }, options }); export const Skipping = () => skippingBuild({ git }); export const Skipped = () => skippedForCommit({ git }); +export const SkippedRebuild = () => skippedRebuild(); export const SkipFailed = () => skipFailed();