Skip to content

Commit 51b13ab

Browse files
committed
Check for gh-pages branch on Remote but also locally.
publishing workflow needs to ensure that gh-pages does not exists yet before creating it, or offer to publish it on remote if existing. This allows to handle more potential error while publishing like #9585
1 parent e1026cf commit 51b13ab

File tree

5 files changed

+86
-14
lines changed

5 files changed

+86
-14
lines changed

src/core/git.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,21 @@ export async function lsFiles(
6464

6565
return Promise.resolve(undefined);
6666
}
67+
68+
export async function gitBranchExists(
69+
branch: string,
70+
cwd?: string,
71+
): Promise<boolean | undefined> {
72+
if (await which("git")) {
73+
const result = await execProcess({
74+
cmd: ["git", "show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
75+
cwd,
76+
stdout: "piped",
77+
stderr: "piped",
78+
});
79+
80+
return result.code === 0;
81+
}
82+
83+
return Promise.resolve(undefined);
84+
}

src/core/github-types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export type GitHubContext = {
99
repo: boolean;
1010
originUrl?: string;
1111
repoUrl?: string;
12-
ghPages?: boolean;
12+
ghPagesRemote?: boolean;
13+
ghPagesLocal?: boolean;
1314
siteUrl?: string;
1415
browse?: boolean;
1516
organization?: string;

src/core/github.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { join } from "../deno_ral/path.ts";
1111
import { existsSync } from "fs/mod.ts";
1212
import { isHttpUrl } from "./url.ts";
1313
import { GitHubContext } from "./github-types.ts";
14+
import { gitBranchExists } from "./git.ts";
1415

1516
export async function gitHubContext(dir: string) {
1617
// establish dir
@@ -43,7 +44,7 @@ export async function gitHubContext(dir: string) {
4344
context.originUrl = result.stdout?.trim();
4445

4546
// check for a gh-pages branch
46-
context.ghPages = (await execProcess({
47+
const ghPagesRemote = await execProcess({
4748
cmd: [
4849
"git",
4950
"ls-remote",
@@ -54,7 +55,22 @@ export async function gitHubContext(dir: string) {
5455
],
5556
stdout: "piped",
5657
stderr: "piped",
57-
})).success;
58+
});
59+
60+
context.ghPagesRemote = ghPagesRemote.success;
61+
if (!ghPagesRemote.success) {
62+
// when no gh-pages branch on remote, check local to avoid creation error
63+
// as if local branch exists, we don't want to create a new one
64+
// https://git-scm.com/docs/git-ls-remote#Documentation/git-ls-remote.txt---exit-code
65+
if (ghPagesRemote.code === 2) {
66+
context.ghPagesLocal = await gitBranchExists("gh-pages");
67+
} else {
68+
// if we go there, this means something is not right with the remote origin
69+
throw new Error(
70+
`There is an error while retrieving information from remote 'origin'.\n Git error: ${ghPagesRemote.stderr}. \n Git status code: ${ghPagesRemote.code}.`,
71+
);
72+
}
73+
}
5874

5975
// determine siteUrl
6076
context.siteUrl = siteUrl(

src/publish/gh-pages/gh-pages.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { joinUrl } from "../../core/url.ts";
2727
import { completeMessage, withSpinner } from "../../core/console.ts";
2828
import { renderForPublish } from "../common/publish.ts";
2929
import { RenderFlags } from "../../command/render/types.ts";
30-
import { gitCmds, gitVersion } from "../../core/git.ts";
30+
import { gitBranchExists, gitCmds, gitVersion } from "../../core/git.ts";
3131
import {
3232
anonymousAccount,
3333
gitHubContextForPublish,
@@ -71,7 +71,7 @@ async function publishRecord(
7171
input: string | ProjectContext,
7272
): Promise<PublishRecord | undefined> {
7373
const ghContext = await gitHubContextForPublish(input);
74-
if (ghContext.ghPages) {
74+
if (ghContext.ghPagesRemote) {
7575
return {
7676
id: "gh-pages",
7777
url: ghContext.siteUrl || ghContext.originUrl,
@@ -114,17 +114,27 @@ async function publish(
114114
const ghContext = await gitHubContextForPublish(options.input);
115115
verifyContext(ghContext, "GitHub Pages");
116116

117-
// create gh pages branch if there is none yet
118-
const createGhPagesBranch = !ghContext.ghPages;
119-
if (createGhPagesBranch) {
117+
// create gh pages branch on remote and local if there is none yet
118+
const createGhPagesBranchRemote = !ghContext.ghPagesRemote;
119+
const createGhPagesBranchLocal = !ghContext.ghPagesLocal;
120+
if (createGhPagesBranchRemote) {
120121
// confirm
121-
const confirmed = await Confirm.prompt({
122+
let confirmed = await Confirm.prompt({
122123
indent: "",
123124
message: `Publish site to ${
124125
ghContext.siteUrl || ghContext.originUrl
125126
} using gh-pages?`,
126127
default: true,
127128
});
129+
if (confirmed && !createGhPagesBranchLocal) {
130+
confirmed = await Confirm.prompt({
131+
indent: "",
132+
message:
133+
`A local gh-pages branch already exists. Should it be pushed to remote 'origin'?`,
134+
default: true,
135+
});
136+
}
137+
128138
if (!confirmed) {
129139
throw new Error();
130140
}
@@ -135,9 +145,29 @@ async function publish(
135145
}
136146
const oldBranch = await gitCurrentBranch(input);
137147
try {
138-
await gitCreateGhPages(input);
148+
// Create and push if necessary, or just push local branch
149+
if (createGhPagesBranchLocal) {
150+
await gitCreateGhPages(input);
151+
} else {
152+
await gitPushGhPages(input);
153+
}
154+
} catch {
155+
// Something failed so clean up, i.e
156+
// if we created the branch then delete it.
157+
// Example of failure: Auth error on push (https://github.com/quarto-dev/quarto-cli/issues/9585)
158+
if (createGhPagesBranchLocal && await gitBranchExists("gh-pages")) {
159+
await gitCmds(input, [
160+
["checkout", oldBranch],
161+
["branch", "-D", "gh-pages"],
162+
]);
163+
}
164+
throw new Error(
165+
"Publishing to gh-pages with `quarto publish gh-pages` failed.",
166+
);
139167
} finally {
140-
await gitCmds(input, [["checkout", oldBranch]]);
168+
if (await gitCurrentBranch(input) !== oldBranch) {
169+
await gitCmds(input, [["checkout", oldBranch]]);
170+
}
141171
if (stash) {
142172
await gitStashApply(input);
143173
}
@@ -360,7 +390,14 @@ async function gitCreateGhPages(dir: string) {
360390
await gitCmds(dir, [
361391
["checkout", "--orphan", "gh-pages"],
362392
["rm", "-rf", "--quiet", "."],
363-
["commit", "--allow-empty", "-m", `Initializing gh-pages branch`],
364-
["push", "origin", `HEAD:gh-pages`],
393+
["commit", "--allow-empty", "-m", "Initializing gh-pages branch"],
365394
]);
395+
await gitPushGhPages(dir);
396+
}
397+
398+
async function gitPushGhPages(dir: string) {
399+
if (await gitCurrentBranch(dir) !== "gh-pages") {
400+
await gitCmds(dir, [["checkout", "gh-pages"]]);
401+
}
402+
await gitCmds(dir, [["push", "origin", "HEAD:gh-pages"]]);
366403
}

src/publish/huggingface/huggingface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ async function publishRecord(
7070
input: string | ProjectContext,
7171
): Promise<PublishRecord | undefined> {
7272
const ghContext = await gitHubContextForPublish(input);
73-
if (ghContext.ghPages) {
73+
if (ghContext.ghPagesRemote) {
7474
return {
7575
id: kHuggingFace,
7676
url: ghContext.siteUrl || ghContext.originUrl,

0 commit comments

Comments
 (0)