@quark-hq/quark-scripts 0.0.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/LICENSE +21 -0
- package/dist/app/base-application.js +67 -0
- package/dist/app/buildApplication.js +20 -0
- package/dist/app/copyStaticApplication.js +34 -0
- package/dist/app/devApplication.js +59 -0
- package/dist/app/prod-publish-application.js +124 -0
- package/dist/app/publish-dev-application.js +104 -0
- package/dist/app/publishDevApplication.js +16 -0
- package/dist/app/release-application.js +85 -0
- package/dist/app/releaseApplication.js +154 -0
- package/dist/app/unfreeze-application.js +75 -0
- package/dist/app/watchStaticApplication.js +34 -0
- package/dist/cli/cli-containers.js +70 -0
- package/dist/cli/cliCommand.js +2 -0
- package/dist/cli/cliContainers.js +62 -0
- package/dist/cli/commands/buildCommands.js +17 -0
- package/dist/cli/commands/copyStaticCommands.js +17 -0
- package/dist/cli/commands/devCommands.js +17 -0
- package/dist/cli/commands/prod-publish-commands.js +18 -0
- package/dist/cli/commands/publish-dev-commands.js +17 -0
- package/dist/cli/commands/publishDevCommands.js +17 -0
- package/dist/cli/commands/release-commands.js +17 -0
- package/dist/cli/commands/releaseCommands.js +17 -0
- package/dist/cli/commands/relesaeCommand.js +15 -0
- package/dist/cli/commands/unfreeze-commands.js +17 -0
- package/dist/cli/commands/watchStaticCommands.js +17 -0
- package/dist/cli/program.js +16 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.js +132 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/domain/graph.js +2 -0
- package/dist/domain/new-package-freeze-from-map.js +21 -0
- package/dist/domain/resolve-workspace-dependency-specifier-for-freeze-map.js +33 -0
- package/dist/domain/reverse-dependents.js +45 -0
- package/dist/domain/topological-sorting.js +43 -0
- package/dist/domain/transitive-dependents.js +25 -0
- package/dist/domain/workspace-transitive-dependencies.js +25 -0
- package/dist/errors/unfreeze-blocked-error.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/adapters/base-release-adapter.js +281 -0
- package/dist/infrastructure/adapters/maven-prod-publish-adapter.js +48 -0
- package/dist/infrastructure/adapters/maven-release-adapter.js +58 -0
- package/dist/infrastructure/adapters/node-prod-publish-adapter.js +111 -0
- package/dist/infrastructure/adapters/node-release-adapter/node-file-update.js +1 -0
- package/dist/infrastructure/adapters/node-release-adapter/node-release-adapter.js +289 -0
- package/dist/infrastructure/adapters/node-release-adapter.js +202 -0
- package/dist/infrastructure/config/loadDotEnv.js +38 -0
- package/dist/infrastructure/config/nodeRegistryEnv.js +41 -0
- package/dist/infrastructure/config/quarkConfigProvider.js +50 -0
- package/dist/infrastructure/git/gitService.js +179 -0
- package/dist/infrastructure/graph/nxGraphProvide.js +84 -0
- package/dist/infrastructure/logging/consoleLogger.js +25 -0
- package/dist/infrastructure/process/nodeProcessRunner.js +14 -0
- package/dist/infrastructure/release/git-release-map-store.js +64 -0
- package/dist/ports/config.js +2 -0
- package/dist/ports/git.js +2 -0
- package/dist/ports/graph.js +2 -0
- package/dist/ports/logger.js +2 -0
- package/dist/ports/map.js +2 -0
- package/dist/ports/platform-dev-publish-adapter.js +2 -0
- package/dist/ports/platform-prod-publish-adapter.js +2 -0
- package/dist/ports/platform-release-adapter.js +2 -0
- package/dist/ports/processRunner.js +2 -0
- package/dist/ports/prompts.js +2 -0
- package/dist/ports/release-map-store.js +2 -0
- package/dist/scripts/dev.d.ts +20 -0
- package/dist/scripts/dev.js +204 -0
- package/dist/scripts/dev.js.map +1 -0
- package/dist/scripts/map.json +1616 -0
- package/dist/scripts/prod.d.ts +1 -0
- package/dist/scripts/prod.js +143 -0
- package/dist/scripts/prod.js.map +1 -0
- package/dist/scripts/release.d.ts +51 -0
- package/dist/scripts/release.js +833 -0
- package/dist/scripts/release.js.map +1 -0
- package/dist/tests/index.test.js +13 -0
- package/dist/tests/mocks/release.js +8 -0
- package/dist/tests/unit/release/index.test.js +32 -0
- package/dist/utils/checkIfFreeze.js +1 -0
- package/dist/utils/commit.js +39 -0
- package/dist/utils/drawRepoStatus.js +66 -0
- package/dist/utils/file.js +14 -0
- package/dist/utils/metrics.js +22 -0
- package/package.json +64 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BaseReleaseAdapter = void 0;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const transitive_dependents_1 = require("../../domain/transitive-dependents");
|
|
42
|
+
const new_package_freeze_from_map_1 = require("../../domain/new-package-freeze-from-map");
|
|
43
|
+
const topological_sorting_1 = require("../../domain/topological-sorting");
|
|
44
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
45
|
+
const semver = __importStar(require("semver"));
|
|
46
|
+
/**
|
|
47
|
+
* Unified base for all platform adapters.
|
|
48
|
+
*
|
|
49
|
+
* Implements both PlatformReleaseAdapter (version-bump prompting, freeze
|
|
50
|
+
* cascading, map.json writes) and PlatformDevPublishAdapter (alpha publish
|
|
51
|
+
* to dev registry).
|
|
52
|
+
*
|
|
53
|
+
* Subclasses only implement platform detection, file writes, version reading,
|
|
54
|
+
* and the dev-publish build+publish cycle.
|
|
55
|
+
*/
|
|
56
|
+
class BaseReleaseAdapter {
|
|
57
|
+
constructor(graphProvider, quarkConfig, logger) {
|
|
58
|
+
this.graphProvider = graphProvider;
|
|
59
|
+
this.quarkConfig = quarkConfig;
|
|
60
|
+
this.logger = logger;
|
|
61
|
+
this.userPrompts = {};
|
|
62
|
+
this.topoSorter = new topological_sorting_1.TopoSorter();
|
|
63
|
+
}
|
|
64
|
+
async execute(packages, graph, sorted, existingMap) {
|
|
65
|
+
const sortedPackages = sorted.filter((pkg) => packages.includes(pkg));
|
|
66
|
+
for (const pkg of sortedPackages) {
|
|
67
|
+
if (!this.userPrompts[pkg]) {
|
|
68
|
+
this.userPrompts[pkg] = await this.promptForPackage(pkg, graph, existingMap, sorted);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return this.userPrompts;
|
|
72
|
+
}
|
|
73
|
+
async writeUserPromptsToFiles(pkg, prompt, mapJsonObject, graph) {
|
|
74
|
+
mapJsonObject[pkg] = {
|
|
75
|
+
bumpType: prompt.bump,
|
|
76
|
+
baseVersion: prompt.baseVersion,
|
|
77
|
+
newVersion: prompt.newVersion,
|
|
78
|
+
changeLog: prompt.changelog,
|
|
79
|
+
frozen: prompt.frozen,
|
|
80
|
+
};
|
|
81
|
+
await this.writePackageFiles(pkg, prompt, mapJsonObject, graph);
|
|
82
|
+
}
|
|
83
|
+
// ── Prompting ──────────────────────────────────────────────────────
|
|
84
|
+
async promptForPackage(pkg, graph, existingMap, sorted) {
|
|
85
|
+
this.logger.info("\n" + chalk_1.default.gray("──────────────────────────────────────────"));
|
|
86
|
+
this.logger.info(this.getPlatformLabel(pkg));
|
|
87
|
+
this.logger.info(chalk_1.default.gray("──────────────────────────────────────────\n"));
|
|
88
|
+
const isNewPackage = !existingMap[pkg];
|
|
89
|
+
const isFrozenPackage = existingMap[pkg]?.frozen;
|
|
90
|
+
const isMajorBumpDisabled = isNewPackage || isFrozenPackage;
|
|
91
|
+
const currentVersion = existingMap[pkg]?.newVersion || "1.0.0";
|
|
92
|
+
const response = await (0, prompts_1.default)([
|
|
93
|
+
{
|
|
94
|
+
type: "select",
|
|
95
|
+
name: "bump",
|
|
96
|
+
message: chalk_1.default.yellow("Select version bump type"),
|
|
97
|
+
choices: this.buildBumpChoices(currentVersion, isNewPackage, isFrozenPackage, isMajorBumpDisabled),
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
name: "changelog",
|
|
102
|
+
message: chalk_1.default.yellow("Enter changelog description"),
|
|
103
|
+
validate: (value) => value.trim().length === 0
|
|
104
|
+
? "Changelog cannot be empty"
|
|
105
|
+
: true,
|
|
106
|
+
},
|
|
107
|
+
], {
|
|
108
|
+
onCancel: () => {
|
|
109
|
+
throw new Error("Release cancelled by user");
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
const result = {
|
|
113
|
+
bump: response.bump,
|
|
114
|
+
frozen: existingMap[pkg]?.frozen || false,
|
|
115
|
+
baseVersion: currentVersion,
|
|
116
|
+
newVersion: response.bump === "new"
|
|
117
|
+
? "1.0.0"
|
|
118
|
+
: semver.inc(currentVersion, response.bump) ?? "1.0.0",
|
|
119
|
+
changelog: response.changelog,
|
|
120
|
+
};
|
|
121
|
+
if (isNewPackage) {
|
|
122
|
+
const freezePolicy = (0, new_package_freeze_from_map_1.resolveNewPackageFreezeFromReleaseMap)(pkg, graph.adjacency, existingMap);
|
|
123
|
+
if (freezePolicy.shouldFreeze) {
|
|
124
|
+
result.frozen = true;
|
|
125
|
+
const deps = freezePolicy.frozenWorkspaceDependencies.join(", ");
|
|
126
|
+
this.logger.warn(chalk_1.default.yellow(`Package "${pkg}" is new but transitively depends on frozen workspace package(s) in .release/map.json (${deps}). ` +
|
|
127
|
+
`It will be marked frozen: workspace dependencies will be pinned to the versions in the map, and pinnedDependencies will be recorded.`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (result.bump === "major") {
|
|
131
|
+
await this.handleMajorVersionBumpConfig(pkg, graph, existingMap);
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
buildBumpChoices(currentVersion, isNewPackage, isFrozenPackage, isMajorBumpDisabled) {
|
|
136
|
+
return [
|
|
137
|
+
{
|
|
138
|
+
title: "🆕 New Package",
|
|
139
|
+
description: !isNewPackage
|
|
140
|
+
? "Disabled as package already published"
|
|
141
|
+
: "New Package Found",
|
|
142
|
+
value: "new",
|
|
143
|
+
disabled: !isNewPackage,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
title: `🐛 Patch (bug fixes) ${isNewPackage ? "Disabled as package is new" : `→ ${semver.inc(currentVersion, "patch")}`}`,
|
|
147
|
+
description: `→ ${semver.inc(currentVersion, "patch")}`,
|
|
148
|
+
value: "patch",
|
|
149
|
+
disabled: isNewPackage,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
title: `✨ Minor (new features) ${isNewPackage ? "Disabled as package is new" : `→ ${semver.inc(currentVersion, "minor")}`}`,
|
|
153
|
+
description: `→ ${semver.inc(currentVersion, "minor")}`,
|
|
154
|
+
value: "minor",
|
|
155
|
+
disabled: isNewPackage,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
title: `💥 Major (breaking changes) ${isNewPackage ? "Disabled as package is new" : isFrozenPackage ? "Disabled as package is frozen" : `→ ${semver.inc(currentVersion, "major")}`}`,
|
|
159
|
+
description: `→ ${semver.inc(currentVersion, "major")}`,
|
|
160
|
+
value: "major",
|
|
161
|
+
disabled: isMajorBumpDisabled,
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
// ── Major-bump cascading ───────────────────────────────────────────
|
|
166
|
+
async handleMajorVersionBumpConfig(pkg, graph, existingMap) {
|
|
167
|
+
const invertedAdjacencyList = await this.graphProvider.getInvertedAdjacencyList(graph.adjacency);
|
|
168
|
+
const transitiveDependents = (0, transitive_dependents_1.collectTransitiveDependents)(pkg, invertedAdjacencyList);
|
|
169
|
+
const dependents = transitiveDependents.length === 0
|
|
170
|
+
? []
|
|
171
|
+
: this.topoSorter.sort(graph.adjacency, transitiveDependents);
|
|
172
|
+
if (dependents.length === 0)
|
|
173
|
+
return;
|
|
174
|
+
let choice = "none";
|
|
175
|
+
if (this.quarkConfig?.release?.freeze) {
|
|
176
|
+
const response = await (0, prompts_1.default)({
|
|
177
|
+
type: "select",
|
|
178
|
+
name: "dependencies",
|
|
179
|
+
message: "Select the dependencies to freeze",
|
|
180
|
+
choices: [
|
|
181
|
+
{
|
|
182
|
+
title: "All",
|
|
183
|
+
description: "Freeze all dependents at their current published version",
|
|
184
|
+
value: "all",
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
title: "None",
|
|
188
|
+
description: "Auto-cascade major bump to all dependents",
|
|
189
|
+
value: "none",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
title: "Selective",
|
|
193
|
+
description: "Select which dependents to freeze and which to cascade",
|
|
194
|
+
value: "selective",
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
});
|
|
198
|
+
choice = response.dependencies;
|
|
199
|
+
}
|
|
200
|
+
if (choice === "all") {
|
|
201
|
+
this.freezeDependents(pkg, existingMap, dependents);
|
|
202
|
+
}
|
|
203
|
+
else if (choice === "none") {
|
|
204
|
+
this.cascadeMajorBump(pkg, existingMap, dependents);
|
|
205
|
+
}
|
|
206
|
+
else if (choice === "selective") {
|
|
207
|
+
await this.handleSelectiveMajorVersionBump(pkg, existingMap, dependents, invertedAdjacencyList);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
cascadeMajorBump(pkg, existingMap, dependents) {
|
|
211
|
+
for (const dependent of dependents) {
|
|
212
|
+
const currentVersion = existingMap[dependent]?.newVersion || "1.0.0";
|
|
213
|
+
this.userPrompts[dependent] = {
|
|
214
|
+
bump: "major",
|
|
215
|
+
frozen: false,
|
|
216
|
+
baseVersion: currentVersion,
|
|
217
|
+
newVersion: semver.inc(currentVersion, "major") || "1.0.0",
|
|
218
|
+
changelog: `Dependency version bumped to major version due to major version bump of ${pkg}`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
freezeDependents(pkg, existingMap, dependents) {
|
|
223
|
+
this.logger.info(`Handling frozen dependents for ${pkg}`);
|
|
224
|
+
for (const dependent of dependents) {
|
|
225
|
+
this.userPrompts[dependent] = {
|
|
226
|
+
bump: existingMap[dependent]?.bumpType ?? "patch",
|
|
227
|
+
frozen: true,
|
|
228
|
+
baseVersion: existingMap[dependent]?.baseVersion || "1.0.0",
|
|
229
|
+
newVersion: existingMap[dependent]?.newVersion || "1.0.0",
|
|
230
|
+
changelog: `Dependency version frozen due to major version bump of ${pkg}`,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ── Selective freeze ───────────────────────────────────────────────
|
|
235
|
+
async handleSelectiveMajorVersionBump(pkg, existingMap, dependents, invertedAdjacencyList) {
|
|
236
|
+
const MAX_ATTEMPTS = 5;
|
|
237
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
238
|
+
const selected = await this.promptSelectiveDependents(dependents);
|
|
239
|
+
if (!selected || !Array.isArray(selected)) {
|
|
240
|
+
this.logger.warn("No selection made. Operation cancelled.");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (this.isValidTopologicalSelection(dependents, selected, invertedAdjacencyList)) {
|
|
244
|
+
const unSelected = dependents.filter((dep) => !selected.includes(dep));
|
|
245
|
+
this.cascadeMajorBump(pkg, existingMap, unSelected);
|
|
246
|
+
this.freezeDependents(pkg, existingMap, selected);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
this.logger.error("Invalid selection: freezing a package requires freezing every downstream dependent shown in this list. Please try again.");
|
|
250
|
+
}
|
|
251
|
+
throw new Error("Maximum selection attempts exceeded. Release aborted.");
|
|
252
|
+
}
|
|
253
|
+
async promptSelectiveDependents(dependents) {
|
|
254
|
+
const response = await (0, prompts_1.default)({
|
|
255
|
+
type: "multiselect",
|
|
256
|
+
name: "dependencies",
|
|
257
|
+
message: "Select the dependencies to freeze",
|
|
258
|
+
choices: dependents.map((dep) => ({
|
|
259
|
+
title: dep,
|
|
260
|
+
value: dep,
|
|
261
|
+
})),
|
|
262
|
+
});
|
|
263
|
+
return response.dependencies;
|
|
264
|
+
}
|
|
265
|
+
isValidTopologicalSelection(ordered, selected, invertedAdjacencyList) {
|
|
266
|
+
if (selected.length === 0)
|
|
267
|
+
return true;
|
|
268
|
+
const selectedSet = new Set(selected);
|
|
269
|
+
for (const node of selected) {
|
|
270
|
+
const dependents = invertedAdjacencyList[node] ?? [];
|
|
271
|
+
for (const dependent of dependents) {
|
|
272
|
+
if (ordered.includes(dependent) &&
|
|
273
|
+
!selectedSet.has(dependent)) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
exports.BaseReleaseAdapter = BaseReleaseAdapter;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MavenProdPublishAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Boilerplate adapter for Maven prod publishing.
|
|
6
|
+
*
|
|
7
|
+
* Extend this class with real implementation when Maven prod-publish
|
|
8
|
+
* support is needed. The key extension points are:
|
|
9
|
+
*
|
|
10
|
+
* - readPackageIdentity() – parse pom.xml for artifactId + version
|
|
11
|
+
* - versionExistsInRegistry() – check the Maven repo for duplicates
|
|
12
|
+
* - publish() – run `mvn deploy` against the prod repository
|
|
13
|
+
*
|
|
14
|
+
* Configure via `publish.maven` in quark-config.json:
|
|
15
|
+
* {
|
|
16
|
+
* "publish": {
|
|
17
|
+
* "maven": {
|
|
18
|
+
* "repositoryUrl": "https://your-nexus/repository/releases/",
|
|
19
|
+
* "prodRepositoryUrl": "https://your-nexus/repository/releases/",
|
|
20
|
+
* "repositoryId": "releases"
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* If only `repositoryUrl` is set, it is used for both dev and prod.
|
|
26
|
+
*/
|
|
27
|
+
class MavenProdPublishAdapter {
|
|
28
|
+
constructor(quarkConfig, logger) {
|
|
29
|
+
this.quarkConfig = quarkConfig;
|
|
30
|
+
this.logger = logger;
|
|
31
|
+
}
|
|
32
|
+
supports(meta) {
|
|
33
|
+
return meta.platform === "maven";
|
|
34
|
+
}
|
|
35
|
+
async readPackageIdentity(_packageDir) {
|
|
36
|
+
throw new Error("Maven prod-publish is not implemented yet. " +
|
|
37
|
+
"Override readPackageIdentity() in a concrete subclass.");
|
|
38
|
+
}
|
|
39
|
+
async versionExistsInRegistry(_packageName, _version) {
|
|
40
|
+
throw new Error("Maven prod-publish is not implemented yet. " +
|
|
41
|
+
"Override versionExistsInRegistry() in a concrete subclass.");
|
|
42
|
+
}
|
|
43
|
+
async publish(_packageDir) {
|
|
44
|
+
throw new Error("Maven prod-publish is not implemented yet. " +
|
|
45
|
+
"Override publish() in a concrete subclass.");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.MavenProdPublishAdapter = MavenProdPublishAdapter;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MavenReleaseAdapter = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const base_release_adapter_1 = require("./base-release-adapter");
|
|
9
|
+
/**
|
|
10
|
+
* Boilerplate adapter for Maven release and dev-publish.
|
|
11
|
+
*
|
|
12
|
+
* Extend this class with real implementation when Maven support
|
|
13
|
+
* is needed. The key extension points are:
|
|
14
|
+
*
|
|
15
|
+
* Release:
|
|
16
|
+
* - writePackageFiles() – update pom.xml with new version / frozen deps
|
|
17
|
+
*
|
|
18
|
+
* Dev-publish:
|
|
19
|
+
* - getCurrentVersion() – read current version from pom.xml
|
|
20
|
+
* - publish() – build + deploy to the dev Maven repository
|
|
21
|
+
*
|
|
22
|
+
* Configure via `publish.maven` in quark-config.json:
|
|
23
|
+
* {
|
|
24
|
+
* "publish": {
|
|
25
|
+
* "maven": {
|
|
26
|
+
* "repositoryUrl": "https://your-nexus/repository/releases/",
|
|
27
|
+
* "devRepositoryUrl": "https://your-nexus/repository/snapshots/",
|
|
28
|
+
* "repositoryId": "releases"
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* If only `repositoryUrl` is set, it is used for both dev and prod.
|
|
34
|
+
*/
|
|
35
|
+
class MavenReleaseAdapter extends base_release_adapter_1.BaseReleaseAdapter {
|
|
36
|
+
constructor(graphProvider, quarkConfig, logger) {
|
|
37
|
+
super(graphProvider, quarkConfig, logger);
|
|
38
|
+
}
|
|
39
|
+
supports(meta) {
|
|
40
|
+
return meta.platform === "maven";
|
|
41
|
+
}
|
|
42
|
+
getPlatformLabel(pkg) {
|
|
43
|
+
return chalk_1.default.bold.magenta(`☕ Releasing (Maven): ${pkg}`);
|
|
44
|
+
}
|
|
45
|
+
async writePackageFiles(_pkg, _prompt, _mapJsonObject, _graph) {
|
|
46
|
+
throw new Error("Maven release is not implemented yet. " +
|
|
47
|
+
"Override writePackageFiles() in a concrete subclass.");
|
|
48
|
+
}
|
|
49
|
+
async getCurrentVersion(_packageDir) {
|
|
50
|
+
throw new Error("Maven dev-publish is not implemented yet. " +
|
|
51
|
+
"Override getCurrentVersion() in a concrete subclass.");
|
|
52
|
+
}
|
|
53
|
+
async publish(_ctx, _alphaVersion) {
|
|
54
|
+
throw new Error("Maven dev-publish is not implemented yet. " +
|
|
55
|
+
"Override publish() in a concrete subclass.");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.MavenReleaseAdapter = MavenReleaseAdapter;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.NodeProdPublishAdapter = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const semver_1 = __importDefault(require("semver"));
|
|
10
|
+
const quark_security_1 = require("@quark-hq/quark-security");
|
|
11
|
+
const nodeRegistryEnv_1 = require("../config/nodeRegistryEnv");
|
|
12
|
+
class NodeProdPublishAdapter {
|
|
13
|
+
constructor(quarkConfig, logger) {
|
|
14
|
+
this.quarkConfig = quarkConfig;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
supports(meta) {
|
|
18
|
+
return meta.platform === "node";
|
|
19
|
+
}
|
|
20
|
+
async readPackageIdentity(packageDir) {
|
|
21
|
+
const safeDir = (0, quark_security_1.assertPathInsideRoot)(process.cwd(), packageDir);
|
|
22
|
+
const pkgJsonPath = path_1.default.join(safeDir, "package.json");
|
|
23
|
+
const raw = await promises_1.default.readFile(pkgJsonPath, "utf8");
|
|
24
|
+
const pkgJson = JSON.parse(raw);
|
|
25
|
+
return { name: pkgJson.name, version: pkgJson.version };
|
|
26
|
+
}
|
|
27
|
+
async versionExistsInRegistry(packageName, version) {
|
|
28
|
+
(0, quark_security_1.assertValidNpmPackageName)(packageName, "package name");
|
|
29
|
+
if (!semver_1.default.valid(version)) {
|
|
30
|
+
throw new Error(`Invalid semver version: ${version}`);
|
|
31
|
+
}
|
|
32
|
+
const registries = this.getUniqueRegistryUrls();
|
|
33
|
+
for (const url of registries) {
|
|
34
|
+
const r = (0, quark_security_1.spawnSyncSafe)("npm", [
|
|
35
|
+
"view",
|
|
36
|
+
`${packageName}@${version}`,
|
|
37
|
+
"version",
|
|
38
|
+
"--registry",
|
|
39
|
+
url,
|
|
40
|
+
], { stdio: "pipe" });
|
|
41
|
+
if (r.status === 0 && !r.error) {
|
|
42
|
+
this.logger.warn(`${packageName}@${version} already exists in registry: ${(0, quark_security_1.stripUrlCredentials)(url)}`);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Publishes to registries in order: dev (or fallback {@link NodePublishConfig.registryUrl}),
|
|
50
|
+
* then prod — matching the legacy prod-publish flow. Duplicate URLs are skipped so the same
|
|
51
|
+
* registry is not published twice.
|
|
52
|
+
*/
|
|
53
|
+
async publish(packageDir) {
|
|
54
|
+
const safeDir = (0, quark_security_1.assertPathInsideRoot)(process.cwd(), packageDir);
|
|
55
|
+
const registries = this.getPublishRegistryUrlsInOrder();
|
|
56
|
+
for (const registryUrl of registries) {
|
|
57
|
+
this.logger.info(`Publishing to registry: ${(0, quark_security_1.stripUrlCredentials)(registryUrl)}`);
|
|
58
|
+
(0, quark_security_1.assertSpawnOk)((0, quark_security_1.spawnSyncSafe)("pnpm", [
|
|
59
|
+
"publish",
|
|
60
|
+
"--registry",
|
|
61
|
+
registryUrl,
|
|
62
|
+
"--no-git-checks",
|
|
63
|
+
], {
|
|
64
|
+
cwd: safeDir,
|
|
65
|
+
stdio: "inherit",
|
|
66
|
+
}), `pnpm publish (${(0, quark_security_1.stripUrlCredentials)(registryUrl)})`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Ordered list for publish: dev URL first, then prod URL. Values come from
|
|
71
|
+
* `.env` (`DEV_REGISTRY_URL`, `PROD_REGISTRY_URL`) when set, else quark-config
|
|
72
|
+
* {@link NodePublishConfig.devRegistryUrl}, {@link NodePublishConfig.prodRegistryUrl},
|
|
73
|
+
* {@link NodePublishConfig.registryUrl}.
|
|
74
|
+
*/
|
|
75
|
+
getPublishRegistryUrlsInOrder() {
|
|
76
|
+
const nodeConfig = this.quarkConfig.publish?.node;
|
|
77
|
+
const devUrl = (0, nodeRegistryEnv_1.effectiveDevRegistryUrl)(nodeConfig);
|
|
78
|
+
const prodUrl = (0, nodeRegistryEnv_1.effectiveProdRegistryUrl)(nodeConfig);
|
|
79
|
+
const ordered = [];
|
|
80
|
+
if (devUrl) {
|
|
81
|
+
ordered.push(devUrl);
|
|
82
|
+
}
|
|
83
|
+
if (prodUrl && prodUrl !== devUrl) {
|
|
84
|
+
ordered.push(prodUrl);
|
|
85
|
+
}
|
|
86
|
+
if (ordered.length === 0) {
|
|
87
|
+
throw new Error("No registry URLs configured. Set DEV_REGISTRY_URL / PROD_REGISTRY_URL in .env or publish.node.registryUrl (and optional dev/prod URLs) in quark-config.json");
|
|
88
|
+
}
|
|
89
|
+
return ordered;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns deduplicated list of all registry URLs that need checking.
|
|
93
|
+
* Collects the effective dev URL and effective prod URL, then deduplicates.
|
|
94
|
+
* If both flows resolve to the same URL, only one check is performed.
|
|
95
|
+
*/
|
|
96
|
+
getUniqueRegistryUrls() {
|
|
97
|
+
const nodeConfig = this.quarkConfig.publish?.node;
|
|
98
|
+
const effectiveDevUrl = (0, nodeRegistryEnv_1.effectiveDevRegistryUrl)(nodeConfig);
|
|
99
|
+
const effectiveProdUrl = (0, nodeRegistryEnv_1.effectiveProdRegistryUrl)(nodeConfig);
|
|
100
|
+
const urls = new Set();
|
|
101
|
+
if (effectiveDevUrl)
|
|
102
|
+
urls.add(effectiveDevUrl);
|
|
103
|
+
if (effectiveProdUrl)
|
|
104
|
+
urls.add(effectiveProdUrl);
|
|
105
|
+
if (urls.size === 0) {
|
|
106
|
+
throw new Error("No registry URLs configured. Set DEV_REGISTRY_URL / PROD_REGISTRY_URL in .env or publish.node.registryUrl in quark-config.json");
|
|
107
|
+
}
|
|
108
|
+
return [...urls];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.NodeProdPublishAdapter = NodeProdPublishAdapter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|