@decohere/ci-tools 0.0.1-dev.122 → 0.0.1-dev.123

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decohere/ci-tools",
3
- "version": "0.0.1-dev.122",
3
+ "version": "0.0.1-dev.123",
4
4
  "description": "CI utility scripts for badge generation, coverage reporting, pages artifact assembly, and GitHub API tooling",
5
5
  "keywords": [
6
6
  "typescript",
@@ -10,6 +10,15 @@
10
10
  "github-actions",
11
11
  "decohere"
12
12
  ],
13
+ "homepage": "https://github.com/typesmiths/decohere/tree/main/projects/ci-tools#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/typesmiths/decohere/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/typesmiths/decohere.git",
20
+ "directory": "projects/ci-tools"
21
+ },
13
22
  "license": "ISC",
14
23
  "author": "Typesmiths",
15
24
  "type": "module",
@@ -0,0 +1,69 @@
1
+ import { join, relative } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { vol } from "memfs";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+ import { listPublishablePackages } from "../../src/github/publish-verify.mjs";
6
+
7
+ const fs = await vi.importActual("node:fs");
8
+ const REPO_ROOT = fileURLToPath(new URL("../../../../", import.meta.url));
9
+ const REPO = "https://github.com/typesmiths/decohere";
10
+
11
+ /** The repo's real package.json files, loaded into the in-memory fs the tests run on. */
12
+ function loadRealManifests() {
13
+ /** @type {Record<string, string>} */
14
+ const files = {};
15
+ const walk = (dir) => {
16
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
17
+ const path = join(dir, entry.name);
18
+ if (entry.isDirectory() && !["node_modules", "dist"].includes(entry.name)) {
19
+ walk(path);
20
+ } else if (entry.name === "package.json") {
21
+ files[join("/repo", relative(REPO_ROOT, path))] = fs.readFileSync(path, "utf8");
22
+ }
23
+ }
24
+ };
25
+ walk(join(REPO_ROOT, "projects"));
26
+ return files;
27
+ }
28
+
29
+ afterEach(() => {
30
+ vol.reset();
31
+ });
32
+
33
+ // npm shows these on each package's page, and Trusted Publishing's provenance is
34
+ // checked against `repository.url`, so a package without it fails to publish.
35
+ describe("published package metadata", () => {
36
+ vol.fromJSON(loadRealManifests());
37
+ const packages = listPublishablePackages("/repo").map((pkg) => ({
38
+ ...pkg,
39
+ json: JSON.parse(String(vol.readFileSync(`/repo/projects/${pkg.dir}/package.json`))),
40
+ }));
41
+ vol.reset();
42
+
43
+ it("finds the publishable packages", () => {
44
+ expect(packages.length).toBeGreaterThan(0);
45
+ });
46
+
47
+ it.each(packages.map((pkg) => [pkg.name, pkg]))(
48
+ "%s links back to the repo",
49
+ (_name, pkg) => {
50
+ expect(pkg.json.repository).toEqual({
51
+ type: "git",
52
+ url: `git+${REPO}.git`,
53
+ directory: `projects/${pkg.dir}`,
54
+ });
55
+ expect(pkg.json.homepage).toBe(`${REPO}/tree/main/projects/${pkg.dir}#readme`);
56
+ expect(pkg.json.bugs).toEqual({ url: `${REPO}/issues` });
57
+ },
58
+ );
59
+
60
+ it.each(packages.map((pkg) => [pkg.name, pkg]))(
61
+ "%s has a description, keywords, license and author",
62
+ (_name, pkg) => {
63
+ expect(pkg.json.description).toBeTruthy();
64
+ expect(pkg.json.keywords?.length).toBeGreaterThan(0);
65
+ expect(pkg.json.license).toBe("ISC");
66
+ expect(pkg.json.author).toBeTruthy();
67
+ },
68
+ );
69
+ });