apify-test-tools 0.10.2-beta.3 → 0.10.2-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/cli/apify-test-tools.mjs +126 -125
- package/.github/scripts/run-with-apify-tokens.mjs +1 -1
- package/.github/workflows/public_pr-build-test.yaml +25 -25
- package/.github/workflows/public_push-build-latest.yaml +20 -4
- package/CHANGELOG.md +1 -0
- package/README.md +67 -17
- package/bin/affected-actors.ts +16 -25
- package/bin/build.ts +55 -38
- package/bin/git.ts +3 -14
- package/bin/main.ts +96 -40
- package/bin/slack.ts +24 -0
- package/bin/stdin-input.ts +65 -0
- package/dist/bin/affected-actors.d.ts +4 -9
- package/dist/bin/affected-actors.d.ts.map +1 -1
- package/dist/bin/affected-actors.js +17 -19
- package/dist/bin/affected-actors.js.map +1 -1
- package/dist/bin/build.d.ts +12 -5
- package/dist/bin/build.d.ts.map +1 -1
- package/dist/bin/build.js +45 -23
- package/dist/bin/build.js.map +1 -1
- package/dist/bin/git.d.ts +1 -6
- package/dist/bin/git.d.ts.map +1 -1
- package/dist/bin/git.js +3 -13
- package/dist/bin/git.js.map +1 -1
- package/dist/bin/main.js +78 -40
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/slack.d.ts +8 -0
- package/dist/bin/slack.d.ts.map +1 -1
- package/dist/bin/slack.js +18 -0
- package/dist/bin/slack.js.map +1 -1
- package/dist/bin/stdin-input.d.ts +17 -0
- package/dist/bin/stdin-input.d.ts.map +1 -0
- package/dist/bin/stdin-input.js +54 -0
- package/dist/bin/stdin-input.js.map +1 -0
- package/dist/test/bundle/cli-bundle.test.js +27 -4
- package/dist/test/bundle/cli-bundle.test.js.map +1 -1
- package/dist/test/e2e/cli-bundle.e2e.test.js +16 -9
- package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -1
- package/dist/test/unit/bin/affected-actors.test.js +7 -13
- package/dist/test/unit/bin/affected-actors.test.js.map +1 -1
- package/dist/test/unit/bin/build-cli.test.d.ts +2 -0
- package/dist/test/unit/bin/build-cli.test.d.ts.map +1 -0
- package/dist/test/unit/bin/build-cli.test.js +52 -0
- package/dist/test/unit/bin/build-cli.test.js.map +1 -0
- package/dist/test/unit/bin/build.test.js +61 -4
- package/dist/test/unit/bin/build.test.js.map +1 -1
- package/dist/test/unit/bin/git.test.js +2 -14
- package/dist/test/unit/bin/git.test.js.map +1 -1
- package/dist/test/unit/bin/slack.test.js +39 -1
- package/dist/test/unit/bin/slack.test.js.map +1 -1
- package/dist/test/unit/bin/stdin-input.test.d.ts +2 -0
- package/dist/test/unit/bin/stdin-input.test.d.ts.map +1 -0
- package/dist/test/unit/bin/stdin-input.test.js +50 -0
- package/dist/test/unit/bin/stdin-input.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/test/bundle/cli-bundle.test.ts +50 -4
- package/test/e2e/cli-bundle.e2e.test.ts +26 -11
- package/test/unit/bin/affected-actors.test.ts +7 -13
- package/test/unit/bin/build-cli.test.ts +61 -0
- package/test/unit/bin/build.test.ts +71 -3
- package/test/unit/bin/git.test.ts +1 -15
- package/test/unit/bin/slack.test.ts +44 -1
- package/test/unit/bin/stdin-input.test.ts +61 -0
package/bin/main.ts
CHANGED
|
@@ -7,12 +7,13 @@ import yargs, { type Options } from 'yargs';
|
|
|
7
7
|
import { hideBin } from 'yargs/helpers';
|
|
8
8
|
|
|
9
9
|
import { getAffectedActors, toAffectedActorsDocument } from './affected-actors.js';
|
|
10
|
-
import { deleteOldBuilds,
|
|
10
|
+
import { buildActors, DEFAULT_VERSION_KEYWORD, deleteOldBuilds, TEST_VERSION_NUMBER } from './build.js';
|
|
11
11
|
import { runBuildsFromLocal } from './build-from-local.js';
|
|
12
|
-
import { getChangedFiles, getCommits, getCurrentBranch
|
|
12
|
+
import { getChangedFiles, getCommits, getCurrentBranch } from './git.js';
|
|
13
13
|
import { logger, logLevels } from './logger.js';
|
|
14
14
|
import { writeJson } from './output.js';
|
|
15
|
-
import {
|
|
15
|
+
import { announceRelease } from './slack.js';
|
|
16
|
+
import { parseBuildInput, parseReleaseChanges, readStdin } from './stdin-input.js';
|
|
16
17
|
import { reportTestResults } from './test-report.js';
|
|
17
18
|
import { readConfigFile } from './utils/config/load-config.js';
|
|
18
19
|
|
|
@@ -83,9 +84,34 @@ const dryRunOptions = {
|
|
|
83
84
|
},
|
|
84
85
|
} as const satisfies Record<string, Options>;
|
|
85
86
|
|
|
86
|
-
/** Flags
|
|
87
|
+
/** Flags of `build`, which builds exactly the Actors it is given. */
|
|
87
88
|
const buildOptions = {
|
|
88
|
-
'
|
|
89
|
+
'version-number': {
|
|
90
|
+
type: 'string',
|
|
91
|
+
demandOption: true,
|
|
92
|
+
describe: `Version to build, like 0.1, or "${DEFAULT_VERSION_KEYWORD}" for each Actor's default version`,
|
|
93
|
+
coerce: (value: string) => {
|
|
94
|
+
if (value !== DEFAULT_VERSION_KEYWORD && !/^\d+\.\d+$/.test(value)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`--version-number must look like 0.1 or be "${DEFAULT_VERSION_KEYWORD}", got "${value}"`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
} as const satisfies Record<string, Options>;
|
|
103
|
+
|
|
104
|
+
/** Range of build-for-test: the checked-out branch's own commits, after its last validated one. */
|
|
105
|
+
const buildForTestOptions = {
|
|
106
|
+
'target-branch': { type: 'string', demandOption: true },
|
|
107
|
+
'base-commit': { type: 'string' },
|
|
108
|
+
'test-files-glob': { type: 'string' },
|
|
109
|
+
} as const satisfies Record<string, Options>;
|
|
110
|
+
|
|
111
|
+
/** Where `release` and `notify-release` post the release. */
|
|
112
|
+
const releaseSlackOptions = {
|
|
113
|
+
'report-slack-channel': { type: 'string', describe: 'Channel for the full report: commits and changed files' },
|
|
114
|
+
'release-slack-channel': { type: 'string', describe: 'Channel for the changelog additions only' },
|
|
89
115
|
} as const satisfies Record<string, Options>;
|
|
90
116
|
|
|
91
117
|
/** Global flags, available to every command. */
|
|
@@ -146,7 +172,7 @@ await yargs()
|
|
|
146
172
|
'Find the Actors whose context changed in a commit range ending at the checked-out HEAD',
|
|
147
173
|
(y) => y.options(affectedRangeOptions).options(actorSelectionOptions),
|
|
148
174
|
async (args) => {
|
|
149
|
-
writeJson(toAffectedActorsDocument(await getAffectedActors(
|
|
175
|
+
writeJson(toAffectedActorsDocument(await getAffectedActors(args)));
|
|
150
176
|
},
|
|
151
177
|
)
|
|
152
178
|
.command(
|
|
@@ -165,92 +191,122 @@ await yargs()
|
|
|
165
191
|
)
|
|
166
192
|
.command(
|
|
167
193
|
'build',
|
|
168
|
-
'',
|
|
194
|
+
'Build the Actors listed on stdin, as {"actors": [{"actorFullName": ...}]}, from the checked-out branch',
|
|
195
|
+
(y) => y.options(buildOptions).options(repoUrlOptions).options(dryRunOptions),
|
|
196
|
+
async (args) => {
|
|
197
|
+
const input = parseBuildInput(await readStdin());
|
|
198
|
+
const names = input.actors.map(({ actorFullName }) => actorFullName);
|
|
199
|
+
// An empty --actors selects every Actor, but an empty list here means there is nothing to build
|
|
200
|
+
const actorConfigs = names.length > 0 ? await readConfigFile({ actors: names, ignore: [] }) : [];
|
|
201
|
+
const builds = await buildActors({
|
|
202
|
+
actorConfigs,
|
|
203
|
+
versionNumber: args.versionNumber,
|
|
204
|
+
repoUrl: args.repoUrl,
|
|
205
|
+
dryRun: args.dryRun,
|
|
206
|
+
});
|
|
207
|
+
writeJson(builds);
|
|
208
|
+
},
|
|
209
|
+
)
|
|
210
|
+
.command(
|
|
211
|
+
'build-for-test',
|
|
212
|
+
'Build the Actors the checked-out branch changed functionally, for testing',
|
|
169
213
|
(y) =>
|
|
170
214
|
y
|
|
171
|
-
.options(
|
|
215
|
+
.options(buildForTestOptions)
|
|
172
216
|
.options(actorSelectionOptions)
|
|
173
|
-
.options(buildOptions)
|
|
174
217
|
.options(repoUrlOptions)
|
|
175
|
-
.options(dryRunOptions)
|
|
176
|
-
.option('test-files-glob', { type: 'string' }),
|
|
218
|
+
.options(dryRunOptions),
|
|
177
219
|
async (config) => {
|
|
220
|
+
logger.info(
|
|
221
|
+
'[BUILD-FOR-TEST]: Same as get-affected-actors --base <target-branch> [--since <base-commit>] ' +
|
|
222
|
+
`| jq '{ actors: .functionallyChangedActors }' | build --version-number ${TEST_VERSION_NUMBER}`,
|
|
223
|
+
);
|
|
178
224
|
// Cosmetic-only changes don't need testing, so they don't need a build either
|
|
179
|
-
const { functionallyChangedActors
|
|
180
|
-
head: config.sourceBranch,
|
|
225
|
+
const { functionallyChangedActors } = await getAffectedActors({
|
|
181
226
|
base: config.targetBranch,
|
|
182
227
|
since: config.baseCommit,
|
|
183
228
|
testFilesGlob: config.testFilesGlob,
|
|
184
229
|
actors: config.actors,
|
|
185
230
|
ignore: config.ignore,
|
|
186
231
|
});
|
|
187
|
-
const builds = await
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
232
|
+
const builds = await buildActors({
|
|
233
|
+
actorConfigs: functionallyChangedActors,
|
|
234
|
+
versionNumber: TEST_VERSION_NUMBER,
|
|
235
|
+
repoUrl: config.repoUrl,
|
|
191
236
|
dryRun: config.dryRun,
|
|
192
|
-
useDockerCache: config.useDockerCache,
|
|
193
237
|
});
|
|
194
238
|
writeJson(builds);
|
|
195
239
|
},
|
|
196
240
|
)
|
|
197
241
|
.command(
|
|
198
242
|
'release',
|
|
199
|
-
'',
|
|
243
|
+
'Build the default version of the Actors changed since the last release and announce it on Slack',
|
|
200
244
|
(y) =>
|
|
201
245
|
y
|
|
202
246
|
.options(actorSelectionOptions)
|
|
203
|
-
.options(buildOptions)
|
|
204
247
|
.options(repoUrlOptions)
|
|
205
248
|
.options(dryRunOptions)
|
|
206
249
|
// The last commit that is already released, everything after it up to HEAD gets released.
|
|
207
250
|
// Required, see the README section "Releasing Actors" for how to set it for each merge strategy.
|
|
208
251
|
.option('base-commit', { type: 'string', demandOption: true })
|
|
209
|
-
.
|
|
210
|
-
.option('release-slack-channel', { type: 'string' }),
|
|
252
|
+
.options(releaseSlackOptions),
|
|
211
253
|
async (args) => {
|
|
212
|
-
|
|
254
|
+
logger.info(
|
|
255
|
+
'[RELEASE]: Same as get-affected-actors --since <base-commit> > affected.json, then ' +
|
|
256
|
+
"jq '{ actors: (.functionallyChangedActors + .cosmeticallyChangedActors) }' affected.json " +
|
|
257
|
+
`| build --version-number ${DEFAULT_VERSION_KEYWORD}, then notify-release < affected.json`,
|
|
258
|
+
);
|
|
259
|
+
// Fail before anything else on a detached HEAD: there is no branch to release
|
|
260
|
+
await getCurrentBranch();
|
|
213
261
|
const { commits, changedFiles, changelog, functionallyChangedActors, cosmeticallyChangedActors } =
|
|
214
262
|
await getAffectedActors({
|
|
215
|
-
head: 'HEAD',
|
|
216
263
|
since: args.baseCommit,
|
|
217
264
|
actors: args.actors,
|
|
218
265
|
ignore: args.ignore,
|
|
219
266
|
});
|
|
220
|
-
// A release ships cosmetic changes (README, input schema descriptions, ...) too
|
|
221
|
-
const actorsChanged = [...functionallyChangedActors, ...cosmeticallyChangedActors];
|
|
222
267
|
if (commits.length === 0) {
|
|
223
268
|
logger.info(`HEAD is the base commit ${args.baseCommit}, there is nothing new to release`);
|
|
224
269
|
return;
|
|
225
270
|
}
|
|
226
|
-
const { repoUrl, shouldVerifyRepoUrl } = await resolveRepoUrl(args.repoUrl);
|
|
227
271
|
|
|
228
|
-
const isLatest = true;
|
|
229
272
|
const { dryRun, reportSlackChannel, releaseSlackChannel } = args;
|
|
230
|
-
const builds = await
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
branch,
|
|
273
|
+
const builds = await buildActors({
|
|
274
|
+
// A release ships cosmetic changes (README, input schema descriptions, ...) too
|
|
275
|
+
actorConfigs: [...functionallyChangedActors, ...cosmeticallyChangedActors],
|
|
276
|
+
versionNumber: DEFAULT_VERSION_KEYWORD,
|
|
277
|
+
repoUrl: args.repoUrl,
|
|
236
278
|
dryRun,
|
|
237
|
-
useDockerCache: args.useDockerCache,
|
|
238
279
|
});
|
|
239
280
|
logger.info(JSON.stringify(builds));
|
|
240
281
|
|
|
241
|
-
await
|
|
242
|
-
changedFiles,
|
|
282
|
+
await announceRelease({
|
|
243
283
|
commits,
|
|
284
|
+
changedFiles,
|
|
244
285
|
changelog,
|
|
245
|
-
|
|
286
|
+
repoUrl: args.repoUrl,
|
|
246
287
|
dryRun,
|
|
247
|
-
// The newest commit, same as the pushed head commit
|
|
248
|
-
author: commits[commits.length - 1].author,
|
|
249
288
|
reportSlackChannel,
|
|
250
289
|
releaseSlackChannel,
|
|
251
290
|
});
|
|
252
291
|
},
|
|
253
292
|
)
|
|
293
|
+
.command(
|
|
294
|
+
'notify-release',
|
|
295
|
+
'Announce a release on Slack, from the get-affected-actors output on stdin',
|
|
296
|
+
(y) => y.options(releaseSlackOptions).options(repoUrlOptions).options(dryRunOptions),
|
|
297
|
+
async (args) => {
|
|
298
|
+
const { commits, changedFiles, changelog } = parseReleaseChanges(await readStdin());
|
|
299
|
+
await announceRelease({
|
|
300
|
+
commits,
|
|
301
|
+
changedFiles,
|
|
302
|
+
changelog,
|
|
303
|
+
repoUrl: args.repoUrl,
|
|
304
|
+
dryRun: args.dryRun,
|
|
305
|
+
reportSlackChannel: args.reportSlackChannel,
|
|
306
|
+
releaseSlackChannel: args.releaseSlackChannel,
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
)
|
|
254
310
|
.command(
|
|
255
311
|
'build-from-local',
|
|
256
312
|
'',
|
package/bin/slack.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebClient } from '@slack/web-api';
|
|
2
2
|
|
|
3
|
+
import { getRepoName, resolveRepoUrl } from './git.js';
|
|
3
4
|
import { logger } from './logger.js';
|
|
4
5
|
import type { Commit } from './types.js';
|
|
5
6
|
import { getEnvVar } from './utils.js';
|
|
@@ -96,6 +97,29 @@ export const notifyToSlack = async ({
|
|
|
96
97
|
}
|
|
97
98
|
};
|
|
98
99
|
|
|
100
|
+
type AnnounceReleaseOptions = Omit<NotifyToSlackOptions, 'author' | 'repository'> & {
|
|
101
|
+
// Defaults to the `origin` remote, see resolveRepoUrl
|
|
102
|
+
repoUrl?: string;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Posts what a release changed: its commits, changed files and changelog, as get-affected-actors reports them.
|
|
107
|
+
* Posts nothing when there are no commits, which means there is nothing new to release.
|
|
108
|
+
*/
|
|
109
|
+
export const announceRelease = async ({ commits, repoUrl, ...options }: AnnounceReleaseOptions) => {
|
|
110
|
+
if (commits.length === 0) {
|
|
111
|
+
logger.info('No new commits, so there is no release to announce');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await notifyToSlack({
|
|
115
|
+
...options,
|
|
116
|
+
commits,
|
|
117
|
+
repository: getRepoName((await resolveRepoUrl(repoUrl)).repoUrl),
|
|
118
|
+
// The newest commit, same as the pushed head commit
|
|
119
|
+
author: commits[commits.length - 1].author,
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
|
|
99
123
|
export const sendSlackMessage = async (slack: WebClient, channel: string, text: string, blocks: string[]) => {
|
|
100
124
|
const { ts } = await slack.chat.postMessage({ text, channel });
|
|
101
125
|
if (blocks.length > 0 && ts) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
|
|
3
|
+
import z, { prettifyError, type ZodType } from 'zod';
|
|
4
|
+
|
|
5
|
+
export const readStdin = async (): Promise<string> => {
|
|
6
|
+
// Nothing piped in: fail right away instead of waiting for someone to type
|
|
7
|
+
if (process.stdin.isTTY) {
|
|
8
|
+
throw new Error('Expected JSON on stdin, but nothing was piped in.');
|
|
9
|
+
}
|
|
10
|
+
let raw = '';
|
|
11
|
+
for await (const chunk of process.stdin) {
|
|
12
|
+
raw += chunk;
|
|
13
|
+
}
|
|
14
|
+
return raw;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const parseStdinJson = <T>(
|
|
18
|
+
raw: string,
|
|
19
|
+
schema: ZodType<T>,
|
|
20
|
+
{ expected, example }: { expected: string; example: string },
|
|
21
|
+
) => {
|
|
22
|
+
// Empty input is an error, not "nothing to do": it is what a failed command earlier in the pipe leaves behind
|
|
23
|
+
if (!raw.trim()) {
|
|
24
|
+
throw new Error(`Expected ${expected} as JSON on stdin, got nothing (${example}).`);
|
|
25
|
+
}
|
|
26
|
+
let json: unknown;
|
|
27
|
+
try {
|
|
28
|
+
json = JSON.parse(raw);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw new Error(`The input on stdin is not valid JSON: ${(error as Error).message}`);
|
|
31
|
+
}
|
|
32
|
+
const result = schema.safeParse(json);
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
throw new Error(`The input on stdin is not ${expected} (${example}):\n${prettifyError(result.error)}`);
|
|
35
|
+
}
|
|
36
|
+
return result.data;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* What `build` reads: the Actors to build. Only their names are read, the config file stays the source of truth
|
|
41
|
+
* for everything else about them. Other fields are ignored, so a get-affected-actors document only needs its Actor
|
|
42
|
+
* list picked, e.g. `jq '{ actors: .functionallyChangedActors }'`.
|
|
43
|
+
*/
|
|
44
|
+
const buildInputSchema = z.object({
|
|
45
|
+
actors: z.array(z.object({ actorFullName: z.string() })),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const parseBuildInput = (raw: string) =>
|
|
49
|
+
parseStdinJson(raw, buildInputSchema, {
|
|
50
|
+
expected: 'the Actors to build',
|
|
51
|
+
example: `e.g. echo '{"actors":[{"actorFullName":"owner/name"}]}' | apify-test-tools build --version-number 0.1`,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/** What `notify-release` reads: the parts of a get-affected-actors document that describe what changed. */
|
|
55
|
+
const releaseChangesSchema = z.object({
|
|
56
|
+
commits: z.array(z.object({ sha: z.string(), author: z.string(), date: z.string(), message: z.string() })),
|
|
57
|
+
changedFiles: z.array(z.string()),
|
|
58
|
+
changelog: z.string().nullable(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export const parseReleaseChanges = (raw: string) =>
|
|
62
|
+
parseStdinJson(raw, releaseChangesSchema, {
|
|
63
|
+
expected: 'the output of get-affected-actors',
|
|
64
|
+
example: 'e.g. apify-test-tools get-affected-actors --since <sha> | apify-test-tools notify-release',
|
|
65
|
+
});
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { ActorConfig, Commit } from './types.js';
|
|
2
2
|
interface AffectedActorsOptions {
|
|
3
|
-
/**
|
|
4
|
-
head: string;
|
|
5
|
-
/** Only the commits on head that are not on base count, i.e. the branch's own changes. */
|
|
3
|
+
/** Only the commits on HEAD that are not on base count, i.e. the branch's own changes. */
|
|
6
4
|
base?: string;
|
|
7
5
|
/**
|
|
8
6
|
* Only changes after this commit count. With `base` it's the last validated commit of the branch and is
|
|
9
|
-
* ignored when it isn't on the branch. Without `base` it must be an ancestor of
|
|
7
|
+
* ignored when it isn't on the branch. Without `base` it must be an ancestor of HEAD (e.g. the last release).
|
|
10
8
|
*/
|
|
11
9
|
since?: string;
|
|
12
10
|
/** Glob relative to the repo root. Matching files count as changes even when .dockerignore lists them. */
|
|
@@ -16,8 +14,6 @@ interface AffectedActorsOptions {
|
|
|
16
14
|
}
|
|
17
15
|
interface AffectedActors {
|
|
18
16
|
headSha: string;
|
|
19
|
-
/** Branch head points to, which is what git builds are made from. Null for a SHA or a detached HEAD. */
|
|
20
|
-
ref: string | null;
|
|
21
17
|
commits: Commit[];
|
|
22
18
|
changedFiles: string[];
|
|
23
19
|
changelog: string | null;
|
|
@@ -30,11 +26,10 @@ interface AffectedActors {
|
|
|
30
26
|
* Finds the Actors whose context changed in the given range. `base` selects the branch's own commits
|
|
31
27
|
* (a PR), `since` the commits after a known one (a release, or the last validated commit of a PR).
|
|
32
28
|
*/
|
|
33
|
-
export declare const getAffectedActors: ({
|
|
29
|
+
export declare const getAffectedActors: ({ base, since: sinceOption, testFilesGlob, actors, ignore, }: AffectedActorsOptions) => Promise<AffectedActors>;
|
|
34
30
|
/** The JSON document `get-affected-actors` prints. Versioned, since other commands and workflows consume it. */
|
|
35
|
-
export declare const toAffectedActorsDocument: ({ headSha,
|
|
31
|
+
export declare const toAffectedActorsDocument: ({ headSha, commits, changedFiles, changelog, functionallyChangedActors, cosmeticallyChangedActors, }: AffectedActors) => {
|
|
36
32
|
version: number;
|
|
37
|
-
ref: string | null;
|
|
38
33
|
head: string;
|
|
39
34
|
commits: Commit[];
|
|
40
35
|
changedFiles: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"affected-actors.d.ts","sourceRoot":"","sources":["../../bin/affected-actors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"affected-actors.d.ts","sourceRoot":"","sources":["../../bin/affected-actors.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAMtD,UAAU,qBAAqB;IAC3B,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0GAA0G;IAC1G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,cAAc;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mFAAmF;IACnF,yBAAyB,EAAE,WAAW,EAAE,CAAC;IACzC,uHAAuH;IACvH,yBAAyB,EAAE,WAAW,EAAE,CAAC;CAC5C;AA2DD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAU,8DAMrC,qBAAqB,KAAG,OAAO,CAAC,cAAc,CAyBhD,CAAC;AAEF,gHAAgH;AAChH,eAAO,MAAM,wBAAwB,GAAI,sGAOtC,cAAc;;;;;;;;;;;;CAWhB,CAAC"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { getChangedActors } from './diff-changes.js';
|
|
2
|
-
import { getBranchOnlyChangedFiles, getChangedFilesBetween, getChangelogAdditions, getCommits, getCommitsBetween, hasMergeFromTarget,
|
|
2
|
+
import { getBranchOnlyChangedFiles, getChangedFilesBetween, getChangelogAdditions, getCommits, getCommitsBetween, hasMergeFromTarget, resolveCommitSha, resolveReleaseBaseCommit, } from './git.js';
|
|
3
3
|
import { logger } from './logger.js';
|
|
4
4
|
import { readConfigFile } from './utils/config/load-config.js';
|
|
5
|
+
// The range always ends at the checked-out commit: check out what you want to inspect
|
|
6
|
+
const HEAD = 'HEAD';
|
|
5
7
|
/** The branch's own commits, after `since` when it is on the branch (see getCommits). */
|
|
6
|
-
const getBranchRange = async (
|
|
7
|
-
const commits = await getCommits({ sourceBranch:
|
|
8
|
+
const getBranchRange = async (base, since) => {
|
|
9
|
+
const commits = await getCommits({ sourceBranch: HEAD, targetBranch: base, baseCommit: since });
|
|
8
10
|
return { commits, fromRef: `${commits[0].sha}~`, toRef: commits[commits.length - 1].sha };
|
|
9
11
|
};
|
|
10
|
-
/** Everything after `since` up to
|
|
11
|
-
const getRangeSince = async (
|
|
12
|
-
const sinceSha = await resolveReleaseBaseCommit(since
|
|
12
|
+
/** Everything after `since` up to HEAD. Unlike on a branch, `since` must be an ancestor of HEAD. */
|
|
13
|
+
const getRangeSince = async (headSha, since) => {
|
|
14
|
+
const sinceSha = await resolveReleaseBaseCommit(since);
|
|
13
15
|
const commits = sinceSha === headSha ? [] : await getCommitsBetween(sinceSha, headSha);
|
|
14
16
|
return { commits, fromRef: sinceSha, toRef: headSha };
|
|
15
17
|
};
|
|
@@ -26,15 +28,15 @@ const getRangeSince = async (head, headSha, since) => {
|
|
|
26
28
|
* and can be skipped even when the branch changes other Actors functionally. Today any functional change of the
|
|
27
29
|
* branch's own keeps every Actor, and the log messages below describe the whole branch.
|
|
28
30
|
*/
|
|
29
|
-
const getOwnChangesIfMergedFromBase = async (
|
|
30
|
-
if (!(await hasMergeFromTarget(
|
|
31
|
+
const getOwnChangesIfMergedFromBase = async (base, actorConfigs, testFilesGlob) => {
|
|
32
|
+
if (!(await hasMergeFromTarget(HEAD, base)))
|
|
31
33
|
return undefined;
|
|
32
34
|
logger.info('[MERGE-FROM-TARGET-OPTIMIZATION]: There is merge from target branch, checking if there are no functional changes in our own branch. If so, we can skip tests');
|
|
33
35
|
const own = await getChangedActors({
|
|
34
|
-
filepathsChanged: await getBranchOnlyChangedFiles(
|
|
36
|
+
filepathsChanged: await getBranchOnlyChangedFiles(HEAD, base),
|
|
35
37
|
actorConfigs,
|
|
36
38
|
// Omit since to get full branch history. Validated functional commits can still interact with merged ones
|
|
37
|
-
commits: await getCommits({ sourceBranch:
|
|
39
|
+
commits: await getCommits({ sourceBranch: HEAD, targetBranch: base }),
|
|
38
40
|
testFilesGlob,
|
|
39
41
|
});
|
|
40
42
|
logger.info(own.functional.length > 0
|
|
@@ -46,25 +48,22 @@ const getOwnChangesIfMergedFromBase = async (head, base, actorConfigs, testFiles
|
|
|
46
48
|
* Finds the Actors whose context changed in the given range. `base` selects the branch's own commits
|
|
47
49
|
* (a PR), `since` the commits after a known one (a release, or the last validated commit of a PR).
|
|
48
50
|
*/
|
|
49
|
-
export const getAffectedActors = async ({
|
|
51
|
+
export const getAffectedActors = async ({ base, since: sinceOption, testFilesGlob, actors, ignore, }) => {
|
|
50
52
|
// An empty --since (e.g. an empty cache file) means the same as not passing it
|
|
51
53
|
const since = sinceOption || undefined;
|
|
52
54
|
if (!base && !since) {
|
|
53
55
|
throw new Error('Pass --base, --since, or both to select the commits to inspect.');
|
|
54
56
|
}
|
|
55
|
-
const headSha = await resolveCommitSha(
|
|
56
|
-
const { commits, fromRef, toRef } = base
|
|
57
|
-
? await getBranchRange(head, base, since)
|
|
58
|
-
: await getRangeSince(head, headSha, since);
|
|
57
|
+
const headSha = await resolveCommitSha(HEAD);
|
|
58
|
+
const { commits, fromRef, toRef } = base ? await getBranchRange(base, since) : await getRangeSince(headSha, since);
|
|
59
59
|
const actorConfigs = await readConfigFile({ actors, ignore });
|
|
60
60
|
// What the branch only merged in from base is already validated. Without functional changes of its own
|
|
61
61
|
// the branch has nothing to test, and without any changes of its own nothing to release either.
|
|
62
|
-
const own = base ? await getOwnChangesIfMergedFromBase(
|
|
62
|
+
const own = base ? await getOwnChangesIfMergedFromBase(base, actorConfigs, testFilesGlob) : undefined;
|
|
63
63
|
const changedFiles = await getChangedFilesBetween(fromRef, toRef);
|
|
64
64
|
const changed = await getChangedActors({ filepathsChanged: changedFiles, actorConfigs, commits, testFilesGlob });
|
|
65
65
|
return {
|
|
66
66
|
headSha,
|
|
67
|
-
ref: await resolveBranchName(head),
|
|
68
67
|
commits,
|
|
69
68
|
changedFiles,
|
|
70
69
|
changelog: await getChangelogAdditions(fromRef, toRef, changedFiles),
|
|
@@ -73,11 +72,10 @@ export const getAffectedActors = async ({ head, base, since: sinceOption, testFi
|
|
|
73
72
|
};
|
|
74
73
|
};
|
|
75
74
|
/** The JSON document `get-affected-actors` prints. Versioned, since other commands and workflows consume it. */
|
|
76
|
-
export const toAffectedActorsDocument = ({ headSha,
|
|
75
|
+
export const toAffectedActorsDocument = ({ headSha, commits, changedFiles, changelog, functionallyChangedActors, cosmeticallyChangedActors, }) => {
|
|
77
76
|
const names = (configs) => configs.map(({ actorFullName }) => ({ actorFullName }));
|
|
78
77
|
return {
|
|
79
78
|
version: 1,
|
|
80
|
-
ref,
|
|
81
79
|
head: headSha,
|
|
82
80
|
commits,
|
|
83
81
|
changedFiles,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"affected-actors.js","sourceRoot":"","sources":["../../bin/affected-actors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EACH,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,
|
|
1
|
+
{"version":3,"file":"affected-actors.js","sourceRoot":"","sources":["../../bin/affected-actors.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/build.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type * as ApifyClientTypes from 'apify-client';
|
|
2
2
|
import type { ActorConfig, BuildData, DryRunPlan } from './types.js';
|
|
3
3
|
export declare const LOCAL_SOURCE_VERSION_NUMBER = "0.98";
|
|
4
|
+
export declare const TEST_VERSION_NUMBER = "0.99";
|
|
5
|
+
export declare const DEFAULT_VERSION_KEYWORD = "default";
|
|
4
6
|
/**
|
|
5
7
|
* Finds the Actor's default version: the one whose build the default build tag points to.
|
|
6
8
|
* Usually tagged 'latest' but not necessarily (can be e.g. 'version-0').
|
|
@@ -47,20 +49,25 @@ export declare const runAndSummarizeBuilds: (actorConfigs: ActorConfig[], label:
|
|
|
47
49
|
type GitBuildPlan = {
|
|
48
50
|
actorFullName: string;
|
|
49
51
|
versionNumber: string;
|
|
50
|
-
buildTag?: string;
|
|
51
52
|
gitRepoUrl: string;
|
|
52
|
-
useDockerCache: boolean;
|
|
53
53
|
};
|
|
54
54
|
type RunBuildsOptions = {
|
|
55
55
|
actorConfigs: ActorConfig[];
|
|
56
|
-
|
|
56
|
+
versionNumber: string;
|
|
57
57
|
repoUrl: string;
|
|
58
58
|
shouldVerifyRepoUrl: boolean;
|
|
59
59
|
branch: string;
|
|
60
60
|
dryRun: boolean;
|
|
61
|
-
useDockerCache: boolean;
|
|
62
61
|
};
|
|
63
|
-
export declare const runBuilds: ({ repoUrl, shouldVerifyRepoUrl, branch, actorConfigs,
|
|
62
|
+
export declare const runBuilds: ({ repoUrl, shouldVerifyRepoUrl, branch, actorConfigs, versionNumber, dryRun, }: RunBuildsOptions) => Promise<BuildData[] | DryRunPlan<GitBuildPlan>>;
|
|
63
|
+
type BuildActorsOptions = Omit<RunBuildsOptions, 'repoUrl' | 'shouldVerifyRepoUrl' | 'branch'> & {
|
|
64
|
+
repoUrl?: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Builds exactly the given Actors from the checked-out Git branch, as it is on the remote. Fails on a detached HEAD,
|
|
68
|
+
* where there is no branch to build. Used by `build` and the commands built on top of it.
|
|
69
|
+
*/
|
|
70
|
+
export declare const buildActors: ({ actorConfigs, repoUrl, ...options }: BuildActorsOptions) => Promise<BuildData[] | DryRunPlan<GitBuildPlan>>;
|
|
64
71
|
export declare const deleteOldBuilds: (actorConfigs: ActorConfig[], { dryRun }: {
|
|
65
72
|
dryRun: boolean;
|
|
66
73
|
}) => Promise<void>;
|
package/dist/bin/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../bin/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,gBAAgB,MAAM,cAAc,CAAC;AAKtD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../bin/build.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/build.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ActorSourceType, ApifyClient } from 'apify-client';
|
|
2
|
-
import { normalizeRepoUrl } from './git.js';
|
|
2
|
+
import { getCurrentBranch, normalizeRepoUrl, resolveRepoUrl } from './git.js';
|
|
3
3
|
import { logger } from './logger.js';
|
|
4
4
|
// Fixed version number used to build from local source files, since there is no real version to track.
|
|
5
5
|
export const LOCAL_SOURCE_VERSION_NUMBER = '0.98';
|
|
6
|
-
|
|
6
|
+
// Version that build-for-test builds, so tests never touch the version users run
|
|
7
|
+
export const TEST_VERSION_NUMBER = '0.99';
|
|
8
|
+
// Stands for each Actor's default version: the one its default build tag points to
|
|
9
|
+
export const DEFAULT_VERSION_KEYWORD = 'default';
|
|
7
10
|
// Shown whenever an Actor isn't set up the way CI builds need it
|
|
8
11
|
const ACTOR_SETUP_REQUIREMENT = 'Before using apify-test-tools, every Actor needs at least one build under its default build tag (usually "latest"), ' +
|
|
9
12
|
'built from a Git repository version whose URL points to this repository. Build it once manually on the platform.';
|
|
@@ -222,11 +225,18 @@ export const runAndSummarizeBuilds = async (actorConfigs, label, buildOneActor)
|
|
|
222
225
|
const startedBuilds = await Promise.all(actorConfigs.map(async (actorConfig) => buildOneActor(actorConfig, buildersByActorFullName.get(actorConfig.actorFullName))));
|
|
223
226
|
return waitAndSummarizeBuilds(startedBuilds, buildersByActorFullName, label);
|
|
224
227
|
};
|
|
225
|
-
export const runBuilds = async ({ repoUrl, shouldVerifyRepoUrl, branch, actorConfigs,
|
|
228
|
+
export const runBuilds = async ({ repoUrl, shouldVerifyRepoUrl, branch, actorConfigs, versionNumber, dryRun, }) => {
|
|
226
229
|
// Fetched once per Actor and reused for the checks, the version numbers and the build itself
|
|
227
230
|
const buildConfigs = await Promise.all(actorConfigs.map(async (actorConfig) => {
|
|
228
231
|
const actorInfo = await ApifyBuilder.fromActorConfig(actorConfig).getActorInfo();
|
|
229
232
|
const { defaultVersionNumber, defaultBuildTag, defaultVersion } = resolveDefaultVersion(actorConfig.actorFullName, actorInfo);
|
|
233
|
+
// Builds keep the tags their version gives them, so a default version without the default build tag
|
|
234
|
+
// would build fine but leave users on the previous build
|
|
235
|
+
if (versionNumber === DEFAULT_VERSION_KEYWORD && defaultVersion?.buildTag !== defaultBuildTag) {
|
|
236
|
+
logger.warn(`[${actorConfig.actorFullName}] Default version ${defaultVersionNumber} has build tag ` +
|
|
237
|
+
`"${defaultVersion?.buildTag ?? 'none'}", not "${defaultBuildTag}", so users keep running the previous build. ` +
|
|
238
|
+
'Set the build tag of the version on the platform to change that.');
|
|
239
|
+
}
|
|
230
240
|
if (shouldVerifyRepoUrl) {
|
|
231
241
|
assertRepoUrlMatchesDefaultVersion(actorConfig.actorFullName, defaultVersion, repoUrl);
|
|
232
242
|
}
|
|
@@ -239,38 +249,50 @@ export const runBuilds = async ({ repoUrl, shouldVerifyRepoUrl, branch, actorCon
|
|
|
239
249
|
actorConfig,
|
|
240
250
|
actorInfo,
|
|
241
251
|
gitRepoUrl,
|
|
242
|
-
versionNumber:
|
|
243
|
-
buildTag: isLatest ? defaultBuildTag : undefined,
|
|
244
|
-
useDockerCache,
|
|
252
|
+
versionNumber: versionNumber === DEFAULT_VERSION_KEYWORD ? defaultVersionNumber : versionNumber,
|
|
245
253
|
};
|
|
246
254
|
}));
|
|
247
255
|
// Everything above only reads, so a dry run has checked what the real run would, short of writing
|
|
248
256
|
if (dryRun) {
|
|
249
257
|
logger.info('[DRY RUN] Would build:');
|
|
250
|
-
|
|
251
|
-
|
|
258
|
+
const builds = buildConfigs.map((buildConfig) => ({
|
|
259
|
+
actorFullName: buildConfig.actorConfig.actorFullName,
|
|
260
|
+
versionNumber: buildConfig.versionNumber,
|
|
261
|
+
gitRepoUrl: buildConfig.gitRepoUrl,
|
|
262
|
+
}));
|
|
263
|
+
for (const build of builds) {
|
|
264
|
+
logger.info(` ${build.actorFullName} (${build.versionNumber}) from ${build.gitRepoUrl}`);
|
|
252
265
|
}
|
|
253
|
-
return {
|
|
254
|
-
dryRun: true,
|
|
255
|
-
builds: buildConfigs.map(({ actorConfig, versionNumber, buildTag, gitRepoUrl, useDockerCache: useCache }) => ({
|
|
256
|
-
actorFullName: actorConfig.actorFullName,
|
|
257
|
-
versionNumber,
|
|
258
|
-
buildTag,
|
|
259
|
-
gitRepoUrl,
|
|
260
|
-
useDockerCache: useCache,
|
|
261
|
-
})),
|
|
262
|
-
};
|
|
266
|
+
return { dryRun: true, builds };
|
|
263
267
|
}
|
|
264
268
|
const buildConfigsByActorFullName = new Map(buildConfigs.map((buildConfig) => [buildConfig.actorConfig.actorFullName, buildConfig]));
|
|
265
269
|
return runAndSummarizeBuilds(actorConfigs, 'BUILDS', async (actorConfig, builder) => {
|
|
266
|
-
const
|
|
270
|
+
const buildConfig = buildConfigsByActorFullName.get(actorConfig.actorFullName);
|
|
271
|
+
// No buildTag: the version keeps the one it has, so its build gets the tag the version already gives it
|
|
267
272
|
const actorVersion = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
gitRepoUrl,
|
|
273
|
+
versionNumber: buildConfig.versionNumber,
|
|
274
|
+
gitRepoUrl: buildConfig.gitRepoUrl,
|
|
271
275
|
sourceType: ActorSourceType.GitRepo,
|
|
272
276
|
};
|
|
273
|
-
|
|
277
|
+
// Always with the Docker cache: CI always asked for it, and a clean build can still be started on the platform
|
|
278
|
+
return builder.createVersionAndBuild(buildConfig.versionNumber, actorVersion, true, buildConfig.actorInfo);
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
/**
|
|
282
|
+
* Builds exactly the given Actors from the checked-out Git branch, as it is on the remote. Fails on a detached HEAD,
|
|
283
|
+
* where there is no branch to build. Used by `build` and the commands built on top of it.
|
|
284
|
+
*/
|
|
285
|
+
export const buildActors = async ({ actorConfigs, repoUrl, ...options }) => {
|
|
286
|
+
if (actorConfigs.length === 0) {
|
|
287
|
+
logger.info('No Actors to build');
|
|
288
|
+
// Still the dry-run shape in a dry run, so it can't pass for a real (empty) result
|
|
289
|
+
return options.dryRun ? { dryRun: true, builds: [] } : [];
|
|
290
|
+
}
|
|
291
|
+
return runBuilds({
|
|
292
|
+
...options,
|
|
293
|
+
...(await resolveRepoUrl(repoUrl)),
|
|
294
|
+
actorConfigs,
|
|
295
|
+
branch: await getCurrentBranch(),
|
|
274
296
|
});
|
|
275
297
|
};
|
|
276
298
|
export const deleteOldBuilds = async (actorConfigs, { dryRun }) => {
|