@git.zone/cli 6.1.2 → 6.2.0

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.
@@ -5,7 +5,33 @@ import {
5
5
  } from "./classes.releasejournal.js";
6
6
  import { assertCredentialFreeGitPushDestination } from "./helpers.releasebranch.js";
7
7
 
8
- const supportedPnpmVersion = "11.25.0";
8
+ const supportedPnpmVersions = ["11.25.0", "12.3.4"] as const;
9
+ const pnpmHelpRequirements = {
10
+ "11.25.0": {
11
+ pack: ["--out <path>", "--json"],
12
+ publish: [
13
+ "publish [<tarball>|<dir>]",
14
+ "--no-git-checks",
15
+ "--ignore-scripts",
16
+ "--json",
17
+ "--tag <tag>",
18
+ "--access <public|restricted>",
19
+ ],
20
+ },
21
+ "12.3.4": {
22
+ pack: ["Usage: pnpm pack [OPTIONS]", "--out <OUT>", "--json"],
23
+ publish: [
24
+ "Usage: pnpm publish [OPTIONS] [PACKAGE]",
25
+ "Tarball or directory to publish",
26
+ "--no-git-checks",
27
+ "--ignore-scripts",
28
+ "--json",
29
+ "--tag <TAG>",
30
+ "--access <ACCESS>",
31
+ "[possible values: public, restricted]",
32
+ ],
33
+ },
34
+ } as const;
9
35
  const maximumMetadataResponseBytes = 8 * 1024 * 1024;
10
36
  const capabilityCommandTimeoutMs = 30_000;
11
37
  const packCommandTimeoutMs = 10 * 60_000;
@@ -13,7 +39,7 @@ const publishCommandTimeoutMs = 5 * 60_000;
13
39
  const packageNameRegex = /^(?:@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)$/;
14
40
 
15
41
  export interface IPnpmReleaseCapability {
16
- version: typeof supportedPnpmVersion;
42
+ version: (typeof supportedPnpmVersions)[number];
17
43
  }
18
44
 
19
45
  export type TNpmArtifactProbeStatus =
