specweave 0.24.1 → 0.24.8
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.
- package/CLAUDE.md +106 -0
- package/README.md +34 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +80 -41
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts +5 -2
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +72 -6
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.d.ts +2 -1
- package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.js +4 -3
- package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +26 -9
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts +2 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.js.map +1 -1
- package/dist/src/config/types.d.ts +24 -24
- package/dist/src/core/config/types.d.ts +25 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js +6 -0
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/repo-structure/git-error-handler.d.ts +37 -0
- package/dist/src/core/repo-structure/git-error-handler.d.ts.map +1 -0
- package/dist/src/core/repo-structure/git-error-handler.js +214 -0
- package/dist/src/core/repo-structure/git-error-handler.js.map +1 -0
- package/dist/src/core/repo-structure/git-provider.d.ts +183 -0
- package/dist/src/core/repo-structure/git-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/git-provider.js +57 -0
- package/dist/src/core/repo-structure/git-provider.js.map +1 -0
- package/dist/src/core/repo-structure/github-validator.d.ts +1 -0
- package/dist/src/core/repo-structure/github-validator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/github-validator.js +35 -9
- package/dist/src/core/repo-structure/github-validator.js.map +1 -1
- package/dist/src/core/repo-structure/platform-registry.d.ts +114 -0
- package/dist/src/core/repo-structure/platform-registry.d.ts.map +1 -0
- package/dist/src/core/repo-structure/platform-registry.js +195 -0
- package/dist/src/core/repo-structure/platform-registry.js.map +1 -0
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts +30 -0
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.js +69 -0
- package/dist/src/core/repo-structure/prompt-consolidator.js.map +1 -1
- package/dist/src/core/repo-structure/providers/bitbucket-provider.d.ts +54 -0
- package/dist/src/core/repo-structure/providers/bitbucket-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/bitbucket-provider.js +104 -0
- package/dist/src/core/repo-structure/providers/bitbucket-provider.js.map +1 -0
- package/dist/src/core/repo-structure/providers/github-provider.d.ts +53 -0
- package/dist/src/core/repo-structure/providers/github-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/github-provider.js +239 -0
- package/dist/src/core/repo-structure/providers/github-provider.js.map +1 -0
- package/dist/src/core/repo-structure/providers/gitlab-provider.d.ts +50 -0
- package/dist/src/core/repo-structure/providers/gitlab-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/gitlab-provider.js +97 -0
- package/dist/src/core/repo-structure/providers/gitlab-provider.js.map +1 -0
- package/dist/src/core/repo-structure/providers/index.d.ts +33 -0
- package/dist/src/core/repo-structure/providers/index.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/index.js +60 -0
- package/dist/src/core/repo-structure/providers/index.js.map +1 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts +33 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.js +275 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +18 -2
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +303 -85
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/repo-structure/url-generator.d.ts +80 -0
- package/dist/src/core/repo-structure/url-generator.d.ts.map +1 -0
- package/dist/src/core/repo-structure/url-generator.js +110 -0
- package/dist/src/core/repo-structure/url-generator.js.map +1 -0
- package/dist/src/init/architecture/types.d.ts +6 -6
- package/dist/src/utils/plugin-validator.d.ts.map +1 -1
- package/dist/src/utils/plugin-validator.js +15 -14
- package/dist/src/utils/plugin-validator.js.map +1 -1
- package/package.json +4 -4
- package/plugins/specweave/.claude-plugin/plugin.json +4 -4
- package/plugins/specweave/agents/pm/AGENT.md +2 -0
- package/plugins/specweave/commands/specweave-do.md +0 -47
- package/plugins/specweave/commands/specweave-increment.md +0 -82
- package/plugins/specweave/commands/specweave-next.md +0 -47
- package/plugins/specweave/hooks/post-task-completion.sh +67 -6
- package/plugins/specweave/hooks/pre-edit-spec.sh +11 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +69 -2
- package/plugins/specweave/hooks/pre-write-spec.sh +11 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +124 -4
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave/agents/pm/AGENT.md.bak +0 -1893
- package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
- package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
- package/plugins/specweave/hooks/lib/migrate-increment-work.sh.bak +0 -245
- package/plugins/specweave/hooks/lib/sync-spec-content.sh.bak +0 -149
- package/plugins/specweave/hooks/lib/validate-spec-status.sh.bak +0 -163
- package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
- package/plugins/specweave/hooks/post-first-increment.sh.bak +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
- package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
- package/plugins/specweave/hooks/post-spec-update.sh.bak +0 -158
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
- package/plugins/specweave/hooks/post-user-story-complete.sh.bak +0 -179
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
- package/plugins/specweave/hooks/pre-command-deduplication.sh.bak +0 -83
- package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
- package/plugins/specweave/hooks/user-prompt-submit.sh.bak +0 -386
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +0 -50
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +0 -84
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +0 -89
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +0 -142
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +0 -269
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +0 -60
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +0 -155
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +0 -264
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +0 -42
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +0 -110
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +0 -178
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +0 -45
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +0 -92
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +0 -156
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +0 -33
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +0 -301
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +0 -484
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +0 -56
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +0 -182
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +0 -306
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +0 -64
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +0 -231
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +0 -369
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +0 -43
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +0 -132
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +0 -258
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +0 -294
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +0 -27
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +0 -339
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +0 -476
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +0 -59
- package/plugins/specweave/lib/hooks/translate-file.js.bak +0 -289
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +0 -428
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +0 -13
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +0 -119
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +0 -224
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +0 -51
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +0 -103
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +0 -29
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +0 -296
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +0 -489
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -228
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -444
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
|
@@ -23,16 +23,22 @@ import { execSync } from 'child_process';
|
|
|
23
23
|
import { execFileNoThrowSync } from '../../utils/execFileNoThrow.js';
|
|
24
24
|
import { generateRepoIdSmart, ensureUniqueId, validateRepoId, suggestRepoName } from './repo-id-generator.js';
|
|
25
25
|
import { SetupStateManager } from './setup-state-manager.js';
|
|
26
|
-
import { validateRepository, validateOwner } from './github-validator.js';
|
|
27
26
|
import { generateEnvFile } from '../../utils/env-file-generator.js';
|
|
28
27
|
import { generateSetupSummary } from './setup-summary.js';
|
|
29
|
-
import { getArchitecturePrompt, getParentRepoBenefits, getVisibilityPrompt } from './prompt-consolidator.js';
|
|
28
|
+
import { getArchitecturePrompt, getParentRepoBenefits, getVisibilityPrompt, getUrlTypePrompt } from './prompt-consolidator.js';
|
|
30
29
|
import { detectRepositoryHints } from './folder-detector.js';
|
|
30
|
+
import { discoverRepositories } from './repo-bulk-discovery.js';
|
|
31
|
+
import { Octokit } from '@octokit/rest';
|
|
32
|
+
import { initializeProviders } from './providers/index.js';
|
|
33
|
+
import { getPlatformRegistry } from './platform-registry.js';
|
|
34
|
+
import { getPlatformSelectionPrompt } from './prompt-consolidator.js';
|
|
31
35
|
export class RepoStructureManager {
|
|
32
36
|
constructor(projectPath, githubToken) {
|
|
33
37
|
this.projectPath = projectPath;
|
|
34
38
|
this.githubToken = githubToken;
|
|
35
39
|
this.stateManager = new SetupStateManager(projectPath);
|
|
40
|
+
// Initialize Git providers on instantiation
|
|
41
|
+
initializeProviders();
|
|
36
42
|
}
|
|
37
43
|
/**
|
|
38
44
|
* Prompt user for repository structure decisions
|
|
@@ -73,14 +79,53 @@ export class RepoStructureManager {
|
|
|
73
79
|
})),
|
|
74
80
|
default: 'single'
|
|
75
81
|
}]);
|
|
82
|
+
// Step 2: Ask about Git hosting platform
|
|
83
|
+
const registry = getPlatformRegistry();
|
|
84
|
+
const platformOptions = registry.getPlatformOptions(true); // Include unsupported platforms
|
|
85
|
+
const platformPromptData = getPlatformSelectionPrompt();
|
|
86
|
+
console.log(chalk.cyan('\n' + platformPromptData.message));
|
|
87
|
+
const { platform } = await inquirer.prompt([{
|
|
88
|
+
type: 'list',
|
|
89
|
+
name: 'platform',
|
|
90
|
+
message: platformPromptData.question,
|
|
91
|
+
choices: platformOptions.map(opt => ({
|
|
92
|
+
name: opt.disabled
|
|
93
|
+
? `${opt.name}\n${chalk.gray(opt.description)}\n${chalk.yellow('⚠️ ' + opt.disabled)}`
|
|
94
|
+
: `${opt.name}\n${chalk.gray(opt.description)}`,
|
|
95
|
+
value: opt.value,
|
|
96
|
+
short: opt.name,
|
|
97
|
+
disabled: opt.disabled ? opt.disabled : false
|
|
98
|
+
})),
|
|
99
|
+
default: 'github'
|
|
100
|
+
}]);
|
|
101
|
+
// Get provider instance
|
|
102
|
+
const provider = registry.getProvider(platform);
|
|
103
|
+
if (!provider) {
|
|
104
|
+
throw new Error(`Platform ${platform} is not available. This should not happen!`);
|
|
105
|
+
}
|
|
106
|
+
console.log(chalk.green(`\n✓ Using ${provider.config.name} as Git hosting platform\n`));
|
|
107
|
+
// Step 3: Ask about Git remote URL format (SSH vs HTTPS)
|
|
108
|
+
const urlTypePromptData = getUrlTypePrompt();
|
|
109
|
+
const { urlType } = await inquirer.prompt([{
|
|
110
|
+
type: 'list',
|
|
111
|
+
name: 'urlType',
|
|
112
|
+
message: urlTypePromptData.question,
|
|
113
|
+
choices: urlTypePromptData.options.map(opt => ({
|
|
114
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
115
|
+
value: opt.value,
|
|
116
|
+
short: opt.label
|
|
117
|
+
})),
|
|
118
|
+
default: urlTypePromptData.default
|
|
119
|
+
}]);
|
|
120
|
+
console.log(chalk.green(`\n✓ Using ${urlType.toUpperCase()} remote URLs\n`));
|
|
76
121
|
// Map ArchitectureChoice to internal architecture
|
|
77
122
|
const mappedArch = this.mapArchitectureChoice(architecture);
|
|
78
123
|
switch (mappedArch) {
|
|
79
124
|
case 'single':
|
|
80
|
-
return this.configureSingleRepo();
|
|
125
|
+
return this.configureSingleRepo(urlType, platform, provider);
|
|
81
126
|
case 'parent':
|
|
82
127
|
// GitHub parent repo (pushed to GitHub)
|
|
83
|
-
return this.configureMultiRepo(true, false);
|
|
128
|
+
return this.configureMultiRepo(true, false, urlType, platform, provider);
|
|
84
129
|
default:
|
|
85
130
|
throw new Error(`Unknown architecture: ${architecture}`);
|
|
86
131
|
}
|
|
@@ -102,9 +147,18 @@ export class RepoStructureManager {
|
|
|
102
147
|
* Resume setup from saved state
|
|
103
148
|
*/
|
|
104
149
|
async resumeSetup(state) {
|
|
150
|
+
// Default to GitHub platform for resumed setups (backward compatibility)
|
|
151
|
+
const registry = getPlatformRegistry();
|
|
152
|
+
const provider = registry.getProvider('github');
|
|
153
|
+
if (!provider) {
|
|
154
|
+
throw new Error('GitHub provider not available. This should not happen!');
|
|
155
|
+
}
|
|
105
156
|
// Convert saved state back to config format
|
|
106
157
|
const config = {
|
|
107
158
|
architecture: state.architecture,
|
|
159
|
+
urlType: 'ssh', // Default to SSH for resumed setups
|
|
160
|
+
platform: 'github', // Default to GitHub for backward compatibility
|
|
161
|
+
provider: provider,
|
|
108
162
|
parentRepo: state.parentRepo,
|
|
109
163
|
repositories: state.repos.map(r => ({
|
|
110
164
|
id: r.id,
|
|
@@ -124,7 +178,7 @@ export class RepoStructureManager {
|
|
|
124
178
|
/**
|
|
125
179
|
* Configure single repository
|
|
126
180
|
*/
|
|
127
|
-
async configureSingleRepo() {
|
|
181
|
+
async configureSingleRepo(urlType = 'ssh', platform = 'github', provider) {
|
|
128
182
|
console.log(chalk.cyan('\n📦 Single Repository Configuration\n'));
|
|
129
183
|
// Check if repo already exists
|
|
130
184
|
const hasGit = existsSync(path.join(this.projectPath, '.git'));
|
|
@@ -170,6 +224,9 @@ export class RepoStructureManager {
|
|
|
170
224
|
}
|
|
171
225
|
return {
|
|
172
226
|
architecture: 'single',
|
|
227
|
+
urlType,
|
|
228
|
+
platform,
|
|
229
|
+
provider,
|
|
173
230
|
repositories: [{
|
|
174
231
|
id: 'main',
|
|
175
232
|
name: repo,
|
|
@@ -235,6 +292,9 @@ export class RepoStructureManager {
|
|
|
235
292
|
}
|
|
236
293
|
return {
|
|
237
294
|
architecture: 'single',
|
|
295
|
+
urlType,
|
|
296
|
+
platform,
|
|
297
|
+
provider,
|
|
238
298
|
repositories: [{
|
|
239
299
|
id: 'main',
|
|
240
300
|
name: answers.repo,
|
|
@@ -251,12 +311,15 @@ export class RepoStructureManager {
|
|
|
251
311
|
* Configure multi-repository architecture
|
|
252
312
|
* @param useParent - Whether to use parent repository/folder
|
|
253
313
|
* @param isLocalParent - If true, parent folder is local only (NOT pushed to GitHub)
|
|
314
|
+
* @param urlType - Git remote URL format (ssh or https)
|
|
315
|
+
* @param platform - Git hosting platform type
|
|
316
|
+
* @param provider - Git provider instance for API operations
|
|
254
317
|
*
|
|
255
318
|
* NOTE: This is primarily user-facing output (console.log/console.error).
|
|
256
319
|
* All console.* calls in this method are legitimate user-facing exceptions
|
|
257
320
|
* as defined in CONTRIBUTING.md (colored messages, confirmations, formatted output).
|
|
258
321
|
*/
|
|
259
|
-
async configureMultiRepo(useParent = true, isLocalParent = false) {
|
|
322
|
+
async configureMultiRepo(useParent = true, isLocalParent = false, urlType = 'ssh', platform = 'github', provider) {
|
|
260
323
|
console.log(chalk.cyan('\n🎯 Multi-Repository Configuration\n'));
|
|
261
324
|
console.log(chalk.gray('This creates separate repositories for each service/component.\n'));
|
|
262
325
|
// Show parent repo benefits if using parent approach
|
|
@@ -266,6 +329,9 @@ export class RepoStructureManager {
|
|
|
266
329
|
}
|
|
267
330
|
const config = {
|
|
268
331
|
architecture: useParent ? 'parent' : 'multi-repo',
|
|
332
|
+
urlType,
|
|
333
|
+
platform,
|
|
334
|
+
provider,
|
|
269
335
|
repositories: []
|
|
270
336
|
};
|
|
271
337
|
// Save state: architecture selected
|
|
@@ -300,15 +366,15 @@ export class RepoStructureManager {
|
|
|
300
366
|
{
|
|
301
367
|
type: 'input',
|
|
302
368
|
name: 'owner',
|
|
303
|
-
message:
|
|
369
|
+
message: `${provider.config.name} owner/organization for IMPLEMENTATION repos:`,
|
|
304
370
|
validate: async (input) => {
|
|
305
371
|
if (!input.trim())
|
|
306
372
|
return 'Owner is required';
|
|
307
|
-
// Validate owner exists on
|
|
373
|
+
// Validate owner exists on the platform
|
|
308
374
|
if (this.githubToken) {
|
|
309
|
-
const result = await validateOwner(input, this.githubToken);
|
|
375
|
+
const result = await provider.validateOwner(input, this.githubToken);
|
|
310
376
|
if (!result.valid) {
|
|
311
|
-
return result.error ||
|
|
377
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
312
378
|
}
|
|
313
379
|
}
|
|
314
380
|
return true;
|
|
@@ -349,15 +415,15 @@ export class RepoStructureManager {
|
|
|
349
415
|
{
|
|
350
416
|
type: 'input',
|
|
351
417
|
name: 'owner',
|
|
352
|
-
message:
|
|
418
|
+
message: `${provider.config.name} owner/organization:`,
|
|
353
419
|
validate: async (input) => {
|
|
354
420
|
if (!input.trim())
|
|
355
421
|
return 'Owner is required';
|
|
356
|
-
// Validate owner exists on
|
|
422
|
+
// Validate owner exists on the platform
|
|
357
423
|
if (this.githubToken) {
|
|
358
|
-
const result = await validateOwner(input, this.githubToken);
|
|
424
|
+
const result = await provider.validateOwner(input, this.githubToken);
|
|
359
425
|
if (!result.valid) {
|
|
360
|
-
return result.error ||
|
|
426
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
361
427
|
}
|
|
362
428
|
}
|
|
363
429
|
return true;
|
|
@@ -374,11 +440,11 @@ export class RepoStructureManager {
|
|
|
374
440
|
validate: async (input) => {
|
|
375
441
|
if (!input.trim())
|
|
376
442
|
return 'Repository name is required';
|
|
377
|
-
// Validate repository EXISTS on
|
|
443
|
+
// Validate repository EXISTS on the platform
|
|
378
444
|
if (this.githubToken && ownerPrompt.owner) {
|
|
379
|
-
const result = await validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
445
|
+
const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
380
446
|
if (!result.exists) {
|
|
381
|
-
return `Repository ${ownerPrompt.owner}/${input} not found on
|
|
447
|
+
return `Repository ${ownerPrompt.owner}/${input} not found on ${provider.config.name}. Please check the name or choose 'Create new'.`;
|
|
382
448
|
}
|
|
383
449
|
}
|
|
384
450
|
return true;
|
|
@@ -423,15 +489,15 @@ export class RepoStructureManager {
|
|
|
423
489
|
{
|
|
424
490
|
type: 'input',
|
|
425
491
|
name: 'owner',
|
|
426
|
-
message:
|
|
492
|
+
message: `${provider.config.name} owner/organization for ALL repos:`,
|
|
427
493
|
validate: async (input) => {
|
|
428
494
|
if (!input.trim())
|
|
429
495
|
return 'Owner is required';
|
|
430
|
-
// Validate owner exists on
|
|
496
|
+
// Validate owner exists on the platform
|
|
431
497
|
if (this.githubToken) {
|
|
432
|
-
const result = await validateOwner(input, this.githubToken);
|
|
498
|
+
const result = await provider.validateOwner(input, this.githubToken);
|
|
433
499
|
if (!result.valid) {
|
|
434
|
-
return result.error ||
|
|
500
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
435
501
|
}
|
|
436
502
|
}
|
|
437
503
|
return true;
|
|
@@ -450,7 +516,7 @@ export class RepoStructureManager {
|
|
|
450
516
|
return 'Repository name is required';
|
|
451
517
|
// Validate repository DOESN'T exist
|
|
452
518
|
if (this.githubToken && ownerPrompt.owner) {
|
|
453
|
-
const result = await validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
519
|
+
const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
454
520
|
if (result.exists) {
|
|
455
521
|
return `Repository ${ownerPrompt.owner}/${input} already exists at ${result.url}. Please choose 'Use existing' or pick a different name.`;
|
|
456
522
|
}
|
|
@@ -565,27 +631,92 @@ export class RepoStructureManager {
|
|
|
565
631
|
console.log(chalk.green(`\n✓ Total repositories to create: ${totalRepos} (1 parent + ${repoCount} implementation)\n`));
|
|
566
632
|
}
|
|
567
633
|
}
|
|
634
|
+
// Bulk repository discovery (optimization for many repos)
|
|
635
|
+
let discoveredRepos = [];
|
|
636
|
+
let bulkDiscoveryStrategy = 'manual';
|
|
637
|
+
if (this.githubToken && config.parentRepo) {
|
|
638
|
+
const octokit = new Octokit({ auth: this.githubToken });
|
|
639
|
+
const owner = config.parentRepo.owner;
|
|
640
|
+
const isOrg = await provider.isOrganization(owner, this.githubToken);
|
|
641
|
+
// Retry loop for pattern adjustment
|
|
642
|
+
let discoveryResult = null;
|
|
643
|
+
while (discoveryResult === null) {
|
|
644
|
+
discoveryResult = await discoverRepositories(octokit, owner, isOrg, repoCount);
|
|
645
|
+
// If null, user selected "go back and adjust pattern", loop will retry
|
|
646
|
+
// If user selected "manual", discoveryResult will be { repositories: [], strategy: 'manual' }
|
|
647
|
+
}
|
|
648
|
+
if (discoveryResult) {
|
|
649
|
+
bulkDiscoveryStrategy = discoveryResult.strategy;
|
|
650
|
+
if (discoveryResult.strategy !== 'manual') {
|
|
651
|
+
discoveredRepos = discoveryResult.repositories;
|
|
652
|
+
// Update repoCount to match discovered repos
|
|
653
|
+
if (discoveredRepos.length !== repoCount) {
|
|
654
|
+
console.log(chalk.yellow(`\n📝 Adjusting repository count from ${repoCount} to ${discoveredRepos.length} (based on discovery)\n`));
|
|
655
|
+
// Override repoCount with discovered count
|
|
656
|
+
repoCount = discoveredRepos.length;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
568
661
|
// Configure each repository
|
|
569
662
|
console.log(chalk.cyan('\n📦 Configure Each Repository:\n'));
|
|
570
663
|
const usedIds = new Set();
|
|
571
664
|
const configuredRepoNames = []; // Track configured repo names for smart ID generation
|
|
572
665
|
for (let i = 0; i < repoCount; i++) {
|
|
666
|
+
const discoveredRepo = discoveredRepos[i]; // May be undefined if manual
|
|
667
|
+
const isDiscovered = bulkDiscoveryStrategy !== 'manual' && discoveredRepo;
|
|
573
668
|
console.log(chalk.white(`\nRepository ${i + 1} of ${repoCount}:`));
|
|
574
669
|
// Smart suggestion for ALL repos (not just first one!)
|
|
575
670
|
const projectName = path.basename(this.projectPath);
|
|
576
|
-
const suggestedName = suggestRepoName(projectName, i, repoCount);
|
|
671
|
+
const suggestedName = isDiscovered ? discoveredRepo.name : suggestRepoName(projectName, i, repoCount);
|
|
672
|
+
// If discovered, show preview and skip prompts (or allow confirmation)
|
|
673
|
+
if (isDiscovered) {
|
|
674
|
+
console.log(chalk.green(` ✓ Discovered: ${chalk.bold(discoveredRepo.name)}`));
|
|
675
|
+
console.log(chalk.gray(` Description: ${discoveredRepo.description || '(none)'}`));
|
|
676
|
+
console.log(chalk.gray(` Visibility: ${discoveredRepo.private ? 'Private' : 'Public'}`));
|
|
677
|
+
const { confirmDiscovered } = await inquirer.prompt([{
|
|
678
|
+
type: 'confirm',
|
|
679
|
+
name: 'confirmDiscovered',
|
|
680
|
+
message: 'Use this repository configuration?',
|
|
681
|
+
default: true
|
|
682
|
+
}]);
|
|
683
|
+
if (!confirmDiscovered) {
|
|
684
|
+
// Allow manual override
|
|
685
|
+
console.log(chalk.yellow(` → Switching to manual entry for this repository\n`));
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
// Use discovered repo configuration directly
|
|
689
|
+
const smartId = generateRepoIdSmart(discoveredRepo.name, configuredRepoNames);
|
|
690
|
+
const { id: suggestedId } = ensureUniqueId(smartId, usedIds);
|
|
691
|
+
console.log(chalk.green(` ✓ Repository ID: ${chalk.bold(suggestedId)} ${chalk.gray('(auto-generated)')}`));
|
|
692
|
+
usedIds.add(suggestedId);
|
|
693
|
+
configuredRepoNames.push(discoveredRepo.name);
|
|
694
|
+
config.repositories.push({
|
|
695
|
+
id: suggestedId,
|
|
696
|
+
name: discoveredRepo.name,
|
|
697
|
+
owner: discoveredRepo.owner,
|
|
698
|
+
description: discoveredRepo.description || `${discoveredRepo.name} service`,
|
|
699
|
+
path: useParent ? suggestedId : suggestedId,
|
|
700
|
+
visibility: discoveredRepo.private ? 'private' : 'public',
|
|
701
|
+
createOnGitHub: false, // Already exists!
|
|
702
|
+
isNested: useParent
|
|
703
|
+
});
|
|
704
|
+
continue; // Skip manual prompts
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// Manual entry (original behavior)
|
|
577
708
|
const repoAnswers = await inquirer.prompt([
|
|
578
709
|
{
|
|
579
710
|
type: 'input',
|
|
580
711
|
name: 'name',
|
|
581
712
|
message: 'Repository name:',
|
|
582
|
-
default: suggestedName,
|
|
713
|
+
default: suggestedName,
|
|
583
714
|
validate: async (input) => {
|
|
584
715
|
if (!input.trim())
|
|
585
716
|
return 'Repository name is required';
|
|
586
|
-
// Validate repository doesn't exist
|
|
587
|
-
if (this.githubToken && config.parentRepo) {
|
|
588
|
-
const result = await validateRepository(config.parentRepo.owner, input, this.githubToken);
|
|
717
|
+
// Validate repository doesn't exist (skip for discovered repos)
|
|
718
|
+
if (!isDiscovered && this.githubToken && config.parentRepo) {
|
|
719
|
+
const result = await provider.validateRepository(config.parentRepo.owner, input, this.githubToken);
|
|
589
720
|
if (result.exists) {
|
|
590
721
|
return `Repository ${config.parentRepo.owner}/${input} already exists at ${result.url}`;
|
|
591
722
|
}
|
|
@@ -603,7 +734,7 @@ export class RepoStructureManager {
|
|
|
603
734
|
type: 'confirm',
|
|
604
735
|
name: 'createOnGitHub',
|
|
605
736
|
message: 'Create this repository on GitHub?',
|
|
606
|
-
default: true
|
|
737
|
+
default: !isDiscovered // Default to true for new repos, false for discovered
|
|
607
738
|
}
|
|
608
739
|
]);
|
|
609
740
|
// Smart auto-generate ID from repository name (context-aware)
|
|
@@ -649,19 +780,23 @@ export class RepoStructureManager {
|
|
|
649
780
|
}
|
|
650
781
|
usedIds.add(id);
|
|
651
782
|
configuredRepoNames.push(repoAnswers.name);
|
|
652
|
-
// Ask about visibility
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
783
|
+
// Ask about visibility only if creating a new repository
|
|
784
|
+
let visibility = 'private';
|
|
785
|
+
if (repoAnswers.createOnGitHub) {
|
|
786
|
+
const visibilityPrompt = getVisibilityPrompt(repoAnswers.name);
|
|
787
|
+
const result = await inquirer.prompt([{
|
|
788
|
+
type: 'list',
|
|
789
|
+
name: 'visibility',
|
|
790
|
+
message: visibilityPrompt.question,
|
|
791
|
+
choices: visibilityPrompt.options.map(opt => ({
|
|
792
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
793
|
+
value: opt.value,
|
|
794
|
+
short: opt.label
|
|
795
|
+
})),
|
|
796
|
+
default: visibilityPrompt.default
|
|
797
|
+
}]);
|
|
798
|
+
visibility = result.visibility;
|
|
799
|
+
}
|
|
665
800
|
config.repositories.push({
|
|
666
801
|
id: id,
|
|
667
802
|
name: repoAnswers.name,
|
|
@@ -707,7 +842,7 @@ export class RepoStructureManager {
|
|
|
707
842
|
/**
|
|
708
843
|
* Configure monorepo
|
|
709
844
|
*/
|
|
710
|
-
async configureMonorepo() {
|
|
845
|
+
async configureMonorepo(urlType = 'ssh', platform = 'github', provider) {
|
|
711
846
|
console.log(chalk.cyan('\n📚 Monorepo Configuration\n'));
|
|
712
847
|
console.log(chalk.gray('Single repository with multiple projects/packages.\n'));
|
|
713
848
|
const answers = await inquirer.prompt([
|
|
@@ -749,22 +884,29 @@ export class RepoStructureManager {
|
|
|
749
884
|
default: !existsSync(path.join(this.projectPath, '.git'))
|
|
750
885
|
}
|
|
751
886
|
]);
|
|
752
|
-
// Ask about visibility
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
887
|
+
// Ask about visibility only if creating a new repository
|
|
888
|
+
let visibility = 'private';
|
|
889
|
+
if (answers.createOnGitHub) {
|
|
890
|
+
const visibilityPrompt = getVisibilityPrompt(answers.repo);
|
|
891
|
+
const result = await inquirer.prompt([{
|
|
892
|
+
type: 'list',
|
|
893
|
+
name: 'visibility',
|
|
894
|
+
message: visibilityPrompt.question,
|
|
895
|
+
choices: visibilityPrompt.options.map(opt => ({
|
|
896
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
897
|
+
value: opt.value,
|
|
898
|
+
short: opt.label
|
|
899
|
+
})),
|
|
900
|
+
default: visibilityPrompt.default
|
|
901
|
+
}]);
|
|
902
|
+
visibility = result.visibility;
|
|
903
|
+
}
|
|
765
904
|
const projects = answers.projects.split(',').map((p) => p.trim());
|
|
766
905
|
return {
|
|
767
906
|
architecture: 'monorepo',
|
|
907
|
+
urlType,
|
|
908
|
+
platform,
|
|
909
|
+
provider,
|
|
768
910
|
repositories: [{
|
|
769
911
|
id: 'main',
|
|
770
912
|
name: answers.repo,
|
|
@@ -779,28 +921,33 @@ export class RepoStructureManager {
|
|
|
779
921
|
};
|
|
780
922
|
}
|
|
781
923
|
/**
|
|
782
|
-
* Create repositories on
|
|
924
|
+
* Create repositories on Git hosting platform via API
|
|
783
925
|
*/
|
|
784
|
-
async
|
|
926
|
+
async createRepositories(config) {
|
|
785
927
|
if (!this.githubToken) {
|
|
786
|
-
console.log(chalk.yellow(
|
|
787
|
-
console.log(chalk.gray(
|
|
928
|
+
console.log(chalk.yellow(`\n⚠️ No ${config.provider.config.name} token available`));
|
|
929
|
+
console.log(chalk.gray(` Skipping ${config.provider.config.name} repository creation`));
|
|
788
930
|
console.log(chalk.gray(' You can create repositories manually later\n'));
|
|
789
931
|
return;
|
|
790
932
|
}
|
|
791
|
-
const spinner = ora(
|
|
933
|
+
const spinner = ora(`Creating ${config.provider.config.name} repositories...`).start();
|
|
792
934
|
const created = [];
|
|
793
935
|
const failed = [];
|
|
794
936
|
// Create parent repository if needed
|
|
795
937
|
if (config.parentRepo?.createOnGitHub) {
|
|
796
938
|
try {
|
|
797
|
-
await
|
|
939
|
+
await config.provider.createRepository({
|
|
940
|
+
owner: config.parentRepo.owner,
|
|
941
|
+
name: config.parentRepo.name,
|
|
942
|
+
description: config.parentRepo.description,
|
|
943
|
+
visibility: config.parentRepo.visibility
|
|
944
|
+
}, this.githubToken);
|
|
798
945
|
created.push(`${config.parentRepo.owner}/${config.parentRepo.name}`);
|
|
799
946
|
// Save state: parent repo created
|
|
800
947
|
await this.saveSetupState({
|
|
801
948
|
version: '1.0.0',
|
|
802
949
|
architecture: config.architecture,
|
|
803
|
-
parentRepo: { ...config.parentRepo, url:
|
|
950
|
+
parentRepo: { ...config.parentRepo, url: config.provider.getRemoteUrl(config.parentRepo.owner, config.parentRepo.name, config.urlType) },
|
|
804
951
|
repos: [],
|
|
805
952
|
currentStep: 'parent-repo-created',
|
|
806
953
|
timestamp: new Date().toISOString(),
|
|
@@ -815,7 +962,12 @@ export class RepoStructureManager {
|
|
|
815
962
|
for (const repo of config.repositories) {
|
|
816
963
|
if (repo.createOnGitHub) {
|
|
817
964
|
try {
|
|
818
|
-
await
|
|
965
|
+
await config.provider.createRepository({
|
|
966
|
+
owner: repo.owner,
|
|
967
|
+
name: repo.name,
|
|
968
|
+
description: repo.description,
|
|
969
|
+
visibility: repo.visibility
|
|
970
|
+
}, this.githubToken);
|
|
819
971
|
created.push(`${repo.owner}/${repo.name}`);
|
|
820
972
|
}
|
|
821
973
|
catch (error) {
|
|
@@ -904,7 +1056,7 @@ export class RepoStructureManager {
|
|
|
904
1056
|
path: r.path,
|
|
905
1057
|
visibility: r.visibility,
|
|
906
1058
|
displayName: r.name,
|
|
907
|
-
url:
|
|
1059
|
+
url: config.provider.getRemoteUrl(r.owner, r.name, config.urlType),
|
|
908
1060
|
created: false
|
|
909
1061
|
})),
|
|
910
1062
|
currentStep: 'complete',
|
|
@@ -975,6 +1127,81 @@ export class RepoStructureManager {
|
|
|
975
1127
|
}
|
|
976
1128
|
return false;
|
|
977
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Check if a repository exists on GitHub
|
|
1132
|
+
*/
|
|
1133
|
+
async repositoryExistsOnGitHub(owner, repo) {
|
|
1134
|
+
if (!this.githubToken) {
|
|
1135
|
+
return false;
|
|
1136
|
+
}
|
|
1137
|
+
try {
|
|
1138
|
+
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
|
|
1139
|
+
headers: {
|
|
1140
|
+
'Authorization': `Bearer ${this.githubToken}`,
|
|
1141
|
+
'Accept': 'application/vnd.github+json'
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1144
|
+
return response.ok;
|
|
1145
|
+
}
|
|
1146
|
+
catch {
|
|
1147
|
+
return false;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Clone or initialize a repository
|
|
1152
|
+
* If the repo exists on the platform, clone it; otherwise, init + add remote
|
|
1153
|
+
*/
|
|
1154
|
+
async cloneOrInitRepository(repoPath, owner, name, createOnGitHub, urlType = 'ssh', provider) {
|
|
1155
|
+
// If .git already exists, skip
|
|
1156
|
+
if (existsSync(path.join(repoPath, '.git'))) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
const remoteUrl = provider.getRemoteUrl(owner, name, urlType);
|
|
1160
|
+
// Check if repository exists on GitHub
|
|
1161
|
+
const repoExists = await this.repositoryExistsOnGitHub(owner, name);
|
|
1162
|
+
if (repoExists) {
|
|
1163
|
+
// Repository exists - clone it
|
|
1164
|
+
console.log(chalk.gray(` → Cloning existing repository from GitHub...`));
|
|
1165
|
+
try {
|
|
1166
|
+
// Remove directory if it exists and is empty
|
|
1167
|
+
if (existsSync(repoPath)) {
|
|
1168
|
+
const files = require('fs').readdirSync(repoPath);
|
|
1169
|
+
if (files.length === 0) {
|
|
1170
|
+
require('fs').rmdirSync(repoPath);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
// Clone the repository
|
|
1174
|
+
const parentDir = path.dirname(repoPath);
|
|
1175
|
+
const repoName = path.basename(repoPath);
|
|
1176
|
+
execFileNoThrowSync('git', ['clone', remoteUrl, repoName], { cwd: parentDir });
|
|
1177
|
+
console.log(chalk.green(` ✓ Cloned ${owner}/${name}`));
|
|
1178
|
+
}
|
|
1179
|
+
catch (error) {
|
|
1180
|
+
console.log(chalk.yellow(` ⚠️ Clone failed: ${error.message}`));
|
|
1181
|
+
console.log(chalk.gray(` → Falling back to init + remote`));
|
|
1182
|
+
// Fallback: init + add remote
|
|
1183
|
+
if (!existsSync(repoPath)) {
|
|
1184
|
+
mkdirSync(repoPath, { recursive: true });
|
|
1185
|
+
}
|
|
1186
|
+
execFileNoThrowSync('git', ['init'], { cwd: repoPath });
|
|
1187
|
+
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: repoPath });
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
// Repository doesn't exist - init + add remote
|
|
1192
|
+
if (!createOnGitHub) {
|
|
1193
|
+
console.log(chalk.gray(` → Repository will be created later (skipping for now)`));
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
console.log(chalk.gray(` → Initializing empty git repository...`));
|
|
1197
|
+
if (!existsSync(repoPath)) {
|
|
1198
|
+
mkdirSync(repoPath, { recursive: true });
|
|
1199
|
+
}
|
|
1200
|
+
execFileNoThrowSync('git', ['init'], { cwd: repoPath });
|
|
1201
|
+
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: repoPath });
|
|
1202
|
+
console.log(chalk.green(` ✓ Initialized ${owner}/${name}`));
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
978
1205
|
/**
|
|
979
1206
|
* Initialize local git repositories
|
|
980
1207
|
*/
|
|
@@ -987,40 +1214,31 @@ export class RepoStructureManager {
|
|
|
987
1214
|
if (!existsSync(path.join(this.projectPath, '.git'))) {
|
|
988
1215
|
execFileNoThrowSync('git', ['init'], { cwd: this.projectPath });
|
|
989
1216
|
if (config.parentRepo) {
|
|
990
|
-
const remoteUrl =
|
|
1217
|
+
const remoteUrl = config.provider.getRemoteUrl(config.parentRepo.owner, config.parentRepo.name, config.urlType);
|
|
991
1218
|
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: this.projectPath });
|
|
992
1219
|
}
|
|
993
1220
|
}
|
|
994
1221
|
// Initialize implementation repos at ROOT LEVEL
|
|
995
1222
|
for (const repo of config.repositories) {
|
|
996
1223
|
const repoPath = path.join(this.projectPath, repo.path);
|
|
997
|
-
//
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
if (!existsSync(path.join(repoPath, '.git'))) {
|
|
1003
|
-
execFileNoThrowSync('git', ['init'], { cwd: repoPath });
|
|
1004
|
-
const remoteUrl = `https://github.com/${repo.owner}/${repo.name}.git`;
|
|
1005
|
-
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: repoPath });
|
|
1224
|
+
// Clone or initialize repository
|
|
1225
|
+
await this.cloneOrInitRepository(repoPath, repo.owner, repo.name, repo.createOnGitHub, config.urlType, config.provider);
|
|
1226
|
+
// Create basic structure (only if repo was just initialized, not cloned)
|
|
1227
|
+
if (!repo.createOnGitHub || !await this.repositoryExistsOnGitHub(repo.owner, repo.name)) {
|
|
1228
|
+
this.createBasicRepoStructure(repoPath, repo.id);
|
|
1006
1229
|
}
|
|
1007
|
-
// Create basic structure
|
|
1008
|
-
this.createBasicRepoStructure(repoPath, repo.id);
|
|
1009
1230
|
}
|
|
1010
1231
|
}
|
|
1011
1232
|
else if (config.architecture === 'multi-repo') {
|
|
1012
1233
|
// Standard multi-repo: repos as subdirectories
|
|
1013
1234
|
for (const repo of config.repositories) {
|
|
1014
1235
|
const repoPath = path.join(this.projectPath, repo.path);
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
if (!
|
|
1019
|
-
|
|
1020
|
-
const remoteUrl = `https://github.com/${repo.owner}/${repo.name}.git`;
|
|
1021
|
-
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: repoPath });
|
|
1236
|
+
// Clone or initialize repository
|
|
1237
|
+
await this.cloneOrInitRepository(repoPath, repo.owner, repo.name, repo.createOnGitHub, config.urlType, config.provider);
|
|
1238
|
+
// Create basic structure (only if repo was just initialized, not cloned)
|
|
1239
|
+
if (!repo.createOnGitHub || !await this.repositoryExistsOnGitHub(repo.owner, repo.name)) {
|
|
1240
|
+
this.createBasicRepoStructure(repoPath, repo.id);
|
|
1022
1241
|
}
|
|
1023
|
-
this.createBasicRepoStructure(repoPath, repo.id);
|
|
1024
1242
|
}
|
|
1025
1243
|
}
|
|
1026
1244
|
else {
|
|
@@ -1029,7 +1247,7 @@ export class RepoStructureManager {
|
|
|
1029
1247
|
execFileNoThrowSync('git', ['init'], { cwd: this.projectPath });
|
|
1030
1248
|
const repo = config.repositories[0];
|
|
1031
1249
|
if (repo) {
|
|
1032
|
-
const remoteUrl =
|
|
1250
|
+
const remoteUrl = config.provider.getRemoteUrl(repo.owner, repo.name, config.urlType);
|
|
1033
1251
|
execFileNoThrowSync('git', ['remote', 'add', 'origin', remoteUrl], { cwd: this.projectPath });
|
|
1034
1252
|
}
|
|
1035
1253
|
}
|