Skip to content

Commit

Permalink
Handle multiple types for advanced scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
mauriziovitale committed Mar 6, 2024
1 parent 76907e7 commit 6888a24
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 47 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ jobs:
last-successful-event: ""

# The path where your repository is. This is only required for cases where the repository code is checked out or moved to a specific path.
# The property can also contain several types separated by comma i.e. schedule,workflow_dispatch
#
# Default: .
working-directory: ""
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ inputs:
description: "By default, if no successful workflow is found on the main branch to determine the SHA, we will log a warning and use HEAD~1. Enable this option to error and exit instead."
default: "false"
last-successful-event:
description: "The type of event to check for the last successful commit corresponding to that workflow-id, e.g. push, pull_request, release etc"
description: "The type of event to check for the last successful commit corresponding to that workflow-id, e.g. push or pull_request or release. The property can also contain several types separated by a comma. E.g. schedule,workflow_dispatch."
default: "push"
working-directory:
description: "The directory where your repository is located"
Expand Down
49 changes: 37 additions & 12 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37971,18 +37971,43 @@ function findSuccessfulCommit(workflow_id, run_id, owner, repo, branch, lastSucc
process.stdout.write("\n");
process.stdout.write(`Workflow Id not provided. Using workflow '${workflow_id}'\n`);
}
// fetch all workflow runs on a given repo/branch/workflow with push and success
const shas = yield octokit
.request(`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`, {
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
workflow_id,
event: lastSuccessfulEvent,
status: "success",
})
.then(({ data: { workflow_runs } }) => workflow_runs.map((run) => run.head_sha));
let shas = [];
// if there are several events separated by comma
if (lastSuccessfulEvent.includes(",")) {
// find the greatest workflow id among the types and retrieve the sha
const events = lastSuccessfulEvent.split(",");
const workflowIdMap = new Map();
for (const event of events) {
const workflowRun = yield octokit
.request(`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`, {
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
event,
workflow_id,
})
.then(({ data }) => {
return data.workflow_runs[0];
});
workflowIdMap.set(workflowRun.id, workflowRun.head_sha);
}
shas.push(workflowIdMap.get(Math.max(...workflowIdMap.keys())));
}
else {
// fetch all workflow runs on a given repo/branch/workflow with push and success
shas = yield octokit
.request(`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`, {
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
workflow_id,
event: lastSuccessfulEvent,
status: "success",
})
.then(({ data: { workflow_runs } }) => workflow_runs.map((run) => run.head_sha));
}
return yield findExistingCommit(octokit, branch, shas);
});
}
Expand Down
95 changes: 61 additions & 34 deletions find-successful-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let BASE_SHA: string;
} else {
process.stdout.write("\n");
process.stdout.write(
`WARNING: Working directory '${workingDirectory}' doesn't exist.\n`
`WARNING: Working directory '${workingDirectory}' doesn't exist.\n`,
);
}
}
Expand All @@ -49,7 +49,7 @@ let BASE_SHA: string;
const baseResult = spawnSync(
"git",
["merge-base", `origin/${mainBranchName}`, mergeBaseRef],
{ encoding: "utf-8" }
{ encoding: "utf-8" },
);
BASE_SHA = baseResult.stdout;
} catch (e) {
Expand All @@ -64,7 +64,7 @@ let BASE_SHA: string;
owner,
repo,
mainBranchName,
lastSuccessfulEvent
lastSuccessfulEvent,
);
} catch (e) {
core.setFailed(e.message);
Expand All @@ -76,27 +76,27 @@ let BASE_SHA: string;
reportFailure(mainBranchName);
return;
} else {
process.stdout.write( "\n");
process.stdout.write("\n");
process.stdout.write(
`WARNING: Unable to find a successful workflow run on 'origin/${mainBranchName}', or the latest successful workflow was connected to a commit which no longer exists on that branch (e.g. if that branch was rebased)\n`
`WARNING: Unable to find a successful workflow run on 'origin/${mainBranchName}', or the latest successful workflow was connected to a commit which no longer exists on that branch (e.g. if that branch was rebased)\n`,
);
process.stdout.write(
`We are therefore defaulting to use HEAD~1 on 'origin/${mainBranchName}'\n`
`We are therefore defaulting to use HEAD~1 on 'origin/${mainBranchName}'\n`,
);
process.stdout.write("\n");
process.stdout.write(
`NOTE: You can instead make this a hard error by setting 'error-on-no-successful-workflow' on the action in your workflow.\n`
`NOTE: You can instead make this a hard error by setting 'error-on-no-successful-workflow' on the action in your workflow.\n`,
);
process.stdout.write("\n");

const commitCountOutput = spawnSync(
"git",
["rev-list", "--count", `origin/${mainBranchName}`],
{ encoding: "utf-8" }
{ encoding: "utf-8" },
).stdout;
const commitCount = parseInt(
stripNewLineEndings(commitCountOutput),
10
10,
);

const LAST_COMMIT_CMD = `origin/${mainBranchName}${
Expand All @@ -111,7 +111,7 @@ let BASE_SHA: string;
} else {
process.stdout.write("\n");
process.stdout.write(
`Found the last successful workflow run on 'origin/${mainBranchName}'\n`
`Found the last successful workflow run on 'origin/${mainBranchName}'\n`,
);
process.stdout.write(`Commit: ${BASE_SHA}\n`);
}
Expand Down Expand Up @@ -148,7 +148,7 @@ async function findSuccessfulCommit(
owner: string,
repo: string,
branch: string,
lastSuccessfulEvent: string
lastSuccessfulEvent: string,
): Promise<string | undefined> {
const octokit = new ProxifiedClient();
if (!workflow_id) {
Expand All @@ -162,26 +162,53 @@ async function findSuccessfulCommit(
.then(({ data: { workflow_id } }) => workflow_id);
process.stdout.write("\n");
process.stdout.write(
`Workflow Id not provided. Using workflow '${workflow_id}'\n`
`Workflow Id not provided. Using workflow '${workflow_id}'\n`,
);
}
// fetch all workflow runs on a given repo/branch/workflow with push and success
const shas = await octokit
.request(
`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`,
{
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
workflow_id,
event: lastSuccessfulEvent,
status: "success",
}
)
.then(({ data: { workflow_runs } }) =>
workflow_runs.map((run: { head_sha: any }) => run.head_sha)
);
let shas = [];
// if there are several events separated by comma
if (lastSuccessfulEvent.includes(",")) {
// find the greatest workflow id among the types and retrieve the sha
const events = lastSuccessfulEvent.split(",");
const workflowIdMap = new Map();
for (const event of events) {
const workflowRun = await octokit
.request(
`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`,
{
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
event,
workflow_id,
},
)
.then(({ data }) => {
return data.workflow_runs[0];
});
workflowIdMap.set(workflowRun.id, workflowRun.head_sha);
}
shas.push(workflowIdMap.get(Math.max(...workflowIdMap.keys())));
} else {
// fetch all workflow runs on a given repo/branch/workflow with push and success
shas = await octokit
.request(
`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`,
{
owner,
repo,
// on non-push workflow runs we do not have branch property
branch: lastSuccessfulEvent !== "push" ? undefined : branch,
workflow_id,
event: lastSuccessfulEvent,
status: "success",
},
)
.then(({ data: { workflow_runs } }) =>
workflow_runs.map((run: { head_sha: any }) => run.head_sha),
);
}

return await findExistingCommit(octokit, branch, shas);
}
Expand All @@ -198,7 +225,7 @@ async function findMergeBaseRef(): Promise<string> {
function findMergeQueuePr(): string {
const { head_ref, base_sha } = github.context.payload.merge_group;
const result = new RegExp(
`^refs/heads/gh-readonly-queue/${mainBranchName}/pr-(\\d+)-${base_sha}$`
`^refs/heads/gh-readonly-queue/${mainBranchName}/pr-(\\d+)-${base_sha}$`,
).exec(head_ref);
return result ? result.at(1) : undefined;
}
Expand All @@ -213,7 +240,7 @@ async function findMergeQueueBranch(): Promise<string> {
const octokit = new ProxifiedClient();
const result = await octokit.request(
`GET /repos/${owner}/${repo}/pulls/${pull_number}`,
{ owner, repo, pull_number: +pull_number }
{ owner, repo, pull_number: +pull_number },
);
return result.data.head.ref;
}
Expand All @@ -224,7 +251,7 @@ async function findMergeQueueBranch(): Promise<string> {
async function findExistingCommit(
octokit: Octokit,
branchName: string,
shas: string[]
shas: string[],
): Promise<string | undefined> {
for (const commitSha of shas) {
if (await commitExists(octokit, branchName, commitSha)) {
Expand All @@ -240,7 +267,7 @@ async function findExistingCommit(
async function commitExists(
octokit: Octokit,
branchName: string,
commitSha: string
commitSha: string,
): Promise<boolean> {
try {
spawnSync("git", ["cat-file", "-e", commitSha], {
Expand All @@ -263,7 +290,7 @@ async function commitExists(
});

return commits.data.some(
(commit: { sha: string }) => commit.sha === commitSha
(commit: { sha: string }) => commit.sha === commitSha,
);
} catch {
return false;
Expand Down

0 comments on commit 6888a24

Please sign in to comment.