Skip to content

Commit f80b355

Browse files
committed
fix(state): push via https when token available
1 parent 8a05ebd commit f80b355

2 files changed

Lines changed: 47 additions & 17 deletions

File tree

packages/lib/src/usecases/state-repo.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ export const statePush = Effect.gen(function*(_) {
253253
)
254254
const token = yield* _(resolveGithubToken(fs, path, root))
255255
const effect = token && token.length > 0 && isGithubHttpsRemote(originUrl)
256-
? withGithubAskpassEnv(token, (env) => git(root, ["push", "-u", "origin", "HEAD"], env))
256+
? withGithubAskpassEnv(
257+
token,
258+
(env) => git(root, ["-c", `remote.origin.pushurl=${originUrl}`, "push", "-u", "origin", "HEAD"], env)
259+
)
257260
: git(root, ["push", "-u", "origin", "HEAD"], gitBaseEnv)
258261
yield* _(effect)
259262
}).pipe(Effect.asVoid)

packages/lib/src/usecases/state-repo/sync-ops.ts

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ import { tryBuildGithubCompareUrl, withGithubAskpassEnv } from "./github-auth.js
1212

1313
type StateRepoEnv = FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor
1414

15+
const withOriginPushUrlOverride = (originUrl: string | null, args: ReadonlyArray<string>): ReadonlyArray<string> => {
16+
const trimmed = originUrl?.trim() ?? ""
17+
if (trimmed.length === 0) {
18+
return args
19+
}
20+
// Use a per-command config override so token-based pushes use HTTPS even when the repo has an SSH pushurl.
21+
// This keeps the repo config unchanged while avoiding non-interactive SSH host key / passphrase prompts.
22+
return ["-c", `remote.origin.pushurl=${trimmed}`, ...args]
23+
}
24+
25+
const resolveSyncMessage = (value: string | null): string => {
26+
const trimmed = value?.trim() ?? ""
27+
return trimmed.length > 0 ? trimmed : defaultSyncMessage
28+
}
29+
30+
const logOpenPr = (originUrl: string, baseBranch: string, prBranch: string, compareUrl: string | null) =>
31+
compareUrl
32+
? Effect.log(`Open PR: ${compareUrl}`)
33+
: Effect.log(`Open PR from '${prBranch}' into '${baseBranch}' (origin: ${originUrl}).`)
34+
1535
const commitAllIfNeeded = (
1636
root: string,
1737
message: string,
@@ -68,6 +88,7 @@ const rebaseOntoOriginIfPossible = (
6888
const pushToNewBranch = (
6989
root: string,
7090
baseBranch: string,
91+
originPushUrlOverride: string | null,
7192
env: GitAuthEnv
7293
): Effect.Effect<string, CommandFailedError | PlatformError, CommandExecutor.CommandExecutor> =>
7394
Effect.gen(function*(_) {
@@ -77,7 +98,9 @@ const pushToNewBranch = (
7798
const timestamp = yield* _(Effect.sync(() => new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-")))
7899
const branch = sanitizeBranchComponent(`state-sync/${baseBranch}/${timestamp}-${headShort}`)
79100

80-
yield* _(git(root, ["push", "origin", `HEAD:refs/heads/${branch}`], env))
101+
yield* _(
102+
git(root, withOriginPushUrlOverride(originPushUrlOverride, ["push", "origin", `HEAD:refs/heads/${branch}`]), env)
103+
)
81104
return branch
82105
})
83106

@@ -93,41 +116,42 @@ export const runStateSyncOps = (
93116
root: string,
94117
originUrl: string,
95118
message: string | null,
96-
env: GitAuthEnv
119+
env: GitAuthEnv,
120+
options?: { readonly originPushUrlOverride?: string | null }
97121
): Effect.Effect<void, CommandFailedError | PlatformError, StateRepoEnv> =>
98122
Effect.gen(function*(_) {
123+
const originPushUrlOverride = options?.originPushUrlOverride ?? null
99124
yield* _(normalizeLegacyStateProjects(root))
100-
const commitMessage = message && message.trim().length > 0 ? message.trim() : defaultSyncMessage
101-
yield* _(commitAllIfNeeded(root, commitMessage, env))
125+
yield* _(commitAllIfNeeded(root, resolveSyncMessage(message), env))
102126

103127
const branch = yield* _(getCurrentBranch(root, env))
104128
const baseBranch = resolveBaseBranch(branch)
105129

106130
const rebaseResult = yield* _(rebaseOntoOriginIfPossible(root, baseBranch, env))
107131
if (rebaseResult === "conflict") {
108-
const prBranch = yield* _(pushToNewBranch(root, baseBranch, env))
132+
const prBranch = yield* _(pushToNewBranch(root, baseBranch, originPushUrlOverride, env))
109133
const compareUrl = tryBuildGithubCompareUrl(originUrl, baseBranch, prBranch)
110134

111135
yield* _(Effect.logWarning(`State sync needs manual merge: pushed changes to branch '${prBranch}'.`))
112-
yield* (compareUrl
113-
? _(Effect.log(`Open PR: ${compareUrl}`))
114-
: _(Effect.log(`Open PR from '${prBranch}' into '${baseBranch}' (origin: ${originUrl}).`)))
136+
yield* _(logOpenPr(originUrl, baseBranch, prBranch, compareUrl))
115137
return
116138
}
117139

118-
const pushExit = yield* _(gitExitCode(root, ["push", "-u", "origin", "HEAD"], env))
140+
const pushExit = yield* _(
141+
gitExitCode(
142+
root,
143+
withOriginPushUrlOverride(originPushUrlOverride, ["push", "-u", "origin", "HEAD"]),
144+
env
145+
)
146+
)
119147
if (pushExit === successExitCode) {
120148
return
121149
}
122150

123-
const prBranch = yield* _(pushToNewBranch(root, baseBranch, env))
151+
const prBranch = yield* _(pushToNewBranch(root, baseBranch, originPushUrlOverride, env))
124152
const compareUrl = tryBuildGithubCompareUrl(originUrl, baseBranch, prBranch)
125153
yield* _(Effect.logWarning(`State push failed (exit ${pushExit}); pushed changes to branch '${prBranch}'.`))
126-
if (compareUrl) {
127-
yield* _(Effect.log(`Open PR: ${compareUrl}`))
128-
return
129-
}
130-
yield* _(Effect.log(`Open PR from '${prBranch}' into '${baseBranch}' (origin: ${originUrl}).`))
154+
yield* _(logOpenPr(originUrl, baseBranch, prBranch, compareUrl))
131155
}).pipe(Effect.asVoid)
132156

133157
export const runStateSyncWithToken = (
@@ -136,4 +160,7 @@ export const runStateSyncWithToken = (
136160
originUrl: string,
137161
message: string | null
138162
): Effect.Effect<void, CommandFailedError | PlatformError, StateRepoEnv> =>
139-
withGithubAskpassEnv(token, (env) => runStateSyncOps(root, originUrl, message, env))
163+
withGithubAskpassEnv(
164+
token,
165+
(env) => runStateSyncOps(root, originUrl, message, env, { originPushUrlOverride: originUrl })
166+
)

0 commit comments

Comments
 (0)