@@ -72,10 +98,12 @@ const readPackageIdentity = async (
72
98
 
73
99
  const requireHelpFragments = (
74
100
  outputArg: string,
75
- fragmentsArg: string[],
101
+ fragmentsArg: readonly string[],
76
102
  commandArg: string,
77
103
  ): void => {
78
- const missing = fragmentsArg.filter((fragmentArg) => !outputArg.includes(fragmentArg));
104
+ const missing = fragmentsArg.filter(
105
+ (fragmentArg) => !outputArg.includes(fragmentArg),
106
+ );
79
107
  if (missing.length > 0) {
80
108
  throw new Error(
81
109
  `pnpm ${commandArg} is missing required exact-release capabilities: ${missing.join(", ")}.`,
@@ -94,11 +122,15 @@ export const assertPnpmReleaseCapability = async (
94
122
  timeoutKillGraceMs: 5_000,
95
123
  });
96
124
  const version = versionResult.stdout.trim();
97
- if (versionResult.exitCode !== 0 || version !== supportedPnpmVersion) {
125
+ const supportedVersion = supportedPnpmVersions.find(
126
+ (candidateArg) => candidateArg === version,
127
+ );
128
+ if (versionResult.exitCode !== 0 || !supportedVersion) {
98
129
  throw new Error(
99
- `Exact release packaging requires the verified pnpm ${supportedPnpmVersion}; resolved ${version || "unknown"}.`,
130
+ `Exact release packaging requires a verified pnpm version (${supportedPnpmVersions.join(", ")}); resolved ${version || "unknown"}.`,
100
131
  );
101
132
  }
133
+ const requirements = pnpmHelpRequirements[supportedVersion];
102
134
 
103
135
  const packHelp = await smartshellArg.execSpawn("pnpm", ["pack", "--help"], {
104
136
  cwd: cwdArg,
@@ -109,7 +141,7 @@ export const assertPnpmReleaseCapability = async (
109
141
  if (packHelp.exitCode !== 0) {
110
142
  throw new Error("Unable to inspect pnpm pack capabilities.");
111
143
  }
112
- requireHelpFragments(packHelp.combinedOutput, ["--out <path>", "--json"], "pack");
144
+ requireHelpFragments(packHelp.combinedOutput, requirements.pack, "pack");
113
145
 
114
146
  const publishHelp = await smartshellArg.execSpawn(
115
147
  "pnpm",
@@ -126,17 +158,10 @@ export const assertPnpmReleaseCapability = async (
126
158
  }
127
159
  requireHelpFragments(
128
160
  publishHelp.combinedOutput,
129
- [
130
- "publish [<tarball>|<dir>]",
131
- "--no-git-checks",
132
- "--ignore-scripts",
133
- "--json",
134
- "--tag <tag>",
135
- "--access <public|restricted>",
136
- ],
161
+ requirements.publish,
137
162
  "publish",
138
163
  );
139
- return { version: supportedPnpmVersion };
164
+ return { version: supportedVersion };
140
165
  };
141
166
 
142
167
  const legacyPublishWorkflowPaths = [
@@ -60,15 +60,19 @@ export interface IDockerArgvExecutionErrorOptions {
60
60
  signal?: NodeJS.Signals;
61
61
  }
62
62
 
63
- export interface IFencedBindOperationOptions {
63
+ export interface IFencedBindOperationSpecification {
64
+ entrypoint: string;
65
+ command: readonly string[];
66
+ }
67
+
68
+ export interface IFencedBindOperationOptions extends IFencedBindOperationSpecification {
64
69
  image: string;
65
70
  hostPath: string;
66
71
  containerPath: string;
67
- entrypoint: string;
68
- command: readonly string[];
69
72
  labels: Record<string, string>;
70
73
  executionOptions: () => IDockerExecArgvOptions;
71
74
  rollbackTimeoutMs?: number;
75
+ recoverablePredecessors?: readonly IFencedBindOperationSpecification[];
72
76
  }
73
77
 
74
78
  interface IFencedBindRuntimeOptions extends IFencedBindOperationOptions {
@@ -607,16 +611,23 @@ export class DockerContainer {
607
611
  inspectionArg.mounts.length === 1 &&
608
612
  inspectionArg.mounts[0].source === plugins.path.resolve(optionsArg.hostPath) &&
609
613
  inspectionArg.mounts[0].readWrite;
614
+ const operationMatches = [
615
+ { entrypoint: optionsArg.entrypoint, command: optionsArg.command },
616
+ ...(optionsArg.recoverablePredecessors ?? []),
617
+ ].some(
618
+ (specificationArg) =>
619
+ inspectionArg.entrypoint.length === 1 &&
620
+ inspectionArg.entrypoint[0] === specificationArg.entrypoint &&
621
+ inspectionArg.command.length === specificationArg.command.length &&
622
+ inspectionArg.command.every(
623
+ (entryArg, indexArg) => entryArg === specificationArg.command[indexArg],
624
+ ),
625
+ );
610
626
  if (
611
627
  inspectionArg.name !== expectedNameArg ||
612
628
  inspectionArg.image !== optionsArg.image ||
613
629
  inspectionArg.user !== '0' ||
614
- inspectionArg.entrypoint.length !== 1 ||
615
- inspectionArg.entrypoint[0] !== optionsArg.entrypoint ||
616
- inspectionArg.command.length !== optionsArg.command.length ||
617
- !inspectionArg.command.every(
618
- (entryArg, indexArg) => entryArg === optionsArg.command[indexArg],
619
- ) ||
630
+ !operationMatches ||
620
631
  !labelsMatch ||
621
632
  !mountMatches ||
622
633
  inspectionArg.mounts[0].destination !== optionsArg.containerPath
@@ -1315,8 +1315,11 @@ export class ServiceManager {
1315
1315
  image: objectStorageImage,
1316
1316
  hostPath: dataPath,
1317
1317
  containerPath: '/data',
1318
- entrypoint: '/bin/chown',
1319
- command: ['-R', 'objectstorage:objectstorage', '/data'],
1318
+ entrypoint: '/bin/sh',
1319
+ command: [
1320
+ '-c',
1321
+ '/bin/chown -R objectstorage:objectstorage /data && /bin/chmod 0700 /data',
1322
+ ],
1320
1323
  labels: {
1321
1324
  'git.zone.tool': serviceToolLabel,
1322
1325
  'git.zone.service': 'objectstorage',
@@ -1327,6 +1330,12 @@ export class ServiceManager {
1327
1330
  },
1328
1331
  executionOptions: dockerTimeoutArg,
1329
1332
  rollbackTimeoutMs: objectStorageRollbackTimeoutMs,
1333
+ recoverablePredecessors: [
1334
+ {
1335
+ entrypoint: '/bin/chown',
1336
+ command: ['-R', 'objectstorage:objectstorage', '/data'],
1337
+ },
1338
+ ],
1330
1339
  });
1331
1340
  return labels;
1332
1341
  }
@@ -1590,6 +1599,28 @@ export class ServiceManager {
1590
1599
  await this.config.validateObjectStoragePorts();
1591
1600
  }
1592
1601
 
1602
+ if (initialInspection?.status === 'restarting') {
1603
+ logger.log('note', ' Stopping restart loop before securing data...');
1604
+ await this.revalidateObjectStorageContainer(
1605
+ initialInspection.id,
1606
+ containers.objectstorage,
1607
+ expectedLabels,
1608
+ dockerTimeout,
1609
+ );
1610
+ await this.docker.execArgv(['stop', initialInspection.id], dockerTimeout());
1611
+ initialInspection = await this.revalidateObjectStorageContainer(
1612
+ initialInspection.id,
1613
+ containers.objectstorage,
1614
+ expectedLabels,
1615
+ dockerTimeout,
1616
+ );
1617
+ if (initialInspection.running || initialInspection.status === 'restarting') {
1618
+ throw new Error(
1619
+ `ObjectStorage container ${containers.objectstorage} remained in its restart loop.`,
1620
+ );
1621
+ }
1622
+ }
1623
+
1593
1624
  const needsRecreate =
1594
1625
  !!initialInspection &&
1595
1626
  !this.objectStorageConfigurationMatches(initialInspection, expectedLabels);
@@ -1614,6 +1645,7 @@ export class ServiceManager {
1614
1645
  ? 'Recreated with canonical configuration and reconciled'
1615
1646
  : 'Created, started, and reconciled';
1616
1647
  } else if (!initialInspection.running) {
1648
+ await this.prepareObjectStorageDataDirectory(dockerTimeout);
1617
1649
  logger.log('note', ' Starting existing container...');
1618
1650
  activeInspection = initialInspection;
1619
1651
  await startById(activeInspection.id, false);
File without changes