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
|
import { exec } from "child_process";
import path from "path";
import { getTurboRoot } from "@turbo/utils";
import { getComparison } from "./getComparison";
import { getTask } from "./getTask";
import { getWorkspace } from "./getWorkspace";
import { info, warn, error } from "./logger";
import { shouldWarn } from "./errors";
import { TurboIgnoreArgs } from "./types";
import { checkCommit } from "./checkCommit";
function ignoreBuild() {
console.log("⏭ Ignoring the change");
return process.exit(0);
}
function continueBuild() {
console.log("✓ Proceeding with deployment");
return process.exit(1);
}
export default function turboIgnore({ args }: { args: TurboIgnoreArgs }) {
info(
`Using Turborepo to determine if this project is affected by the commit...\n`
);
// set default directory
args.directory = args.directory
? path.resolve(args.directory)
: process.cwd();
// check for TURBO_FORCE and bail early if it's set
if (process.env.TURBO_FORCE === "true") {
info("`TURBO_FORCE` detected");
return continueBuild();
}
// find the monorepo root
const root = getTurboRoot(args.directory);
if (!root) {
error("Monorepo root not found. turbo-ignore inferencing failed");
return continueBuild();
}
// Find the workspace from the command-line args, or the package.json at the current directory
const workspace = getWorkspace(args);
if (!workspace) {
return continueBuild();
}
// Identify which task to execute from the command-line args
let task = getTask(args);
// check the commit message
const parsedCommit = checkCommit({ workspace });
if (parsedCommit.result === "skip") {
info(parsedCommit.reason);
return ignoreBuild();
}
if (parsedCommit.result === "deploy") {
info(parsedCommit.reason);
return continueBuild();
}
if (parsedCommit.result === "conflict") {
info(parsedCommit.reason);
}
// Get the start of the comparison (previous deployment when available, or previous commit by default)
const comparison = getComparison({ workspace, fallback: args.fallback });
if (!comparison) {
// This is either the first deploy of the project, or the first deploy for the branch, either way - build it.
return continueBuild();
}
// Build, and execute the command
const command = `npx turbo run ${task} --filter=${workspace}...[${comparison.ref}] --dry=json`;
info(`Analyzing results of \`${command}\``);
exec(
command,
{
cwd: root,
},
(err, stdout) => {
if (err) {
const { level, code, message } = shouldWarn({ err: err.message });
if (level === "warn") {
warn(message);
} else {
error(`${code}: ${err}`);
}
return continueBuild();
}
try {
const parsed = JSON.parse(stdout);
if (parsed == null) {
error(`Failed to parse JSON output from \`${command}\`.`);
return continueBuild();
}
const { packages } = parsed;
if (packages && packages.length > 0) {
if (packages.length === 1) {
info(`This commit affects "${workspace}"`);
} else {
// subtract 1 because the first package is the workspace itself
info(
`This commit affects "${workspace}" and ${packages.length - 1} ${
packages.length - 1 === 1 ? "dependency" : "dependencies"
} (${packages.slice(1).join(", ")})`
);
}
return continueBuild();
} else {
info(`This project and its dependencies are not affected`);
return ignoreBuild();
}
} catch (e) {
error(`Failed to parse JSON output from \`${command}\`.`);
error(e);
return continueBuild();
}
}
);
}
|