Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions actions/setup/js/push_signed_commits.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ async function readBlobAsBase64(blobHash, cwd) {
* @param {string} opts.baseRef - Git ref of the remote head before commits were applied (used for rev-list)
* @param {string} opts.cwd - Working directory of the local git checkout
* @param {object} [opts.gitAuthEnv] - Environment variables for git push fallback auth
* @returns {Promise<void>}
* @returns {Promise<string | undefined>} SHA of the commit that landed on the target branch
*/
async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, cwd, gitAuthEnv }) {
// Collect the commits introduced (oldest-first) using topological order to ensure
Expand All @@ -141,7 +141,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c

if (shas.length === 0) {
core.info("pushSignedCommits: no new commits to push via GraphQL");
return;
return undefined;
}

core.info(`pushSignedCommits: replaying ${shas.length} commit(s) via GraphQL createCommitOnBranch (branch: ${branch}, repo: ${owner}/${repo})`);
Expand Down Expand Up @@ -362,12 +362,16 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c
core.info(`pushSignedCommits: signed commit created: ${lastOid}`);
}
core.info(`pushSignedCommits: all ${shas.length} commit(s) pushed as signed commits`);
return lastOid ?? shas[shas.length - 1];
} catch (graphqlError) {
core.warning(`pushSignedCommits: GraphQL signed push failed, falling back to git push: ${graphqlError instanceof Error ? graphqlError.message : String(graphqlError)}`);
await exec.exec("git", ["push", "origin", branch], {
cwd,
env: { ...process.env, ...(gitAuthEnv || {}) },
});
const fallbackSha = shas[shas.length - 1];
core.info(`pushSignedCommits: git push fallback completed, using pushed SHA ${fallbackSha}`);
return fallbackSha;
}
}

Expand Down
21 changes: 15 additions & 6 deletions actions/setup/js/push_to_pull_request_branch.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ async function main(config = {}) {
// token on multi-commit branches where workflow files may have been modified).
let newCommitCount = 0;
let remoteHeadBeforePatch = "";
let pushedCommitSha = "";
if (hasChanges) {
// Capture HEAD before applying changes to compute new-commit count later
try {
Expand Down Expand Up @@ -736,7 +737,7 @@ async function main(config = {}) {

// Push the applied commits to the branch using signed GraphQL commits (outside patch try/catch so push failures are not misattributed)
try {
await pushSignedCommits({
const pushedSha = await pushSignedCommits({
githubClient,
owner: repoParts.owner,
repo: repoParts.repo,
Expand All @@ -745,6 +746,10 @@ async function main(config = {}) {
cwd: process.cwd(),
gitAuthEnv,
});
if (pushedSha) {
pushedCommitSha = pushedSha;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add logging of pushed sha

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added logging in push_to_pull_request_branch.cjs right after pushSignedCommits returns, so the pushed SHA is logged when present. Included in b91965d.

core.info(`pushSignedCommits returned pushed SHA: ${pushedSha}`);
}
core.info(`Changes committed and pushed to branch: ${branchName}`);
} catch (pushError) {
const pushErrorMessage = getErrorMessage(pushError);
Expand Down Expand Up @@ -856,12 +861,16 @@ async function main(config = {}) {
}
}

// Get commit SHA and push URL
const commitShaRes = await exec.getExecOutput("git", ["rev-parse", "HEAD"]);
if (commitShaRes.exitCode !== 0) {
return { success: false, error: "Failed to get commit SHA" };
// The signed-push helper returns the commit SHA that landed on the branch.
// Fall back to local HEAD only if the helper did not return one.
let commitSha = pushedCommitSha;
if (!commitSha) {
const commitShaRes = await exec.getExecOutput("git", ["rev-parse", "HEAD"]);
if (commitShaRes.exitCode !== 0) {
return { success: false, error: "Failed to get commit SHA" };
}
commitSha = commitShaRes.stdout.trim();
}
const commitSha = commitShaRes.stdout.trim();

// Get repository base URL and construct URLs
// For cross-repo scenarios, use repoParts (the target repo) not context.repo (the workflow repo)
Expand Down
27 changes: 27 additions & 0 deletions actions/setup/js/push_to_pull_request_branch.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,33 @@ index 0000000..abc1234
expect(result.commit_url).toContain("test-owner/test-repo/commit/");
});

it("should use pushed commit SHA returned by pushSignedCommits for activation comment commit link", async () => {
const patchPath = createPatchFile();
const updateActivationCommentModule = require("./update_activation_comment.cjs");
const updateCommitSpy = vi.spyOn(updateActivationCommentModule, "updateActivationCommentWithCommit").mockResolvedValue(undefined);
const pushSignedCommitsModule = require("./push_signed_commits.cjs");
const pushSignedSpy = vi.spyOn(pushSignedCommitsModule, "pushSignedCommits").mockResolvedValue("remote-head-after");

try {
mockExec.getExecOutput
.mockResolvedValueOnce({ exitCode: 0, stdout: "preflight-sha\trefs/heads/feature-branch\n", stderr: "" }) // preflight ls-remote
.mockResolvedValueOnce({ exitCode: 0, stdout: "local-head-before\n", stderr: "" }) // rev-parse HEAD before patch
.mockResolvedValueOnce({ exitCode: 0, stdout: "1\n", stderr: "" }); // rev-list --count

const module = await loadModule();
const handler = await module.main({});
const result = await handler({ patch_path: patchPath }, {});

expect(result.success).toBe(true);
expect(result.commit_sha).toBe("remote-head-after");
expect(result.commit_url).toContain("/commit/remote-head-after");
expect(updateCommitSpy).toHaveBeenCalledWith(mockGithub, mockContext, mockCore, "remote-head-after", "https://github.com/test-owner/test-repo/commit/remote-head-after", { targetIssueNumber: 123 });
} finally {
pushSignedSpy.mockRestore();
updateCommitSpy.mockRestore();
}
});

it("should detect deleted branch before fetch", async () => {
const patchPath = createPatchFile();

Expand Down
Loading