@aidc-toolkit/dev 0.9.17-beta → 0.9.18-beta

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.
@@ -10,44 +10,51 @@
10
10
  "config/publish.json",
11
11
  "config/publish.secure.json"
12
12
  ],
13
- "lastExternalVersion": "0.9.16-beta",
14
- "lastInternalPublished": "2025-03-02T19:42:30.219Z"
13
+ "lastInternalPublished": "2025-06-07T13:56:48.735Z",
14
+ "lastExternalPublished": "2025-03-02T22:50:20.357Z",
15
+ "lastExternalVersion": "0.9.17-beta"
15
16
  },
16
17
  "core": {
17
18
  "dependencyType": "external",
18
- "lastExternalVersion": "0.9.16-beta",
19
- "lastInternalPublished": "2025-03-02T19:46:27.439Z"
19
+ "lastInternalPublished": "2025-06-07T13:57:03.451Z",
20
+ "lastExternalPublished": "2025-03-02T22:50:20.372Z",
21
+ "lastExternalVersion": "0.9.17-beta"
20
22
  },
21
23
  "utility": {
22
24
  "dependencyType": "external",
23
- "lastExternalVersion": "0.9.16-beta",
24
- "lastInternalPublished": "2025-03-02T19:46:37.087Z"
25
+ "lastInternalPublished": "2025-06-07T14:03:30.895Z",
26
+ "lastExternalPublished": "2025-03-02T22:43:30.438Z",
27
+ "lastExternalVersion": "0.9.17-beta"
25
28
  },
26
29
  "gs1": {
27
30
  "dependencyType": "external",
28
- "lastExternalVersion": "0.9.16-beta",
29
- "lastInternalPublished": "2025-03-02T19:46:50.266Z"
31
+ "lastInternalPublished": "2025-06-07T14:03:47.000Z",
32
+ "lastExternalPublished": "2025-03-02T22:52:24.105Z",
33
+ "lastExternalVersion": "0.9.17-beta"
30
34
  },
31
35
  "demo": {
32
36
  "dependencyType": "none",
33
- "lastExternalVersion": "0.9.16-beta"
37
+ "lastExternalPublished": "2025-03-02T22:53:44.418Z",
38
+ "lastExternalVersion": "0.9.17-beta"
34
39
  },
35
40
  "app-extension": {
36
41
  "dependencyType": "internal",
37
- "lastExternalVersion": "0.9.16-beta",
38
- "internal": true,
39
- "lastInternalPublished": "2025-03-02T19:47:50.192Z"
42
+ "lastInternalPublished": "2025-06-07T14:07:34.783Z",
43
+ "lastExternalPublished": "2025-03-02T22:53:47.379Z",
44
+ "lastExternalVersion": "0.9.17-beta"
40
45
  },
41
46
  "app-generator": {
42
47
  "dependencyType": "internal",
43
- "lastExternalVersion": "0.9.16-beta",
44
- "internal": true,
45
- "lastInternalPublished": "2025-03-02T19:47:58.982Z"
48
+ "lastInternalPublished": "2025-04-21T21:55:49.582Z",
49
+ "lastExternalPublished": "2025-03-02T22:53:50.359Z",
50
+ "lastExternalVersion": "0.9.17-beta"
46
51
  },
47
52
  "aidc-toolkit.github.io": {
48
53
  "directory": "doc",
49
54
  "dependencyType": "none",
50
- "lastExternalVersion": "0.9.16-beta"
55
+ "publishExternalAlways": true,
56
+ "lastExternalPublished": "2025-03-03T03:49:32.778Z",
57
+ "lastExternalVersion": "0.9.17-beta"
51
58
  }
52
59
  }
