@tallyrelease/cli 0.1.0-beta.3 → 0.1.0-beta.5
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/dist/affected-schema.d.ts +1 -0
- package/dist/affected-schema.js +1 -0
- package/dist/affected.schema.json +1 -0
- package/dist/ci/base.d.ts +5 -2
- package/dist/ci/base.js +41 -2
- package/dist/commands/affected.d.ts +1 -0
- package/dist/commands/affected.js +72 -5
- package/dist/commands/check.js +2 -1
- package/dist/commands/graph.js +34 -4
- package/dist/config/load.js +2 -1
- package/dist/config/schema.d.ts +103 -0
- package/dist/config/schema.js +78 -16
- package/dist/git/reader.d.ts +2 -0
- package/dist/git/reader.js +4 -0
- package/dist/main.js +14 -4
- package/dist/output/columns.d.ts +10 -0
- package/dist/output/columns.js +32 -0
- package/dist/output/count.d.ts +2 -0
- package/dist/output/count.js +2 -0
- package/dist/output/paint.d.ts +6 -0
- package/dist/output/paint.js +10 -0
- package/dist/output/tree.d.ts +12 -0
- package/dist/output/tree.js +45 -0
- package/dist/session.js +3 -1
- package/dist/tallyrelease.schema.json +163 -0
- package/package.json +7 -4
package/dist/affected-schema.js
CHANGED
package/dist/ci/base.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import type { GithubContext } from "./github-env.js";
|
|
1
|
+
import type { Env, GithubContext } from "./github-env.js";
|
|
2
2
|
import type { Forge } from "../forge/forge.js";
|
|
3
3
|
import type { RepoGit } from "../git/reader.js";
|
|
4
4
|
import type { BaseSource, Warning } from "@tallyrelease/core";
|
|
5
5
|
export interface BuildBase {
|
|
6
6
|
base: string | null;
|
|
7
7
|
source: BaseSource;
|
|
8
|
+
/** The `--base` value, or the branch of a local merge base. */
|
|
9
|
+
ref?: string;
|
|
8
10
|
warnings: Warning[];
|
|
9
11
|
}
|
|
10
12
|
export interface BuildBaseInput {
|
|
11
13
|
git: RepoGit;
|
|
14
|
+
env: Env;
|
|
12
15
|
/** Resolved HEAD sha. */
|
|
13
16
|
head: string;
|
|
14
17
|
/** `--base`. */
|
|
@@ -17,5 +20,5 @@ export interface BuildBaseInput {
|
|
|
17
20
|
/** Present only when a token is available. */
|
|
18
21
|
forge?: Forge | undefined;
|
|
19
22
|
}
|
|
20
|
-
/** Resolves the build base from `--base`, the CI event, then the
|
|
23
|
+
/** Resolves the build base from `--base`, the CI event, the forge, then the local default branch. */
|
|
21
24
|
export declare const resolveBuildBase: (input: BuildBaseInput) => Promise<BuildBase>;
|
package/dist/ci/base.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { TallyError } from "@tallyrelease/core";
|
|
2
2
|
const ZERO_SHA = /^0+$/;
|
|
3
|
+
const CI_VARS = [
|
|
4
|
+
"JENKINS_URL",
|
|
5
|
+
"TF_BUILD",
|
|
6
|
+
"CODEBUILD_BUILD_ID",
|
|
7
|
+
"BUILDKITE",
|
|
8
|
+
"GITLAB_CI",
|
|
9
|
+
"TEAMCITY_VERSION",
|
|
10
|
+
"BITBUCKET_BUILD_NUMBER",
|
|
11
|
+
];
|
|
12
|
+
const DEFAULT_REFS = ["origin/main", "origin/master", "main", "master"];
|
|
13
|
+
const isCi = (env) => {
|
|
14
|
+
const ci = env["CI"];
|
|
15
|
+
return ((ci !== undefined && !["", "false", "0"].includes(ci)) ||
|
|
16
|
+
CI_VARS.some((name) => env[name] !== undefined));
|
|
17
|
+
};
|
|
3
18
|
const str = (value) => typeof value === "string" && value !== "" ? value : undefined;
|
|
4
19
|
const field = (value, key) => typeof value === "object" && value !== null
|
|
5
20
|
? value[key]
|
|
@@ -24,7 +39,7 @@ const noLastSuccess = {
|
|
|
24
39
|
code: "W_NO_LAST_SUCCESS",
|
|
25
40
|
message: "no successful push run of this workflow on this branch",
|
|
26
41
|
};
|
|
27
|
-
/** Resolves the build base from `--base`, the CI event, then the
|
|
42
|
+
/** Resolves the build base from `--base`, the CI event, the forge, then the local default branch. */
|
|
28
43
|
export const resolveBuildBase = async (input) => {
|
|
29
44
|
const { git, head, github, forge } = input;
|
|
30
45
|
// A named sha missing from a shallow clone must not silently become "everything".
|
|
@@ -84,8 +99,32 @@ export const resolveBuildBase = async (input) => {
|
|
|
84
99
|
? result(last, "forge-last-success")
|
|
85
100
|
: result(null, "none", last);
|
|
86
101
|
};
|
|
102
|
+
/** First of `origin/HEAD` and the common default branch names that resolves. */
|
|
103
|
+
const defaultRef = async () => {
|
|
104
|
+
const candidates = [await git.defaultBranch(), ...DEFAULT_REFS];
|
|
105
|
+
for (const candidate of candidates) {
|
|
106
|
+
if (candidate === undefined) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// eslint-disable-next-line no-await-in-loop -- first match wins
|
|
110
|
+
if ((await git.resolve(candidate)) !== undefined) {
|
|
111
|
+
return candidate;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
};
|
|
87
116
|
if (input.cliBase !== undefined) {
|
|
88
|
-
return
|
|
117
|
+
return {
|
|
118
|
+
...result(await required(input.cliBase, "--base"), "cli"),
|
|
119
|
+
ref: input.cliBase,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (github === undefined && !isCi(input.env)) {
|
|
123
|
+
const ref = await defaultRef();
|
|
124
|
+
const base = ref === undefined ? undefined : await git.mergeBase(head, ref);
|
|
125
|
+
return ref === undefined || base === undefined
|
|
126
|
+
? result(null, "none")
|
|
127
|
+
: { ...result(base, "local-merge-base"), ref };
|
|
89
128
|
}
|
|
90
129
|
switch (github?.eventName) {
|
|
91
130
|
case "pull_request": {
|
|
@@ -3,7 +3,40 @@ import { appendFileSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { resolveBuildBase } from "../ci/base.js";
|
|
5
5
|
import { affectedGithubOutput } from "../ci/outputs.js";
|
|
6
|
+
import { alignColumns } from "../output/columns.js";
|
|
7
|
+
import { count } from "../output/count.js";
|
|
8
|
+
import { painter } from "../output/paint.js";
|
|
6
9
|
import { version } from "../version.js";
|
|
10
|
+
const GROUPS = [
|
|
11
|
+
"all",
|
|
12
|
+
"global",
|
|
13
|
+
"direct",
|
|
14
|
+
"dependent",
|
|
15
|
+
];
|
|
16
|
+
const baseLabel = (base) => {
|
|
17
|
+
switch (base.source) {
|
|
18
|
+
case "cli":
|
|
19
|
+
return `--base ${base.ref ?? ""}`;
|
|
20
|
+
case "push-before":
|
|
21
|
+
return "push before";
|
|
22
|
+
case "pr-merge-base":
|
|
23
|
+
return "merge base with the PR target";
|
|
24
|
+
case "merge-group":
|
|
25
|
+
return "merge group base";
|
|
26
|
+
case "forge-last-success":
|
|
27
|
+
return "last successful run";
|
|
28
|
+
case "local-merge-base":
|
|
29
|
+
return `merge base with ${base.ref ?? ""}`;
|
|
30
|
+
case "none":
|
|
31
|
+
return "everything is affected";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const tsv = (doc) => [
|
|
35
|
+
"id\tpath\treason\tvia",
|
|
36
|
+
...doc.units.map((u) => [u.id, u.path, u.reason, u.via.join(",")].join("\t")),
|
|
37
|
+
]
|
|
38
|
+
.map((line) => `${line}\n`)
|
|
39
|
+
.join("");
|
|
7
40
|
/** Computes the build set and writes the requested outputs. */
|
|
8
41
|
export const affected = async (session, flags) => {
|
|
9
42
|
const { git, github } = session;
|
|
@@ -15,6 +48,7 @@ export const affected = async (session, flags) => {
|
|
|
15
48
|
const base = await resolveBuildBase({
|
|
16
49
|
git,
|
|
17
50
|
head,
|
|
51
|
+
env: session.env,
|
|
18
52
|
cliBase: flags.base,
|
|
19
53
|
github,
|
|
20
54
|
forge: session.forge,
|
|
@@ -42,13 +76,46 @@ export const affected = async (session, flags) => {
|
|
|
42
76
|
}
|
|
43
77
|
appendFileSync(path, affectedGithubOutput(doc));
|
|
44
78
|
}
|
|
45
|
-
|
|
79
|
+
const format = flags.format ?? (flags.json ? "json" : "text");
|
|
80
|
+
if (format === "json") {
|
|
46
81
|
session.stdout.write(json);
|
|
47
82
|
return;
|
|
48
83
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
if (format === "tsv") {
|
|
85
|
+
session.stdout.write(tsv(doc));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const paint = painter(session.stdout);
|
|
89
|
+
const released = new Set(workspace.units.filter((u) => u.version !== "none").map((u) => u.id));
|
|
90
|
+
const rows = alignColumns(doc.units.map((u) => [
|
|
91
|
+
u.id,
|
|
92
|
+
u.path,
|
|
93
|
+
u.via.length > 0 ? `via ${u.via.join(", ")}` : "",
|
|
94
|
+
released.has(u.id) ? "released" : "",
|
|
95
|
+
]), { indent: 2, styles: [undefined, "dim", "dim", "cyan"] }, paint);
|
|
96
|
+
const sha = doc.build.base?.slice(0, 7) ?? "none";
|
|
97
|
+
const lines = [
|
|
98
|
+
`${paint("bold", "base")} ${paint("yellow", sha)} ${paint("dim", `(${baseLabel(base)})`)}`,
|
|
99
|
+
"",
|
|
100
|
+
];
|
|
101
|
+
for (const group of GROUPS) {
|
|
102
|
+
const members = rows.filter((_, i) => doc.units[i]?.reason === group);
|
|
103
|
+
if (members.length > 0) {
|
|
104
|
+
lines.push(paint("bold", `${group} (${String(members.length)})`));
|
|
105
|
+
if (group === "global") {
|
|
106
|
+
lines.push(` changed: ${doc.build.globalInputs.join(", ")}`);
|
|
107
|
+
}
|
|
108
|
+
lines.push(...members);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (doc.units.length > 0) {
|
|
112
|
+
lines.push("");
|
|
53
113
|
}
|
|
114
|
+
const outside = doc.unattributed.length > 0
|
|
115
|
+
? `, ${count(doc.unattributed.length, "file")} outside any unit`
|
|
116
|
+
: "";
|
|
117
|
+
lines.push(doc.units.length > 0
|
|
118
|
+
? `${String(doc.units.length)} of ${count(workspace.units.length, "unit")} affected${outside}`
|
|
119
|
+
: `no units affected${outside}`);
|
|
120
|
+
session.stdout.write(`${lines.join("\n")}\n`);
|
|
54
121
|
};
|
package/dist/commands/check.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { count } from "../output/count.js";
|
|
1
2
|
/** Validates config, plugins, units and graph. */
|
|
2
3
|
export const check = async (session) => {
|
|
3
4
|
const workspace = await session.workspace();
|
|
@@ -6,5 +7,5 @@ export const check = async (session) => {
|
|
|
6
7
|
.filter((u) => u.version !== "none")
|
|
7
8
|
.map((u) => u.id);
|
|
8
9
|
const list = released.length > 0 ? `: ${released.join(", ")}` : "";
|
|
9
|
-
session.stdout.write(`ok: ${
|
|
10
|
+
session.stdout.write(`ok: ${count(workspace.units.length, "unit")} (${String(released.length)} released${list}), ${count(workspace.graph.edges.length, "edge")}\n`);
|
|
10
11
|
};
|
package/dist/commands/graph.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { alignColumns } from "../output/columns.js";
|
|
2
|
+
import { count } from "../output/count.js";
|
|
3
|
+
import { painter } from "../output/paint.js";
|
|
4
|
+
import { renderTree } from "../output/tree.js";
|
|
1
5
|
import { renderMermaid } from "../render/mermaid.js";
|
|
2
6
|
/** Prints units and edges. */
|
|
3
7
|
export const graph = async (session, flags) => {
|
|
@@ -24,10 +28,36 @@ export const graph = async (session, flags) => {
|
|
|
24
28
|
session.stdout.write(`${JSON.stringify({ repo: workspace.repo, units, edges }, null, 2)}\n`);
|
|
25
29
|
return;
|
|
26
30
|
}
|
|
27
|
-
|
|
28
|
-
session.stdout.write(
|
|
31
|
+
if (units.length === 0) {
|
|
32
|
+
session.stdout.write("no units\n");
|
|
33
|
+
return;
|
|
29
34
|
}
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const paint = painter(session.stdout);
|
|
36
|
+
const table = [
|
|
37
|
+
["UNIT", "PATH", "PLUGIN", "RELEASE"],
|
|
38
|
+
...units.map((u) => [
|
|
39
|
+
u.id,
|
|
40
|
+
u.path,
|
|
41
|
+
u.plugin,
|
|
42
|
+
u.version === "none" ? "-" : u.version,
|
|
43
|
+
]),
|
|
44
|
+
];
|
|
45
|
+
// Header is aligned unstyled so column styles do not apply to it.
|
|
46
|
+
const [header = ""] = alignColumns(table);
|
|
47
|
+
const [, ...rows] = alignColumns(table, { styles: [undefined, "dim"] }, paint);
|
|
48
|
+
const lines = [paint("bold", header), ...rows];
|
|
49
|
+
const tree = renderTree(units.map((u) => u.id), (id) => workspace.graph.dependents.get(id) ?? []);
|
|
50
|
+
if (edges.length > 0) {
|
|
51
|
+
lines.push("", paint("bold", "dependents"), ...tree.lines);
|
|
32
52
|
}
|
|
53
|
+
const released = units.filter((u) => u.version !== "none").length;
|
|
54
|
+
const legend = [
|
|
55
|
+
...(tree.shared ? ["(*) expanded above"] : []),
|
|
56
|
+
...(tree.cycle ? ["(cycle) edge back into the current path"] : []),
|
|
57
|
+
];
|
|
58
|
+
lines.push("", [
|
|
59
|
+
`${count(units.length, "unit")} (${String(released)} released), ${count(edges.length, "edge")}`,
|
|
60
|
+
...legend,
|
|
61
|
+
].join("; "));
|
|
62
|
+
session.stdout.write(`${lines.join("\n")}\n`);
|
|
33
63
|
};
|
package/dist/config/load.js
CHANGED
package/dist/config/schema.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/** Schema of `tallyrelease.yaml`. */
|
|
3
3
|
export declare const configSchema: z.ZodObject<{
|
|
4
|
+
$schema: z.ZodExactOptional<z.ZodString>;
|
|
4
5
|
plugins: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
|
|
5
6
|
defaults: z.ZodExactOptional<z.ZodObject<{
|
|
6
7
|
release: z.ZodExactOptional<z.ZodBoolean>;
|
|
@@ -37,3 +38,105 @@ export declare const configSchema: z.ZodObject<{
|
|
|
37
38
|
ignore: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
38
39
|
globalInputs: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
39
40
|
}, z.core.$strict>;
|
|
41
|
+
/** JSON schema (draft-07) of `tallyrelease.yaml` as published for editors. */
|
|
42
|
+
export declare const configJsonSchema: () => {
|
|
43
|
+
$id: string;
|
|
44
|
+
title: string;
|
|
45
|
+
"~standard": z.core.ZodStandardSchemaWithJSON<z.ZodObject<{
|
|
46
|
+
$schema: z.ZodExactOptional<z.ZodString>;
|
|
47
|
+
plugins: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
|
|
48
|
+
defaults: z.ZodExactOptional<z.ZodObject<{
|
|
49
|
+
release: z.ZodExactOptional<z.ZodBoolean>;
|
|
50
|
+
tagFormat: z.ZodExactOptional<z.ZodString>;
|
|
51
|
+
propagate: z.ZodExactOptional<z.ZodEnum<{
|
|
52
|
+
auto: "auto";
|
|
53
|
+
patch: "patch";
|
|
54
|
+
rebuild: "rebuild";
|
|
55
|
+
}>>;
|
|
56
|
+
}, z.core.$strict>>;
|
|
57
|
+
units: z.ZodExactOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
58
|
+
id: z.ZodExactOptional<z.ZodString>;
|
|
59
|
+
include: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
60
|
+
exclude: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
61
|
+
release: z.ZodExactOptional<z.ZodBoolean>;
|
|
62
|
+
version: z.ZodExactOptional<z.ZodEnum<{
|
|
63
|
+
file: "file";
|
|
64
|
+
tag: "tag";
|
|
65
|
+
}>>;
|
|
66
|
+
scheme: z.ZodExactOptional<z.ZodString>;
|
|
67
|
+
tagFormat: z.ZodExactOptional<z.ZodString>;
|
|
68
|
+
propagate: z.ZodExactOptional<z.ZodEnum<{
|
|
69
|
+
auto: "auto";
|
|
70
|
+
patch: "patch";
|
|
71
|
+
rebuild: "rebuild";
|
|
72
|
+
}>>;
|
|
73
|
+
}, z.core.$strict>>>;
|
|
74
|
+
deps: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
|
|
75
|
+
from: z.ZodString;
|
|
76
|
+
to: z.ZodString;
|
|
77
|
+
pinned: z.ZodExactOptional<z.ZodBoolean>;
|
|
78
|
+
reason: z.ZodExactOptional<z.ZodString>;
|
|
79
|
+
}, z.core.$strict>>>;
|
|
80
|
+
ignore: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
81
|
+
globalInputs: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
82
|
+
}, z.core.$strict>>;
|
|
83
|
+
$schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#" | "http://json-schema.org/draft-04/schema#";
|
|
84
|
+
$anchor?: string;
|
|
85
|
+
$ref?: string;
|
|
86
|
+
$dynamicRef?: string;
|
|
87
|
+
$dynamicAnchor?: string;
|
|
88
|
+
$vocabulary?: Record<string, boolean>;
|
|
89
|
+
$comment?: string;
|
|
90
|
+
$defs?: Record<string, z.core.JSONSchema.JSONSchema>;
|
|
91
|
+
type?: z.core.JSONSchema.SchemaType | z.core.JSONSchema.SchemaType[];
|
|
92
|
+
additionalItems?: z.core.JSONSchema._JSONSchema;
|
|
93
|
+
unevaluatedItems?: z.core.JSONSchema._JSONSchema;
|
|
94
|
+
prefixItems?: z.core.JSONSchema._JSONSchema[];
|
|
95
|
+
items?: z.core.JSONSchema._JSONSchema | z.core.JSONSchema._JSONSchema[];
|
|
96
|
+
contains?: z.core.JSONSchema._JSONSchema;
|
|
97
|
+
additionalProperties?: z.core.JSONSchema._JSONSchema;
|
|
98
|
+
unevaluatedProperties?: z.core.JSONSchema._JSONSchema;
|
|
99
|
+
properties?: Record<string, z.core.JSONSchema._JSONSchema>;
|
|
100
|
+
patternProperties?: Record<string, z.core.JSONSchema._JSONSchema>;
|
|
101
|
+
dependentSchemas?: Record<string, z.core.JSONSchema._JSONSchema>;
|
|
102
|
+
propertyNames?: z.core.JSONSchema._JSONSchema;
|
|
103
|
+
if?: z.core.JSONSchema._JSONSchema;
|
|
104
|
+
then?: z.core.JSONSchema._JSONSchema;
|
|
105
|
+
else?: z.core.JSONSchema._JSONSchema;
|
|
106
|
+
allOf?: z.core.JSONSchema.JSONSchema[];
|
|
107
|
+
anyOf?: z.core.JSONSchema.JSONSchema[];
|
|
108
|
+
oneOf?: z.core.JSONSchema.JSONSchema[];
|
|
109
|
+
not?: z.core.JSONSchema._JSONSchema;
|
|
110
|
+
multipleOf?: number;
|
|
111
|
+
maximum?: number;
|
|
112
|
+
exclusiveMaximum?: number | boolean;
|
|
113
|
+
minimum?: number;
|
|
114
|
+
exclusiveMinimum?: number | boolean;
|
|
115
|
+
maxLength?: number;
|
|
116
|
+
minLength?: number;
|
|
117
|
+
pattern?: string;
|
|
118
|
+
maxItems?: number;
|
|
119
|
+
minItems?: number;
|
|
120
|
+
uniqueItems?: boolean;
|
|
121
|
+
maxContains?: number;
|
|
122
|
+
minContains?: number;
|
|
123
|
+
maxProperties?: number;
|
|
124
|
+
minProperties?: number;
|
|
125
|
+
required?: string[];
|
|
126
|
+
dependentRequired?: Record<string, string[]>;
|
|
127
|
+
enum?: Array<string | number | boolean | null>;
|
|
128
|
+
const?: string | number | boolean | null;
|
|
129
|
+
id?: string;
|
|
130
|
+
description?: string;
|
|
131
|
+
default?: unknown;
|
|
132
|
+
deprecated?: boolean;
|
|
133
|
+
readOnly?: boolean;
|
|
134
|
+
writeOnly?: boolean;
|
|
135
|
+
nullable?: boolean;
|
|
136
|
+
examples?: unknown[];
|
|
137
|
+
format?: string;
|
|
138
|
+
contentMediaType?: string;
|
|
139
|
+
contentEncoding?: string;
|
|
140
|
+
contentSchema?: z.core.JSONSchema.JSONSchema;
|
|
141
|
+
_prefault?: unknown;
|
|
142
|
+
};
|
package/dist/config/schema.js
CHANGED
|
@@ -1,43 +1,105 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
const globs = z.array(z.string()).exactOptional();
|
|
3
|
-
const propagate = z.enum(["auto", "patch", "rebuild"])
|
|
3
|
+
const propagate = z.enum(["auto", "patch", "rebuild"]).meta({
|
|
4
|
+
description: "Policy for this unit when a dependency is released: patch (at least a patch bump), rebuild (rebuild only) or auto (patch if the edge is pinned, else rebuild).",
|
|
5
|
+
});
|
|
6
|
+
const tagFormat = z.string().meta({
|
|
7
|
+
description: "Tag template. Defaults to {id}-v{version}, or v{version} for the root unit.",
|
|
8
|
+
});
|
|
4
9
|
const unitOverlay = z.strictObject({
|
|
5
|
-
id: z
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
id: z
|
|
11
|
+
.string()
|
|
12
|
+
.meta({
|
|
13
|
+
description: "Unit id (letters, digits, dot, underscore, dash). Defaults to the discovered id, or the repo name for the root unit.",
|
|
14
|
+
})
|
|
15
|
+
.exactOptional(),
|
|
16
|
+
include: globs.meta({
|
|
17
|
+
description: "Globs of files owned by the unit. Replaces the default (the unit root).",
|
|
18
|
+
}),
|
|
19
|
+
exclude: globs.meta({
|
|
20
|
+
description: "Globs excluded from the unit, appended to the default (roots of nested units).",
|
|
21
|
+
}),
|
|
22
|
+
release: z
|
|
23
|
+
.boolean()
|
|
24
|
+
.meta({
|
|
25
|
+
description: "Whether the unit is versioned and tagged. Default false (build-only).",
|
|
26
|
+
})
|
|
27
|
+
.exactOptional(),
|
|
9
28
|
version: z
|
|
10
29
|
.enum(["file", "tag"], {
|
|
11
30
|
error: (issue) => issue.input === "none"
|
|
12
31
|
? 'version "none" is not supported, use release: false'
|
|
13
32
|
: undefined,
|
|
33
|
+
})
|
|
34
|
+
.meta({
|
|
35
|
+
description: "Where a released unit's version lives. file: version file written by the plugin. tag: git tags only. Defaults to the plugin's version source.",
|
|
14
36
|
})
|
|
15
37
|
.exactOptional(),
|
|
16
|
-
scheme: z
|
|
17
|
-
|
|
38
|
+
scheme: z
|
|
39
|
+
.string()
|
|
40
|
+
.meta({ description: "Versioning scheme. Defaults to semver." })
|
|
41
|
+
.exactOptional(),
|
|
42
|
+
tagFormat: tagFormat.exactOptional(),
|
|
18
43
|
propagate: propagate.exactOptional(),
|
|
19
44
|
});
|
|
20
45
|
/** Schema of `tallyrelease.yaml`. */
|
|
21
46
|
export const configSchema = z.strictObject({
|
|
47
|
+
$schema: z
|
|
48
|
+
.string()
|
|
49
|
+
.meta({ description: "Schema reference for editors, ignored." })
|
|
50
|
+
.exactOptional(),
|
|
22
51
|
plugins: z
|
|
23
52
|
.record(z.string(), z.record(z.string(), z.unknown()).nullable())
|
|
53
|
+
.meta({
|
|
54
|
+
description: "Enabled plugins and their options, run in the listed order. Only listed plugins run.",
|
|
55
|
+
})
|
|
24
56
|
.default({}),
|
|
25
57
|
defaults: z
|
|
26
58
|
.strictObject({
|
|
27
|
-
release: z
|
|
28
|
-
|
|
59
|
+
release: z
|
|
60
|
+
.boolean()
|
|
61
|
+
.meta({
|
|
62
|
+
description: "Release all units unless a unit sets release: false. Default false.",
|
|
63
|
+
})
|
|
64
|
+
.exactOptional(),
|
|
65
|
+
tagFormat: tagFormat.exactOptional(),
|
|
29
66
|
propagate: propagate.exactOptional(),
|
|
67
|
+
})
|
|
68
|
+
.meta({ description: "Defaults applied to every unit." })
|
|
69
|
+
.exactOptional(),
|
|
70
|
+
units: z
|
|
71
|
+
.record(z.string(), unitOverlay)
|
|
72
|
+
.meta({
|
|
73
|
+
description: "Unit overlays keyed by root path. A root without a discovered unit becomes a config-only unit.",
|
|
30
74
|
})
|
|
31
75
|
.exactOptional(),
|
|
32
|
-
units: z.record(z.string(), unitOverlay).exactOptional(),
|
|
33
76
|
deps: z
|
|
34
77
|
.array(z.strictObject({
|
|
35
|
-
from: z.string(),
|
|
36
|
-
to: z.string(),
|
|
37
|
-
pinned: z
|
|
38
|
-
|
|
78
|
+
from: z.string().meta({ description: "Id of the dependency." }),
|
|
79
|
+
to: z.string().meta({ description: "Id of the dependent unit." }),
|
|
80
|
+
pinned: z
|
|
81
|
+
.boolean()
|
|
82
|
+
.meta({
|
|
83
|
+
description: "Whether the dependent pins an exact version.",
|
|
84
|
+
})
|
|
85
|
+
.exactOptional(),
|
|
86
|
+
reason: z
|
|
87
|
+
.string()
|
|
88
|
+
.meta({ description: "Why the edge exists." })
|
|
89
|
+
.exactOptional(),
|
|
39
90
|
}))
|
|
91
|
+
.meta({ description: "Extra dependency edges between units." })
|
|
40
92
|
.exactOptional(),
|
|
41
|
-
ignore: globs
|
|
42
|
-
|
|
93
|
+
ignore: globs.meta({
|
|
94
|
+
description: "Globs of files that never affect any unit, for example docs.",
|
|
95
|
+
}),
|
|
96
|
+
globalInputs: globs.meta({
|
|
97
|
+
description: "Globs of files whose change affects all units, unioned with plugin defaults.",
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
/** JSON schema (draft-07) of `tallyrelease.yaml` as published for editors. */
|
|
101
|
+
export const configJsonSchema = () => ({
|
|
102
|
+
...z.toJSONSchema(configSchema, { target: "draft-7", io: "input" }),
|
|
103
|
+
$id: "https://cdn.jsdelivr.net/npm/@tallyrelease/cli@0/dist/tallyrelease.schema.json",
|
|
104
|
+
title: "tallyrelease.yaml",
|
|
43
105
|
});
|
package/dist/git/reader.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface RepoGit extends GitReader {
|
|
|
8
8
|
isShallow: () => MaybePromise<boolean>;
|
|
9
9
|
/** Current branch, undefined when detached. */
|
|
10
10
|
branch: () => MaybePromise<string | undefined>;
|
|
11
|
+
/** Target of `origin/HEAD`, for example `origin/main`; undefined if unset. */
|
|
12
|
+
defaultBranch: () => MaybePromise<string | undefined>;
|
|
11
13
|
}
|
|
12
14
|
/** `RepoGit` backed by the `git` executable in `cwd`. */
|
|
13
15
|
export declare const gitReader: (cwd: string, debug?: (message: string) => void) => RepoGit;
|
package/dist/git/reader.js
CHANGED
|
@@ -110,5 +110,9 @@ export const gitReader = (cwd, debug) => {
|
|
|
110
110
|
const result = await run(cwd, ["symbolic-ref", "--quiet", "--short", "HEAD"], debug);
|
|
111
111
|
return result.code === 0 ? result.stdout.trim() : undefined;
|
|
112
112
|
},
|
|
113
|
+
defaultBranch: async () => {
|
|
114
|
+
const result = await run(cwd, ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"], debug);
|
|
115
|
+
return result.code === 0 ? result.stdout.trim() : undefined;
|
|
116
|
+
},
|
|
113
117
|
};
|
|
114
118
|
};
|
package/dist/main.js
CHANGED
|
@@ -4,6 +4,7 @@ import { inspect } from "node:util";
|
|
|
4
4
|
import { affected } from "./commands/affected.js";
|
|
5
5
|
import { check } from "./commands/check.js";
|
|
6
6
|
import { graph } from "./commands/graph.js";
|
|
7
|
+
import { painter } from "./output/paint.js";
|
|
7
8
|
import { createSession } from "./session.js";
|
|
8
9
|
import { version } from "./version.js";
|
|
9
10
|
/** Runs the cli; returns the exit code (0 ok, 1 error, 2 usage). */
|
|
@@ -46,10 +47,18 @@ export const main = async (argv, deps) => {
|
|
|
46
47
|
.command("affected")
|
|
47
48
|
.description("compute the build set")
|
|
48
49
|
.option("--base <ref>", "diff against this ref")
|
|
49
|
-
.option("--json", "print the affected document")
|
|
50
|
+
.option("--json", "print the affected document (same as --format json)")
|
|
51
|
+
.addOption(new Option("--format <format>", "output format").choices([
|
|
52
|
+
"text",
|
|
53
|
+
"json",
|
|
54
|
+
"tsv",
|
|
55
|
+
]))
|
|
50
56
|
.option("--out <file>", "write the affected document to a file")
|
|
51
57
|
.option("--github-output", "append outputs to $GITHUB_OUTPUT")
|
|
52
|
-
.action(async (flags) => {
|
|
58
|
+
.action(async (flags, cmd) => {
|
|
59
|
+
if (flags.json && flags.format !== undefined) {
|
|
60
|
+
cmd.error("--json and --format cannot be combined", { exitCode: 2 });
|
|
61
|
+
}
|
|
53
62
|
await affected(session(), flags);
|
|
54
63
|
});
|
|
55
64
|
try {
|
|
@@ -60,11 +69,12 @@ export const main = async (argv, deps) => {
|
|
|
60
69
|
if (error instanceof CommanderError) {
|
|
61
70
|
return error.exitCode === 0 ? 0 : 2;
|
|
62
71
|
}
|
|
72
|
+
const paint = painter(deps.stderr);
|
|
63
73
|
if (error instanceof TallyError) {
|
|
64
|
-
deps.stderr.write(`${error.code}: ${error.message}\n`);
|
|
74
|
+
deps.stderr.write(`${paint("red", `error[${error.code}]`)}: ${error.message}\n`);
|
|
65
75
|
}
|
|
66
76
|
else {
|
|
67
|
-
deps.stderr.write(
|
|
77
|
+
deps.stderr.write(`${paint("red", "error[E_INTERNAL]")}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
68
78
|
if (program.opts().verbose) {
|
|
69
79
|
deps.stderr.write(`${inspect(error)}\n`);
|
|
70
80
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Format, Paint } from "./paint.js";
|
|
2
|
+
export interface ColumnOptions {
|
|
3
|
+
indent?: number;
|
|
4
|
+
styles?: readonly (Format | undefined)[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pads cells to aligned columns; widths come from the plain text, styles apply
|
|
8
|
+
* per cell. Columns that are empty in every row are dropped.
|
|
9
|
+
*/
|
|
10
|
+
export declare const alignColumns: (rows: readonly (readonly string[])[], opts?: ColumnOptions, paint?: Paint) => string[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pads cells to aligned columns; widths come from the plain text, styles apply
|
|
3
|
+
* per cell. Columns that are empty in every row are dropped.
|
|
4
|
+
*/
|
|
5
|
+
export const alignColumns = (rows, opts = {}, paint = (_format, text) => text) => {
|
|
6
|
+
const widths = [];
|
|
7
|
+
for (const row of rows) {
|
|
8
|
+
row.forEach((cell, i) => {
|
|
9
|
+
widths[i] = Math.max(widths[i] ?? 0, cell.length);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const indent = " ".repeat(opts.indent ?? 0);
|
|
13
|
+
return rows.map((row) => {
|
|
14
|
+
const cells = [...row];
|
|
15
|
+
while (cells.at(-1) === "") {
|
|
16
|
+
cells.pop();
|
|
17
|
+
}
|
|
18
|
+
return (indent +
|
|
19
|
+
cells
|
|
20
|
+
.map((cell, i) => {
|
|
21
|
+
if (widths[i] === 0) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const style = opts.styles?.[i];
|
|
25
|
+
const text = style && cell !== "" ? paint(style, cell) : cell;
|
|
26
|
+
const pad = i === cells.length - 1 ? 0 : (widths[i] ?? 0) - cell.length;
|
|
27
|
+
return text + " ".repeat(pad);
|
|
28
|
+
})
|
|
29
|
+
.filter((cell) => cell !== undefined)
|
|
30
|
+
.join(" "));
|
|
31
|
+
});
|
|
32
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import type { Writer } from "../session.js";
|
|
3
|
+
export type Format = Parameters<typeof styleText>[0];
|
|
4
|
+
export type Paint = (format: Format, text: string) => string;
|
|
5
|
+
/** Styles text for `stream`; Node decides on color for real streams, other writers stay plain. */
|
|
6
|
+
export declare const painter: (stream: Writer) => Paint;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Stream } from "node:stream";
|
|
2
|
+
import { styleText } from "node:util";
|
|
3
|
+
/** Styles text for `stream`; Node decides on color for real streams, other writers stay plain. */
|
|
4
|
+
export const painter = (stream) => stream instanceof Stream
|
|
5
|
+
? (format, text) =>
|
|
6
|
+
// styleText validates the stream at runtime.
|
|
7
|
+
styleText(format, text, {
|
|
8
|
+
stream: stream,
|
|
9
|
+
})
|
|
10
|
+
: (_format, text) => text;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface Tree {
|
|
2
|
+
lines: string[];
|
|
3
|
+
/** A `(*)` marker was printed. */
|
|
4
|
+
shared: boolean;
|
|
5
|
+
/** A `(cycle)` marker was printed. */
|
|
6
|
+
cycle: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Renders `children` as trees from the units without dependencies, in id order.
|
|
10
|
+
* Units left unvisited (pure cycles) become extra roots, smallest id first.
|
|
11
|
+
*/
|
|
12
|
+
export declare const renderTree: (ids: readonly string[], children: (id: string) => readonly string[]) => Tree;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders `children` as trees from the units without dependencies, in id order.
|
|
3
|
+
* Units left unvisited (pure cycles) become extra roots, smallest id first.
|
|
4
|
+
*/
|
|
5
|
+
export const renderTree = (ids, children) => {
|
|
6
|
+
const tree = { lines: [], shared: false, cycle: false };
|
|
7
|
+
const visited = new Set();
|
|
8
|
+
const path = new Set();
|
|
9
|
+
const visit = (id, branch, prefix) => {
|
|
10
|
+
const kids = children(id);
|
|
11
|
+
if (path.has(id)) {
|
|
12
|
+
tree.lines.push(`${branch}${id} (cycle)`);
|
|
13
|
+
tree.cycle = true;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (visited.has(id) && kids.length > 0) {
|
|
17
|
+
tree.lines.push(`${branch}${id} (*)`);
|
|
18
|
+
tree.shared = true;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
tree.lines.push(`${branch}${id}`);
|
|
22
|
+
visited.add(id);
|
|
23
|
+
path.add(id);
|
|
24
|
+
kids.forEach((kid, i) => {
|
|
25
|
+
const last = i === kids.length - 1;
|
|
26
|
+
visit(kid, `${prefix}${last ? "└── " : "├── "}`, `${prefix}${last ? " " : "│ "}`);
|
|
27
|
+
});
|
|
28
|
+
path.delete(id);
|
|
29
|
+
};
|
|
30
|
+
const inDegree = new Map(ids.map((id) => [id, 0]));
|
|
31
|
+
for (const id of ids) {
|
|
32
|
+
for (const kid of children(id)) {
|
|
33
|
+
inDegree.set(kid, (inDegree.get(kid) ?? 0) + 1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const id of ids) {
|
|
37
|
+
if (inDegree.get(id) === 0) {
|
|
38
|
+
visit(id, "", "");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (let root = ids.find((id) => !visited.has(id)); root !== undefined; root = ids.find((id) => !visited.has(id))) {
|
|
42
|
+
visit(root, "", "");
|
|
43
|
+
}
|
|
44
|
+
return tree;
|
|
45
|
+
};
|
package/dist/session.js
CHANGED
|
@@ -6,6 +6,7 @@ import { githubForge } from "./forge/github.js";
|
|
|
6
6
|
import { nodeFs } from "./fs-ctx.js";
|
|
7
7
|
import { git as runGit } from "./git/exec.js";
|
|
8
8
|
import { gitReader } from "./git/reader.js";
|
|
9
|
+
import { painter } from "./output/paint.js";
|
|
9
10
|
import { builtinPlugins } from "./plugins/index.js";
|
|
10
11
|
export const createSession = (deps, opts) => {
|
|
11
12
|
const root = resolve(deps.cwd, opts.cwd ?? ".");
|
|
@@ -69,8 +70,9 @@ export const createSession = (deps, opts) => {
|
|
|
69
70
|
});
|
|
70
71
|
},
|
|
71
72
|
warn: (warnings) => {
|
|
73
|
+
const paint = painter(deps.stderr);
|
|
72
74
|
for (const w of warnings) {
|
|
73
|
-
deps.stderr.write(`${w.code}: ${w.plugin ? `${w.plugin}: ` : ""}${w.message}\n`);
|
|
75
|
+
deps.stderr.write(`${paint("yellow", `warning[${w.code}]`)}: ${w.plugin ? `${w.plugin}: ` : ""}${w.message}\n`);
|
|
74
76
|
}
|
|
75
77
|
},
|
|
76
78
|
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"$schema": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "Schema reference for editors, ignored."
|
|
8
|
+
},
|
|
9
|
+
"plugins": {
|
|
10
|
+
"default": {},
|
|
11
|
+
"type": "object",
|
|
12
|
+
"propertyNames": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"additionalProperties": {
|
|
16
|
+
"anyOf": [
|
|
17
|
+
{
|
|
18
|
+
"type": "object",
|
|
19
|
+
"propertyNames": {
|
|
20
|
+
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"additionalProperties": {}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "null"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"description": "Enabled plugins and their options, run in the listed order. Only listed plugins run."
|
|
30
|
+
},
|
|
31
|
+
"defaults": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"release": {
|
|
35
|
+
"type": "boolean",
|
|
36
|
+
"description": "Release all units unless a unit sets release: false. Default false."
|
|
37
|
+
},
|
|
38
|
+
"tagFormat": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Tag template. Defaults to {id}-v{version}, or v{version} for the root unit."
|
|
41
|
+
},
|
|
42
|
+
"propagate": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": [
|
|
45
|
+
"auto",
|
|
46
|
+
"patch",
|
|
47
|
+
"rebuild"
|
|
48
|
+
],
|
|
49
|
+
"description": "Policy for this unit when a dependency is released: patch (at least a patch bump), rebuild (rebuild only) or auto (patch if the edge is pinned, else rebuild)."
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"description": "Defaults applied to every unit."
|
|
54
|
+
},
|
|
55
|
+
"units": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"propertyNames": {
|
|
58
|
+
"type": "string"
|
|
59
|
+
},
|
|
60
|
+
"additionalProperties": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"id": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": "Unit id (letters, digits, dot, underscore, dash). Defaults to the discovered id, or the repo name for the root unit."
|
|
66
|
+
},
|
|
67
|
+
"include": {
|
|
68
|
+
"description": "Globs of files owned by the unit. Replaces the default (the unit root).",
|
|
69
|
+
"type": "array",
|
|
70
|
+
"items": {
|
|
71
|
+
"type": "string"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"exclude": {
|
|
75
|
+
"description": "Globs excluded from the unit, appended to the default (roots of nested units).",
|
|
76
|
+
"type": "array",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "string"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"release": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"description": "Whether the unit is versioned and tagged. Default false (build-only)."
|
|
84
|
+
},
|
|
85
|
+
"version": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"enum": [
|
|
88
|
+
"file",
|
|
89
|
+
"tag"
|
|
90
|
+
],
|
|
91
|
+
"description": "Where a released unit's version lives. file: version file written by the plugin. tag: git tags only. Defaults to the plugin's version source."
|
|
92
|
+
},
|
|
93
|
+
"scheme": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "Versioning scheme. Defaults to semver."
|
|
96
|
+
},
|
|
97
|
+
"tagFormat": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Tag template. Defaults to {id}-v{version}, or v{version} for the root unit."
|
|
100
|
+
},
|
|
101
|
+
"propagate": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"enum": [
|
|
104
|
+
"auto",
|
|
105
|
+
"patch",
|
|
106
|
+
"rebuild"
|
|
107
|
+
],
|
|
108
|
+
"description": "Policy for this unit when a dependency is released: patch (at least a patch bump), rebuild (rebuild only) or auto (patch if the edge is pinned, else rebuild)."
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"additionalProperties": false
|
|
112
|
+
},
|
|
113
|
+
"description": "Unit overlays keyed by root path. A root without a discovered unit becomes a config-only unit."
|
|
114
|
+
},
|
|
115
|
+
"deps": {
|
|
116
|
+
"type": "array",
|
|
117
|
+
"items": {
|
|
118
|
+
"type": "object",
|
|
119
|
+
"properties": {
|
|
120
|
+
"from": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"description": "Id of the dependency."
|
|
123
|
+
},
|
|
124
|
+
"to": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"description": "Id of the dependent unit."
|
|
127
|
+
},
|
|
128
|
+
"pinned": {
|
|
129
|
+
"type": "boolean",
|
|
130
|
+
"description": "Whether the dependent pins an exact version."
|
|
131
|
+
},
|
|
132
|
+
"reason": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"description": "Why the edge exists."
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"required": [
|
|
138
|
+
"from",
|
|
139
|
+
"to"
|
|
140
|
+
],
|
|
141
|
+
"additionalProperties": false
|
|
142
|
+
},
|
|
143
|
+
"description": "Extra dependency edges between units."
|
|
144
|
+
},
|
|
145
|
+
"ignore": {
|
|
146
|
+
"description": "Globs of files that never affect any unit, for example docs.",
|
|
147
|
+
"type": "array",
|
|
148
|
+
"items": {
|
|
149
|
+
"type": "string"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"globalInputs": {
|
|
153
|
+
"description": "Globs of files whose change affects all units, unioned with plugin defaults.",
|
|
154
|
+
"type": "array",
|
|
155
|
+
"items": {
|
|
156
|
+
"type": "string"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"additionalProperties": false,
|
|
161
|
+
"$id": "https://cdn.jsdelivr.net/npm/@tallyrelease/cli@0/dist/tallyrelease.schema.json",
|
|
162
|
+
"title": "tallyrelease.yaml"
|
|
163
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyrelease/cli",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.5",
|
|
4
4
|
"description": "Command line interface of tallyrelease",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"import": "./dist/index.js",
|
|
21
21
|
"default": "./dist/index.js"
|
|
22
22
|
},
|
|
23
|
-
"./affected.schema.json": "./dist/affected.schema.json"
|
|
23
|
+
"./affected.schema.json": "./dist/affected.schema.json",
|
|
24
|
+
"./tallyrelease.schema.json": "./dist/tallyrelease.schema.json"
|
|
24
25
|
},
|
|
25
26
|
"bin": {
|
|
26
27
|
"tallyrelease": "./dist/bin.js"
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"prettier": "@abinnovision/prettier-config",
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@octokit/rest": "^22.0.1",
|
|
50
|
-
"@tallyrelease/core": "^0.1.0-beta.
|
|
51
|
+
"@tallyrelease/core": "^0.1.0-beta.3",
|
|
51
52
|
"commander": "^15.0.0",
|
|
52
53
|
"tinyglobby": "^0.2.17",
|
|
53
54
|
"yaml": "^2.9.1",
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
"@internal/tsconfig": "0.0.0",
|
|
60
61
|
"@types/node": "^24.0.0",
|
|
61
62
|
"@vitest/coverage-v8": "^5.0.3",
|
|
63
|
+
"ajv": "^8.20.0",
|
|
62
64
|
"eslint": "^10.12.0",
|
|
63
65
|
"prettier": "^3.9.9",
|
|
64
66
|
"typescript": "^6.0.3",
|
|
@@ -76,7 +78,8 @@
|
|
|
76
78
|
"import": "./dist/index.js",
|
|
77
79
|
"default": "./dist/index.js"
|
|
78
80
|
},
|
|
79
|
-
"./affected.schema.json": "./dist/affected.schema.json"
|
|
81
|
+
"./affected.schema.json": "./dist/affected.schema.json",
|
|
82
|
+
"./tallyrelease.schema.json": "./dist/tallyrelease.schema.json"
|
|
80
83
|
},
|
|
81
84
|
"npm": true
|
|
82
85
|
}
|