Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ on:
inputs:
version:
description: >-
Release spec. `beta` (the default) publishes the next
`2.0.0-beta.N`; `beta.N` publishes that exact candidate. `rc[.N]`
and `alpha[.N]` select those prerelease channels.
`patch|minor|major` or `x.y.z` publishes a stable release. Anything
else publishes `0.0.0-<name>`.
Release spec, bumped from the version every package.json shares.
`beta` (the default) publishes the next beta, e.g. `2.0.0-beta.81`
to `2.0.0-beta.82`; `beta.N` publishes that candidate. `rc[.N]` and
`alpha[.N]` select those prerelease channels. `patch|minor|major`
bump per semver, and `x.y.z[-beta.N]` publishes exactly that
version. Anything else publishes `0.0.0-<name>` without committing
it.
required: false
type: string
default: "beta"
Expand Down
29 changes: 29 additions & 0 deletions scripts/package-manifest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// `package.json` reading shared by the release scripts.
import * as Data from "effect/Data";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Path from "effect/Path";
Expand Down Expand Up @@ -33,6 +34,9 @@ export const publishablePackages = Effect.fn(function* (root: string, directory:
const entries = (yield* fs.readDirectory(path.join(root, directory))).sort();
const packages = yield* Effect.forEach(entries, (entry) =>
Effect.gen(function* () {
// Skip stray files such as `.DS_Store`.
if ((yield* fs.stat(path.join(root, directory, entry))).type !== "Directory")
return undefined;
const manifestPath = path.join(root, directory, entry, "package.json");
if (!(yield* fs.exists(manifestPath))) return undefined;
const text = yield* fs.readFileString(manifestPath);
Expand All @@ -47,3 +51,28 @@ export const publishablePackages = Effect.fn(function* (root: string, directory:
(pkg): pkg is WorkspacePackage => pkg !== undefined && pkg.manifest.private !== true,
);
});

export class VersionMismatch extends Data.TaggedError("VersionMismatch")<{
readonly message: string;
readonly specs: ReadonlyArray<string>;
}> {}

/** The one version every package carries; they are released in lockstep. */
export const sharedVersion = Effect.fn(function* (packages: ReadonlyArray<WorkspacePackage>) {
const versions = new Set(packages.map(({ manifest }) => manifest.version));
if (versions.size !== 1) {
const specs = packages.map(({ manifest }) => `${manifest.name}@${manifest.version}`);
// Name the packages on each version, except where that is most of them.
const groups = [...versions].map((version) => {
const names = packages
.filter(({ manifest }) => manifest.version === version)
.map(({ manifest }) => manifest.name);
return `${version}: ${names.length > 5 ? `${names.length} packages` : names.join(", ")}`;
});
return yield* new VersionMismatch({
message: `Packages must share one version; found ${groups.join("; ")}`,
specs,
});
}
return [...versions][0]!;
});
Loading
Loading