53
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"eslint-config-template.d.ts","sourceRoot":"","sources":["../src/eslint-config-template.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,uBAAuB,qEA0GnC,CAAC"}
1
+ {"version":3,"file":"eslint-config-template.d.ts","sourceRoot":"","sources":["../src/eslint-config-template.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,uBAAuB,qEAkHnC,CAAC"}
@@ -18,8 +18,7 @@ export const esLintConfigAIDCToolkit = tseslint.config({
18
18
  "complexity": "off",
19
19
  "max-depth": ["error", 10],
20
20
  "max-lines": "off",
21
- "no-dupe-class-members": "off",
22
- "no-redeclare": "off",
21
+ // Handled by @typescript-eslint/no-unused-vars.
23
22
  "no-unused-vars": "off",
24
23
  "@typescript-eslint/class-literal-property-style": "off",
25
24
  "@typescript-eslint/class-methods-use-this": "off",
@@ -46,6 +45,10 @@ export const esLintConfigAIDCToolkit = tseslint.config({
46
45
  allowSingleLine: false
47
46
  }],
48
47
  "@stylistic/comma-dangle": ["error", "never"],
48
+ "@stylistic/generator-star-spacing": ["error", {
49
+ before: true,
50
+ after: true
51
+ }],
49
52
  "@stylistic/indent": ["error", 4],
50
53
  "@stylistic/member-delimiter-style": ["error", {
51
54
  multiline: {
@@ -71,6 +74,10 @@ export const esLintConfigAIDCToolkit = tseslint.config({
71
74
  }
72
75
  }],
73
76
  "@stylistic/object-property-newline": "error",
77
+ "@stylistic/yield-star-spacing": ["error", {
78
+ before: true,
79
+ after: true
80
+ }],
74
81
  "jsdoc/require-description": ["warn", {
75
82
  contexts: ["ClassDeclaration", "ClassProperty", "FunctionDeclaration", "MethodDefinition", "TSEnumDeclaration", "TSInterfaceDeclaration", "TSModuleDeclaration", "TSTypeAliasDeclaration"]
76
83
  }],
@@ -1 +1 @@
1
- {"version":3,"file":"eslint-config-template.js","sourceRoot":"","sources":["../src/eslint-config-template.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eslint-config-template.js","sourceRoot":"","sources":["../src/eslint-config-template.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utility.d.ts","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAS/B;;GAEG;AACH,eAAO,MAAM,MAAM,iBAEjB,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA0BxF"}
1
+ {"version":3,"file":"utility.d.ts","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAS/B;;GAEG;AACH,eAAO,MAAM,MAAM,iBAEjB,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA2BxF"}
package/dist/utility.js CHANGED
@@ -35,7 +35,7 @@ export const logger = new Logger({
35
35
  * Output if captured or empty array if not.
36
36
  */
37
37
  export function run(captureOutput, command, ...args) {
38
- logger.debug(`Running command "${command}" with arguments ${JSON.stringify(args)}.`);
38
+ logger.trace(`Running command "${command}" with arguments ${JSON.stringify(args)}.`);
39
39
  const spawnResult = spawnSync(command, args, {
40
40
  stdio: ["inherit", captureOutput ? "pipe" : "inherit", "inherit"]
41
41
  });
@@ -48,9 +48,10 @@ export function run(captureOutput, command, ...args) {
48
48
  if (spawnResult.status !== 0) {
49
49
  throw new Error(`Failed with status ${spawnResult.status}`);
50
50
  }
51
+ // Last line is also terminated by newline and split() places empty string at the end, so use slice() to remove it.
51
52
  const output = captureOutput ? spawnResult.stdout.toString().split("\n").slice(0, -1) : [];
52
53
  if (captureOutput) {
53
- logger.debug(`Output is ${JSON.stringify(output)}.`);
54
+ logger.trace(`Output is ${JSON.stringify(output)}.`);
54
55
  }
55
56
  return output;
56
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B;;GAEG;AACH,IAAK,QAEJ;AAFD,WAAK,QAAQ;IACT,yCAAK,CAAA;IAAE,yCAAK,CAAA;IAAE,yCAAK,CAAA;IAAE,uCAAI,CAAA;IAAE,uCAAI,CAAA;IAAE,yCAAK,CAAA;IAAE,yCAAK,CAAA;AACjD,CAAC,EAFI,QAAQ,KAAR,QAAQ,QAEZ;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC,IAAI;CAC1B,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,GAAG,CAAC,aAAsB,EAAE,OAAe,EAAE,GAAG,IAAc;IAC1E,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,oBAAoB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAErF,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACzC,KAAK,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC;KACpE,CAAC,CAAC;IAEH,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,WAAW,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3F,IAAI,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B;;GAEG;AACH,IAAK,QAEJ;AAFD,WAAK,QAAQ;IACT,yCAAK,CAAA;IAAE,yCAAK,CAAA;IAAE,yCAAK,CAAA;IAAE,uCAAI,CAAA;IAAE,uCAAI,CAAA;IAAE,yCAAK,CAAA;IAAE,yCAAK,CAAA;AACjD,CAAC,EAFI,QAAQ,KAAR,QAAQ,QAEZ;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC,IAAI;CAC1B,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,GAAG,CAAC,aAAsB,EAAE,OAAe,EAAE,GAAG,IAAc;IAC1E,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,oBAAoB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAErF,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACzC,KAAK,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC;KACpE,CAAC,CAAC;IAEH,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,WAAW,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,mHAAmH;IACnH,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3F,IAAI,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/dev",
3
- "version": "0.9.17-beta",
3
+ "version": "0.9.18-beta",
4
4
  "description": "Shared development artefacts for AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,27 +25,27 @@
25
25
  "build:dev": "npm run build:core -- tsconfig-build-dev-local.json",
26
26
  "build:release": "npm run build:core -- tsconfig-build-local.json",
27
27
  "build:doc": "npm run build:dev",
28
- "publish-internal": "tsx src/publish-internal.ts",
28
+ "publish-internal": "tsx src/publish-internal.ts $*",
29
29
  "publish-external": "tsx src/publish-external.ts"
30
30
  },
31
31
  "devDependencies": {
32
32
  "copy-files-from-to": "^3.12.1"
33
33
  },
34
34
  "dependencies": {
35
- "@eslint/js": "^9.20.0",
36
- "@octokit/types": "^13.8.0",
37
- "@stylistic/eslint-plugin": "^4.1.0",
38
- "eslint": "^9.21.0",
39
- "eslint-config-love": "^118.0.0",
40
- "eslint-plugin-jsdoc": "^50.6.3",
35
+ "@eslint/js": "^9.28.0",
36
+ "@octokit/types": "^14.1.0",
37
+ "@stylistic/eslint-plugin": "^4.4.1",
38
+ "eslint": "^9.28.0",
39
+ "eslint-config-love": "^120.0.0",
40
+ "eslint-plugin-jsdoc": "^50.7.1",
41
41
  "jiti": "^2.4.2",
42
- "octokit": "^4.1.2",
42
+ "octokit": "^5.0.3",
43
43
  "rimraf": "^6.0.1",
44
44
  "ts-node": "^10.9.2",
45
45
  "tslog": "^4.9.3",
46
- "tsx": "^4.19.3",
47
- "typescript": "^5.7.3",
48
- "typescript-eslint": "^8.25.0",
49
- "yaml": "^2.7.0"
46
+ "tsx": "^4.19.4",
47
+ "typescript": "^5.8.3",
48
+ "typescript-eslint": "^8.33.1",
49
+ "yaml": "^2.8.0"
50
50
  }
51
51
  }
@@ -28,8 +28,8 @@ export const esLintConfigAIDCToolkit = tseslint.config(
28
28
  "complexity": "off",
29
29
  "max-depth": ["error", 10],
30
30
  "max-lines": "off",
31
- "no-dupe-class-members": "off",
32
- "no-redeclare": "off",
31
+
32
+ // Handled by @typescript-eslint/no-unused-vars.
33
33
  "no-unused-vars": "off",
34
34
 
35
35
  "@typescript-eslint/class-literal-property-style": "off",
@@ -58,6 +58,10 @@ export const esLintConfigAIDCToolkit = tseslint.config(
58
58
  allowSingleLine: false
59
59
  }],
60
60
  "@stylistic/comma-dangle": ["error", "never"],
61
+ "@stylistic/generator-star-spacing": ["error", {
62
+ before: true,
63
+ after: true
64
+ }],
61
65
  "@stylistic/indent": ["error", 4],
62
66
  "@stylistic/member-delimiter-style": ["error", {
63
67
  multiline: {
@@ -83,6 +87,10 @@ export const esLintConfigAIDCToolkit = tseslint.config(
83
87
  }
84
88
  }],
85
89
  "@stylistic/object-property-newline": "error",
90
+ "@stylistic/yield-star-spacing": ["error", {
91
+ before: true,
92
+ after: true
93
+ }],
86
94
 
87
95
  "jsdoc/require-description": ["warn", {
88
96
  contexts: ["ClassDeclaration", "ClassProperty", "FunctionDeclaration", "MethodDefinition", "TSEnumDeclaration", "TSInterfaceDeclaration", "TSModuleDeclaration", "TSTypeAliasDeclaration"]
@@ -1,12 +1,14 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "node:path";
3
- import * as util from "node:util";
3
+ import { setTimeout } from "node:timers/promises";
4
4
  import { Octokit } from "octokit";
5
5
  import { parse as yamlParse } from "yaml";
6
6
  import {
7
7
  anyChanges,
8
+ commitConfiguration,
8
9
  configuration,
9
- organizationRepository, type PackageConfiguration,
10
+ organizationRepository,
11
+ type PackageConfiguration,
10
12
  publishRepositories,
11
13
  type Repository,
12
14
  saveConfiguration,
@@ -52,8 +54,7 @@ interface WorkflowConfiguration {
52
54
  /**
53
55
  * Supported steps.
54
56
  */
55
- type Step =
56
- "skipped" | "install" | "build" | "commit" | "tag" | "push" | "workflow (push)" | "release" | "workflow (release)" | "restore alpha" | "complete";
57
+ type Step = "skipped" | "install" | "build" | "commit" | "tag" | "push" | "workflow (push)" | "release" | "workflow (release)" | "restore alpha" | "complete";
57
58
 
58
59
  /**
59
60
  * Execute a step.
@@ -141,42 +142,61 @@ const octokit = new Octokit({
141
142
  });
142
143
 
143
144
  await publishRepositories(async (name, repository) => {
144
- // Repository must be on main branch.
145
- if (run(true, "git", "branch", "--show-current")[0] !== "main") {
146
- throw new Error("Repository is not on main branch");
147
- }
148
-
149
145
  const packageConfigurationPath = "package.json";
150
146
 
151
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Package configuration format is known.
152
- const packageConfiguration: PackageConfiguration = JSON.parse(fs.readFileSync(packageConfigurationPath).toString());
147
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Package configuration format is known.
148
+ const packageConfiguration = JSON.parse(fs.readFileSync(packageConfigurationPath).toString()) as PackageConfiguration;
149
+
150
+ let packageVersion = packageConfiguration.version;
151
+
152
+ const packageVersionSplits = packageVersion.split("-");
153
+
154
+ // Extract semantic version and pre-release identifier.
155
+ const semanticVersion = packageVersionSplits[0];
156
+ const preReleaseIdentifier = packageVersionSplits.length !== 1 ? `-${packageVersionSplits[1]}` : "";
157
+
158
+ // Parse semantic version into its components.
159
+ const [majorVersion, minorVersion, patchVersion] = semanticVersion.split(".").map(versionString => Number(versionString));
160
+
161
+ // Local code must be on branch matching version.
162
+ const branch = run(true, "git", "branch", "--show-current")[0];
163
+ if (branch !== `v${majorVersion}.${minorVersion}`) {
164
+ throw new Error(`Repository must be on version branch ${branch}`);
165
+ }
153
166
 
154
167
  let publish: boolean;
155
168
 
156
- if (repository.publishExternalStep === undefined) {
157
- publish = anyChanges(repository, true);
158
- } else {
159
- publish = true;
169
+ switch (repository.publishExternalStep) {
170
+ case undefined:
171
+ // Check for publish external always is done afterward so that check for uncommitted files can be done.
172
+ publish = anyChanges(repository, true) || repository.publishExternalAlways === true;
173
+
174
+ if (publish && anyChanges(repository, false)) {
175
+ throw new Error("Repository has internal changes that have not been published");
176
+ }
177
+ break;
178
+
179
+ case "complete":
180
+ // Previous publication succeeded but subsequent repository failed; skip this repository.
181
+ publish = false;
182
+ break;
183
+
184
+ default:
185
+ // Previous publication failed.
186
+ publish = true;
187
+ break;
160
188
  }
161
189
 
162
- if (packageConfiguration.version !== repository.lastExternalVersion) {
190
+ if (packageVersion !== repository.lastExternalVersion) {
163
191
  // Package version has already been updated, either manually or by previous failed run.
164
192
  publish = true;
165
193
  } else if (publish) {
166
- const packageVersionSplits = packageConfiguration.version.split("-");
167
-
168
- // Extract semantic version and pre-release identifier.
169
- const semanticVersion = packageVersionSplits[0];
170
- const preReleaseIdentifier = packageVersionSplits.length !== 1 ? `-${packageVersionSplits[1]}` : "";
171
-
172
- // Parse semantic version into its components.
173
- const [majorVersion, minorVersion, patchVersion] = semanticVersion.split(".").map(versionString => Number(versionString));
174
-
175
194
  // Increment patch version number.
176
- packageConfiguration.version = `${majorVersion}.${minorVersion}.${patchVersion + 1}${preReleaseIdentifier}`;
195
+ packageVersion = `${majorVersion}.${minorVersion}.${patchVersion + 1}${preReleaseIdentifier}`;
196
+ packageConfiguration.version = packageVersion;
177
197
  }
178
198
 
179
- const tag = `v${packageConfiguration.version}`;
199
+ const tag = `v${packageVersion}`;
180
200
 
181
201
  const octokitParameterBase = {
182
202
  owner: configuration.organization,
@@ -207,7 +227,7 @@ await publishRepositories(async (name, repository) => {
207
227
  // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Workflow configuration format is known.
208
228
  const workflowOn = (yamlParse(fs.readFileSync(path.resolve(workflowsPath, workflowFile)).toString()) as WorkflowConfiguration).on;
209
229
 
210
- if (workflowOn.push !== undefined && (workflowOn.push.branches === undefined || workflowOn.push.branches.includes("main"))) {
230
+ if (workflowOn.push !== undefined && (workflowOn.push.branches === undefined || workflowOn.push.branches.includes("v*"))) {
211
231
  logger.debug("Repository has push workflow");
212
232
 
213
233
  hasPushWorkflow = true;
@@ -232,7 +252,7 @@ await publishRepositories(async (name, repository) => {
232
252
  let workflowRunID = -1;
233
253
 
234
254
  do {
235
- await util.promisify(setTimeout)(2000);
255
+ await setTimeout(2000);
236
256
 
237
257
  const response = await octokit.rest.actions.listWorkflowRunsForRepo({
238
258
  ...octokitParameterBase,
@@ -273,11 +293,11 @@ await publishRepositories(async (name, repository) => {
273
293
  });
274
294
 
275
295
  await runStep(repository, "build", () => {
276
- run(false, "npm", "run", "build", "--if-present");
296
+ run(false, "npm", "run", "build:release", "--if-present");
277
297
  });
278
298
 
279
299
  await runStep(repository, "commit", () => {
280
- run(false, "git", "commit", "--all", `--message=Updated to version ${packageConfiguration.version}.`);
300
+ run(false, "git", "commit", "--all", "--message", `Updated to version ${packageVersion}.`);
281
301
  });
282
302
 
283
303
  await runStep(repository, "tag", () => {
@@ -285,7 +305,7 @@ await publishRepositories(async (name, repository) => {
285
305
  });
286
306
 
287
307
  await runStep(repository, "push", () => {
288
- run(false, "git", "push", "--atomic", "origin", "main", tag);
308
+ run(false, "git", "push", "--atomic", "origin", branch, tag);
289
309
  });
290
310
 
291
311
  if (hasPushWorkflow) {
@@ -295,7 +315,7 @@ await publishRepositories(async (name, repository) => {
295
315
  }
296
316
 
297
317
  await runStep(repository, "release", async () => {
298
- const versionSplit = packageConfiguration.version.split("-");
318
+ const versionSplit = packageVersion.split("-");
299
319
  const prerelease = versionSplit.length !== 1;
300
320
 
301
321
  await octokit.rest.repos.createRelease({
@@ -319,14 +339,24 @@ await publishRepositories(async (name, repository) => {
319
339
 
320
340
  if (devDependenciesUpdated || dependenciesUpdated) {
321
341
  fs.writeFileSync(packageConfigurationPath, `${JSON.stringify(packageConfiguration, null, 2)}\n`);
322
- run(false, "git", "commit", "--all", "--message=Restored alpha version.");
342
+
343
+ run(false, "git", "commit", packageConfigurationPath, "--message", "Restored alpha versions to organization dependencies.");
323
344
  }
324
345
  });
325
346
 
326
347
  repository.lastExternalPublished = new Date().toISOString();
327
- repository.lastExternalVersion = packageConfiguration.version;
348
+ repository.lastExternalVersion = packageVersion;
349
+ repository.publishExternalStep = "complete";
350
+ }
351
+ }).then(() => {
352
+ // Publication complete; reset steps to undefined for next run.
353
+ for (const repository of Object.values(configuration.repositories)) {
328
354
  repository.publishExternalStep = undefined;
329
355
  }
356
+
357
+ saveConfiguration();
358
+
359
+ commitConfiguration(true);
330
360
  }).catch((e: unknown) => {
331
361
  logger.error(e);
332
362
  });
@@ -1,35 +1,53 @@
1
1
  import * as fs from "fs";
2
- import { anyChanges, organizationRepository, type PackageConfiguration, publishRepositories } from "./publish";
2
+ import {
3
+ anyChanges,
4
+ commitConfiguration,
5
+ organizationRepository,
6
+ type PackageConfiguration,
7
+ publishRepositories
8
+ } from "./publish";
3
9
  import { logger, run } from "./utility.js";
4
10
 
11
+ // Detailed syntax checking not required as this is an internal tool.
12
+ const updateAll = process.argv[2] === "--update-all";
13
+
5
14
  /**
6
- * Check dependencies for belonging to the organization; if not, check for updates and log a message if an update is
7
- * available.
15
+ * Check dependencies for belonging to the organization; if not, check for updates and log a message, and optionally
16
+ * update, if an update is available.
8
17
  *
9
18
  * @param dependencies
10
19
  * Dependencies.
11
20
  *
12
21
  * @returns
13
- * Dependencies belonging to the organization.
22
+ * Dependencies belonging to the organization if not updating all, or external dependencies pending update if updating
23
+ * all.
14
24
  */
15
25
  function checkDependencyUpdates(dependencies?: Record<string, string>): string[] {
16
- const organizationDependencies = [];
26
+ const dependencyUpdates = [];
17
27
 
18
28
  if (dependencies !== undefined) {
19
29
  for (const [dependency, version] of Object.entries(dependencies)) {
20
30
  if (organizationRepository(dependency) !== null) {
21
- organizationDependencies.push(dependency);
31
+ if (!updateAll) {
32
+ dependencyUpdates.push(dependency);
33
+ }
22
34
  } else if (version.startsWith("^")) {
23
35
  const [latestVersion] = run(true, "npm", "view", dependency, "version");
24
36
 
25
37
  if (latestVersion !== version.substring(1)) {
26
- logger.info(`Dependency ${dependency}@${version} pending update to version ${latestVersion}.`);
38
+ logger.info(`Dependency ${dependency}@${version} ${!updateAll ? "pending update" : "updating"} to version ${latestVersion}.`);
39
+
40
+ if (updateAll) {
41
+ dependencies[dependency] = `^${latestVersion}`;
42
+
43
+ dependencyUpdates.push(dependency);
44
+ }
27
45
  }
28
46
  }
29
47
  }
30
48
  }
31
49
 
32
- return organizationDependencies;
50
+ return dependencyUpdates;
33
51
  }
34
52
 
35
53
  /**
@@ -48,21 +66,67 @@ function zeroPadded(n: number, length: number): string {
48
66
  return `${"0".repeat(length - 1)}${n}`.slice(-length);
49
67
  }
50
68
 
51
- await publishRepositories((_name, repository) => {
69
+ const dependencyDependenciesMap = new Map<string, string[]>();
70
+
71
+ await publishRepositories((name, repository) => {
52
72
  const packageConfigurationPath = "package.json";
53
73
 
54
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Package configuration format is known.
55
- const packageConfiguration: PackageConfiguration = JSON.parse(fs.readFileSync(packageConfigurationPath).toString());
74
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Package configuration format is known.
75
+ const packageConfiguration = JSON.parse(fs.readFileSync(packageConfigurationPath).toString()) as PackageConfiguration;
56
76
 
57
77
  // Check dependency updates, even if there are no changes.
58
- const organizationDependencies = [...checkDependencyUpdates(packageConfiguration.devDependencies), ...checkDependencyUpdates(packageConfiguration.dependencies)];
78
+ const dependencyUpdates = [...checkDependencyUpdates(packageConfiguration.devDependencies), ...checkDependencyUpdates(packageConfiguration.dependencies)];
79
+
80
+ if (!updateAll) {
81
+ if (dependencyUpdates.length !== 0) {
82
+ dependencyDependenciesMap.set(name, dependencyUpdates);
83
+
84
+ const allDependencyUpdates = new Array<string>();
85
+
86
+ /**
87
+ * Add all dependency updates and those of their dependencies.
88
+ *
89
+ * @param dependencies
90
+ * Dependencies.
91
+ */
92
+ function addAllDependencyUpdates(dependencies: string[]): void {
93
+ for (const dependency of dependencies) {
94
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Dependency is an organization repository.
95
+ const dependencyDependencies = dependencyDependenciesMap.get(organizationRepository(dependency)!);
96
+
97
+ if (dependencyDependencies !== undefined) {
98
+ addAllDependencyUpdates(dependencyDependencies);
99
+ }
100
+
101
+ if (!allDependencyUpdates.includes(dependency)) {
102
+ allDependencyUpdates.push(dependency);
103
+ }
104
+ }
105
+ }
106
+
107
+ addAllDependencyUpdates(dependencyUpdates);
59
108
 
60
- if (organizationDependencies.length !== 0) {
61
- logger.debug(`Updating organization dependencies ${JSON.stringify(organizationDependencies)}`);
109
+ logger.debug(`Updating organization dependencies ${JSON.stringify(allDependencyUpdates)}`);
62
110
 
63
- run(false, "npm", "update", ...organizationDependencies);
111
+ run(false, "npm", "update", ...allDependencyUpdates);
112
+ }
113
+ } else {
114
+ if (dependencyUpdates.length !== 0) {
115
+ // Update the package configuration for the update.
116
+ fs.writeFileSync(packageConfigurationPath, `${JSON.stringify(packageConfiguration, null, 2)}\n`);
117
+ }
118
+
119
+ logger.debug("Updating all dependencies");
120
+
121
+ run(false, "npm", "update");
64
122
  }
65
123
 
124
+ // Run lint if present.
125
+ run(false, "npm", "run", "lint", "--if-present");
126
+
127
+ // Run development build if present.
128
+ run(false, "npm", "run", "build:dev", "--if-present");
129
+
66
130
  // Nothing further required if this repository is not a dependency.
67
131
  if (repository.dependencyType !== "none" && anyChanges(repository, false)) {
68
132
  const backupPackageConfigurationPath = ".package.json";
@@ -85,9 +149,6 @@ await publishRepositories((_name, repository) => {
85
149
  // Update the package configuration for the build.
86
150
  fs.writeFileSync(packageConfigurationPath, `${JSON.stringify(packageConfiguration, null, 2)}\n`);
87
151
 
88
- // Run development build.
89
- run(false, "npm", "run", "build:dev");
90
-
91
152
  // Publish to development npm registry.
92
153
  run(false, "npm", "publish", "--tag", "alpha");
93
154
 
@@ -106,6 +167,8 @@ await publishRepositories((_name, repository) => {
106
167
  fs.renameSync(backupPackageConfigurationPath, packageConfigurationPath);
107
168
  }
108
169
  }
170
+ }).then(() => {
171
+ commitConfiguration(false);
109
172
  }).catch((e: unknown) => {
110
173
  logger.error(e);
111
174
  });
package/src/publish.ts CHANGED
@@ -28,6 +28,11 @@ export interface Repository {
28
28
  */
29
29
  lastInternalPublished?: string;
30
30
 
31
+ /**
32
+ * If true, publish repository externally always.
33
+ */
34
+ publishExternalAlways?: boolean;
35
+
31
36
  /**
32
37
  * Date/time the package was last published externally in ISO format.
33
38
  */
@@ -129,22 +134,54 @@ export function anyChanges(repository: Repository, external: boolean): boolean {
129
134
 
130
135
  const lastPublishedString = !external ? repository.lastInternalPublished : repository.lastExternalPublished;
131
136
 
137
+ const excludedFilesSet = new Set(repository.excludeFiles ?? []);
138
+
132
139
  const changedFilesSet = new Set<string>();
133
140
 
134
- if (lastPublishedString !== undefined) {
135
- for (const line of run(true, "git", "log", `--since="${lastPublishedString}"`, "--name-status", "--pretty=oneline")) {
136
- // Header starts with 40-character SHA.
137
- if (!/^[0-9a-f]{40} /.test(line)) {
138
- const [status, file] = line.split("\t");
141
+ /**
142
+ * Process a changed file.
143
+ *
144
+ * @param status
145
+ * "R" if the file has been renamed, "D" if the file has been deleted, otherwise file has been added.
146
+ *
147
+ * @param file
148
+ * Original file name if status is "R", otherwise file to be added or deleted.
149
+ *
150
+ * @param newFile
151
+ * New file name if status is "R", undefined otherwise.
152
+ */
153
+ function processChangedFile(status: string, file: string, newFile: string | undefined): void {
154
+ // Status is "D" if deleted, "R" if renamed.
155
+ const deleteFile = status === "D" || status === "R" ? file : undefined;
156
+ const addFile = status === "R" ? newFile : status !== "D" ? file : undefined;
157
+
158
+ // Remove deleted file; anything that depends on a deleted file will have been modified.
159
+ if (deleteFile !== undefined && changedFilesSet.delete(deleteFile)) {
160
+ logger.debug(`-${deleteFile}`);
161
+ }
139
162
 
140
- // Ignore deleted files; anything that depends on a deleted file will have been modified.
141
- if (status !== "D") {
142
- logger.debug(`+File: ${file}`);
163
+ if (addFile !== undefined && !changedFilesSet.has(addFile)) {
164
+ // Exclude hidden files and directories except .github directory, as well as test directory and any explicitly excluded files.
165
+ if (((!addFile.startsWith(".") && !addFile.includes("/.")) || addFile.startsWith(".github/")) && !addFile.startsWith("test/") && !excludedFilesSet.has(addFile)) {
166
+ changedFilesSet.add(addFile);
143
167
 
144
- changedFilesSet.add(file);
145
- }
168
+ logger.debug(`+${addFile}`);
146
169
  } else {
170
+ // File is excluded.
171
+ logger.debug(`*${addFile}`);
172
+ }
173
+ }
174
+ }
175
+
176
+ if (lastPublishedString !== undefined) {
177
+ for (const line of run(true, "git", "log", "--since", lastPublishedString, "--name-status", "--pretty=oneline")) {
178
+ // Header starts with 40-character SHA.
179
+ if (/^[0-9a-f]{40} /.test(line)) {
147
180
  logger.debug(`Commit SHA ${line.substring(0, 40)}`);
181
+ } else {
182
+ const [status, file, newFile] = line.split("\t");
183
+
184
+ processChangedFile(status.charAt(0), file, newFile);
148
185
  }
149
186
  }
150
187
  }
@@ -153,102 +190,63 @@ export function anyChanges(repository: Repository, external: boolean): boolean {
153
190
  const output = run(true, "git", "status", "--porcelain");
154
191
 
155
192
  if (output.length !== 0) {
156
- if (external) {
157
- throw new Error("Repository has uncommitted changes");
158
- }
193
+ // External publication requires that repository be fully committed.
194
+ // if (external) {
195
+ // throw new Error("Repository has uncommitted changes");
196
+ // }
159
197
 
160
198
  logger.debug("Uncommitted");
161
199
 
162
200
  for (const line of output) {
163
201
  // Line is two-character status, space, and detail.
164
- const status = line.substring(0, 2);
165
- const detail = line.substring(3);
166
-
167
- // Ignore deleted files; anything that depends on a deleted file will have been modified.
168
- if (status !== "D ") {
169
- let file: string;
170
-
171
- if (status.startsWith("R")) {
172
- // File has been renamed; get old and new file names.
173
- const [oldFile, newFile] = detail.split(" -> ");
202
+ const status = line.substring(0, 1);
203
+ const [file, newFile] = line.substring(3).split(" -> ");
174
204
 
175
- logger.debug(`-File: ${oldFile}`);
176
-
177
- changedFilesSet.delete(oldFile);
178
-
179
- file = newFile;
180
- } else {
181
- file = detail;
182
- }
183
-
184
- logger.debug(`+File: ${file}`);
185
-
186
- changedFilesSet.add(file);
187
- }
205
+ processChangedFile(status, file, newFile);
188
206
  }
189
207
  }
190
208
  }
191
209
 
192
210
  if (lastPublishedString !== undefined) {
193
- logger.debug("Excluded");
194
-
195
- const hiddenFiles = [];
196
-
197
- // Get list of hidden files and directories.
198
- for (const changedFile of changedFilesSet) {
199
- if (changedFile.startsWith(".") || changedFile.includes("/.")) {
200
- hiddenFiles.push(changedFile);
201
- }
202
- }
203
-
204
- // Exclude hidden files and directories.
205
- for (const hiddenFile of hiddenFiles) {
206
- logger.debug(`-File: ${hiddenFile}`);
207
-
208
- changedFilesSet.delete(hiddenFile);
209
- }
210
-
211
- if (repository.excludeFiles !== undefined) {
212
- for (const excludeFile of repository.excludeFiles) {
213
- if (changedFilesSet.delete(excludeFile)) {
214
- logger.debug(`-File: ${excludeFile}`);
215
- }
216
- }
217
- }
218
-
219
- logger.info("Changed");
220
-
221
211
  const lastPublished = new Date(lastPublishedString);
222
212
 
223
213
  anyChanges = false;
224
214
 
225
215
  for (const changedFile of changedFilesSet) {
226
216
  if (fs.lstatSync(changedFile).mtime > lastPublished) {
227
- logger.info(`File: ${changedFile}`);
217
+ if (!anyChanges) {
218
+ anyChanges = true;
228
219
 
229
- anyChanges = true;
220
+ logger.info("Changes");
221
+ }
222
+
223
+ logger.info(`>${changedFile}`);
230
224
  }
231
225
  }
226
+
227
+ if (!anyChanges) {
228
+ logger.info("No changes");
229
+ }
232
230
  } else {
233
231
  // No last published, so there must have been changes.
234
232
  anyChanges = true;
235
- }
236
233
 
237
- if (!anyChanges) {
238
- logger.debug("No changes");
234
+ logger.info("No last published");
239
235
  }
240
236
 
241
237
  return anyChanges;
242
238
  }
243
239
 
240
+ const configurationPath = "config/publish.json";
241
+
244
242
  // Configuration may be written from any directory so full path is required.
245
- const configurationPath = path.resolve("config/publish.json");
243
+ const configurationFullPath = path.resolve(configurationPath);
246
244
 
247
245
  /**
248
246
  * Save the current configuration.
249
247
  */
250
248
  export function saveConfiguration(): void {
251
- fs.writeFileSync(configurationPath, `${JSON.stringify(configuration, null, 2)}\n`);
249
+ fs.writeFileSync(configurationFullPath, `${JSON.stringify(configuration, null, 2)}\n`);
252
250
  }
253
251
 
254
252
  /**
@@ -258,7 +256,7 @@ export function saveConfiguration(): void {
258
256
  * Callback taking the name and properties of the repository to publish.
259
257
  */
260
258
  export async function publishRepositories(callback: (name: string, repository: Repository) => void | Promise<void>): Promise<void> {
261
- logger.settings.minLevel = 2;
259
+ const startDirectory = process.cwd();
262
260
 
263
261
  for (const [name, repository] of Object.entries(configuration.repositories)) {
264
262
  logger.info(`Repository ${name}...`);
@@ -270,4 +268,20 @@ export async function publishRepositories(callback: (name: string, repository: R
270
268
 
271
269
  saveConfiguration();
272
270
  }
271
+
272
+ // Return to the start directory.
273
+ process.chdir(startDirectory);
274
+ }
275
+
276
+ /**
277
+ * Commit the current configuration.
278
+ *
279
+ * @param external
280
+ * False if committing due to internal publication, true if committing due to external publication.
281
+ */
282
+ export function commitConfiguration(external: boolean): void {
283
+ // Check for changes before committing.
284
+ if (run(true, "git", "status", configurationPath, "--porcelain").length !== 0) {
285
+ run(false, "git", "commit", configurationPath, "--message", !external ? "Published internally." : "Published externally.");
286
+ }
273
287
  }
package/src/utility.ts CHANGED
@@ -31,7 +31,7 @@ export const logger = new Logger({
31
31
  * Output if captured or empty array if not.
32
32
  */
33
33
  export function run(captureOutput: boolean, command: string, ...args: string[]): string[] {
34
- logger.debug(`Running command "${command}" with arguments ${JSON.stringify(args)}.`);
34
+ logger.trace(`Running command "${command}" with arguments ${JSON.stringify(args)}.`);
35
35
 
36
36
  const spawnResult = spawnSync(command, args, {
37
37
  stdio: ["inherit", captureOutput ? "pipe" : "inherit", "inherit"]
@@ -49,10 +49,11 @@ export function run(captureOutput: boolean, command: string, ...args: string[]):
49
49
  throw new Error(`Failed with status ${spawnResult.status}`);
50
50
  }
51
51
 
52
+ // Last line is also terminated by newline and split() places empty string at the end, so use slice() to remove it.
52
53
  const output = captureOutput ? spawnResult.stdout.toString().split("\n").slice(0, -1) : [];
53
54
 
54
55
  if (captureOutput) {
55
- logger.debug(`Output is ${JSON.stringify(output)}.`);
56
+ logger.trace(`Output is ${JSON.stringify(output)}.`);
56
57
  }
57
58
 
58
59
  return output;