Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 853746ba65 | |||
| efb4ad186f |
@@ -83327,7 +83327,7 @@ function query({
|
||||
// package.json
|
||||
var package_default = {
|
||||
name: "@pullfrog/action",
|
||||
version: "0.0.142",
|
||||
version: "0.0.144",
|
||||
type: "module",
|
||||
files: [
|
||||
"index.js",
|
||||
@@ -123148,19 +123148,19 @@ function PushBranchTool(ctx) {
|
||||
parameters: PushBranch,
|
||||
execute: execute(ctx, async ({ branchName, force }) => {
|
||||
const branch = branchName || $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
||||
log.info(`Pushing branch ${branch} to ${remote}`);
|
||||
const isUrl = remote.startsWith("https://");
|
||||
const args3 = force ? ["push", "--force", ...isUrl ? [] : ["-u"], remote, branch] : ["push", ...isUrl ? [] : ["-u"], remote, branch];
|
||||
log.info(`Pushing branch ${branch} to ${isUrl ? "(fork URL)" : remote}`);
|
||||
if (force) {
|
||||
log.warning(`Force pushing - this will overwrite remote history`);
|
||||
$("git", ["push", "--force", "-u", remote, branch]);
|
||||
} else {
|
||||
$("git", ["push", "-u", remote, branch]);
|
||||
}
|
||||
$("git", args3);
|
||||
return {
|
||||
success: true,
|
||||
branch,
|
||||
remote,
|
||||
remote: isUrl ? "(fork URL)" : remote,
|
||||
force,
|
||||
message: `Successfully pushed branch ${branch} to ${remote}`
|
||||
message: `Successfully pushed branch ${branch}`
|
||||
};
|
||||
})
|
||||
});
|
||||
@@ -123859,7 +123859,7 @@ function setupGitConfig() {
|
||||
);
|
||||
}
|
||||
}
|
||||
function setupGit(ctx) {
|
||||
async function setupGit(ctx) {
|
||||
const repoDir = process.cwd();
|
||||
log.info("\u{1F527} Setting up git authentication...");
|
||||
try {
|
||||
@@ -123871,43 +123871,34 @@ function setupGit(ctx) {
|
||||
} catch {
|
||||
log.debug("No existing authentication headers to remove");
|
||||
}
|
||||
const originUrl = `https://x-access-token:${ctx.githubInstallationToken}@github.com/${ctx.owner}/${ctx.name}.git`;
|
||||
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
||||
log.info("\u2713 Updated origin URL with authentication token");
|
||||
if (ctx.payload.event.is_pr !== true || !ctx.payload.event.issue_number) {
|
||||
log.debug("Not a PR event, staying on default branch");
|
||||
const originUrl = `https://x-access-token:${ctx.githubInstallationToken}@github.com/${ctx.owner}/${ctx.name}.git`;
|
||||
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
||||
log.info("\u2713 Updated origin URL with authentication token");
|
||||
return { pushRemote: "origin" };
|
||||
}
|
||||
const prNumber = ctx.payload.event.issue_number;
|
||||
log.info(`\u{1F33F} Checking out PR #${prNumber}...`);
|
||||
$("gh", ["pr", "checkout", prNumber.toString()], {
|
||||
cwd: repoDir,
|
||||
env: { GH_TOKEN: ctx.githubInstallationToken }
|
||||
const pr = await ctx.octokit.rest.pulls.get({
|
||||
owner: ctx.owner,
|
||||
repo: ctx.name,
|
||||
pull_number: prNumber
|
||||
});
|
||||
const headRepo = pr.data.head.repo;
|
||||
if (!headRepo) {
|
||||
throw new Error(`PR #${prNumber} source repository was deleted`);
|
||||
}
|
||||
const branch = pr.data.head.ref;
|
||||
log.info(`\u{1F33F} Checking out PR #${prNumber} (${branch})...`);
|
||||
$("git", ["fetch", "origin", `pull/${prNumber}/head:${branch}`], { cwd: repoDir });
|
||||
$("git", ["checkout", branch], { cwd: repoDir });
|
||||
log.info(`\u2713 Successfully checked out PR #${prNumber}`);
|
||||
const pushRemote = detectPushRemote();
|
||||
if (pushRemote !== "origin") {
|
||||
log.info(`\u{1F374} Fork PR detected, will push to remote: ${pushRemote}`);
|
||||
const forkUrl = $("git", ["remote", "get-url", pushRemote], { cwd: repoDir, log: false });
|
||||
const authedForkUrl = forkUrl.replace(
|
||||
"https://github.com/",
|
||||
`https://x-access-token:${ctx.githubInstallationToken}@github.com/`
|
||||
);
|
||||
$("git", ["remote", "set-url", pushRemote, authedForkUrl], { cwd: repoDir });
|
||||
log.info(`\u2713 Updated ${pushRemote} URL with authentication token`);
|
||||
}
|
||||
return { pushRemote };
|
||||
}
|
||||
function detectPushRemote() {
|
||||
try {
|
||||
const branch = $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
||||
const upstream = $("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], {
|
||||
log: false
|
||||
});
|
||||
return upstream.split("/")[0];
|
||||
} catch {
|
||||
return "origin";
|
||||
const token = process.env.GITHUB_TOKEN || ctx.githubInstallationToken;
|
||||
const pushUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`;
|
||||
const isFork = headRepo.full_name !== pr.data.base.repo.full_name;
|
||||
if (isFork) {
|
||||
log.info(`\u{1F374} Fork PR detected, will push to: ${headRepo.full_name}`);
|
||||
}
|
||||
return { pushRemote: pushUrl };
|
||||
}
|
||||
|
||||
// utils/timer.ts
|
||||
@@ -123946,7 +123937,7 @@ async function main(inputs) {
|
||||
const partialCtx = await initializeContext(inputs, payload);
|
||||
const ctx = partialCtx;
|
||||
timer.checkpoint("initializeContext");
|
||||
const { pushRemote } = setupGit(ctx);
|
||||
const { pushRemote } = await setupGit(ctx);
|
||||
ctx.pushRemote = pushRemote;
|
||||
timer.checkpoint("setupGit");
|
||||
await setupTempDirectory(ctx);
|
||||
|
||||
@@ -64,7 +64,7 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
const ctx = partialCtx as Context;
|
||||
timer.checkpoint("initializeContext");
|
||||
|
||||
const { pushRemote } = setupGit(ctx);
|
||||
const { pushRemote } = await setupGit(ctx);
|
||||
ctx.pushRemote = pushRemote;
|
||||
timer.checkpoint("setupGit");
|
||||
|
||||
|
||||
+10
-6
@@ -152,20 +152,24 @@ export function PushBranchTool(ctx: Context) {
|
||||
execute: execute(ctx, async ({ branchName, force }) => {
|
||||
const branch = branchName || $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
||||
|
||||
log.info(`Pushing branch ${branch} to ${remote}`);
|
||||
// skip -u flag when pushing to URL (can't set upstream without a remote name)
|
||||
const isUrl = remote.startsWith("https://");
|
||||
const args = force
|
||||
? ["push", "--force", ...(isUrl ? [] : ["-u"]), remote, branch]
|
||||
: ["push", ...(isUrl ? [] : ["-u"]), remote, branch];
|
||||
|
||||
log.info(`Pushing branch ${branch} to ${isUrl ? "(fork URL)" : remote}`);
|
||||
if (force) {
|
||||
log.warning(`Force pushing - this will overwrite remote history`);
|
||||
$("git", ["push", "--force", "-u", remote, branch]);
|
||||
} else {
|
||||
$("git", ["push", "-u", remote, branch]);
|
||||
}
|
||||
$("git", args);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
branch,
|
||||
remote,
|
||||
remote: isUrl ? "(fork URL)" : remote,
|
||||
force,
|
||||
message: `Successfully pushed branch ${branch} to ${remote}`,
|
||||
message: `Successfully pushed branch ${branch}`,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pullfrog/action",
|
||||
"version": "0.0.142",
|
||||
"version": "0.0.144",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.js",
|
||||
|
||||
+30
-42
@@ -68,11 +68,10 @@ export type SetupGitResult = {
|
||||
|
||||
/**
|
||||
* Unified git setup: configures authentication and checks out PR branch if applicable.
|
||||
* Uses gh as credential helper so git push works with any remote (including forks).
|
||||
* For PR events, gh pr checkout sets up proper remote tracking.
|
||||
* Returns the remote to push to (detected from branch tracking after checkout).
|
||||
* For PR events, always returns a push URL constructed from the PR's head repo.
|
||||
* This works for both same-repo and fork PRs with a single code path.
|
||||
*/
|
||||
export function setupGit(ctx: Context): SetupGitResult {
|
||||
export async function setupGit(ctx: Context): Promise<SetupGitResult> {
|
||||
const repoDir = process.cwd();
|
||||
|
||||
log.info("🔧 Setting up git authentication...");
|
||||
@@ -88,51 +87,40 @@ export function setupGit(ctx: Context): SetupGitResult {
|
||||
log.debug("No existing authentication headers to remove");
|
||||
}
|
||||
|
||||
// embed token directly in origin URL - simple and doesn't expose token in env
|
||||
const originUrl = `https://x-access-token:${ctx.githubInstallationToken}@github.com/${ctx.owner}/${ctx.name}.git`;
|
||||
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
||||
log.info("✓ Updated origin URL with authentication token");
|
||||
|
||||
// non-PR events: stay on default branch, push to origin
|
||||
// non-PR events: set up origin with token, stay on default branch
|
||||
if (ctx.payload.event.is_pr !== true || !ctx.payload.event.issue_number) {
|
||||
log.debug("Not a PR event, staying on default branch");
|
||||
const originUrl = `https://x-access-token:${ctx.githubInstallationToken}@github.com/${ctx.owner}/${ctx.name}.git`;
|
||||
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
||||
log.info("✓ Updated origin URL with authentication token");
|
||||
return { pushRemote: "origin" };
|
||||
}
|
||||
|
||||
// checkout PR branch - gh pr checkout handles fork remotes and tracking automatically
|
||||
// PR event: fetch PR info to get branch name and head repo
|
||||
const prNumber = ctx.payload.event.issue_number;
|
||||
log.info(`🌿 Checking out PR #${prNumber}...`);
|
||||
$("gh", ["pr", "checkout", prNumber.toString()], {
|
||||
cwd: repoDir,
|
||||
env: { GH_TOKEN: ctx.githubInstallationToken },
|
||||
const pr = await ctx.octokit.rest.pulls.get({
|
||||
owner: ctx.owner,
|
||||
repo: ctx.name,
|
||||
pull_number: prNumber,
|
||||
});
|
||||
|
||||
const headRepo = pr.data.head.repo;
|
||||
if (!headRepo) {
|
||||
throw new Error(`PR #${prNumber} source repository was deleted`);
|
||||
}
|
||||
|
||||
// checkout PR branch using plain git (no gh cli needed)
|
||||
const branch = pr.data.head.ref;
|
||||
log.info(`🌿 Checking out PR #${prNumber} (${branch})...`);
|
||||
$("git", ["fetch", "origin", `pull/${prNumber}/head:${branch}`], { cwd: repoDir });
|
||||
$("git", ["checkout", branch], { cwd: repoDir });
|
||||
log.info(`✓ Successfully checked out PR #${prNumber}`);
|
||||
|
||||
// detect the push remote from branch tracking (set by gh pr checkout)
|
||||
const pushRemote = detectPushRemote();
|
||||
if (pushRemote !== "origin") {
|
||||
log.info(`🍴 Fork PR detected, will push to remote: ${pushRemote}`);
|
||||
// embed token in fork remote URL too
|
||||
const forkUrl = $("git", ["remote", "get-url", pushRemote], { cwd: repoDir, log: false });
|
||||
const authedForkUrl = forkUrl.replace(
|
||||
"https://github.com/",
|
||||
`https://x-access-token:${ctx.githubInstallationToken}@github.com/`
|
||||
);
|
||||
$("git", ["remote", "set-url", pushRemote, authedForkUrl], { cwd: repoDir });
|
||||
log.info(`✓ Updated ${pushRemote} URL with authentication token`);
|
||||
}
|
||||
return { pushRemote };
|
||||
}
|
||||
|
||||
function detectPushRemote(): string {
|
||||
try {
|
||||
const branch = $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
||||
const upstream = $("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], {
|
||||
log: false,
|
||||
});
|
||||
// upstream is like "remote/branch", extract remote name
|
||||
return upstream.split("/")[0];
|
||||
} catch {
|
||||
return "origin";
|
||||
// unified push URL - works for both same-repo and fork PRs
|
||||
const token = process.env.GITHUB_TOKEN || ctx.githubInstallationToken;
|
||||
const pushUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`;
|
||||
const isFork = headRepo.full_name !== pr.data.base.repo.full_name;
|
||||
if (isFork) {
|
||||
log.info(`🍴 Fork PR detected, will push to: ${headRepo.full_name}`);
|
||||
}
|
||||
return { pushRemote: pushUrl };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user