@tallyrelease/cli 0.1.0-beta.6 → 0.1.1-beta.1
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/CHANGELOG.md +24 -0
- package/README.md +36 -1
- package/dist/affected-schema.d.ts +2 -0
- package/dist/affected-schema.js +2 -0
- package/dist/affected.schema.json +12 -1
- package/dist/ci/outputs.js +1 -1
- package/dist/commands/affected.d.ts +2 -0
- package/dist/commands/affected.js +22 -6
- package/dist/commands/graph.js +4 -1
- package/dist/config/schema.d.ts +2 -0
- package/dist/config/schema.js +6 -0
- package/dist/main.js +1 -0
- package/dist/tallyrelease.schema.json +8 -0
- package/package.json +6 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-10-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* bootstrap tallyrelease with build selection (v0.1) ([#1](https://github.com/abinnovision/tally-release/issues/1)) ([4efde72](https://github.com/abinnovision/tally-release/commit/4efde72e32091df3c84a2b497272a3a0efdac659))
|
|
9
|
+
* **cli:** align human-readable output and add a local build base ([#8](https://github.com/abinnovision/tally-release/issues/8)) ([96cb5f0](https://github.com/abinnovision/tally-release/commit/96cb5f010f3090806da4317a50c23ba17884c5c5))
|
|
10
|
+
* **cli:** publish the tallyrelease.yaml JSON schema ([#9](https://github.com/abinnovision/tally-release/issues/9)) ([c5b5c94](https://github.com/abinnovision/tally-release/commit/c5b5c946315fdcab2a486cfc2eeef5dd47b6a8f8))
|
|
11
|
+
* **cli:** render the unit graph as mermaid ([#7](https://github.com/abinnovision/tally-release/issues/7)) ([297413a](https://github.com/abinnovision/tally-release/commit/297413a06534b803c5e98e3ee84cb8921bdebdd6))
|
|
12
|
+
* make units build-only unless opted into release ([#6](https://github.com/abinnovision/tally-release/issues/6)) ([4b01768](https://github.com/abinnovision/tally-release/commit/4b0176809d38504eec22e35168f57ca17840ef13))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **cli:** clearer errors and package docs for the 0.1.0 release ([#11](https://github.com/abinnovision/tally-release/issues/11)) ([85fc7ed](https://github.com/abinnovision/tally-release/commit/85fc7ed70693bae01c9b90319d808f72f5eef6f6))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Dependencies
|
|
21
|
+
|
|
22
|
+
* The following workspace dependencies were updated
|
|
23
|
+
* dependencies
|
|
24
|
+
* @tallyrelease/core bumped to 0.1.0
|
package/README.md
CHANGED
|
@@ -27,13 +27,21 @@ units:
|
|
|
27
27
|
|
|
28
28
|
Units are build-only unless opted in with `release: true` (per unit) or `defaults.release: true`.
|
|
29
29
|
|
|
30
|
+
Tags label units so CI can split the build set by kind:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
units:
|
|
34
|
+
apps/web: { tags: [docker] }
|
|
35
|
+
packages/api: { release: true, tags: [npm] }
|
|
36
|
+
```
|
|
37
|
+
|
|
30
38
|
## Commands
|
|
31
39
|
|
|
32
40
|
Global flags: `--cwd <dir>` (repository root), `--config <file>` (default `tallyrelease.yaml`), `--token <token>` (forge token, default `GITHUB_TOKEN`), `--verbose`.
|
|
33
41
|
|
|
34
42
|
- `tallyrelease check` validates config, plugins, units and graph.
|
|
35
43
|
- `tallyrelease graph [--format text|json|mermaid] [--json]` prints units and edges.
|
|
36
|
-
- `tallyrelease affected [--base <ref>] [--format text|json|tsv] [--json] [--out <file>] [--github-output]` computes the build set. `--out` writes the affected document as JSON, `--github-output` appends outputs to `$GITHUB_OUTPUT`.
|
|
44
|
+
- `tallyrelease affected [--base <ref>] [--format text|json|tsv] [--json] [--out <file>] [--github-output] [--tag <tag>]` computes the build set. `--out` writes the affected document as JSON, `--github-output` appends outputs to `$GITHUB_OUTPUT`. `--tag` (repeatable) keeps units with any of the given tags.
|
|
37
45
|
|
|
38
46
|
Exit codes: `0` ok, `1` error, `2` usage. For scripts use `--format tsv` or `--json`; the text layout may change between versions.
|
|
39
47
|
|
|
@@ -57,6 +65,33 @@ steps:
|
|
|
57
65
|
|
|
58
66
|
The job needs `actions: read` for the base lookup.
|
|
59
67
|
|
|
68
|
+
The `affected` output is a JSON array of `{id, path, plugin, reason, released, tags}` and works as a matrix:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
jobs:
|
|
72
|
+
affected:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
outputs:
|
|
75
|
+
docker: ${{ steps.docker.outputs.affected }}
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
with:
|
|
79
|
+
fetch-depth: 0
|
|
80
|
+
- id: docker
|
|
81
|
+
run: npx @tallyrelease/cli affected --tag docker --github-output
|
|
82
|
+
env:
|
|
83
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
84
|
+
image:
|
|
85
|
+
needs: affected
|
|
86
|
+
if: needs.affected.outputs.docker != '[]'
|
|
87
|
+
strategy:
|
|
88
|
+
matrix:
|
|
89
|
+
unit: ${{ fromJSON(needs.affected.outputs.docker) }}
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
steps:
|
|
92
|
+
- run: echo "build ${{ matrix.unit.id }} from ${{ matrix.unit.path }}"
|
|
93
|
+
```
|
|
94
|
+
|
|
60
95
|
## Editor support
|
|
61
96
|
|
|
62
97
|
`tallyrelease.yaml` has a JSON schema for completion and validation in editors using the YAML language server. Add one of these modelines as the first line.
|
|
@@ -31,6 +31,8 @@ export declare const affectedDocSchema: z.ZodObject<{
|
|
|
31
31
|
all: "all";
|
|
32
32
|
}>;
|
|
33
33
|
via: z.ZodArray<z.ZodString>;
|
|
34
|
+
released: z.ZodBoolean;
|
|
35
|
+
tags: z.ZodArray<z.ZodString>;
|
|
34
36
|
}, z.core.$strict>>;
|
|
35
37
|
unattributed: z.ZodArray<z.ZodString>;
|
|
36
38
|
warnings: z.ZodArray<z.ZodObject<{
|
package/dist/affected-schema.js
CHANGED
|
@@ -85,6 +85,15 @@
|
|
|
85
85
|
"items": {
|
|
86
86
|
"type": "string"
|
|
87
87
|
}
|
|
88
|
+
},
|
|
89
|
+
"released": {
|
|
90
|
+
"type": "boolean"
|
|
91
|
+
},
|
|
92
|
+
"tags": {
|
|
93
|
+
"type": "array",
|
|
94
|
+
"items": {
|
|
95
|
+
"type": "string"
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
},
|
|
90
99
|
"required": [
|
|
@@ -92,7 +101,9 @@
|
|
|
92
101
|
"path",
|
|
93
102
|
"plugin",
|
|
94
103
|
"reason",
|
|
95
|
-
"via"
|
|
104
|
+
"via",
|
|
105
|
+
"released",
|
|
106
|
+
"tags"
|
|
96
107
|
],
|
|
97
108
|
"additionalProperties": false
|
|
98
109
|
}
|
package/dist/ci/outputs.js
CHANGED
|
@@ -5,7 +5,7 @@ const multiline = (key, value) => {
|
|
|
5
5
|
};
|
|
6
6
|
/** `$GITHUB_OUTPUT` entries of `affected`; units are ordered by id. */
|
|
7
7
|
export const affectedGithubOutput = (doc) => [
|
|
8
|
-
`affected=${JSON.stringify(doc.units.map(({ id, path, reason }) => ({ id, path, reason })))}\n`,
|
|
8
|
+
`affected=${JSON.stringify(doc.units.map(({ id, path, plugin, reason, released, tags }) => ({ id, path, plugin, reason, released, tags })))}\n`,
|
|
9
9
|
multiline("affected-paths", doc.units.map((u) => u.path).join("\n")),
|
|
10
10
|
`all=${String(doc.build.all)}\n`,
|
|
11
11
|
`base=${doc.build.base ?? ""}\n`,
|
|
@@ -5,6 +5,8 @@ export interface AffectedFlags {
|
|
|
5
5
|
json?: boolean;
|
|
6
6
|
out?: string;
|
|
7
7
|
githubOutput?: boolean;
|
|
8
|
+
/** Keeps units with at least one of these tags. */
|
|
9
|
+
tag?: string[];
|
|
8
10
|
}
|
|
9
11
|
/** Computes the build set and writes the requested outputs. */
|
|
10
12
|
export declare const affected: (session: Session, flags: AffectedFlags) => Promise<void>;
|
|
@@ -32,8 +32,15 @@ const baseLabel = (base) => {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
const tsv = (doc) => [
|
|
35
|
-
"id\tpath\treason\tvia",
|
|
36
|
-
...doc.units.map((u) => [
|
|
35
|
+
"id\tpath\treason\tvia\treleased\ttags",
|
|
36
|
+
...doc.units.map((u) => [
|
|
37
|
+
u.id,
|
|
38
|
+
u.path,
|
|
39
|
+
u.reason,
|
|
40
|
+
u.via.join(","),
|
|
41
|
+
String(u.released),
|
|
42
|
+
u.tags.join(","),
|
|
43
|
+
].join("\t")),
|
|
37
44
|
]
|
|
38
45
|
.map((line) => `${line}\n`)
|
|
39
46
|
.join("");
|
|
@@ -60,9 +67,19 @@ export const affected = async (session, flags) => {
|
|
|
60
67
|
base: base.base,
|
|
61
68
|
baseSource: base.source,
|
|
62
69
|
});
|
|
70
|
+
const tags = new Set(flags.tag ?? []);
|
|
71
|
+
const known = new Set(workspace.units.flatMap((u) => u.tags));
|
|
72
|
+
const unknownTags = [...tags]
|
|
73
|
+
.filter((t) => !known.has(t))
|
|
74
|
+
.map((t) => ({
|
|
75
|
+
code: "W_TAG_UNKNOWN",
|
|
76
|
+
message: `no unit has tag "${t}"`,
|
|
77
|
+
}));
|
|
78
|
+
const selected = (u) => tags.size === 0 || u.tags.some((t) => tags.has(t));
|
|
63
79
|
const doc = {
|
|
64
80
|
...computed,
|
|
65
|
-
|
|
81
|
+
units: computed.units.filter(selected),
|
|
82
|
+
warnings: [...computed.warnings, ...base.warnings, ...unknownTags],
|
|
66
83
|
};
|
|
67
84
|
session.warn(doc.warnings);
|
|
68
85
|
const json = `${JSON.stringify(doc, null, 2)}\n`;
|
|
@@ -86,12 +103,11 @@ export const affected = async (session, flags) => {
|
|
|
86
103
|
return;
|
|
87
104
|
}
|
|
88
105
|
const paint = painter(session.stdout);
|
|
89
|
-
const released = new Set(workspace.units.filter((u) => u.version !== "none").map((u) => u.id));
|
|
90
106
|
const rows = alignColumns(doc.units.map((u) => [
|
|
91
107
|
u.id,
|
|
92
108
|
u.path,
|
|
93
109
|
u.via.length > 0 ? `via ${u.via.join(", ")}` : "",
|
|
94
|
-
|
|
110
|
+
u.released ? "released" : "",
|
|
95
111
|
]), { indent: 2, styles: [undefined, "dim", "dim", "cyan"] }, paint);
|
|
96
112
|
const sha = doc.build.base?.slice(0, 7) ?? "none";
|
|
97
113
|
const lines = [
|
|
@@ -115,7 +131,7 @@ export const affected = async (session, flags) => {
|
|
|
115
131
|
? `, ${count(doc.unattributed.length, "file")} outside any unit`
|
|
116
132
|
: "";
|
|
117
133
|
lines.push(doc.units.length > 0
|
|
118
|
-
? `${String(doc.units.length)} of ${count(workspace.units.length, "unit")} affected${outside}`
|
|
134
|
+
? `${String(doc.units.length)} of ${count(workspace.units.filter(selected).length, "unit")} affected${outside}`
|
|
119
135
|
: `no units affected${outside}`);
|
|
120
136
|
session.stdout.write(`${lines.join("\n")}\n`);
|
|
121
137
|
};
|
package/dist/commands/graph.js
CHANGED
|
@@ -12,6 +12,7 @@ export const graph = async (session, flags) => {
|
|
|
12
12
|
path: u.root,
|
|
13
13
|
plugin: u.plugin,
|
|
14
14
|
version: u.version,
|
|
15
|
+
tags: [...u.tags],
|
|
15
16
|
}));
|
|
16
17
|
const edges = workspace.graph.edges.map((e) => ({
|
|
17
18
|
from: e.from,
|
|
@@ -33,13 +34,15 @@ export const graph = async (session, flags) => {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
const paint = painter(session.stdout);
|
|
37
|
+
const tagged = units.some((u) => u.tags.length > 0);
|
|
36
38
|
const table = [
|
|
37
|
-
["UNIT", "PATH", "PLUGIN", "RELEASE"],
|
|
39
|
+
["UNIT", "PATH", "PLUGIN", "RELEASE", ...(tagged ? ["TAGS"] : [])],
|
|
38
40
|
...units.map((u) => [
|
|
39
41
|
u.id,
|
|
40
42
|
u.path,
|
|
41
43
|
u.plugin,
|
|
42
44
|
u.version === "none" ? "-" : u.version,
|
|
45
|
+
...(tagged ? [u.tags.join(",")] : []),
|
|
43
46
|
]),
|
|
44
47
|
];
|
|
45
48
|
// Header is aligned unstyled so column styles do not apply to it.
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
28
28
|
patch: "patch";
|
|
29
29
|
rebuild: "rebuild";
|
|
30
30
|
}>>;
|
|
31
|
+
tags: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
31
32
|
}, z.core.$strict>>>;
|
|
32
33
|
deps: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
|
|
33
34
|
from: z.ZodString;
|
|
@@ -70,6 +71,7 @@ export declare const configJsonSchema: () => {
|
|
|
70
71
|
patch: "patch";
|
|
71
72
|
rebuild: "rebuild";
|
|
72
73
|
}>>;
|
|
74
|
+
tags: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
73
75
|
}, z.core.$strict>>>;
|
|
74
76
|
deps: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
|
|
75
77
|
from: z.ZodString;
|
package/dist/config/schema.js
CHANGED
|
@@ -41,6 +41,12 @@ const unitOverlay = z.strictObject({
|
|
|
41
41
|
.exactOptional(),
|
|
42
42
|
tagFormat: tagFormat.exactOptional(),
|
|
43
43
|
propagate: propagate.exactOptional(),
|
|
44
|
+
tags: z
|
|
45
|
+
.array(z.string().regex(/^[A-Za-z0-9._-]+$/))
|
|
46
|
+
.meta({
|
|
47
|
+
description: "Labels for filtering with affected --tag (letters, digits, dot, underscore, dash), for example docker or npm.",
|
|
48
|
+
})
|
|
49
|
+
.exactOptional(),
|
|
44
50
|
});
|
|
45
51
|
/** Schema of `tallyrelease.yaml`. */
|
|
46
52
|
export const configSchema = z.strictObject({
|
package/dist/main.js
CHANGED
|
@@ -55,6 +55,7 @@ export const main = async (argv, deps) => {
|
|
|
55
55
|
]))
|
|
56
56
|
.option("--out <file>", "write the affected document to a file")
|
|
57
57
|
.option("--github-output", "append outputs to $GITHUB_OUTPUT")
|
|
58
|
+
.option("--tag <tag>", "keep units with this tag (repeatable)", (tag, prior) => [...(prior ?? []), tag])
|
|
58
59
|
.action(async (flags, cmd) => {
|
|
59
60
|
if (flags.json && flags.format !== undefined) {
|
|
60
61
|
cmd.error("--json and --format cannot be combined", { exitCode: 2 });
|
|
@@ -106,6 +106,14 @@
|
|
|
106
106
|
"rebuild"
|
|
107
107
|
],
|
|
108
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
|
+
"tags": {
|
|
111
|
+
"type": "array",
|
|
112
|
+
"items": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"pattern": "^[A-Za-z0-9._-]+$"
|
|
115
|
+
},
|
|
116
|
+
"description": "Labels for filtering with affected --tag (letters, digits, dot, underscore, dash), for example docker or npm."
|
|
109
117
|
}
|
|
110
118
|
},
|
|
111
119
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyrelease/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1-beta.1",
|
|
4
4
|
"description": "Command line interface of tallyrelease",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"prettier": "@abinnovision/prettier-config",
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@octokit/rest": "^22.0.1",
|
|
51
|
-
"@tallyrelease/core": "^0.1.
|
|
51
|
+
"@tallyrelease/core": "^0.1.1-beta.1",
|
|
52
52
|
"commander": "^15.0.0",
|
|
53
53
|
"tinyglobby": "^0.2.17",
|
|
54
54
|
"yaml": "^2.9.1",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"@abinnovision/eslint-config-base": "^3.4.2",
|
|
59
59
|
"@abinnovision/prettier-config": "^2.2.0",
|
|
60
60
|
"@internal/tsconfig": "0.0.0",
|
|
61
|
-
"@types/node": "^24.
|
|
62
|
-
"@vitest/coverage-v8": "^5.0.
|
|
61
|
+
"@types/node": "^24.19.2",
|
|
62
|
+
"@vitest/coverage-v8": "^5.0.4",
|
|
63
63
|
"ajv": "^8.20.0",
|
|
64
64
|
"eslint": "^10.12.0",
|
|
65
|
-
"prettier": "^3.9.
|
|
65
|
+
"prettier": "^3.9.10",
|
|
66
66
|
"typescript": "^6.0.3",
|
|
67
67
|
"vite": "^8.3.4",
|
|
68
|
-
"vitest": "^5.0.
|
|
68
|
+
"vitest": "^5.0.4"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": ">=24"
|