-
Notifications
You must be signed in to change notification settings - Fork 233
Expand file tree
/
Copy pathciYamlUtils.ts
More file actions
210 lines (183 loc) · 8.57 KB
/
ciYamlUtils.ts
File metadata and controls
210 lines (183 loc) · 8.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import { NpmPackageInfo, VersionPolicyName } from './types.js';
import { dirname, posix } from 'path';
import { getNpmPackageName, getNpmPackageSafeName } from './npmUtils.js';
import { parse, stringify } from 'yaml';
import { readFile, writeFile } from 'fs/promises';
import { existsAsync } from './utils.js';
import { logger } from '../utils/logger.js';
import { fileURLToPath } from 'url';
interface ArtifactInfo {
name: string;
safeName: string;
}
const comment = '# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file.\n\n';
async function createOrUpdateManagePlaneCiYaml(
packageDirToSdkRoot: string,
npmPackageInfo: NpmPackageInfo
): Promise<string> {
const serviceDirToSDKDir = posix.join(packageDirToSdkRoot, '..');
const ciMgmtPath = posix.join(serviceDirToSDKDir, 'ci.mgmt.yml');
if (!(await existsAsync(ciMgmtPath))) {
await createManagementPlaneCiYaml(
packageDirToSdkRoot,
ciMgmtPath,
serviceDirToSDKDir,
npmPackageInfo
);
return ciMgmtPath;
}
await updateManagementPlaneCiYaml(packageDirToSdkRoot, ciMgmtPath, npmPackageInfo);
return ciMgmtPath;
}
function tryAddItemInArray<TItem>(
array: TItem[],
item: TItem,
include: (array: TItem[], item: TItem) => boolean = (a, i) => a.includes(i)
): boolean {
let needUpdate = false;
if (include(array, item) !== true) {
needUpdate = true;
array.push(item);
}
return needUpdate;
}
function makeSureArrayAvailableInCiYaml(current: any, path: string[]) {
path.forEach((p, i) => {
if (!current?.[p]) {
current[p] = i === path.length - 1 ? [] : {};
}
current = current[p];
});
}
async function updateManagementPlaneCiYaml(
generatedPackageDirectory: string,
ciMgmtPath: string,
npmPackageInfo: NpmPackageInfo
): Promise<void> {
const content = await readFile(ciMgmtPath, { encoding: 'utf-8' });
let parsed = parse(content.toString());
makeSureArrayAvailableInCiYaml(parsed, ['trigger', 'branches', 'exclude']);
makeSureArrayAvailableInCiYaml(parsed, ['pr', 'branches', 'exclude']);
makeSureArrayAvailableInCiYaml(parsed, ['trigger', 'paths', 'include']);
makeSureArrayAvailableInCiYaml(parsed, ['pr', 'paths', 'include']);
makeSureArrayAvailableInCiYaml(parsed, ['extends', 'parameters', 'Artifacts']);
var artifact: ArtifactInfo = getArtifact(npmPackageInfo);
var artifactInclude = (array: ArtifactInfo[], item: ArtifactInfo) => array.map((a) => a.name).includes(item.name);
let needUpdate = false;
needUpdate = tryAddItemInArray(parsed.trigger.branches.exclude, 'feature/v4') || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.branches.exclude, 'feature/v4') || needUpdate;
needUpdate = tryAddItemInArray(parsed.trigger.paths.include, generatedPackageDirectory) || needUpdate;
needUpdate = tryAddItemInArray(parsed.trigger.paths.include, ciMgmtPath) || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.paths.include, generatedPackageDirectory) || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.paths.include, ciMgmtPath) || needUpdate;
needUpdate = tryAddItemInArray(parsed.extends.parameters.Artifacts, artifact, artifactInclude) || needUpdate;
await writeCiYaml(ciMgmtPath, parsed);
}
function getArtifact(npmPackageInfo: NpmPackageInfo): ArtifactInfo {
const name = getNpmPackageName(npmPackageInfo);
const safeName = getNpmPackageSafeName(npmPackageInfo);
return { name, safeName };
}
async function createManagementPlaneCiYaml(
packageDirToSdkRoot: string,
ciMgmtPath: string,
serviceDirToSdkRoot: string,
npmPackageInfo: NpmPackageInfo
): Promise<void> {
const artifact = getArtifact(npmPackageInfo);
// Use two ways to get the dirname to avoid failures caused by node version issues.
const __dirname = import.meta.dirname || dirname(fileURLToPath(import.meta.url));
const templatePath = posix.join(__dirname, 'ciYamlTemplates/ci.mgmt.template.yml');
const template = await readFile(templatePath, { encoding: 'utf-8' });
const parsed = parse(template.toString());
parsed.trigger.paths.include = [packageDirToSdkRoot, ciMgmtPath];
parsed.pr.paths.include = [packageDirToSdkRoot, ciMgmtPath];
parsed.extends.parameters.ServiceDirectory = serviceDirToSdkRoot.split('/')[1];
parsed.extends.parameters.Artifacts = [artifact];
await writeCiYaml(ciMgmtPath, parsed);
}
async function writeCiYaml(ciPath: string, config: any) {
const content = comment + stringify(config);
await writeFile(ciPath, content, { encoding: 'utf-8', flush: true });
logger.info(`Created or updated CI file '${posix.resolve(ciPath)}' with content: \n${content}`);
}
async function updateDataPlaneCiYaml(
generatedPackageDirectory: string,
ciPath: string,
npmPackageInfo: NpmPackageInfo
): Promise<void> {
const content = await readFile(ciPath, { encoding: 'utf-8' });
let parsed = parse(content.toString());
makeSureArrayAvailableInCiYaml(parsed, ['trigger', 'branches', 'exclude']);
makeSureArrayAvailableInCiYaml(parsed, ['pr', 'branches', 'exclude']);
makeSureArrayAvailableInCiYaml(parsed, ['trigger', 'paths', 'include']);
makeSureArrayAvailableInCiYaml(parsed, ['pr', 'paths', 'include']);
makeSureArrayAvailableInCiYaml(parsed, ['extends', 'parameters', 'Artifacts']);
const artifact: ArtifactInfo = getArtifact(npmPackageInfo);
const artifactInclude = (array: ArtifactInfo[], item: ArtifactInfo) => array.map((a) => a.name).includes(item.name);
let needUpdate = false;
needUpdate = tryAddItemInArray(parsed.trigger.branches.exclude, 'feature/v4') || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.branches.exclude, 'feature/v4') || needUpdate;
needUpdate = tryAddItemInArray(parsed.trigger.paths.include, generatedPackageDirectory) || needUpdate;
needUpdate = tryAddItemInArray(parsed.trigger.paths.include, ciPath) || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.paths.include, generatedPackageDirectory) || needUpdate;
needUpdate = tryAddItemInArray(parsed.pr.paths.include, ciPath) || needUpdate;
needUpdate = tryAddItemInArray(parsed.extends.parameters.Artifacts, artifact, artifactInclude) || needUpdate;
await writeCiYaml(ciPath, parsed);
}
async function createDataPlaneCiYaml(
packageDirToSdkRoot: string,
ciPath: string,
serviceDirToSdkRoot: string,
npmPackageInfo: NpmPackageInfo
): Promise<void> {
const artifact = getArtifact(npmPackageInfo);
const __dirname = import.meta.dirname || dirname(fileURLToPath(import.meta.url));
const templatePath = posix.join(__dirname, 'ciYamlTemplates/ci.template.yml');
const template = await readFile(templatePath, { encoding: 'utf-8' });
const parsed = parse(template.toString());
parsed.trigger.paths.include = [packageDirToSdkRoot, ciPath];
parsed.pr.paths.include = [packageDirToSdkRoot, ciPath];
parsed.extends.parameters.ServiceDirectory = serviceDirToSdkRoot.split('/')[1];
parsed.extends.parameters.Artifacts = [artifact];
await writeCiYaml(ciPath, parsed);
}
async function createOrUpdateDataPlaneCiYaml(
packageDirToSdkRoot: string,
npmPackageInfo: NpmPackageInfo
): Promise<string> {
const serviceDirToSDKDir = posix.join(packageDirToSdkRoot, '..');
const ciPath = posix.join(serviceDirToSDKDir, 'ci.yml');
if (!(await existsAsync(ciPath))) {
await createDataPlaneCiYaml(packageDirToSdkRoot, ciPath, serviceDirToSDKDir, npmPackageInfo);
}
await updateDataPlaneCiYaml(packageDirToSdkRoot, ciPath, npmPackageInfo);
return ciPath;
}
export async function createOrUpdateCiYaml(
relativeGeneratedPackageDirectoryToSdkRoot: string,
versionPolicyName: VersionPolicyName,
npmPackageInfo: NpmPackageInfo
): Promise<string> {
logger.info('Start to create or update CI files');
switch (versionPolicyName) {
case 'management': {
const ciPath = await createOrUpdateManagePlaneCiYaml(
relativeGeneratedPackageDirectoryToSdkRoot,
npmPackageInfo
);
logger.info('Created or updated MPG CI files successfully.');
return ciPath;
}
case 'client': {
const ciPath = await createOrUpdateDataPlaneCiYaml(
relativeGeneratedPackageDirectoryToSdkRoot,
npmPackageInfo
);
logger.info('Created or updated DPG CI files successfully.');
return ciPath;
}
default:
throw new Error(`Unsupported version policy name: ${versionPolicyName}`);
}
}