@tallyrelease/core 0.5.0-beta.34 → 0.5.0-beta.41
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/README.md +15 -1
- package/dist/branches.js +1 -2
- package/dist/changelog.js +1 -2
- package/dist/discover.d.ts +3 -2
- package/dist/facts.js +1 -2
- package/dist/index.d.ts +5 -10
- package/dist/index.js +3 -6
- package/dist/plan.js +2 -2
- package/dist/plugins.d.ts +8 -15
- package/dist/plugins.js +12 -3
- package/dist/released.js +1 -2
- package/dist/schemes.d.ts +7 -11
- package/dist/schemes.js +27 -15
- package/dist/testing/conformance.d.ts +7 -1
- package/dist/testing/conformance.js +91 -0
- package/dist/testing/index.d.ts +0 -4
- package/dist/testing/index.js +0 -15
- package/dist/validate.d.ts +3 -3
- package/dist/validate.js +5 -5
- package/dist/version-files.js +1 -2
- package/dist/workspace.d.ts +13 -6
- package/dist/workspace.js +4 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,9 +24,23 @@ export const example = definePlugin({
|
|
|
24
24
|
|
|
25
25
|
See `Plugin` in [`src/plugin.ts`](https://github.com/abinnovision/tallyrelease/blob/main/packages/core/src/plugin.ts) for the available hooks (`discover`, `edges`, `inputs`, `versionFiles`, `schemes`, `intent`).
|
|
26
26
|
|
|
27
|
+
Core always registers the `semver` scheme and the Conventional Commits intent source. A plugin that reads commit messages can use `parseCommit` for the same parsing.
|
|
28
|
+
|
|
29
|
+
### Tag formats
|
|
30
|
+
|
|
31
|
+
A plugin that sets `tagFormat` on its units can check the format with the same rules core applies. `compileTagFormat(format, unitId)` throws `E_TAG_FORMAT` unless `{version}` occurs exactly once, and returns a `TagFormat` whose `match(tag)` gives the `{version}` part of a matching tag. `renderTag(unit, version)` renders the tag of a version.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { compileTagFormat, renderTag } from "@tallyrelease/core";
|
|
35
|
+
|
|
36
|
+
const format = compileTagFormat("{id}-v{version}", "web");
|
|
37
|
+
format.match("web-v1.2.0"); // "1.2.0"
|
|
38
|
+
renderTag({ id: "web", tagFormat: "{id}-v{version}" }, "1.2.0"); // "web-v1.2.0"
|
|
39
|
+
```
|
|
40
|
+
|
|
27
41
|
## Testing
|
|
28
42
|
|
|
29
|
-
The `@tallyrelease/core/testing` export provides in-memory fakes: `memoryFs`, `memoryCtx` and `memoryGit`. The `@tallyrelease/core/testing/conformance` export provides `gitReaderConformance`,
|
|
43
|
+
The `@tallyrelease/core/testing` export provides in-memory fakes: `memoryFs`, `memoryCtx` and `memoryGit`. The `@tallyrelease/core/testing/conformance` export provides `gitReaderConformance` and `schemeConformance`, shared `GitReader` and `VersionScheme` specs that require vitest.
|
|
30
44
|
|
|
31
45
|
## Licence
|
|
32
46
|
|
package/dist/branches.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { coreCodes } from "./codes.js";
|
|
2
|
-
import { schemeRegistry } from "./schemes.js";
|
|
3
2
|
import { maxLevel } from "./util.js";
|
|
4
3
|
const SPECIAL = /[\\^$.*+?()[\]{}|/]/gu;
|
|
5
4
|
const PART = /\{(major|minor)\}|\*/gu;
|
|
@@ -177,7 +176,7 @@ export const maintenanceCut = (workspace, plan, item) => {
|
|
|
177
176
|
? plan.groups.find((g) => g.name === item.name)
|
|
178
177
|
: plan.units.find((u) => u.id === item.name);
|
|
179
178
|
const unit = workspace.units.find((u) => u.id === item.units[0]);
|
|
180
|
-
const scheme = unit &&
|
|
179
|
+
const scheme = unit && workspace.schemes.get(unit.scheme);
|
|
181
180
|
if (plan.line?.kind !== "default" ||
|
|
182
181
|
!scheme ||
|
|
183
182
|
!base?.from ||
|
package/dist/changelog.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { schemeRegistry } from "./schemes.js";
|
|
2
1
|
import { renderTag } from "./tags.js";
|
|
3
2
|
import { compare } from "./util.js";
|
|
4
3
|
/** Commit types in section order; hidden sections list only breaking or Release-As changes. */
|
|
@@ -238,7 +237,7 @@ export const updateChangelog = (content, section, { baseVersion, scheme, }) => {
|
|
|
238
237
|
*/
|
|
239
238
|
export const releaseNotes = (workspace, id, read) => {
|
|
240
239
|
const unit = workspace.units.find((u) => u.id === id);
|
|
241
|
-
const scheme = unit &&
|
|
240
|
+
const scheme = unit && workspace.schemes.get(unit.scheme);
|
|
242
241
|
const content = unit && read(changelogPath(unit));
|
|
243
242
|
if (!scheme || content === undefined) {
|
|
244
243
|
return undefined;
|
package/dist/discover.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Warning } from "./errors.js";
|
|
2
2
|
import type { Unit } from "./plugin.js";
|
|
3
|
-
import type { ActivePlugin
|
|
3
|
+
import type { ActivePlugin } from "./plugins.js";
|
|
4
|
+
import type { WorkspaceInput } from "./workspace.js";
|
|
4
5
|
/** Drops `.` and empty segments; rejects absolute roots and `..` segments. */
|
|
5
6
|
export declare const normalizeRoot: (root: string) => string;
|
|
6
7
|
/**
|
|
7
8
|
* Runs `discover` hooks in config order, applies config overlays (glob keys
|
|
8
9
|
* first, then exact keys) and fills defaults. Returns units sorted by id.
|
|
9
10
|
*/
|
|
10
|
-
export declare const discoverUnits: (active: readonly ActivePlugin[], env: Pick<
|
|
11
|
+
export declare const discoverUnits: (active: readonly ActivePlugin[], env: Pick<WorkspaceInput, "config" | "fs" | "repo">, warnings?: Warning[]) => Promise<Unit[]>;
|
package/dist/facts.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { attribution, matcher } from "./attribution.js";
|
|
2
2
|
import { coreCodes } from "./codes.js";
|
|
3
3
|
import { pluginCtx, runHook } from "./plugins.js";
|
|
4
|
-
import { schemeRegistry } from "./schemes.js";
|
|
5
4
|
import { matchUnitTags } from "./tags.js";
|
|
6
5
|
import { compare, uniqueSorted } from "./util.js";
|
|
7
6
|
const instant = (commit) => {
|
|
@@ -78,7 +77,7 @@ export const lineFacts = async (git, head) => {
|
|
|
78
77
|
/** Tags of every unit and fixed group, relative to `head`. */
|
|
79
78
|
export const tagFacts = async (workspace, git, line) => {
|
|
80
79
|
const { head } = line;
|
|
81
|
-
const schemes =
|
|
80
|
+
const { schemes } = workspace;
|
|
82
81
|
const allTags = await git.tags();
|
|
83
82
|
const tags = matchUnitTags(workspace.units, allTags, schemes);
|
|
84
83
|
const merged = new Set((await git.tagsMerged(head)).map((t) => t.name));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/** @deprecated Unused, will be removed in 1.0. */
|
|
2
2
|
export declare const version = "0.0.0";
|
|
3
3
|
export type { AffectedDoc, AffectedOptions, AffectedReason, AffectedUnit, BaseSource, } from "./model/affected-types.js";
|
|
4
|
-
export type { ChangelogDependency, ChangelogInput } from "./changelog.js";
|
|
5
4
|
export type { CodeDoc, CodeOf, CodeRegistry, ErrorCode, WarningCode, } from "./codes.js";
|
|
6
5
|
export type { ParsedCommit } from "./conventional.js";
|
|
7
6
|
export type { ExplainedChange, ExplainOptions, ReleaseAsFooter, UnitExplanation, } from "./explain.js";
|
|
@@ -9,34 +8,30 @@ export type { BranchRule, Line as PlanLine } from "./model/branch-types.js";
|
|
|
9
8
|
export type { GroupPlan, Plan, PlanChange, PlanOptions, ReleasedUnit, UnitPlan, } from "./model/plan-types.js";
|
|
10
9
|
export type { DepConfig, GroupConfig, ReleasePrMode, TallyConfig, UnitOverlay, VersionTemplate, } from "./config.js";
|
|
11
10
|
export type { Warning } from "./errors.js";
|
|
12
|
-
export type { Graph
|
|
11
|
+
export type { Graph } from "./graph.js";
|
|
13
12
|
export type { Group } from "./groups.js";
|
|
14
13
|
export type { BumpLevel, Change, Ctx, Edge, EdgeDraft, GitReader, IntentSource, MaybePromise, Plugin, PreCtx, Propagate, RawCommit, ReadonlyFs, ReleaseAsValue, TagRef, Unit, UnitDraft, VersionFile, VersionMode, VersionScheme, VersionSource, WriteCtx, } from "./plugin.js";
|
|
15
14
|
export type { Marker, MarkerRelease } from "./marker.js";
|
|
16
|
-
export type { ActivePlugin, PluginEnv } from "./plugins.js";
|
|
17
15
|
export type { ReleaseItem } from "./release-items.js";
|
|
18
16
|
export type { ReleaseSettings } from "./release-settings.js";
|
|
19
|
-
export type { SchemeEntry } from "./schemes.js";
|
|
20
17
|
export type { SemVer } from "./semver.js";
|
|
18
|
+
export type { TagFormat } from "./tags.js";
|
|
21
19
|
export type { IntentEntry, Workspace, WorkspaceInput } from "./workspace.js";
|
|
22
20
|
export { computeAffected } from "./affected.js";
|
|
23
21
|
export { maintenanceCut } from "./branches.js";
|
|
24
|
-
export {
|
|
22
|
+
export { releaseNotes } from "./changelog.js";
|
|
25
23
|
export { coreCodes, defineCodes } from "./codes.js";
|
|
26
24
|
export { CONFIG_FILE } from "./config.js";
|
|
27
|
-
export {
|
|
28
|
-
export { discoverUnits } from "./discover.js";
|
|
25
|
+
export { parseCommit } from "./conventional.js";
|
|
29
26
|
export { TallyError } from "./errors.js";
|
|
30
27
|
export { explainUnit } from "./explain.js";
|
|
31
|
-
export { renderFloatingTags } from "./floating.js";
|
|
32
|
-
export { buildGraph } from "./graph.js";
|
|
33
28
|
export { definePlugin, defaultUnitId, PLUGIN_API_VERSION } from "./plugin.js";
|
|
34
29
|
export { computePlan } from "./plan.js";
|
|
35
30
|
export { decodeMarker, encodeMarker } from "./marker.js";
|
|
36
|
-
export { activatePlugins } from "./plugins.js";
|
|
37
31
|
export { planEquals, releaseEntries, releaseItems } from "./release-items.js";
|
|
38
32
|
export { releasedFromTags, withReleased } from "./released.js";
|
|
39
33
|
export { semver } from "./semver.js";
|
|
34
|
+
export { compileTagFormat, renderTag } from "./tags.js";
|
|
40
35
|
export { validateRelease, validateTags } from "./validate.js";
|
|
41
36
|
export { releaseFiles, versionFileClaims } from "./version-files.js";
|
|
42
37
|
export { loadWorkspace } from "./workspace.js";
|
package/dist/index.js
CHANGED
|
@@ -2,22 +2,19 @@
|
|
|
2
2
|
export const version = "0.0.0";
|
|
3
3
|
export { computeAffected } from "./affected.js";
|
|
4
4
|
export { maintenanceCut } from "./branches.js";
|
|
5
|
-
export {
|
|
5
|
+
export { releaseNotes } from "./changelog.js";
|
|
6
6
|
export { coreCodes, defineCodes } from "./codes.js";
|
|
7
7
|
export { CONFIG_FILE } from "./config.js";
|
|
8
|
-
export {
|
|
9
|
-
export { discoverUnits } from "./discover.js";
|
|
8
|
+
export { parseCommit } from "./conventional.js";
|
|
10
9
|
export { TallyError } from "./errors.js";
|
|
11
10
|
export { explainUnit } from "./explain.js";
|
|
12
|
-
export { renderFloatingTags } from "./floating.js";
|
|
13
|
-
export { buildGraph } from "./graph.js";
|
|
14
11
|
export { definePlugin, defaultUnitId, PLUGIN_API_VERSION } from "./plugin.js";
|
|
15
12
|
export { computePlan } from "./plan.js";
|
|
16
13
|
export { decodeMarker, encodeMarker } from "./marker.js";
|
|
17
|
-
export { activatePlugins } from "./plugins.js";
|
|
18
14
|
export { planEquals, releaseEntries, releaseItems } from "./release-items.js";
|
|
19
15
|
export { releasedFromTags, withReleased } from "./released.js";
|
|
20
16
|
export { semver } from "./semver.js";
|
|
17
|
+
export { compileTagFormat, renderTag } from "./tags.js";
|
|
21
18
|
export { validateRelease, validateTags } from "./validate.js";
|
|
22
19
|
export { releaseFiles, versionFileClaims } from "./version-files.js";
|
|
23
20
|
export { loadWorkspace } from "./workspace.js";
|
package/dist/plan.js
CHANGED
|
@@ -327,7 +327,7 @@ const resolveReleases = (workspace, input) => {
|
|
|
327
327
|
export const resolvePlan = (workspace, input) => resolveReleases(workspace, input).plan;
|
|
328
328
|
/** `computePlan` keeping the collected facts, for `explainUnit`. */
|
|
329
329
|
export const planWithFacts = async (workspace, git, opts) => {
|
|
330
|
-
|
|
330
|
+
validateRelease(workspace);
|
|
331
331
|
const affected = await computeAffected(workspace, git, opts);
|
|
332
332
|
const facts = await collectPlanFacts(workspace, git, {
|
|
333
333
|
head: opts.head,
|
|
@@ -337,7 +337,7 @@ export const planWithFacts = async (workspace, git, opts) => {
|
|
|
337
337
|
const { plan, releases } = resolveReleases(workspace, {
|
|
338
338
|
affected,
|
|
339
339
|
facts,
|
|
340
|
-
schemes,
|
|
340
|
+
schemes: workspace.schemes,
|
|
341
341
|
all: opts.all ?? false,
|
|
342
342
|
});
|
|
343
343
|
return { plan, facts, releases };
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { TallyConfig } from "./config.js";
|
|
2
1
|
import type { Warning } from "./errors.js";
|
|
3
|
-
import type { Ctx, MaybePromise, Plugin
|
|
2
|
+
import type { Ctx, MaybePromise, Plugin } from "./plugin.js";
|
|
3
|
+
import type { WorkspaceInput } from "./workspace.js";
|
|
4
4
|
/** An enabled plugin with its validated options. */
|
|
5
5
|
export interface ActivePlugin {
|
|
6
6
|
readonly plugin: Plugin;
|
|
@@ -8,19 +8,12 @@ export interface ActivePlugin {
|
|
|
8
8
|
/** False when `plugins.<name>.globalInputs: false`. */
|
|
9
9
|
readonly globalInputs: boolean;
|
|
10
10
|
}
|
|
11
|
-
export interface PluginEnv {
|
|
12
|
-
config: TallyConfig;
|
|
13
|
-
/** Available plugins; `config.plugins` selects and orders them. */
|
|
14
|
-
plugins: readonly Plugin[];
|
|
15
|
-
fs: ReadonlyFs;
|
|
16
|
-
repo: {
|
|
17
|
-
name: string;
|
|
18
|
-
};
|
|
19
|
-
debug?: (message: string) => void;
|
|
20
|
-
}
|
|
21
11
|
/** Frozen `Ctx` factory; warnings are tagged with the plugin name. */
|
|
22
|
-
export declare const pluginCtx: (env: Pick<
|
|
23
|
-
/**
|
|
24
|
-
|
|
12
|
+
export declare const pluginCtx: (env: Pick<WorkspaceInput, "fs" | "repo" | "debug">, warnings: Warning[]) => (name: string, options: unknown) => Ctx;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves core, then enabled plugins in config order, and validates their
|
|
15
|
+
* options.
|
|
16
|
+
*/
|
|
17
|
+
export declare const activatePlugins: (env: WorkspaceInput, warnings: Warning[]) => Promise<ActivePlugin[]>;
|
|
25
18
|
/** Awaits a plugin hook, wrapping thrown errors as `E_PLUGIN_HOOK`. */
|
|
26
19
|
export declare const runHook: <T>(plugin: string, hook: string, call: () => MaybePromise<T>) => Promise<T>;
|
package/dist/plugins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CORE_PLUGIN } from "./builtin.js";
|
|
1
|
+
import { CORE_PLUGIN, corePlugin } from "./builtin.js";
|
|
2
2
|
import { coreCodes } from "./codes.js";
|
|
3
3
|
import { assertPlugin } from "./plugin.js";
|
|
4
4
|
/** Frozen `Ctx` factory; warnings are tagged with the plugin name. */
|
|
@@ -13,9 +13,18 @@ export const pluginCtx = (env, warnings) => (name, options) => Object.freeze({
|
|
|
13
13
|
debug: (message) => env.debug?.(`${name}: ${message}`),
|
|
14
14
|
}),
|
|
15
15
|
});
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Resolves core, then enabled plugins in config order, and validates their
|
|
18
|
+
* options.
|
|
19
|
+
*/
|
|
17
20
|
export const activatePlugins = async (env, warnings) => {
|
|
18
|
-
const active = [
|
|
21
|
+
const active = [
|
|
22
|
+
{
|
|
23
|
+
plugin: corePlugin,
|
|
24
|
+
ctx: pluginCtx(env, warnings)(CORE_PLUGIN, {}),
|
|
25
|
+
globalInputs: true,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
19
28
|
for (const [name, raw] of Object.entries(env.config.plugins)) {
|
|
20
29
|
const plugin = env.plugins.find((p) => p.name === name);
|
|
21
30
|
if (!plugin) {
|
package/dist/released.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { coreCodes } from "./codes.js";
|
|
2
2
|
import { renderFloatingTags } from "./floating.js";
|
|
3
|
-
import { schemeRegistry } from "./schemes.js";
|
|
4
3
|
import { matchUnitTags } from "./tags.js";
|
|
5
4
|
import { compare } from "./util.js";
|
|
6
5
|
const stable = (scheme, version) => {
|
|
@@ -13,7 +12,7 @@ const stable = (scheme, version) => {
|
|
|
13
12
|
* tag name.
|
|
14
13
|
*/
|
|
15
14
|
const releasedEntries = async (workspace, plan, { git, keep, }) => {
|
|
16
|
-
const matched = matchUnitTags(workspace.units, await git.tags(),
|
|
15
|
+
const matched = matchUnitTags(workspace.units, await git.tags(), workspace.schemes);
|
|
17
16
|
const line = plan.line?.kind ?? "default";
|
|
18
17
|
const built = new Set(plan.units.filter((u) => u.affected !== null).map((u) => u.id));
|
|
19
18
|
const candidates = workspace.units.flatMap((unit) => {
|
package/dist/schemes.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import type { Plugin, VersionScheme } from "./plugin.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
export declare const
|
|
9
|
-
readonly plugin: Plugin;
|
|
10
|
-
}[]) => SchemeEntry[];
|
|
11
|
-
/** Name to scheme; throws `E_SCHEME_CLASH` on a duplicate name. */
|
|
12
|
-
export declare const schemeRegistry: (list: readonly SchemeEntry[]) => ReadonlyMap<string, VersionScheme<any>>;
|
|
2
|
+
/**
|
|
3
|
+
* Name to scheme of `plugins`; the first registration of a name wins and a
|
|
4
|
+
* duplicate is recorded for `assertSchemes`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const schemeRegistry: (plugins: readonly Plugin[]) => ReadonlyMap<string, VersionScheme<any>>;
|
|
7
|
+
/** Throws the `E_SCHEME_CLASH` recorded by `schemeRegistry`. */
|
|
8
|
+
export declare const assertSchemes: (registry: ReadonlyMap<string, unknown>) => void;
|
package/dist/schemes.js
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
import { corePlugin } from "./builtin.js";
|
|
2
1
|
import { coreCodes } from "./codes.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/** Name to scheme; throws `E_SCHEME_CLASH` on a duplicate name. */
|
|
10
|
-
export const schemeRegistry = (list) => {
|
|
2
|
+
const clashes = new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
* Name to scheme of `plugins`; the first registration of a name wins and a
|
|
5
|
+
* duplicate is recorded for `assertSchemes`.
|
|
6
|
+
*/
|
|
7
|
+
export const schemeRegistry = (plugins) => {
|
|
11
8
|
const owners = new Map();
|
|
12
9
|
const registry = new Map();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
let clash;
|
|
11
|
+
for (const plugin of plugins) {
|
|
12
|
+
for (const [name, scheme] of Object.entries(plugin.schemes ?? {})) {
|
|
13
|
+
const owner = owners.get(name);
|
|
14
|
+
if (owner !== undefined) {
|
|
15
|
+
clash ??= { scheme: name, plugins: [owner, plugin.name] };
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
owners.set(name, plugin.name);
|
|
19
|
+
registry.set(name, scheme);
|
|
17
20
|
}
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
}
|
|
22
|
+
if (clash) {
|
|
23
|
+
clashes.set(registry, clash);
|
|
20
24
|
}
|
|
21
25
|
return registry;
|
|
22
26
|
};
|
|
27
|
+
/** Throws the `E_SCHEME_CLASH` recorded by `schemeRegistry`. */
|
|
28
|
+
export const assertSchemes = (registry) => {
|
|
29
|
+
const clash = clashes.get(registry);
|
|
30
|
+
if (clash) {
|
|
31
|
+
const [first, second] = clash.plugins;
|
|
32
|
+
throw coreCodes.error("E_SCHEME_CLASH", `scheme "${clash.scheme}" is registered by "${first}" and "${second}"`, { scheme: clash.scheme, plugins: [first, second] });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Dag } from "./index.js";
|
|
2
|
-
import type { GitReader, MaybePromise } from "../plugin.js";
|
|
2
|
+
import type { GitReader, MaybePromise, VersionScheme } from "../plugin.js";
|
|
3
3
|
/** Builds a reader for `dag`; `sha` maps a commit id to the reader's sha. */
|
|
4
4
|
export type ReaderFactory = (dag: Dag) => MaybePromise<{
|
|
5
5
|
git: GitReader;
|
|
@@ -13,3 +13,9 @@ export type ReaderFactory = (dag: Dag) => MaybePromise<{
|
|
|
13
13
|
* `introduced` runs on its own fixture.
|
|
14
14
|
*/
|
|
15
15
|
export declare const gitReaderConformance: (makeReader: ReaderFactory) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Shared `VersionScheme` spec. Versions are derived from `initial()`:
|
|
18
|
+
* `parse`/`format` round-trip, `compare` order, `bump` monotonicity per level,
|
|
19
|
+
* and `release`/`prerelease` keeping the core triple.
|
|
20
|
+
*/
|
|
21
|
+
export declare const schemeConformance: <V>(scheme: VersionScheme<V>) => void;
|
|
@@ -202,3 +202,94 @@ export const gitReaderConformance = (makeReader) => {
|
|
|
202
202
|
});
|
|
203
203
|
});
|
|
204
204
|
};
|
|
205
|
+
const LEVELS = ["major", "minor", "patch"];
|
|
206
|
+
const PRE_CTX = {
|
|
207
|
+
unit: {
|
|
208
|
+
id: "u",
|
|
209
|
+
root: ".",
|
|
210
|
+
plugin: "conformance",
|
|
211
|
+
include: [],
|
|
212
|
+
exclude: [],
|
|
213
|
+
version: "tag",
|
|
214
|
+
scheme: "conformance",
|
|
215
|
+
tagFormat: "v{version}",
|
|
216
|
+
propagate: "auto",
|
|
217
|
+
tags: [],
|
|
218
|
+
initialVersion: null,
|
|
219
|
+
meta: {},
|
|
220
|
+
},
|
|
221
|
+
head: "0".repeat(40),
|
|
222
|
+
baseTag: null,
|
|
223
|
+
tags: [],
|
|
224
|
+
firstParent: { sinceLineBase: 3, total: 7 },
|
|
225
|
+
channel: "rc",
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Shared `VersionScheme` spec. Versions are derived from `initial()`:
|
|
229
|
+
* `parse`/`format` round-trip, `compare` order, `bump` monotonicity per level,
|
|
230
|
+
* and `release`/`prerelease` keeping the core triple.
|
|
231
|
+
*/
|
|
232
|
+
export const schemeConformance = (scheme) => {
|
|
233
|
+
describe("VersionScheme conformance", () => {
|
|
234
|
+
const initial = scheme.initial();
|
|
235
|
+
const bumped = (level) => scheme.bump(initial, level);
|
|
236
|
+
it("round-trips parse and format", () => {
|
|
237
|
+
for (const v of [initial, ...LEVELS.map(bumped)]) {
|
|
238
|
+
const raw = scheme.format(v);
|
|
239
|
+
const parsed = scheme.parse(raw);
|
|
240
|
+
expect(parsed).toBeDefined();
|
|
241
|
+
expect(scheme.format(parsed)).toBe(raw);
|
|
242
|
+
expect(scheme.compare(parsed, v)).toBe(0);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
it("rejects input that is not a version", () => {
|
|
246
|
+
expect(scheme.parse("")).toBeUndefined();
|
|
247
|
+
expect(scheme.parse("not a version")).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
it("compares consistently", () => {
|
|
250
|
+
const low = initial;
|
|
251
|
+
const high = bumped("patch");
|
|
252
|
+
expect(scheme.compare(low, low)).toBe(0);
|
|
253
|
+
expect(scheme.compare(low, high)).toBeLessThan(0);
|
|
254
|
+
expect(scheme.compare(high, low)).toBeGreaterThan(0);
|
|
255
|
+
});
|
|
256
|
+
it.each(LEVELS)("bumps %s above the previous version", (level) => {
|
|
257
|
+
const next = bumped(level);
|
|
258
|
+
expect(scheme.compare(next, initial)).toBeGreaterThan(0);
|
|
259
|
+
expect(scheme.isPrerelease(next)).toBe(false);
|
|
260
|
+
});
|
|
261
|
+
it("orders bump levels major > minor > patch", () => {
|
|
262
|
+
const [major, minor, patch] = LEVELS.map(bumped);
|
|
263
|
+
expect(scheme.compare(major, minor)).toBeGreaterThan(0);
|
|
264
|
+
expect(scheme.compare(minor, patch)).toBeGreaterThan(0);
|
|
265
|
+
});
|
|
266
|
+
it("resets lower core parts on a bump", () => {
|
|
267
|
+
const { major, minor, patch } = scheme.core(initial);
|
|
268
|
+
expect(scheme.core(bumped("major"))).toEqual({
|
|
269
|
+
major: major + 1,
|
|
270
|
+
minor: 0,
|
|
271
|
+
patch: 0,
|
|
272
|
+
});
|
|
273
|
+
expect(scheme.core(bumped("minor"))).toEqual({
|
|
274
|
+
major,
|
|
275
|
+
minor: minor + 1,
|
|
276
|
+
patch: 0,
|
|
277
|
+
});
|
|
278
|
+
expect(scheme.core(bumped("patch"))).toEqual({
|
|
279
|
+
major,
|
|
280
|
+
minor,
|
|
281
|
+
patch: patch + 1,
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
it("keeps the core when releasing or prereleasing", () => {
|
|
285
|
+
const next = bumped("minor");
|
|
286
|
+
const release = scheme.release(next, PRE_CTX);
|
|
287
|
+
const pre = scheme.prerelease(next, PRE_CTX);
|
|
288
|
+
expect(scheme.core(release)).toEqual(scheme.core(next));
|
|
289
|
+
expect(scheme.core(pre)).toEqual(scheme.core(next));
|
|
290
|
+
expect(scheme.isPrerelease(release)).toBe(false);
|
|
291
|
+
expect(scheme.compare(pre, release)).toBeLessThanOrEqual(0);
|
|
292
|
+
expect(scheme.parse(scheme.format(pre))).toBeDefined();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
};
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Ctx, GitReader, ReadonlyFs } from "../plugin.js";
|
|
2
|
-
import type { ReaderFactory } from "./conformance.js";
|
|
3
2
|
/** In-memory `ReadonlyFs` over a path-to-content map. */
|
|
4
3
|
export declare const memoryFs: (files: Record<string, string>) => ReadonlyFs;
|
|
5
4
|
export interface MemoryCtxOptions<O> {
|
|
@@ -43,6 +42,3 @@ export interface MemoryGit extends GitReader {
|
|
|
43
42
|
}
|
|
44
43
|
/** In-memory `GitReader` over a commit graph. */
|
|
45
44
|
export declare const memoryGit: (dag: Dag) => MemoryGit;
|
|
46
|
-
export type { ReaderFactory } from "./conformance.js";
|
|
47
|
-
/** Re-export of `@tallyrelease/core/testing/conformance`; requires vitest. */
|
|
48
|
-
export declare const gitReaderConformance: (makeReader: ReaderFactory) => void;
|
package/dist/testing/index.js
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import picomatch from "picomatch/posix.js";
|
|
2
2
|
import { compare, uniqueSorted } from "../util.js";
|
|
3
|
-
// Loaded optionally so the fakes work without vitest installed.
|
|
4
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
5
|
-
const conformance = await import("./conformance.js").catch((error) => {
|
|
6
|
-
if (error.code === "ERR_MODULE_NOT_FOUND") {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
throw error;
|
|
10
|
-
});
|
|
11
3
|
const SKIPPED = new Set([".git", "node_modules"]);
|
|
12
4
|
const changed = (a, b) => uniqueSorted([...a.keys(), ...b.keys()]).filter((p) => a.get(p) !== b.get(p));
|
|
13
5
|
/** In-memory `ReadonlyFs` over a path-to-content map. */
|
|
@@ -149,10 +141,3 @@ export const memoryGit = (dag) => {
|
|
|
149
141
|
parents: (ref) => [...node(ref).parents],
|
|
150
142
|
};
|
|
151
143
|
};
|
|
152
|
-
/** Re-export of `@tallyrelease/core/testing/conformance`; requires vitest. */
|
|
153
|
-
export const gitReaderConformance = (makeReader) => {
|
|
154
|
-
if (conformance === null) {
|
|
155
|
-
throw new Error("gitReaderConformance requires vitest");
|
|
156
|
-
}
|
|
157
|
-
conformance.gitReaderConformance(makeReader);
|
|
158
|
-
};
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Warning } from "./errors.js";
|
|
2
|
-
import type { TagRef
|
|
2
|
+
import type { TagRef } from "./plugin.js";
|
|
3
3
|
import type { Workspace } from "./workspace.js";
|
|
4
4
|
/**
|
|
5
5
|
* Release-only checks, never run by `affected`: scheme registry, schemes, tag
|
|
6
6
|
* formats and initial versions of released units, group members, branch rules,
|
|
7
7
|
* their absolute check targets and channels, release items, floating tag
|
|
8
|
-
* formats and version file templates.
|
|
8
|
+
* formats and version file templates.
|
|
9
9
|
*/
|
|
10
|
-
export declare const validateRelease: (workspace: Workspace) =>
|
|
10
|
+
export declare const validateRelease: (workspace: Workspace) => void;
|
|
11
11
|
/**
|
|
12
12
|
* Checks `tags` against the released units: throws `E_TAG_FORMAT_OVERLAP`,
|
|
13
13
|
* returns `W_NO_MATCHING_TAG` warnings.
|
package/dist/validate.js
CHANGED
|
@@ -2,7 +2,7 @@ import { validateBranches } from "./branches.js";
|
|
|
2
2
|
import { coreCodes } from "./codes.js";
|
|
3
3
|
import { validateFloating } from "./floating.js";
|
|
4
4
|
import { validateReleaseItems } from "./release-items.js";
|
|
5
|
-
import {
|
|
5
|
+
import { assertSchemes } from "./schemes.js";
|
|
6
6
|
import { compileTagFormat, matchUnitTags, noMatchingTag } from "./tags.js";
|
|
7
7
|
import { uniqueSorted } from "./util.js";
|
|
8
8
|
import { validateTemplates } from "./version-files.js";
|
|
@@ -10,10 +10,11 @@ import { validateTemplates } from "./version-files.js";
|
|
|
10
10
|
* Release-only checks, never run by `affected`: scheme registry, schemes, tag
|
|
11
11
|
* formats and initial versions of released units, group members, branch rules,
|
|
12
12
|
* their absolute check targets and channels, release items, floating tag
|
|
13
|
-
* formats and version file templates.
|
|
13
|
+
* formats and version file templates.
|
|
14
14
|
*/
|
|
15
15
|
export const validateRelease = (workspace) => {
|
|
16
|
-
const schemes =
|
|
16
|
+
const { schemes } = workspace;
|
|
17
|
+
assertSchemes(schemes);
|
|
17
18
|
for (const unit of workspace.units) {
|
|
18
19
|
if (unit.version === "none") {
|
|
19
20
|
continue;
|
|
@@ -62,13 +63,12 @@ export const validateRelease = (workspace) => {
|
|
|
62
63
|
validateReleaseItems(workspace);
|
|
63
64
|
validateFloating(workspace.release.floating);
|
|
64
65
|
validateTemplates(workspace);
|
|
65
|
-
return schemes;
|
|
66
66
|
};
|
|
67
67
|
/**
|
|
68
68
|
* Checks `tags` against the released units: throws `E_TAG_FORMAT_OVERLAP`,
|
|
69
69
|
* returns `W_NO_MATCHING_TAG` warnings.
|
|
70
70
|
*/
|
|
71
71
|
export const validateTags = (workspace, tags) => {
|
|
72
|
-
const matched = matchUnitTags(workspace.units, tags,
|
|
72
|
+
const matched = matchUnitTags(workspace.units, tags, workspace.schemes);
|
|
73
73
|
return noMatchingTag(workspace.units, [...matched].map(([id, m]) => ({ id, tags: m.tags })), uniqueSorted(tags.map((t) => t.name)));
|
|
74
74
|
};
|
package/dist/version-files.js
CHANGED
|
@@ -2,7 +2,6 @@ import { changelogPath, changelogSection, updateChangelog, } from "./changelog.j
|
|
|
2
2
|
import { coreCodes } from "./codes.js";
|
|
3
3
|
import { normalizeRoot } from "./discover.js";
|
|
4
4
|
import { runHook } from "./plugins.js";
|
|
5
|
-
import { schemeRegistry } from "./schemes.js";
|
|
6
5
|
const TOKEN = /\{([^{}]*)\}/gu;
|
|
7
6
|
const SPECIAL = /[\\^$.*+?()[\]{}|/]/gu;
|
|
8
7
|
const CORE_TOKENS = ["major", "minor", "patch"];
|
|
@@ -229,7 +228,7 @@ export const versionFileClaims = async (workspace) => {
|
|
|
229
228
|
export const releaseFiles = async (workspace, plan, opts) => {
|
|
230
229
|
const { fs, items, repoUrl, date } = opts;
|
|
231
230
|
const pluginFiles = await versionFileClaims(workspace);
|
|
232
|
-
const schemes =
|
|
231
|
+
const { schemes } = workspace;
|
|
233
232
|
const units = new Map(workspace.units.map((u) => [u.id, u]));
|
|
234
233
|
const planned = new Map(plan.units.map((u) => [u.id, u]));
|
|
235
234
|
const versions = new Map(items.flatMap((i) => i.units.map((id) => [id, i.version])));
|
package/dist/workspace.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
+
import type { TallyConfig } from "./config.js";
|
|
1
2
|
import type { Warning } from "./errors.js";
|
|
2
3
|
import type { Graph } from "./graph.js";
|
|
3
4
|
import type { Group } from "./groups.js";
|
|
4
|
-
import type { IntentSource, Unit, VersionFile } from "./plugin.js";
|
|
5
|
-
import type { PluginEnv } from "./plugins.js";
|
|
5
|
+
import type { IntentSource, Plugin, ReadonlyFs, Unit, VersionFile, VersionScheme } from "./plugin.js";
|
|
6
6
|
import type { ReleaseSettings } from "./release-settings.js";
|
|
7
|
-
import type { SchemeEntry } from "./schemes.js";
|
|
8
7
|
/** An intent source with its plugin's validated options; callers build the `Ctx`. */
|
|
9
8
|
export interface IntentEntry {
|
|
10
9
|
readonly plugin: string;
|
|
11
10
|
readonly options: unknown;
|
|
12
11
|
readonly source: IntentSource;
|
|
13
12
|
}
|
|
14
|
-
export interface WorkspaceInput
|
|
13
|
+
export interface WorkspaceInput {
|
|
14
|
+
config: TallyConfig;
|
|
15
|
+
/** Available plugins; `config.plugins` selects and orders them. */
|
|
16
|
+
plugins: readonly Plugin[];
|
|
17
|
+
fs: ReadonlyFs;
|
|
18
|
+
repo: {
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
debug?: (message: string) => void;
|
|
15
22
|
/** Repo-relative config file path, a global input; defaults to `CONFIG_FILE`. */
|
|
16
23
|
configFile?: string;
|
|
17
24
|
}
|
|
@@ -25,8 +32,8 @@ export interface Workspace {
|
|
|
25
32
|
readonly globalInputs: readonly string[];
|
|
26
33
|
readonly ignore: readonly string[];
|
|
27
34
|
readonly warnings: readonly Warning[];
|
|
28
|
-
/** Registered schemes
|
|
29
|
-
readonly schemes:
|
|
35
|
+
/** Registered schemes by name; `validateRelease` throws on a clash. */
|
|
36
|
+
readonly schemes: ReadonlyMap<string, VersionScheme<any>>;
|
|
30
37
|
/** Core sources first, then enabled plugins in config order. */
|
|
31
38
|
readonly intents: readonly IntentEntry[];
|
|
32
39
|
/** Bumps and branch rules with defaults applied. */
|
package/dist/workspace.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { corePlugin } from "./builtin.js";
|
|
2
1
|
import { CONFIG_FILE } from "./config.js";
|
|
3
2
|
import { discoverUnits } from "./discover.js";
|
|
4
3
|
import { buildGraph } from "./graph.js";
|
|
5
4
|
import { resolveGroups } from "./groups.js";
|
|
6
5
|
import { activatePlugins, runHook } from "./plugins.js";
|
|
7
6
|
import { releaseSettings } from "./release-settings.js";
|
|
8
|
-
import {
|
|
7
|
+
import { schemeRegistry } from "./schemes.js";
|
|
9
8
|
import { uniqueSorted } from "./util.js";
|
|
10
9
|
const collectEdges = async (active, config, units) => {
|
|
11
10
|
const edges = [];
|
|
@@ -74,12 +73,9 @@ export const loadWorkspace = async (input) => {
|
|
|
74
73
|
const graph = buildGraph(units, await collectEdges(active, input.config, units));
|
|
75
74
|
const globalInputs = await collectGlobalInputs(active, input.config, input.configFile ?? CONFIG_FILE);
|
|
76
75
|
const groups = resolveGroups(units, input.config.groups, warnings);
|
|
77
|
-
const intents = [
|
|
78
|
-
{ plugin: corePlugin, options: {} },
|
|
79
|
-
...active.map(({ plugin, ctx }) => ({ plugin, options: ctx.options })),
|
|
80
|
-
].flatMap(({ plugin, options }) => (plugin.intent ?? []).map((source) => ({
|
|
76
|
+
const intents = active.flatMap(({ plugin, ctx }) => (plugin.intent ?? []).map((source) => ({
|
|
81
77
|
plugin: plugin.name,
|
|
82
|
-
options,
|
|
78
|
+
options: ctx.options,
|
|
83
79
|
source,
|
|
84
80
|
})));
|
|
85
81
|
return {
|
|
@@ -89,7 +85,7 @@ export const loadWorkspace = async (input) => {
|
|
|
89
85
|
globalInputs,
|
|
90
86
|
ignore: input.config.ignore ?? [],
|
|
91
87
|
warnings: [...warnings, ...graph.warnings],
|
|
92
|
-
schemes:
|
|
88
|
+
schemes: schemeRegistry(active.map((a) => a.plugin)),
|
|
93
89
|
intents,
|
|
94
90
|
release: releaseSettings(input.config, units),
|
|
95
91
|
groups,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyrelease/core",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.41",
|
|
4
4
|
"description": "Pure planning core of tallyrelease",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"eslint": "^10.13.0",
|
|
67
67
|
"prettier": "^3.9.10",
|
|
68
68
|
"typescript": "^6.0.3",
|
|
69
|
-
"vite": "^8.3.
|
|
69
|
+
"vite": "^8.3.5",
|
|
70
70
|
"vitest": "^5.0.5",
|
|
71
71
|
"yaml": "^2.9.1"
|
|
72
72
|
},
|