fabrica-e-commerce 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/github.js +94 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabrica-e-commerce",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Orange themed CMD launcher for deploying Fabrica e-commerce stores with Supabase and Vercel.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/github.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import process from 'node:process';
2
2
  import { commandExists, runCommand, runCommandCapture } from './system.js';
3
+ import { choose } from './prompt.js';
3
4
  import { kv, section, spinner } from './ui.js';
4
5
 
5
6
  export async function isGithubCliInstalled() {
@@ -11,6 +12,11 @@ export async function isLoggedInToGithub() {
11
12
  return result.code === 0;
12
13
  }
13
14
 
15
+ async function setupGithubGitCredentials() {
16
+ const result = await runCommandCapture('gh', ['auth', 'setup-git']);
17
+ return result.code === 0;
18
+ }
19
+
14
20
  export async function ensureGithubLogin() {
15
21
  section('GitHub login');
16
22
  if (!(await isGithubCliInstalled())) {
@@ -19,15 +25,23 @@ export async function ensureGithubLogin() {
19
25
  const spin = spinner('Checking GitHub CLI login');
20
26
  if (await isLoggedInToGithub()) {
21
27
  spin.succeed('Already logged in to GitHub');
22
- return;
28
+ } else {
29
+ spin.fail('Not logged in to GitHub');
30
+ console.log('A browser/device flow will open so you can log in with "gh auth login"...');
31
+ await runCommand('gh', ['auth', 'login', '--hostname', 'github.com', '--git-protocol', 'https', '--web']);
32
+ if (!(await isLoggedInToGithub())) {
33
+ throw new Error('GitHub login was not completed. Run "fabrica build" again after logging in with "gh auth login".');
34
+ }
35
+ kv('GitHub', 'Logged in');
23
36
  }
24
- spin.fail('Not logged in to GitHub');
25
- console.log('A browser/device flow will open so you can log in with "gh auth login"...');
26
- await runCommand('gh', ['auth', 'login', '--hostname', 'github.com', '--git-protocol', 'https', '--web']);
27
- if (!(await isLoggedInToGithub())) {
28
- throw new Error('GitHub login was not completed. Run "fabrica build" again after logging in with "gh auth login".');
37
+
38
+ const gitSpin = spinner('Configuring GitHub credentials for git push');
39
+ if (await setupGithubGitCredentials()) {
40
+ gitSpin.succeed('GitHub credentials ready for git push');
41
+ } else {
42
+ gitSpin.fail('Could not configure GitHub git credentials automatically');
43
+ console.log('If git push asks for credentials, complete the prompt or run: gh auth setup-git');
29
44
  }
30
- kv('GitHub', 'Logged in');
31
45
  }
32
46
 
33
47
  async function getGithubLogin() {
@@ -36,6 +50,72 @@ async function getGithubLogin() {
36
50
  return result.stdout.trim();
37
51
  }
38
52
 
53
+ async function githubRepoExists(owner, repoName) {
54
+ const result = await runCommandCapture('gh', ['repo', 'view', `${owner}/${repoName}`, '--json', 'name']);
55
+ return result.code === 0;
56
+ }
57
+
58
+ async function ensureGithubRepo(owner, repoName) {
59
+ const fullName = `${owner}/${repoName}`;
60
+ if (await githubRepoExists(owner, repoName)) {
61
+ const action = await choose(`GitHub repo ${fullName} already exists. What should Fabrica do?`, [
62
+ { name: 'Use the existing repo and push this storefront to it', value: 'use' },
63
+ { name: 'Stop so I can choose a different Vercel project/repo name', value: 'stop' }
64
+ ]);
65
+ if (action === 'stop') throw new Error(`GitHub repo ${fullName} already exists. Re-run build with a different project name.`);
66
+ return;
67
+ }
68
+
69
+ const spin = spinner(`Creating GitHub repo ${fullName}`);
70
+ const create = await runCommandCapture('gh', ['repo', 'create', fullName, '--private']);
71
+ if (create.code !== 0) {
72
+ spin.fail('Could not create GitHub repository');
73
+ throw new Error(create.stderr || 'gh repo create failed');
74
+ }
75
+ spin.succeed(`Created GitHub repo ${fullName}`);
76
+ }
77
+
78
+ async function setOrigin(project, repoUrl) {
79
+ const existing = await runCommandCapture('git', ['remote', 'get-url', 'origin'], { cwd: project.target });
80
+ if (existing.code === 0) {
81
+ await runCommand('git', ['remote', 'set-url', 'origin', repoUrl], { cwd: project.target });
82
+ } else {
83
+ await runCommand('git', ['remote', 'add', 'origin', repoUrl], { cwd: project.target });
84
+ }
85
+ }
86
+
87
+ async function pushWithCredentialFallback(project) {
88
+ const spin = spinner('Pushing storefront to GitHub');
89
+ let push = await runCommandCapture('git', ['push', '-u', 'origin', 'main'], { cwd: project.target });
90
+ if (push.code === 0) {
91
+ spin.succeed('Pushed storefront to GitHub');
92
+ return;
93
+ }
94
+
95
+ spin.fail('Initial git push failed');
96
+ console.log('GitHub rejected the push credentials. Re-configuring GitHub CLI credentials and retrying...');
97
+ await setupGithubGitCredentials();
98
+ push = await runCommandCapture('git', ['push', '-u', 'origin', 'main'], { cwd: project.target });
99
+ if (push.code === 0) {
100
+ kv('GitHub push', 'Succeeded after refreshing credentials');
101
+ return;
102
+ }
103
+
104
+ console.log(push.stderr || push.stdout || 'git push failed');
105
+ const action = await choose('GitHub push still needs authentication. What should Fabrica do?', [
106
+ { name: 'Open GitHub login again, then retry push', value: 'login' },
107
+ { name: 'Stop so I can fix GitHub credentials manually', value: 'stop' }
108
+ ]);
109
+ if (action === 'login') {
110
+ await runCommand('gh', ['auth', 'login', '--hostname', 'github.com', '--git-protocol', 'https', '--web']);
111
+ await setupGithubGitCredentials();
112
+ await runCommand('git', ['push', '-u', 'origin', 'main'], { cwd: project.target });
113
+ kv('GitHub push', 'Succeeded after login');
114
+ return;
115
+ }
116
+ throw new Error('GitHub push failed. Run "gh auth setup-git" or "gh auth login", then rerun build.');
117
+ }
118
+
39
119
  // Re-homes the cloned storefront code into a brand new GitHub repository
40
120
  // owned by the logged-in user, so the deployed Vercel project can stay
41
121
  // connected to that repo (git push -> auto deploy) instead of the original
@@ -45,6 +125,7 @@ export async function createGithubRepoFromClone(project) {
45
125
  await ensureGithubLogin();
46
126
  const owner = await getGithubLogin();
47
127
  const repoName = project.projectName;
128
+ const repoUrl = `https://github.com/${owner}/${repoName}.git`;
48
129
 
49
130
  // Detach from the template's git history and start a clean repo so we
50
131
  // don't try to push into someone else's repository history.
@@ -57,15 +138,11 @@ export async function createGithubRepoFromClone(project) {
57
138
  await runCommand('git', ['add', '-A'], { cwd: project.target });
58
139
  await runCommand('git', ['-c', 'user.email=fabrica-cli@local', '-c', 'user.name=Fabrica CLI', 'commit', '-m', 'Initial commit from Fabrica storefront'], { cwd: project.target });
59
140
 
60
- const spin = spinner(`Creating GitHub repo ${owner}/${repoName}`);
61
- const create = await runCommandCapture('gh', ['repo', 'create', repoName, '--private', '--source', '.', '--remote', 'origin', '--push'], { cwd: project.target });
62
- if (create.code !== 0) {
63
- spin.fail('Could not create GitHub repository');
64
- throw new Error(create.stderr || 'gh repo create failed');
65
- }
66
- spin.succeed(`Pushed code to ${owner}/${repoName}`);
141
+ await ensureGithubRepo(owner, repoName);
142
+ await setOrigin(project, repoUrl);
143
+ await pushWithCredentialFallback(project);
67
144
 
68
- const repoUrl = `https://github.com/${owner}/${repoName}`;
69
- kv('GitHub repo', repoUrl);
70
- return { owner, repoName, repoUrl };
145
+ const browserUrl = `https://github.com/${owner}/${repoName}`;
146
+ kv('GitHub repo', browserUrl);
147
+ return { owner, repoName, repoUrl: browserUrl };
71
148
  }