specweave 0.32.3 ā 0.32.6
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 +12 -9
- package/bin/specweave.js +78 -0
- package/dist/src/cli/commands/docs.d.ts +45 -0
- package/dist/src/cli/commands/docs.d.ts.map +1 -0
- package/dist/src/cli/commands/docs.js +307 -0
- package/dist/src/cli/commands/docs.js.map +1 -0
- package/dist/src/cli/commands/init-multiproject.js +1 -1
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js +2 -2
- package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.d.ts +14 -2
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.js +292 -188
- package/dist/src/cli/helpers/init/repository-setup.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 +9 -3
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts +18 -2
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +325 -25
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js +61 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts +25 -0
- 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/core/living-docs/cross-project-sync.d.ts +97 -0
- package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -0
- package/dist/src/core/living-docs/cross-project-sync.js +135 -0
- package/dist/src/core/living-docs/cross-project-sync.js.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts +106 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js +146 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +77 -2
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts +8 -1
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js +18 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +3 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.js +24 -2
- package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -1
- package/dist/src/core/living-docs/types.d.ts +6 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/validators/index.d.ts +7 -0
- package/dist/src/core/living-docs/validators/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/index.js +7 -0
- package/dist/src/core/living-docs/validators/index.js.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts +92 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.js +142 -0
- package/dist/src/core/living-docs/validators/project-validator.js.map +1 -0
- package/dist/src/core/project/project-manager.d.ts.map +1 -1
- package/dist/src/core/project/project-manager.js +19 -17
- package/dist/src/core/project/project-manager.js.map +1 -1
- package/dist/src/core/types/config.d.ts +4 -2
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +34 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/utils/cross-cutting-detector.d.ts +66 -0
- package/dist/src/utils/cross-cutting-detector.d.ts.map +1 -0
- package/dist/src/utils/cross-cutting-detector.js +179 -0
- package/dist/src/utils/cross-cutting-detector.js.map +1 -0
- package/dist/src/utils/docs-preview/config-generator.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/config-generator.js +12 -16
- package/dist/src/utils/docs-preview/config-generator.js.map +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.js +24 -5
- package/dist/src/utils/docs-preview/docusaurus-setup.js.map +1 -1
- package/dist/src/utils/docs-preview/package-installer.d.ts +3 -0
- package/dist/src/utils/docs-preview/package-installer.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/package-installer.js +18 -9
- package/dist/src/utils/docs-preview/package-installer.js.map +1 -1
- package/dist/src/utils/docs-preview/server-manager.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/server-manager.js +2 -1
- package/dist/src/utils/docs-preview/server-manager.js.map +1 -1
- package/dist/src/utils/project-detection.d.ts +12 -8
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +13 -19
- package/dist/src/utils/project-detection.js.map +1 -1
- package/dist/src/utils/validators/jira-validator.d.ts +25 -1
- package/dist/src/utils/validators/jira-validator.d.ts.map +1 -1
- package/dist/src/utils/validators/jira-validator.js +254 -172
- package/dist/src/utils/validators/jira-validator.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-status.md +64 -0
- package/plugins/specweave/hooks/hooks.json +1 -1
- package/plugins/specweave/hooks/spec-project-validator.sh +2 -1
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +34 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +77 -2
- package/plugins/specweave/skills/spec-generator/SKILL.md +78 -7
- package/plugins/specweave/commands/specweave-switch-project.md +0 -168
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository-setup.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/repository-setup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AA6DrE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,cAAc,GAAG,eAAe,GAAG,MAAM,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"repository-setup.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/repository-setup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AA6DrE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,cAAc,GAAG,eAAe,GAAG,MAAM,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAGD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,0FAA0F;IAC1F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4BAA4B;IAC5B,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C;AAopBD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,cAAc,GAAG,eAAe,GAAG,MAAM,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA6GD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA+G5G"}
|
|
@@ -56,6 +56,110 @@ async function safeParseJsonResponse(response, context) {
|
|
|
56
56
|
` Response preview: ${preview}${responseText.length > 100 ? '...' : ''}`);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Fetch all accessible projects for an ADO organization
|
|
61
|
+
*/
|
|
62
|
+
async function fetchAdoProjects(org, pat) {
|
|
63
|
+
const auth = Buffer.from(`:${pat}`).toString('base64');
|
|
64
|
+
const endpoint = `https://dev.azure.com/${org}/_apis/projects?api-version=7.0`;
|
|
65
|
+
const response = await fetch(endpoint, {
|
|
66
|
+
headers: { 'Authorization': `Basic ${auth}`, 'Accept': 'application/json' }
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
// Read response body to check for HTML error pages
|
|
70
|
+
const errorBody = await response.text();
|
|
71
|
+
const looksLikeHtml = errorBody.trim().startsWith('<!DOCTYPE') || errorBody.trim().startsWith('<html');
|
|
72
|
+
if (looksLikeHtml) {
|
|
73
|
+
throw new Error(`Azure DevOps returned an error page (HTTP ${response.status}).\n` +
|
|
74
|
+
` This usually indicates an authentication or configuration issue.\n` +
|
|
75
|
+
` \n` +
|
|
76
|
+
` Possible causes:\n` +
|
|
77
|
+
` ⢠Invalid or expired Personal Access Token (PAT)\n` +
|
|
78
|
+
` ⢠Incorrect organization name "${org}"\n` +
|
|
79
|
+
` ⢠Corporate firewall or proxy intercepting the request\n` +
|
|
80
|
+
` ⢠SSO/authentication redirect (try accessing Azure DevOps in browser first)`);
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`Failed to fetch projects: ${response.status} - ${errorBody.substring(0, 200)}`);
|
|
83
|
+
}
|
|
84
|
+
// Use safe JSON parser to detect HTML responses even on 200 OK
|
|
85
|
+
const data = await safeParseJsonResponse(response, 'Azure DevOps');
|
|
86
|
+
return (data.value || []).map((p) => ({ name: p.name, id: p.id }));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Prompt user for ADO organization, credentials, and project selection
|
|
90
|
+
* For repository cloning in multi-repo setups
|
|
91
|
+
*/
|
|
92
|
+
async function promptAdoProjectSelection(targetDir, strings) {
|
|
93
|
+
// Check for existing credentials in .env or environment
|
|
94
|
+
let existingOrg;
|
|
95
|
+
let existingPat;
|
|
96
|
+
const envContent = readEnvFile(targetDir);
|
|
97
|
+
if (envContent) {
|
|
98
|
+
const parsed = parseEnvFile(envContent);
|
|
99
|
+
existingOrg = parsed.AZURE_DEVOPS_ORG;
|
|
100
|
+
existingPat = parsed.AZURE_DEVOPS_PAT;
|
|
101
|
+
}
|
|
102
|
+
// Fall back to environment variables
|
|
103
|
+
if (!existingOrg || !existingPat) {
|
|
104
|
+
const auth = getAzureDevOpsAuth();
|
|
105
|
+
if (auth) {
|
|
106
|
+
existingOrg = existingOrg || auth.org;
|
|
107
|
+
existingPat = existingPat || auth.pat;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Prompt for organization
|
|
111
|
+
const org = await input({
|
|
112
|
+
message: strings.adoOrgPrompt,
|
|
113
|
+
default: existingOrg,
|
|
114
|
+
validate: (value) => {
|
|
115
|
+
if (!value.trim())
|
|
116
|
+
return 'Organization name is required';
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Prompt for PAT
|
|
121
|
+
const pat = await password({
|
|
122
|
+
message: strings.adoPatPrompt,
|
|
123
|
+
mask: true,
|
|
124
|
+
validate: (value) => {
|
|
125
|
+
if (!value.trim())
|
|
126
|
+
return 'Personal Access Token is required';
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
// Fetch projects
|
|
131
|
+
const spinner = ora(strings.adoFetchingProjects).start();
|
|
132
|
+
let projects;
|
|
133
|
+
try {
|
|
134
|
+
projects = await fetchAdoProjects(org, pat);
|
|
135
|
+
spinner.succeed();
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
spinner.fail(strings.adoConnectionFailed);
|
|
139
|
+
console.log(chalk.red(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (projects.length === 0) {
|
|
143
|
+
console.log(chalk.yellow(` ${strings.adoNoProjects}`));
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
// Let user select projects
|
|
147
|
+
const selectedProjects = await checkbox({
|
|
148
|
+
message: strings.adoProjectPrompt,
|
|
149
|
+
choices: projects.map((p, index) => ({
|
|
150
|
+
name: p.name,
|
|
151
|
+
value: p.name,
|
|
152
|
+
checked: index === 0 // First project selected by default
|
|
153
|
+
})),
|
|
154
|
+
required: true
|
|
155
|
+
});
|
|
156
|
+
console.log(chalk.green(` ā ${strings.adoProjectsSelected.replace('{count}', String(selectedProjects.length))}`));
|
|
157
|
+
return {
|
|
158
|
+
org,
|
|
159
|
+
pat,
|
|
160
|
+
projects: selectedProjects
|
|
161
|
+
};
|
|
162
|
+
}
|
|
59
163
|
/**
|
|
60
164
|
* Get translated strings for repository setup
|
|
61
165
|
*/
|
|
@@ -77,7 +181,7 @@ function getRepoStrings(language) {
|
|
|
77
181
|
other: 'Other (GitLab, etc - coming soon)',
|
|
78
182
|
adoCloneQuestion: 'Enter repo name pattern to clone (e.g., sw-* or leave empty to skip):',
|
|
79
183
|
adoCloneSkip: 'Skipping repo cloning - you can configure later',
|
|
80
|
-
//
|
|
184
|
+
// Unified selection strings
|
|
81
185
|
adoSelectStrategy: 'How do you want to select repositories to clone?',
|
|
82
186
|
adoAllRepos: 'All',
|
|
83
187
|
adoAllReposDesc: 'Clone all repositories from the project',
|
|
@@ -105,6 +209,13 @@ function getRepoStrings(language) {
|
|
|
105
209
|
adoFetchingProjects: 'Fetching projects...',
|
|
106
210
|
adoNoProjects: 'No projects found in this organization',
|
|
107
211
|
adoConnectionFailed: 'Failed to connect to Azure DevOps',
|
|
212
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
213
|
+
githubMultiRepoHeader: 'š GitHub Multi-Repository Selection',
|
|
214
|
+
githubMultiRepoDesc: 'Select which repositories to work with from your GitHub organization.',
|
|
215
|
+
githubSelectStrategy: 'How do you want to select GitHub repositories?',
|
|
216
|
+
bitbucketMultiRepoHeader: 'š Bitbucket Multi-Repository Selection',
|
|
217
|
+
bitbucketMultiRepoDesc: 'Select which repositories to work with from your Bitbucket workspace.',
|
|
218
|
+
bitbucketSelectStrategy: 'How do you want to select Bitbucket repositories?',
|
|
108
219
|
},
|
|
109
220
|
ru: {
|
|
110
221
|
header: 'š¦ Š„оŃŃŠøŠ½Š³ ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŃ',
|
|
@@ -122,7 +233,7 @@ function getRepoStrings(language) {
|
|
|
122
233
|
other: 'ŠŃŃŠ³Š¾Š¹ (GitLab Šø Ń.Š“. - ŃŠŗŠ¾Ńо)',
|
|
123
234
|
adoCloneQuestion: 'ŠŠ²ŠµŠ“ŠøŃŠµ ŃŠ°Š±Š»Š¾Š½ имени ŃŠµŠæŠ¾ Š“Š»Ń ŠŗŠ»Š¾Š½ŠøŃŠ¾Š²Š°Š½ŠøŃ (напŃ., sw-* или оŃŃŠ°Š²ŃŃŠµ ŠæŃŃŃŃŠ¼):',
|
|
124
235
|
adoCloneSkip: 'ŠŃопŃŃŠŗ ŠŗŠ»Š¾Š½ŠøŃŠ¾Š²Š°Š½ŠøŃ - можно наŃŃŃŠ¾ŠøŃŃ ŠæŠ¾Š·Š¶Šµ',
|
|
125
|
-
//
|
|
236
|
+
// Unified selection strings
|
|
126
237
|
adoSelectStrategy: 'ŠŠ°Šŗ Š²Ń Ń
Š¾ŃŠøŃе Š²ŃбŃаŃŃ ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø Š“Š»Ń ŠŗŠ»Š¾Š½ŠøŃŠ¾Š²Š°Š½ŠøŃ?',
|
|
127
238
|
adoAllRepos: 'ŠŃе',
|
|
128
239
|
adoAllReposDesc: 'ŠŠ»Š¾Š½ŠøŃоваŃŃ Š²ŃŠµ ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø ŠøŠ· ŠæŃŠ¾ŠµŠŗŃа',
|
|
@@ -150,6 +261,13 @@ function getRepoStrings(language) {
|
|
|
150
261
|
adoFetchingProjects: 'ŠŠ°Š³ŃŃŠ·ŠŗŠ° ŠæŃŠ¾ŠµŠŗŃов...',
|
|
151
262
|
adoNoProjects: 'ŠŃоекŃŃ Š½Šµ Š½Š°Š¹Š“ŠµŠ½Ń Š² ŃŃŠ¾Š¹ Š¾ŃŠ³Š°Š½ŠøŠ·Š°ŃŠøŠø',
|
|
152
263
|
adoConnectionFailed: 'ŠŠµ ŃŠ“алоŃŃ ŠæŠ¾Š“ŠŗŠ»ŃŃŠøŃŃŃŃ Šŗ Azure DevOps',
|
|
264
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
265
|
+
githubMultiRepoHeader: 'š ŠŃŠ±Š¾Ń ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠµŠ² GitHub',
|
|
266
|
+
githubMultiRepoDesc: 'ŠŃŠ±ŠµŃŠøŃе ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø Š“Š»Ń ŃŠ°Š±Š¾ŃŃ ŠøŠ· Š²Š°ŃŠµŠ¹ Š¾ŃŠ³Š°Š½ŠøŠ·Š°ŃŠøŠø GitHub.',
|
|
267
|
+
githubSelectStrategy: 'ŠŠ°Šŗ Š²Ń Ń
Š¾ŃŠøŃе Š²ŃбŃаŃŃ ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø GitHub?',
|
|
268
|
+
bitbucketMultiRepoHeader: 'š ŠŃŠ±Š¾Ń ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠµŠ² Bitbucket',
|
|
269
|
+
bitbucketMultiRepoDesc: 'ŠŃŠ±ŠµŃŠøŃе ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø Š“Š»Ń ŃŠ°Š±Š¾ŃŃ ŠøŠ· Š²Š°ŃŠµŠ³Š¾ ŃŠ°Š±Š¾Ńего ŠæŃоŃŃŃŠ°Š½ŃŃŠ²Š° Bitbucket.',
|
|
270
|
+
bitbucketSelectStrategy: 'ŠŠ°Šŗ Š²Ń Ń
Š¾ŃŠøŃе Š²ŃбŃаŃŃ ŃŠµŠæŠ¾Š·ŠøŃŠ¾ŃŠøŠø Bitbucket?',
|
|
153
271
|
},
|
|
154
272
|
es: {
|
|
155
273
|
header: 'š¦ Alojamiento del repositorio',
|
|
@@ -167,7 +285,7 @@ function getRepoStrings(language) {
|
|
|
167
285
|
other: 'Otro (GitLab, etc - próximamente)',
|
|
168
286
|
adoCloneQuestion: 'Ingrese patrón de nombre de repo a clonar (ej., sw-* o deje vacĆo):',
|
|
169
287
|
adoCloneSkip: 'Omitiendo clonación - puede configurar después',
|
|
170
|
-
//
|
|
288
|
+
// Unified selection strings
|
|
171
289
|
adoSelectStrategy: '¿Cómo quiere seleccionar repositorios para clonar?',
|
|
172
290
|
adoAllRepos: 'Todos',
|
|
173
291
|
adoAllReposDesc: 'Clonar todos los repositorios del proyecto',
|
|
@@ -195,6 +313,13 @@ function getRepoStrings(language) {
|
|
|
195
313
|
adoFetchingProjects: 'Obteniendo proyectos...',
|
|
196
314
|
adoNoProjects: 'No se encontraron proyectos en esta organización',
|
|
197
315
|
adoConnectionFailed: 'Error al conectar con Azure DevOps',
|
|
316
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
317
|
+
githubMultiRepoHeader: 'š Selección de repositorios GitHub',
|
|
318
|
+
githubMultiRepoDesc: 'Seleccione los repositorios de su organización GitHub.',
|
|
319
|
+
githubSelectStrategy: '¿Cómo desea seleccionar los repositorios de GitHub?',
|
|
320
|
+
bitbucketMultiRepoHeader: 'š Selección de repositorios Bitbucket',
|
|
321
|
+
bitbucketMultiRepoDesc: 'Seleccione los repositorios de su espacio de trabajo Bitbucket.',
|
|
322
|
+
bitbucketSelectStrategy: '¿Cómo desea seleccionar los repositorios de Bitbucket?',
|
|
198
323
|
},
|
|
199
324
|
zh: {
|
|
200
325
|
header: 'š¦ ä»åŗęē®”',
|
|
@@ -212,7 +337,7 @@ function getRepoStrings(language) {
|
|
|
212
337
|
other: 'å
¶ä»ļ¼GitLab ē - å³å°ęØåŗļ¼',
|
|
213
338
|
adoCloneQuestion: 'č¾å
„č¦å
éēä»åŗå称樔å¼ļ¼ä¾å¦ sw-* ęē空跳čæļ¼ļ¼',
|
|
214
339
|
adoCloneSkip: 'č·³čæå
é - ēØååÆä»„é
ē½®',
|
|
215
|
-
//
|
|
340
|
+
// Unified selection strings
|
|
216
341
|
adoSelectStrategy: 'ęØę³å¦ä½éę©č¦å
éēä»åŗļ¼',
|
|
217
342
|
adoAllRepos: 'å
ØéØ',
|
|
218
343
|
adoAllReposDesc: 'å
é锹ē®äøēęęä»åŗ',
|
|
@@ -240,6 +365,13 @@ function getRepoStrings(language) {
|
|
|
240
365
|
adoFetchingProjects: 'ę£åØč·å锹ē®...',
|
|
241
366
|
adoNoProjects: 'åØę¤ē»ē»äøęŖę¾å°é”¹ē®',
|
|
242
367
|
adoConnectionFailed: 'ę ę³čæę„å° Azure DevOps',
|
|
368
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
369
|
+
githubMultiRepoHeader: 'š GitHub å¤ä»åŗéę©',
|
|
370
|
+
githubMultiRepoDesc: 'ä»ęØē GitHub ē»ē»äøéę©č¦ä½æēØēä»åŗć',
|
|
371
|
+
githubSelectStrategy: 'ęØę³å¦ä½éę© GitHub ä»åŗļ¼',
|
|
372
|
+
bitbucketMultiRepoHeader: 'š Bitbucket å¤ä»åŗéę©',
|
|
373
|
+
bitbucketMultiRepoDesc: 'ä»ęØē Bitbucket å·„ä½åŗäøéę©č¦ä½æēØēä»åŗć',
|
|
374
|
+
bitbucketSelectStrategy: 'ęØę³å¦ä½éę© Bitbucket ä»åŗļ¼',
|
|
243
375
|
},
|
|
244
376
|
de: {
|
|
245
377
|
header: 'š¦ Repository-Hosting',
|
|
@@ -257,7 +389,7 @@ function getRepoStrings(language) {
|
|
|
257
389
|
other: 'Andere (GitLab, etc - kommt bald)',
|
|
258
390
|
adoCloneQuestion: 'Repo-Namensmuster zum Klonen eingeben (z.B. sw-* oder leer lassen):',
|
|
259
391
|
adoCloneSkip: 'Klonen übersprungen - später konfigurierbar',
|
|
260
|
-
//
|
|
392
|
+
// Unified selection strings
|
|
261
393
|
adoSelectStrategy: 'Wie mƶchten Sie Repositories zum Klonen auswƤhlen?',
|
|
262
394
|
adoAllRepos: 'Alle',
|
|
263
395
|
adoAllReposDesc: 'Alle Repositories aus dem Projekt klonen',
|
|
@@ -285,6 +417,13 @@ function getRepoStrings(language) {
|
|
|
285
417
|
adoFetchingProjects: 'Projekte werden abgerufen...',
|
|
286
418
|
adoNoProjects: 'Keine Projekte in dieser Organisation gefunden',
|
|
287
419
|
adoConnectionFailed: 'Verbindung zu Azure DevOps fehlgeschlagen',
|
|
420
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
421
|
+
githubMultiRepoHeader: 'š GitHub Multi-Repository Auswahl',
|
|
422
|
+
githubMultiRepoDesc: 'WƤhlen Sie die Repositories aus Ihrer GitHub-Organisation.',
|
|
423
|
+
githubSelectStrategy: 'Wie mƶchten Sie GitHub-Repositories auswƤhlen?',
|
|
424
|
+
bitbucketMultiRepoHeader: 'š Bitbucket Multi-Repository Auswahl',
|
|
425
|
+
bitbucketMultiRepoDesc: 'WƤhlen Sie die Repositories aus Ihrem Bitbucket-Workspace.',
|
|
426
|
+
bitbucketSelectStrategy: 'Wie mƶchten Sie Bitbucket-Repositories auswƤhlen?',
|
|
288
427
|
},
|
|
289
428
|
fr: {
|
|
290
429
|
header: 'š¦ HĆ©bergement du dĆ©pĆ“t',
|
|
@@ -302,7 +441,7 @@ function getRepoStrings(language) {
|
|
|
302
441
|
other: 'Autre (GitLab, etc - bientƓt)',
|
|
303
442
|
adoCloneQuestion: 'Entrez le modĆØle de nom de repo Ć cloner (ex. sw-* ou laissez vide):',
|
|
304
443
|
adoCloneSkip: 'Clonage ignorƩ - configurable plus tard',
|
|
305
|
-
//
|
|
444
|
+
// Unified selection strings
|
|
306
445
|
adoSelectStrategy: 'Comment voulez-vous sélectionner les repos à cloner?',
|
|
307
446
|
adoAllRepos: 'Tous',
|
|
308
447
|
adoAllReposDesc: 'Cloner tous les repos du projet',
|
|
@@ -330,6 +469,13 @@ function getRepoStrings(language) {
|
|
|
330
469
|
adoFetchingProjects: 'RƩcupƩration des projets...',
|
|
331
470
|
adoNoProjects: 'Aucun projet trouvƩ dans cette organisation',
|
|
332
471
|
adoConnectionFailed: 'Ćchec de connexion Ć Azure DevOps',
|
|
472
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
473
|
+
githubMultiRepoHeader: 'š SĆ©lection multi-dĆ©pĆ“t GitHub',
|
|
474
|
+
githubMultiRepoDesc: 'SƩlectionnez les dƩpƓts de votre organisation GitHub.',
|
|
475
|
+
githubSelectStrategy: 'Comment voulez-vous sƩlectionner les dƩpƓts GitHub?',
|
|
476
|
+
bitbucketMultiRepoHeader: 'š SĆ©lection multi-dĆ©pĆ“t Bitbucket',
|
|
477
|
+
bitbucketMultiRepoDesc: 'SƩlectionnez les dƩpƓts de votre espace de travail Bitbucket.',
|
|
478
|
+
bitbucketSelectStrategy: 'Comment voulez-vous sƩlectionner les dƩpƓts Bitbucket?',
|
|
333
479
|
},
|
|
334
480
|
ja: {
|
|
335
481
|
header: 'š¦ ćŖććøććŖćć¹ćć£ć³ć°',
|
|
@@ -347,7 +493,7 @@ function getRepoStrings(language) {
|
|
|
347
493
|
other: 'ćć®ä»ļ¼GitLabćŖć© - čæę„å
¬éļ¼',
|
|
348
494
|
adoCloneQuestion: 'ćÆćć¼ć³ćććŖćåććæć¼ć³ćå
„åļ¼ä¾: sw-* ć¾ććÆē©ŗē½ć§ć¹ćććļ¼:',
|
|
349
495
|
adoCloneSkip: 'ćÆćć¼ć³ćć¹ććć - å¾ć§čØå®åÆč½',
|
|
350
|
-
//
|
|
496
|
+
// Unified selection strings
|
|
351
497
|
adoSelectStrategy: 'ćÆćć¼ć³ćććŖććøććŖćć©ć®ććć«éøęćć¾ććļ¼',
|
|
352
498
|
adoAllRepos: 'ćć¹ć¦',
|
|
353
499
|
adoAllReposDesc: 'ćććøć§ćÆćć®ćć¹ć¦ć®ćŖććøććŖććÆćć¼ć³',
|
|
@@ -375,6 +521,13 @@ function getRepoStrings(language) {
|
|
|
375
521
|
adoFetchingProjects: 'ćććøć§ćÆććåå¾äø...',
|
|
376
522
|
adoNoProjects: 'ćć®ēµē¹ć«ćććøć§ćÆććč¦ć¤ććć¾ćć',
|
|
377
523
|
adoConnectionFailed: 'Azure DevOps ćøć®ę„ē¶ć«å¤±ęćć¾ćć',
|
|
524
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
525
|
+
githubMultiRepoHeader: 'š GitHub ćć«ććŖććøććŖéøę',
|
|
526
|
+
githubMultiRepoDesc: 'GitHubēµē¹ćććŖććøććŖćéøęćć¦ćć ććć',
|
|
527
|
+
githubSelectStrategy: 'GitHubćŖććøććŖćć©ć®ććć«éøęćć¾ććļ¼',
|
|
528
|
+
bitbucketMultiRepoHeader: 'š Bitbucket ćć«ććŖććøććŖéøę',
|
|
529
|
+
bitbucketMultiRepoDesc: 'BitbucketćÆć¼ćÆć¹ćć¼ć¹ćććŖććøććŖćéøęćć¦ćć ććć',
|
|
530
|
+
bitbucketSelectStrategy: 'BitbucketćŖććøććŖćć©ć®ććć«éøęćć¾ććļ¼',
|
|
378
531
|
},
|
|
379
532
|
ko: {
|
|
380
533
|
header: 'š¦ ģ ģ„ģ ķøģ¤ķ
',
|
|
@@ -392,7 +545,7 @@ function getRepoStrings(language) {
|
|
|
392
545
|
other: 'źø°ķ (GitLab ė± - ź³§ ģ¶ģ)',
|
|
393
546
|
adoCloneQuestion: 'ė³µģ ķ ģ ģ„ģ ģ“ė¦ ķØķ“ ģ
ė „ (ģ: sw-* ėė ė¹ģėźø°):',
|
|
394
547
|
adoCloneSkip: 'ė³µģ ź±“ėė - ėģ¤ģ ģ¤ģ ź°ė„',
|
|
395
|
-
//
|
|
548
|
+
// Unified selection strings
|
|
396
549
|
adoSelectStrategy: 'ė³µģ ķ ģ ģ„ģ넼 ģ“ė»ź² ģ ķķģź² ģµėź¹?',
|
|
397
550
|
adoAllRepos: 'ėŖØė',
|
|
398
551
|
adoAllReposDesc: 'ķė”ģ ķøģ ėŖØė ģ ģ„ģ ė³µģ ',
|
|
@@ -420,6 +573,13 @@ function getRepoStrings(language) {
|
|
|
420
573
|
adoFetchingProjects: 'ķė”ģ ķø ź°ģ øģ¤ė ģ¤...',
|
|
421
574
|
adoNoProjects: 'ģ“ ģ”°ģ§ģģ ķė”ģ ķøė„¼ ģ°¾ģ ģ ģģµėė¤',
|
|
422
575
|
adoConnectionFailed: 'Azure DevOps ģ°ź²° ģ¤ķØ',
|
|
576
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
577
|
+
githubMultiRepoHeader: 'š GitHub ė¤ģ¤ ģ ģ„ģ ģ ķ',
|
|
578
|
+
githubMultiRepoDesc: 'GitHub ģ”°ģ§ģģ ģ ģ„ģ넼 ģ ķķģøģ.',
|
|
579
|
+
githubSelectStrategy: 'GitHub ģ ģ„ģ넼 ģ“ė»ź² ģ ķķģź² ģµėź¹?',
|
|
580
|
+
bitbucketMultiRepoHeader: 'š Bitbucket ė¤ģ¤ ģ ģ„ģ ģ ķ',
|
|
581
|
+
bitbucketMultiRepoDesc: 'Bitbucket ģķ¬ģ¤ķģ“ģ¤ģģ ģ ģ„ģ넼 ģ ķķģøģ.',
|
|
582
|
+
bitbucketSelectStrategy: 'Bitbucket ģ ģ„ģ넼 ģ“ė»ź² ģ ķķģź² ģµėź¹?',
|
|
423
583
|
},
|
|
424
584
|
pt: {
|
|
425
585
|
header: 'š¦ Hospedagem do repositório',
|
|
@@ -437,7 +597,7 @@ function getRepoStrings(language) {
|
|
|
437
597
|
other: 'Outro (GitLab, etc - em breve)',
|
|
438
598
|
adoCloneQuestion: 'Digite padrão de nome de repo para clonar (ex. sw-* ou deixe vazio):',
|
|
439
599
|
adoCloneSkip: 'Clonagem ignorada - configurƔvel depois',
|
|
440
|
-
//
|
|
600
|
+
// Unified selection strings
|
|
441
601
|
adoSelectStrategy: 'Como você quer selecionar repositórios para clonar?',
|
|
442
602
|
adoAllRepos: 'Todos',
|
|
443
603
|
adoAllReposDesc: 'Clonar todos os repositórios do projeto',
|
|
@@ -465,113 +625,112 @@ function getRepoStrings(language) {
|
|
|
465
625
|
adoFetchingProjects: 'Buscando projetos...',
|
|
466
626
|
adoNoProjects: 'Nenhum projeto encontrado nesta organização',
|
|
467
627
|
adoConnectionFailed: 'Falha ao conectar ao Azure DevOps',
|
|
628
|
+
// GitHub/Bitbucket multi-repo strings (v0.32.6+)
|
|
629
|
+
githubMultiRepoHeader: 'š Seleção de mĆŗltiplos repositórios GitHub',
|
|
630
|
+
githubMultiRepoDesc: 'Selecione os repositórios da sua organização GitHub.',
|
|
631
|
+
githubSelectStrategy: 'Como você quer selecionar os repositórios do GitHub?',
|
|
632
|
+
bitbucketMultiRepoHeader: 'š Seleção de mĆŗltiplos repositórios Bitbucket',
|
|
633
|
+
bitbucketMultiRepoDesc: 'Selecione os repositórios do seu workspace Bitbucket.',
|
|
634
|
+
bitbucketSelectStrategy: 'Como você quer selecionar os repositórios do Bitbucket?',
|
|
468
635
|
},
|
|
469
636
|
};
|
|
470
637
|
return strings[language] || strings.en;
|
|
471
638
|
}
|
|
472
639
|
/**
|
|
473
|
-
*
|
|
640
|
+
* Prompt for multi-repo pattern selection (unified for GitHub, Bitbucket, ADO)
|
|
641
|
+
*
|
|
642
|
+
* @param provider - The git provider ('github' | 'bitbucket' | 'ado')
|
|
643
|
+
* @param strings - Localized strings
|
|
644
|
+
* @returns Selected pattern result
|
|
474
645
|
*/
|
|
475
|
-
async function
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
});
|
|
481
|
-
if (!response.ok) {
|
|
482
|
-
// Read response body to check for HTML error pages
|
|
483
|
-
const errorBody = await response.text();
|
|
484
|
-
const looksLikeHtml = errorBody.trim().startsWith('<!DOCTYPE') || errorBody.trim().startsWith('<html');
|
|
485
|
-
if (looksLikeHtml) {
|
|
486
|
-
throw new Error(`Azure DevOps returned an error page (HTTP ${response.status}).\n` +
|
|
487
|
-
` This usually indicates an authentication or configuration issue.\n` +
|
|
488
|
-
` \n` +
|
|
489
|
-
` Possible causes:\n` +
|
|
490
|
-
` ⢠Invalid or expired Personal Access Token (PAT)\n` +
|
|
491
|
-
` ⢠Incorrect organization name "${org}"\n` +
|
|
492
|
-
` ⢠Corporate firewall or proxy intercepting the request\n` +
|
|
493
|
-
` ⢠SSO/authentication redirect (try accessing Azure DevOps in browser first)`);
|
|
494
|
-
}
|
|
495
|
-
throw new Error(`Failed to fetch projects: ${response.status} - ${errorBody.substring(0, 200)}`);
|
|
646
|
+
async function promptMultiRepoPatternSelection(provider, strings) {
|
|
647
|
+
// Display provider-specific header
|
|
648
|
+
if (provider === 'github') {
|
|
649
|
+
console.log(chalk.blue(`\n${strings.githubMultiRepoHeader}\n`));
|
|
650
|
+
console.log(chalk.gray(` ${strings.githubMultiRepoDesc}\n`));
|
|
496
651
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Prompt user for ADO organization, credentials, and project selection
|
|
503
|
-
* For repository cloning in multi-repo setups
|
|
504
|
-
*/
|
|
505
|
-
async function promptAdoProjectSelection(targetDir, strings) {
|
|
506
|
-
// Check for existing credentials in .env or environment
|
|
507
|
-
let existingOrg;
|
|
508
|
-
let existingPat;
|
|
509
|
-
const envContent = readEnvFile(targetDir);
|
|
510
|
-
if (envContent) {
|
|
511
|
-
const parsed = parseEnvFile(envContent);
|
|
512
|
-
existingOrg = parsed.AZURE_DEVOPS_ORG;
|
|
513
|
-
existingPat = parsed.AZURE_DEVOPS_PAT;
|
|
652
|
+
else if (provider === 'bitbucket') {
|
|
653
|
+
console.log(chalk.blue(`\n${strings.bitbucketMultiRepoHeader}\n`));
|
|
654
|
+
console.log(chalk.gray(` ${strings.bitbucketMultiRepoDesc}\n`));
|
|
514
655
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
if (auth) {
|
|
519
|
-
existingOrg = existingOrg || auth.org;
|
|
520
|
-
existingPat = existingPat || auth.pat;
|
|
521
|
-
}
|
|
656
|
+
else {
|
|
657
|
+
console.log(chalk.blue('\nš Azure DevOps Repository Selection\n'));
|
|
658
|
+
console.log(chalk.gray(' Select which repositories to clone from your ADO project.\n'));
|
|
522
659
|
}
|
|
523
|
-
//
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
660
|
+
// Get provider-specific strategy message
|
|
661
|
+
const strategyMessage = provider === 'github'
|
|
662
|
+
? strings.githubSelectStrategy
|
|
663
|
+
: provider === 'bitbucket'
|
|
664
|
+
? strings.bitbucketSelectStrategy
|
|
665
|
+
: strings.adoSelectStrategy;
|
|
666
|
+
const strategyChoices = [
|
|
667
|
+
{
|
|
668
|
+
name: `${chalk.green('ā')} ${strings.adoAllRepos} ${chalk.gray(`- ${strings.adoAllReposDesc}`)}`,
|
|
669
|
+
value: 'all',
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
name: `${strings.adoPatternGlob} ${chalk.gray(`- ${strings.adoPatternGlobDesc}`)}`,
|
|
673
|
+
value: 'pattern-glob',
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
name: `${strings.adoPatternRegex} ${chalk.gray(`- ${strings.adoPatternRegexDesc}`)}`,
|
|
677
|
+
value: 'pattern-regex',
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
name: `${strings.adoSkipOption} ${chalk.gray(`- ${strings.adoSkipDesc}`)}`,
|
|
681
|
+
value: 'skip',
|
|
682
|
+
},
|
|
683
|
+
];
|
|
684
|
+
const strategy = await select({
|
|
685
|
+
message: strategyMessage,
|
|
686
|
+
choices: strategyChoices,
|
|
687
|
+
default: 'all',
|
|
532
688
|
});
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
689
|
+
switch (strategy) {
|
|
690
|
+
case 'all': {
|
|
691
|
+
console.log(chalk.green(` ā ${strings.adoSelectedAll}`));
|
|
692
|
+
return { strategy: 'all', pattern: '*' };
|
|
693
|
+
}
|
|
694
|
+
case 'pattern-glob': {
|
|
695
|
+
console.log(chalk.gray(`\n š” ${strings.adoPatternHint}`));
|
|
696
|
+
console.log(chalk.gray(` š” ${strings.adoShortcutsHint}\n`));
|
|
697
|
+
const pattern = await input({
|
|
698
|
+
message: strings.adoPatternPrompt,
|
|
699
|
+
validate: (value) => {
|
|
700
|
+
if (!value.trim())
|
|
701
|
+
return strings.adoPatternRequired;
|
|
702
|
+
return true;
|
|
703
|
+
},
|
|
704
|
+
});
|
|
705
|
+
// Parse shortcuts (starts:, ends:, contains:)
|
|
706
|
+
const parsedPattern = parsePatternShortcut(pattern.trim());
|
|
707
|
+
const message = strings.adoSelectedPattern.replace('{pattern}', parsedPattern);
|
|
708
|
+
console.log(chalk.green(` ā ${message}`));
|
|
709
|
+
return { strategy: 'pattern-glob', pattern: parsedPattern };
|
|
710
|
+
}
|
|
711
|
+
case 'pattern-regex': {
|
|
712
|
+
console.log(chalk.gray(`\n š” ${strings.adoRegexHint}\n`));
|
|
713
|
+
const pattern = await input({
|
|
714
|
+
message: strings.adoRegexPrompt,
|
|
715
|
+
validate: (value) => {
|
|
716
|
+
if (!value.trim())
|
|
717
|
+
return strings.adoPatternRequired;
|
|
718
|
+
const validation = validateRegex(value.trim());
|
|
719
|
+
if (validation !== true) {
|
|
720
|
+
return `${strings.adoInvalidRegex}: ${validation}`;
|
|
721
|
+
}
|
|
722
|
+
return true;
|
|
723
|
+
},
|
|
724
|
+
});
|
|
725
|
+
const message = strings.adoSelectedRegex.replace('{pattern}', pattern.trim());
|
|
726
|
+
console.log(chalk.green(` ā ${message}`));
|
|
727
|
+
return { strategy: 'pattern-regex', pattern: pattern.trim(), isRegex: true };
|
|
728
|
+
}
|
|
729
|
+
case 'skip': {
|
|
730
|
+
console.log(chalk.gray(` ā ${strings.adoCloneSkip}`));
|
|
731
|
+
return { strategy: 'skip' };
|
|
541
732
|
}
|
|
542
|
-
});
|
|
543
|
-
// Fetch projects
|
|
544
|
-
const spinner = ora(strings.adoFetchingProjects).start();
|
|
545
|
-
let projects;
|
|
546
|
-
try {
|
|
547
|
-
projects = await fetchAdoProjects(org, pat);
|
|
548
|
-
spinner.succeed();
|
|
549
|
-
}
|
|
550
|
-
catch (error) {
|
|
551
|
-
spinner.fail(strings.adoConnectionFailed);
|
|
552
|
-
console.log(chalk.red(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
if (projects.length === 0) {
|
|
556
|
-
console.log(chalk.yellow(` ${strings.adoNoProjects}`));
|
|
557
|
-
return null;
|
|
558
733
|
}
|
|
559
|
-
// Let user select projects
|
|
560
|
-
const selectedProjects = await checkbox({
|
|
561
|
-
message: strings.adoProjectPrompt,
|
|
562
|
-
choices: projects.map((p, index) => ({
|
|
563
|
-
name: p.name,
|
|
564
|
-
value: p.name,
|
|
565
|
-
checked: index === 0 // First project selected by default
|
|
566
|
-
})),
|
|
567
|
-
required: true
|
|
568
|
-
});
|
|
569
|
-
console.log(chalk.green(` ā ${strings.adoProjectsSelected.replace('{count}', String(selectedProjects.length))}`));
|
|
570
|
-
return {
|
|
571
|
-
org,
|
|
572
|
-
pat,
|
|
573
|
-
projects: selectedProjects
|
|
574
|
-
};
|
|
575
734
|
}
|
|
576
735
|
/**
|
|
577
736
|
* Prompt user for repository hosting configuration
|
|
@@ -643,95 +802,40 @@ export async function setupRepositoryHosting(options) {
|
|
|
643
802
|
else {
|
|
644
803
|
repositoryHosting = `${provider}-${structure}`;
|
|
645
804
|
}
|
|
646
|
-
// Step 3: For
|
|
805
|
+
// Step 3: For multi-repo setups, prompt for pattern selection
|
|
806
|
+
// Now unified for ADO, GitHub, and Bitbucket (v0.32.6+)
|
|
647
807
|
let adoClonePattern;
|
|
648
808
|
let adoClonePatternResult;
|
|
649
809
|
let adoProjectSelection;
|
|
650
|
-
if (provider === 'ado'
|
|
651
|
-
// Step 3a:
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
// Step 3b: Show unified strategy selection
|
|
659
|
-
const strategyChoices = [
|
|
660
|
-
{
|
|
661
|
-
name: `${chalk.green('ā')} ${strings.adoAllRepos} ${chalk.gray(`- ${strings.adoAllReposDesc}`)}`,
|
|
662
|
-
value: 'all',
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
name: `${strings.adoPatternGlob} ${chalk.gray(`- ${strings.adoPatternGlobDesc}`)}`,
|
|
666
|
-
value: 'pattern-glob',
|
|
667
|
-
},
|
|
668
|
-
{
|
|
669
|
-
name: `${strings.adoPatternRegex} ${chalk.gray(`- ${strings.adoPatternRegexDesc}`)}`,
|
|
670
|
-
value: 'pattern-regex',
|
|
671
|
-
},
|
|
672
|
-
{
|
|
673
|
-
name: `${strings.adoSkipOption} ${chalk.gray(`- ${strings.adoSkipDesc}`)}`,
|
|
674
|
-
value: 'skip',
|
|
675
|
-
},
|
|
676
|
-
];
|
|
677
|
-
const strategy = await select({
|
|
678
|
-
message: strings.adoSelectStrategy,
|
|
679
|
-
choices: strategyChoices,
|
|
680
|
-
default: 'all',
|
|
681
|
-
});
|
|
682
|
-
switch (strategy) {
|
|
683
|
-
case 'all': {
|
|
684
|
-
adoClonePattern = '*';
|
|
685
|
-
adoClonePatternResult = { strategy: 'all', pattern: '*' };
|
|
686
|
-
console.log(chalk.green(` ā ${strings.adoSelectedAll}`));
|
|
687
|
-
break;
|
|
688
|
-
}
|
|
689
|
-
case 'pattern-glob': {
|
|
690
|
-
console.log(chalk.gray(`\n š” ${strings.adoPatternHint}`));
|
|
691
|
-
console.log(chalk.gray(` š” ${strings.adoShortcutsHint}\n`));
|
|
692
|
-
const pattern = await input({
|
|
693
|
-
message: strings.adoPatternPrompt,
|
|
694
|
-
validate: (value) => {
|
|
695
|
-
if (!value.trim())
|
|
696
|
-
return strings.adoPatternRequired;
|
|
697
|
-
return true;
|
|
698
|
-
},
|
|
699
|
-
});
|
|
700
|
-
// Parse shortcuts (starts:, ends:, contains:)
|
|
701
|
-
const parsedPattern = parsePatternShortcut(pattern.trim());
|
|
702
|
-
adoClonePattern = parsedPattern;
|
|
703
|
-
adoClonePatternResult = { strategy: 'pattern-glob', pattern: parsedPattern };
|
|
704
|
-
const message = strings.adoSelectedPattern.replace('{pattern}', parsedPattern);
|
|
705
|
-
console.log(chalk.green(` ā ${message}`));
|
|
706
|
-
break;
|
|
707
|
-
}
|
|
708
|
-
case 'pattern-regex': {
|
|
709
|
-
console.log(chalk.gray(`\n š” ${strings.adoRegexHint}\n`));
|
|
710
|
-
const pattern = await input({
|
|
711
|
-
message: strings.adoRegexPrompt,
|
|
712
|
-
validate: (value) => {
|
|
713
|
-
if (!value.trim())
|
|
714
|
-
return strings.adoPatternRequired;
|
|
715
|
-
const validation = validateRegex(value.trim());
|
|
716
|
-
if (validation !== true) {
|
|
717
|
-
return `${strings.adoInvalidRegex}: ${validation}`;
|
|
718
|
-
}
|
|
719
|
-
return true;
|
|
720
|
-
},
|
|
721
|
-
});
|
|
722
|
-
// Store as regex: prefix for downstream processing
|
|
723
|
-
adoClonePattern = `regex:${pattern.trim()}`;
|
|
724
|
-
adoClonePatternResult = { strategy: 'pattern-regex', pattern: pattern.trim(), isRegex: true };
|
|
725
|
-
const message = strings.adoSelectedRegex.replace('{pattern}', pattern.trim());
|
|
726
|
-
console.log(chalk.green(` ā ${message}`));
|
|
727
|
-
break;
|
|
728
|
-
}
|
|
729
|
-
case 'skip': {
|
|
730
|
-
adoClonePatternResult = { strategy: 'skip' };
|
|
731
|
-
console.log(chalk.gray(` ā ${strings.adoCloneSkip}`));
|
|
732
|
-
break;
|
|
810
|
+
if (isMultiRepo && (provider === 'ado' || provider === 'github' || provider === 'bitbucket')) {
|
|
811
|
+
// Step 3a: For ADO only - prompt for organization and project selection
|
|
812
|
+
if (provider === 'ado') {
|
|
813
|
+
console.log(chalk.blue('\nš Azure DevOps Project Selection\n'));
|
|
814
|
+
console.log(chalk.gray(' Select which project(s) to clone repositories from.\n'));
|
|
815
|
+
const projectSelection = await promptAdoProjectSelection(options.targetDir, strings);
|
|
816
|
+
if (projectSelection) {
|
|
817
|
+
adoProjectSelection = projectSelection;
|
|
733
818
|
}
|
|
734
819
|
}
|
|
820
|
+
// Step 3b: Show unified strategy selection (ALL providers)
|
|
821
|
+
const patternResult = await promptMultiRepoPatternSelection(provider, strings);
|
|
822
|
+
// Map to ADO-style result for backward compatibility
|
|
823
|
+
adoClonePatternResult = {
|
|
824
|
+
strategy: patternResult.strategy,
|
|
825
|
+
pattern: patternResult.pattern,
|
|
826
|
+
isRegex: patternResult.isRegex,
|
|
827
|
+
};
|
|
828
|
+
// Set the clone pattern string
|
|
829
|
+
if (patternResult.strategy === 'all') {
|
|
830
|
+
adoClonePattern = '*';
|
|
831
|
+
}
|
|
832
|
+
else if (patternResult.strategy === 'pattern-glob') {
|
|
833
|
+
adoClonePattern = patternResult.pattern;
|
|
834
|
+
}
|
|
835
|
+
else if (patternResult.strategy === 'pattern-regex') {
|
|
836
|
+
adoClonePattern = `regex:${patternResult.pattern}`;
|
|
837
|
+
}
|
|
838
|
+
// For 'skip', adoClonePattern remains undefined
|
|
735
839
|
}
|
|
736
840
|
return { hosting: repositoryHosting, isMultiRepo, adoClonePattern, adoClonePatternResult, adoProjectSelection };
|
|
737
841
|
}
|