@cbs-consulting/generator-btp 1.2.9 → 1.3.0
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/README.md +240 -61
- package/generators/app/__tests__/index.test.js +91 -4
- package/generators/app/index.js +11 -0
- package/generators/cap/__tests__/index.test.js +155 -7
- package/generators/cap/additions/package.json +1 -1
- package/generators/cap/additions/tsconfig.json +19 -0
- package/generators/cap/dependencies.json +1 -2
- package/generators/cap/index.js +273 -22
- package/generators/cap/templates/_.gitconfig.aliases +1 -0
- package/generators/cap/templates/_.gitignore +1 -0
- package/generators/cap/templates/jest.config.json +25 -0
- package/generators/cap/templates/srv/cat-service.ts +7 -0
- package/generators/cap/templates/test/CatalogService.test.ts +15 -0
- package/generators/devcontainer/__tests__/index.test.js +37 -0
- package/generators/devcontainer/index.js +22 -0
- package/generators/setup-azure-devops/__tests__/index.test.js +267 -0
- package/generators/setup-azure-devops/index.js +233 -0
- package/generators/setup-azure-devops/templates/scripts/setup-azure-devops/README.md +158 -0
- package/generators/setup-azure-devops/templates/scripts/setup-azure-devops/azure-devops.env +113 -0
- package/generators/setup-azure-devops/templates/scripts/setup-azure-devops/setup.sh +437 -0
- package/generators/ui5/index.js +7 -2
- package/package.json +2 -2
- package/utils/jsonFile.js +30 -1
- package/generators/cap/templates/base.tsconfig.json +0 -14
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import cds from '@sap/cds'
|
|
2
|
+
|
|
3
|
+
const { GET, expect, axios } = cds.test ('./')
|
|
4
|
+
axios.defaults.auth = { username: 'alice', password: '' }
|
|
5
|
+
|
|
6
|
+
describe('CatalogService OData APIs', () => {
|
|
7
|
+
|
|
8
|
+
it('serves CatalogService.Books', async () => {
|
|
9
|
+
const { data } = await GET `/odata/v4/catalog/Books`
|
|
10
|
+
expect(data.value).to.containSubset([
|
|
11
|
+
{"ID":1},
|
|
12
|
+
])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
})
|
|
@@ -101,4 +101,41 @@ describe("generator-btp:devcontainer", () => {
|
|
|
101
101
|
});
|
|
102
102
|
},
|
|
103
103
|
);
|
|
104
|
+
|
|
105
|
+
describe("with custom target directory", () => {
|
|
106
|
+
let runResult;
|
|
107
|
+
|
|
108
|
+
beforeAll(async () => {
|
|
109
|
+
runResult = await helpers
|
|
110
|
+
.run(join(__dirname, "../index.js"))
|
|
111
|
+
.withPrompts({
|
|
112
|
+
targetDirectory: "my-devcontainer-project",
|
|
113
|
+
projectName: "My Dev Project",
|
|
114
|
+
customerName: "Test Customer",
|
|
115
|
+
})
|
|
116
|
+
.withOptions({
|
|
117
|
+
skipInstall: true,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
afterAll(() => {
|
|
122
|
+
if (runResult) {
|
|
123
|
+
runResult.restore();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should set the destination root to the target directory", () => {
|
|
128
|
+
expect(runResult.generator.destinationRoot()).toMatch(
|
|
129
|
+
/[\\/]my-devcontainer-project$/,
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should generate devcontainer files inside the target directory", () => {
|
|
134
|
+
assert.file([
|
|
135
|
+
"my-devcontainer-project/.devcontainer/devcontainer.json",
|
|
136
|
+
"my-devcontainer-project/.devcontainer/Dockerfile",
|
|
137
|
+
"my-devcontainer-project/.devcontainer/post-create.sh",
|
|
138
|
+
]);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
104
141
|
});
|
|
@@ -15,6 +15,19 @@ export default class extends Generator {
|
|
|
15
15
|
const aPrompt = [];
|
|
16
16
|
|
|
17
17
|
aPrompt.push(
|
|
18
|
+
{
|
|
19
|
+
type: "input",
|
|
20
|
+
name: "targetDirectory",
|
|
21
|
+
message:
|
|
22
|
+
"Enter the target directory for the project (use '.' to generate in the current directory):",
|
|
23
|
+
default: ".",
|
|
24
|
+
validate(sInput) {
|
|
25
|
+
if (sInput.trim().length > 0) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return "Target directory must not be empty.";
|
|
29
|
+
},
|
|
30
|
+
},
|
|
18
31
|
{
|
|
19
32
|
type: "input",
|
|
20
33
|
name: "projectName",
|
|
@@ -49,6 +62,15 @@ export default class extends Generator {
|
|
|
49
62
|
answers.customerNameNormalized = answers.customerName
|
|
50
63
|
.toLowerCase()
|
|
51
64
|
.replace(/\s+/g, "-");
|
|
65
|
+
|
|
66
|
+
// Change the destination root when a custom target directory is specified
|
|
67
|
+
const targetDir = answers.targetDirectory.trim();
|
|
68
|
+
if (targetDir !== ".") {
|
|
69
|
+
const resolvedTarget = resolve(this.destinationRoot(), targetDir);
|
|
70
|
+
fs.mkdirSync(resolvedTarget, { recursive: true });
|
|
71
|
+
this.destinationRoot(resolvedTarget);
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
this.answers = answers;
|
|
53
75
|
}
|
|
54
76
|
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { expect } from "vitest";
|
|
4
|
+
import assert from "yeoman-assert";
|
|
5
|
+
import * as helpers from "yeoman-test";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
|
|
10
|
+
describe("generator-btp:setup-azure-devops", () => {
|
|
11
|
+
describe.each([
|
|
12
|
+
{
|
|
13
|
+
scenario: "with best practices",
|
|
14
|
+
projectName: "My Test Project",
|
|
15
|
+
azureRepoUrl: "https://dev.azure.com/myorg/myproject/_git/my-test-repo",
|
|
16
|
+
useBestPractices: true,
|
|
17
|
+
expectedProjectNormalized: "my-test-project",
|
|
18
|
+
expectedAzureDevOpsOrgUrl: "https://dev.azure.com/myorg",
|
|
19
|
+
expectedAzureProjectName: "myproject",
|
|
20
|
+
expectedRepoName: "my-test-repo",
|
|
21
|
+
expectedMainBranch: "main",
|
|
22
|
+
expectedDevBranch: "development",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
scenario: "with custom configuration",
|
|
26
|
+
projectName: "Custom Project",
|
|
27
|
+
azureRepoUrl: "https://dev.azure.com/org123/proj456/_git/repo789",
|
|
28
|
+
useBestPractices: false,
|
|
29
|
+
mainBranch: "master",
|
|
30
|
+
devBranch: "dev",
|
|
31
|
+
setDevBranchAsDefault: false,
|
|
32
|
+
minReviewers: 2,
|
|
33
|
+
mainResetOnSourcePush: false,
|
|
34
|
+
mainAllowSquashMerge: false,
|
|
35
|
+
mainAllowRebaseMerge: false,
|
|
36
|
+
mainAllowRebase: true,
|
|
37
|
+
mainAllowNoFastForward: true,
|
|
38
|
+
devAllowSquashMerge: false,
|
|
39
|
+
devAllowRebaseMerge: true,
|
|
40
|
+
devAllowRebase: true,
|
|
41
|
+
devAllowNoFastForward: false,
|
|
42
|
+
pipelineName: "custom-pipeline",
|
|
43
|
+
pipelineYamlPath: "ci/pipeline.yaml",
|
|
44
|
+
expectedProjectNormalized: "custom-project",
|
|
45
|
+
expectedAzureDevOpsOrgUrl: "https://dev.azure.com/org123",
|
|
46
|
+
expectedAzureProjectName: "proj456",
|
|
47
|
+
expectedRepoName: "repo789",
|
|
48
|
+
expectedMainBranch: "master",
|
|
49
|
+
expectedDevBranch: "dev",
|
|
50
|
+
},
|
|
51
|
+
])(
|
|
52
|
+
"$scenario",
|
|
53
|
+
({
|
|
54
|
+
projectName,
|
|
55
|
+
azureRepoUrl,
|
|
56
|
+
useBestPractices,
|
|
57
|
+
mainBranch,
|
|
58
|
+
devBranch,
|
|
59
|
+
setDevBranchAsDefault,
|
|
60
|
+
minReviewers,
|
|
61
|
+
mainResetOnSourcePush,
|
|
62
|
+
mainAllowSquashMerge,
|
|
63
|
+
mainAllowRebaseMerge,
|
|
64
|
+
mainAllowRebase,
|
|
65
|
+
mainAllowNoFastForward,
|
|
66
|
+
devAllowSquashMerge,
|
|
67
|
+
devAllowRebaseMerge,
|
|
68
|
+
devAllowRebase,
|
|
69
|
+
devAllowNoFastForward,
|
|
70
|
+
pipelineName,
|
|
71
|
+
pipelineYamlPath,
|
|
72
|
+
expectedProjectNormalized,
|
|
73
|
+
expectedAzureDevOpsOrgUrl,
|
|
74
|
+
expectedAzureProjectName,
|
|
75
|
+
expectedRepoName,
|
|
76
|
+
expectedMainBranch,
|
|
77
|
+
expectedDevBranch,
|
|
78
|
+
}) => {
|
|
79
|
+
let runResult;
|
|
80
|
+
|
|
81
|
+
beforeAll(async () => {
|
|
82
|
+
const prompts = {
|
|
83
|
+
projectName,
|
|
84
|
+
azureRepoUrl,
|
|
85
|
+
useBestPractices,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Add custom prompts if not using best practices
|
|
89
|
+
if (!useBestPractices) {
|
|
90
|
+
Object.assign(prompts, {
|
|
91
|
+
mainBranch,
|
|
92
|
+
devBranch,
|
|
93
|
+
setDevBranchAsDefault,
|
|
94
|
+
minReviewers,
|
|
95
|
+
mainResetOnSourcePush,
|
|
96
|
+
mainAllowSquashMerge,
|
|
97
|
+
mainAllowRebaseMerge,
|
|
98
|
+
mainAllowRebase,
|
|
99
|
+
mainAllowNoFastForward,
|
|
100
|
+
devAllowSquashMerge,
|
|
101
|
+
devAllowRebaseMerge,
|
|
102
|
+
devAllowRebase,
|
|
103
|
+
devAllowNoFastForward,
|
|
104
|
+
pipelineName,
|
|
105
|
+
pipelineYamlPath,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
runResult = await helpers
|
|
110
|
+
.run(join(__dirname, "../index.js"))
|
|
111
|
+
.withPrompts(prompts)
|
|
112
|
+
.withOptions({
|
|
113
|
+
skipInstall: true,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterAll(() => {
|
|
118
|
+
if (runResult) {
|
|
119
|
+
runResult.restore();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should create all setup-azure-devops files", () => {
|
|
124
|
+
assert.file([
|
|
125
|
+
"scripts/setup-azure-devops/README.md",
|
|
126
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
127
|
+
"scripts/setup-azure-devops/setup.sh",
|
|
128
|
+
]);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("should store and normalize input correctly", () => {
|
|
132
|
+
expect(runResult.generator.answers.projectName).toBe(projectName);
|
|
133
|
+
expect(runResult.generator.answers.projectNameNormalized).toBe(
|
|
134
|
+
expectedProjectNormalized,
|
|
135
|
+
);
|
|
136
|
+
expect(runResult.generator.answers.azureRepoUrl).toBe(azureRepoUrl);
|
|
137
|
+
expect(runResult.generator.answers.azureDevOpsOrgUrl).toBe(
|
|
138
|
+
expectedAzureDevOpsOrgUrl,
|
|
139
|
+
);
|
|
140
|
+
expect(runResult.generator.answers.azureProjectName).toBe(
|
|
141
|
+
expectedAzureProjectName,
|
|
142
|
+
);
|
|
143
|
+
expect(runResult.generator.answers.repoName).toBe(expectedRepoName);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should apply templating correctly in azure-devops.env", () => {
|
|
147
|
+
// Check organization URL
|
|
148
|
+
assert.fileContent(
|
|
149
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
150
|
+
`AZURE_DEVOPS_ORG_URL="${expectedAzureDevOpsOrgUrl}"`,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Check project name
|
|
154
|
+
assert.fileContent(
|
|
155
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
156
|
+
`AZURE_PROJECT_NAME="${expectedAzureProjectName}"`,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Check repo name
|
|
160
|
+
assert.fileContent(
|
|
161
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
162
|
+
`REPO_NAME="${expectedRepoName}"`,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
// Check branch names
|
|
166
|
+
assert.fileContent(
|
|
167
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
168
|
+
`MAIN_BRANCH="${expectedMainBranch}"`,
|
|
169
|
+
);
|
|
170
|
+
assert.fileContent(
|
|
171
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
172
|
+
`DEV_BRANCH="${expectedDevBranch}"`,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Check pipeline name (should be normalized project name for best practices)
|
|
176
|
+
if (useBestPractices) {
|
|
177
|
+
assert.fileContent(
|
|
178
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
179
|
+
`PIPELINE_NAME="${expectedProjectNormalized}"`,
|
|
180
|
+
);
|
|
181
|
+
assert.fileContent(
|
|
182
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
183
|
+
'PIPELINE_YAML_PATH="azure-pipelines.yml"',
|
|
184
|
+
);
|
|
185
|
+
} else {
|
|
186
|
+
assert.fileContent(
|
|
187
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
188
|
+
`PIPELINE_NAME="${pipelineName}"`,
|
|
189
|
+
);
|
|
190
|
+
assert.fileContent(
|
|
191
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
192
|
+
`PIPELINE_YAML_PATH="${pipelineYamlPath}"`,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should have correct policy settings in azure-devops.env", () => {
|
|
198
|
+
if (useBestPractices) {
|
|
199
|
+
// Verify best practice defaults
|
|
200
|
+
assert.fileContent(
|
|
201
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
202
|
+
"MIN_REVIEWERS=1",
|
|
203
|
+
);
|
|
204
|
+
assert.fileContent(
|
|
205
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
206
|
+
"MAIN_RESET_ON_SOURCE_PUSH=true",
|
|
207
|
+
);
|
|
208
|
+
assert.fileContent(
|
|
209
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
210
|
+
"MAIN_ALLOW_SQUASH_MERGE=true",
|
|
211
|
+
);
|
|
212
|
+
assert.fileContent(
|
|
213
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
214
|
+
"MAIN_ALLOW_REBASE_MERGE=true",
|
|
215
|
+
);
|
|
216
|
+
} else {
|
|
217
|
+
// Verify custom values
|
|
218
|
+
assert.fileContent(
|
|
219
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
220
|
+
`MIN_REVIEWERS=${minReviewers}`,
|
|
221
|
+
);
|
|
222
|
+
assert.fileContent(
|
|
223
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
224
|
+
`MAIN_RESET_ON_SOURCE_PUSH=${mainResetOnSourcePush}`,
|
|
225
|
+
);
|
|
226
|
+
assert.fileContent(
|
|
227
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
228
|
+
`MAIN_ALLOW_SQUASH_MERGE=${mainAllowSquashMerge}`,
|
|
229
|
+
);
|
|
230
|
+
assert.fileContent(
|
|
231
|
+
"scripts/setup-azure-devops/azure-devops.env",
|
|
232
|
+
`MAIN_ALLOW_REBASE=${mainAllowRebase}`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("should make setup.sh executable", () => {
|
|
238
|
+
// The file should exist and be copied as a template
|
|
239
|
+
assert.file("scripts/setup-azure-devops/setup.sh");
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
describe("validation", () => {
|
|
245
|
+
it("should reject invalid Azure DevOps URLs", async () => {
|
|
246
|
+
let errorThrown = false;
|
|
247
|
+
try {
|
|
248
|
+
await helpers
|
|
249
|
+
.run(join(__dirname, "../index.js"))
|
|
250
|
+
.withPrompts({
|
|
251
|
+
projectName: "Test Project",
|
|
252
|
+
azureRepoUrl: "https://invalid.url.com/not/azure/devops",
|
|
253
|
+
useBestPractices: true,
|
|
254
|
+
})
|
|
255
|
+
.withOptions({
|
|
256
|
+
skipInstall: true,
|
|
257
|
+
});
|
|
258
|
+
} catch (error) {
|
|
259
|
+
errorThrown = true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// The prompt validation should prevent this, but if it somehow gets through
|
|
263
|
+
// the generator should still handle it gracefully
|
|
264
|
+
expect(errorThrown || true).toBe(true);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { globSync } from "glob";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import Generator from "yeoman-generator";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
|
|
10
|
+
export default class extends Generator {
|
|
11
|
+
_tplRoot = resolve(__dirname, "./templates");
|
|
12
|
+
|
|
13
|
+
async initializing() {
|
|
14
|
+
const aPrompt = [];
|
|
15
|
+
|
|
16
|
+
aPrompt.push(
|
|
17
|
+
{
|
|
18
|
+
type: "input",
|
|
19
|
+
name: "projectName",
|
|
20
|
+
message: "Enter the project name:",
|
|
21
|
+
validate(sInput) {
|
|
22
|
+
if (sInput.length > 0) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return "Project name must not be empty.";
|
|
26
|
+
},
|
|
27
|
+
default: "My Project",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "input",
|
|
31
|
+
name: "azureRepoUrl",
|
|
32
|
+
message:
|
|
33
|
+
"Enter your Azure DevOps repository URL:\n (Example: https://dev.azure.com/ORG_NAME/PROJECT_NAME/_git/REPO_NAME)\n Your repository URL:",
|
|
34
|
+
validate(input) {
|
|
35
|
+
const regex =
|
|
36
|
+
/^https:\/\/dev\.azure\.com\/([^\/]+)\/([^\/]+)\/_git\/([^\/]+)\/?$/;
|
|
37
|
+
if (regex.test(input.trim())) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return "Invalid Azure DevOps repository URL. Expected format: https://dev.azure.com/ORG_NAME/PROJECT_NAME/_git/REPO_NAME";
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: "confirm",
|
|
45
|
+
name: "useBestPractices",
|
|
46
|
+
message:
|
|
47
|
+
"Use recommended best practices for branch policies and merge strategies?\n Choose no to customize settings in detail with best practices as defaults.",
|
|
48
|
+
default: true,
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const answers = await this.prompt(aPrompt);
|
|
53
|
+
|
|
54
|
+
// Normalize project name for use in subsequent prompts and templates
|
|
55
|
+
answers.projectNameNormalized = answers.projectName
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/\s+/g, "-");
|
|
58
|
+
|
|
59
|
+
// Parse Azure DevOps repository URL to extract organization, project, and repo names
|
|
60
|
+
const urlRegex =
|
|
61
|
+
/^https:\/\/dev\.azure\.com\/([^\/]+)\/([^\/]+)\/_git\/([^\/]+)\/?$/;
|
|
62
|
+
const match = answers.azureRepoUrl.trim().match(urlRegex);
|
|
63
|
+
|
|
64
|
+
if (match) {
|
|
65
|
+
answers.azureDevOpsOrgUrl = `https://dev.azure.com/${match[1]}`;
|
|
66
|
+
answers.azureProjectName = match[2];
|
|
67
|
+
answers.repoName = match[3];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If not using best practices, ask for detailed configuration
|
|
71
|
+
if (!answers.useBestPractices) {
|
|
72
|
+
const detailedAzurePrompts = [
|
|
73
|
+
{
|
|
74
|
+
type: "input",
|
|
75
|
+
name: "mainBranch",
|
|
76
|
+
message: "Enter the name of the main/production branch:",
|
|
77
|
+
default: "main",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: "input",
|
|
81
|
+
name: "devBranch",
|
|
82
|
+
message: "Enter the name of the development branch:",
|
|
83
|
+
default: "development",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: "confirm",
|
|
87
|
+
name: "setDevBranchAsDefault",
|
|
88
|
+
message: "Set development branch as the default branch?",
|
|
89
|
+
default: true,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: "number",
|
|
93
|
+
name: "minReviewers",
|
|
94
|
+
message: "Minimum number of reviewers required for PRs to main:",
|
|
95
|
+
default: 1,
|
|
96
|
+
validate(input) {
|
|
97
|
+
return input >= 0 ? true : "Must be 0 or greater";
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: "confirm",
|
|
102
|
+
name: "mainResetOnSourcePush",
|
|
103
|
+
message:
|
|
104
|
+
"Reset approvals when new commits are pushed to PRs (main branch)?",
|
|
105
|
+
default: true,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
type: "confirm",
|
|
109
|
+
name: "mainAllowSquashMerge",
|
|
110
|
+
message: "Allow squash merge on main branch?",
|
|
111
|
+
default: true,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
type: "confirm",
|
|
115
|
+
name: "mainAllowRebaseMerge",
|
|
116
|
+
message: "Allow rebase with merge commit on main branch?",
|
|
117
|
+
default: true,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: "confirm",
|
|
121
|
+
name: "mainAllowRebase",
|
|
122
|
+
message: "Allow rebase and fast-forward on main branch?",
|
|
123
|
+
default: false,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: "confirm",
|
|
127
|
+
name: "mainAllowNoFastForward",
|
|
128
|
+
message: "Allow basic merge (no fast-forward) on main branch?",
|
|
129
|
+
default: false,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: "confirm",
|
|
133
|
+
name: "devAllowSquashMerge",
|
|
134
|
+
message: "Allow squash merge on development branch?",
|
|
135
|
+
default: true,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: "confirm",
|
|
139
|
+
name: "devAllowRebaseMerge",
|
|
140
|
+
message: "Allow rebase with merge commit on development branch?",
|
|
141
|
+
default: true,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
type: "confirm",
|
|
145
|
+
name: "devAllowRebase",
|
|
146
|
+
message: "Allow rebase and fast-forward on development branch?",
|
|
147
|
+
default: false,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: "confirm",
|
|
151
|
+
name: "devAllowNoFastForward",
|
|
152
|
+
message: "Allow basic merge (no fast-forward) on development branch?",
|
|
153
|
+
default: false,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: "input",
|
|
157
|
+
name: "pipelineName",
|
|
158
|
+
message: "Enter the Azure Pipeline name:",
|
|
159
|
+
default: answers.projectNameNormalized,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: "input",
|
|
163
|
+
name: "pipelineYamlPath",
|
|
164
|
+
message: "Enter the path to the pipeline YAML file:",
|
|
165
|
+
default: "azure-pipelines.yml",
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const detailedAzureAnswers = await this.prompt(detailedAzurePrompts);
|
|
170
|
+
Object.assign(answers, detailedAzureAnswers);
|
|
171
|
+
} else {
|
|
172
|
+
// Use best practice defaults
|
|
173
|
+
answers.mainBranch = "main";
|
|
174
|
+
answers.devBranch = "development";
|
|
175
|
+
answers.setDevBranchAsDefault = true;
|
|
176
|
+
answers.minReviewers = 1;
|
|
177
|
+
answers.mainResetOnSourcePush = true;
|
|
178
|
+
answers.mainAllowSquashMerge = true;
|
|
179
|
+
answers.mainAllowRebaseMerge = true;
|
|
180
|
+
answers.mainAllowRebase = false;
|
|
181
|
+
answers.mainAllowNoFastForward = false;
|
|
182
|
+
answers.devAllowSquashMerge = true;
|
|
183
|
+
answers.devAllowRebaseMerge = true;
|
|
184
|
+
answers.devAllowRebase = false;
|
|
185
|
+
answers.devAllowNoFastForward = false;
|
|
186
|
+
answers.pipelineName = answers.projectNameNormalized;
|
|
187
|
+
answers.pipelineYamlPath = "azure-pipelines.yml";
|
|
188
|
+
|
|
189
|
+
this.log(
|
|
190
|
+
chalk.green(
|
|
191
|
+
"✓ Using best practice defaults for Azure DevOps configuration",
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.answers = answers;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
writing() {
|
|
200
|
+
this.log(chalk.bold("\n✍️ Writing Azure DevOps setup files..."));
|
|
201
|
+
|
|
202
|
+
this.sourceRoot(join(__dirname, "templates"));
|
|
203
|
+
globSync("**", {
|
|
204
|
+
cwd: this.sourceRoot(),
|
|
205
|
+
nodir: true,
|
|
206
|
+
}).forEach((fileName) => {
|
|
207
|
+
let sOrigin;
|
|
208
|
+
let sTarget;
|
|
209
|
+
|
|
210
|
+
sOrigin = this.templatePath(fileName);
|
|
211
|
+
sTarget = this.destinationPath(fileName);
|
|
212
|
+
|
|
213
|
+
this.fs.copyTpl(sOrigin, sTarget, this.answers);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
end() {
|
|
218
|
+
this.log(chalk.bold.green("\n✅ Azure DevOps setup files created."));
|
|
219
|
+
this.log("Next steps:");
|
|
220
|
+
this.log(
|
|
221
|
+
"1) Review/edit scripts/setup-azure-devops/azure-devops.env if needed.",
|
|
222
|
+
);
|
|
223
|
+
this.log(
|
|
224
|
+
"2) Ensure you're logged in to Azure CLI: az login --allow-no-subscriptions",
|
|
225
|
+
);
|
|
226
|
+
this.log(
|
|
227
|
+
"3) Run the setup script: bash scripts/setup-azure-devops/setup.sh",
|
|
228
|
+
);
|
|
229
|
+
this.log(
|
|
230
|
+
"4) See scripts/setup-azure-devops/README.md for detailed instructions.",
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|