Skip to content
Merged
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
59 changes: 30 additions & 29 deletions apps/api/src/services/githubPusher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,36 +72,19 @@ async function emitProgress(
}

async function ensureMainBranchExists(octokit: Octokit, owner: string, repo: string): Promise<void> {
try {
await octokit.repos.getBranch({
owner,
repo,
branch: "main",
});
return;
} catch {
// Branch does not exist yet. Initialize it below.
// With auto_init the repo is created with an initial commit on `main`, but
// GitHub populates it asynchronously. Poll briefly until the branch is
// visible before pushing files.
for (let attempt = 0; attempt < 10; attempt++) {
try {
await octokit.repos.getBranch({ owner, repo, branch: "main" });
return;
} catch {
await wait(500);
}
}

const tree = await octokit.git.createTree({
owner,
repo,
tree: [],
});

const commit = await octokit.git.createCommit({
owner,
repo,
message: "chore: initialize main branch",
tree: tree.data.sha,
});

await octokit.git.createRef({
owner,
repo,
ref: "refs/heads/main",
sha: commit.data.sha,
});
throw new Error("Timed out waiting for the 'main' branch to be initialized");
}

export async function pushToGitHub(
Expand All @@ -124,7 +107,7 @@ export async function pushToGitHub(
name: repoName,
description: "Generated by StackForge",
private: false,
auto_init: false,
auto_init: true,
});

const owner = repo.data.owner?.login ?? authUser.data.login;
Expand All @@ -148,13 +131,31 @@ export async function pushToGitHub(
}

for (const [filePath, content] of entries) {
// The repo was auto-initialized with a README, so updating an existing
// file requires its current blob sha. Look it up; absent for new files.
let existingSha: string | undefined;
try {
const existing = await octokit.repos.getContent({
owner,
repo: repoName,
path: filePath,
ref: "main",
});
if (!Array.isArray(existing.data) && "sha" in existing.data) {
existingSha = existing.data.sha;
}
} catch {
// File does not exist yet; create it fresh.
}

await octokit.repos.createOrUpdateFileContents({
owner,
repo: repoName,
path: filePath,
message: "feat: initial project generated by StackForge",
content: Buffer.from(content, "utf8").toString("base64"),
branch: "main",
...(existingSha !== undefined ? { sha: existingSha } : {}),
});

await emitProgress(onProgress, {
Expand Down
Loading