@platforma-sdk/block-tools 2.4.2 → 2.4.3

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": "@platforma-sdk/block-tools",
3
- "version": "2.4.2",
3
+ "version": "2.4.3",
4
4
  "description": "Utility to manipulate Platforma Blocks and Block Registry",
5
5
  "types": "./dist/lib.d.ts",
6
6
  "main": "./dist/index.js",
@@ -33,9 +33,9 @@
33
33
  "tar": "^7.4.3",
34
34
  "yaml": "^2.6.1",
35
35
  "zod": "^3.23.8",
36
+ "@milaboratories/ts-helpers-oclif": "^1.1.11",
36
37
  "@milaboratories/pl-model-middle-layer": "^1.6.1",
37
38
  "@milaboratories/resolve-helper": "^1.0.2",
38
- "@milaboratories/ts-helpers-oclif": "^1.1.11",
39
39
  "@milaboratories/ts-helpers": "^1.1.2"
40
40
  },
41
41
  "devDependencies": {
@@ -69,8 +69,8 @@
69
69
  "scripts": {
70
70
  "type-check": "tsc --noEmit --composite false",
71
71
  "oclif:index": "oclif-index --commands-root=./src/cmd/ --index-file=./src/cmd/index.ts",
72
- "build": "pnpm run oclif:index && vite build",
73
- "readme": "exec oclif readme",
72
+ "build": "vite build",
73
+ "readme": "oclif readme",
74
74
  "test": "jest"
75
75
  }
76
76
  }
package/src/cmd/index.ts CHANGED
@@ -5,7 +5,8 @@ import Cmd1 from './build-model';
5
5
  import Cmd3 from './mark-stable';
6
6
  import Cmd4 from './pack';
7
7
  import Cmd5 from './publish';
8
- import Cmd6 from './upload-package-v1';
8
+ import Cmd6 from './refresh-registry';
9
+ import Cmd7 from './upload-package-v1';
9
10
 
10
11
  // prettier-ignore
11
12
  export const COMMANDS = {
@@ -14,5 +15,6 @@ export const COMMANDS = {
14
15
  'mark-stable': Cmd3,
15
16
  'pack': Cmd4,
16
17
  'publish': Cmd5,
17
- 'upload-package-v1': Cmd6
18
+ 'refresh-registry': Cmd6,
19
+ 'upload-package-v1': Cmd7
18
20
  };
@@ -0,0 +1,40 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { BlockRegistryV2, loadPackDescriptionRaw } from '../v2';
3
+ import path from 'path';
4
+ import {
5
+ overrideDescriptionVersion,
6
+ overrideManifestVersion,
7
+ StableChannel
8
+ } from '@milaboratories/pl-model-middle-layer';
9
+ import { storageByUrl } from '../io';
10
+ import { OclifLoggerAdapter } from '@milaboratories/ts-helpers-oclif';
11
+
12
+ export default class RefreshRegistry extends Command {
13
+ static description = 'Refresh overview files based on published but not proecessed artefacts';
14
+
15
+ static flags = {
16
+ registry: Flags.string({
17
+ char: 'r',
18
+ summary: 'full address of the registry',
19
+ helpValue: '<address>',
20
+ env: 'PL_REGISTRY',
21
+ required: true
22
+ }),
23
+
24
+ mode: Flags.string({
25
+ char: 'm',
26
+ summary: 'refresh mode (allowed valiues: "force", "normal", "dry-run")',
27
+ helpValue: '<mode>',
28
+ options: ['force', 'normal', 'dry-run'],
29
+ env: 'PL_REGISTRY_REFRESH_DRY_RUN',
30
+ default: 'normal'
31
+ })
32
+ };
33
+
34
+ public async run(): Promise<void> {
35
+ const { flags } = await this.parse(RefreshRegistry);
36
+ const storage = storageByUrl(flags.registry);
37
+ const registry = new BlockRegistryV2(storage, new OclifLoggerAdapter(this));
38
+ await registry.updateIfNeeded(flags.mode as 'force' | 'normal' | 'dry-run');
39
+ }
40
+ }
@@ -65,6 +65,10 @@ if (testS3Address) {
65
65
  const testS3AddressURL = new URL(testS3Address);
66
66
  testS3AddressURL.pathname = `${testS3AddressURL.pathname.replace(/\/$/, '')}/${uuid}`;
67
67
  const storage = storageByUrl(testS3AddressURL.toString()) as S3Storage;
68
+
69
+ const nonExistingFolderListing = await storage.listFiles('not_existing_folder');
70
+ expect(nonExistingFolderListing).toEqual([]);
71
+
68
72
  await storage.putFile('some/deep1/file_1.txt', Buffer.from('test1'));
69
73
  await storage.putFile('some/deep1/file_2.txt', Buffer.from('test1'));
70
74
  await storage.putFile('some/deep2/file_1.txt', Buffer.from('test1'));
package/src/io/storage.ts CHANGED
@@ -47,7 +47,7 @@ export class S3Storage implements RegistryStorage {
47
47
  );
48
48
  const result: string[] = [];
49
49
  for await (const page of paginator)
50
- result.push(...page.Contents!.map((e) => pathPosix.relative(listRoot, e.Key!)));
50
+ result.push(...(page.Contents ?? []).map((e) => pathPosix.relative(listRoot, e.Key!)));
51
51
  return result;
52
52
  }
53
53
 
@@ -45,14 +45,14 @@ export class BlockRegistryV2 {
45
45
  private readonly logger: MiLogger = new ConsoleLoggerAdapter()
46
46
  ) {}
47
47
 
48
- private async updateRegistry() {
49
- this.logger?.info('Initiating registry refresh...');
48
+ private async updateRegistry(dryRun: boolean = false) {
49
+ this.logger.info('Initiating registry refresh...');
50
50
 
51
51
  // reading update requests
52
52
  const packagesToUpdate = new Map<string, PackageUpdateInfo>();
53
53
  const seedPaths: string[] = [];
54
54
  const rawSeedPaths = await this.storage.listFiles(VersionUpdatesPrefix);
55
- this.logger?.info('Packages to be updated:');
55
+ this.logger.info('Packages to be updated:');
56
56
  for (const seedPath of rawSeedPaths) {
57
57
  const match = seedPath.match(PackageUpdatePattern);
58
58
  if (!match) continue;
@@ -71,7 +71,7 @@ export class BlockRegistryV2 {
71
71
  update.versions.add(version);
72
72
  added = true;
73
73
  }
74
- this.logger?.info(` - ${organization}:${name}:${version} added:${added}`);
74
+ this.logger.info(` - ${organization}:${name}:${version} added:${added}`);
75
75
  }
76
76
 
77
77
  // loading global overview
@@ -81,7 +81,7 @@ export class BlockRegistryV2 {
81
81
  ? { schema: 'v2', packages: [] }
82
82
  : GlobalOverviewReg.parse(JSON.parse(overviewContent.toString()));
83
83
  let overviewPackages = overview.packages;
84
- this.logger?.info(`Global overview loaded, ${overviewPackages.length} records`);
84
+ this.logger.info(`Global overview loaded, ${overviewPackages.length} records`);
85
85
 
86
86
  // updating packages
87
87
  for (const [, packageInfo] of packagesToUpdate.entries()) {
@@ -92,7 +92,7 @@ export class BlockRegistryV2 {
92
92
  pOverviewContent === undefined
93
93
  ? { schema: 'v2', versions: [] }
94
94
  : PackageOverview.parse(JSON.parse(pOverviewContent.toString()));
95
- this.logger?.info(
95
+ this.logger.info(
96
96
  `Updating ${packageInfo.package.organization}:${packageInfo.package.name} overview, ${packageOverview.versions.length} records`
97
97
  );
98
98
 
@@ -137,13 +137,14 @@ export class BlockRegistryV2 {
137
137
  );
138
138
 
139
139
  // write package overview back
140
- await this.storage.putFile(
141
- overviewFile,
142
- Buffer.from(
143
- JSON.stringify({ schema: 'v2', versions: newVersions } satisfies PackageOverview)
144
- )
145
- );
146
- this.logger?.info(`Done (${newVersions.length} records)`);
140
+ if (!dryRun)
141
+ await this.storage.putFile(
142
+ overviewFile,
143
+ Buffer.from(
144
+ JSON.stringify({ schema: 'v2', versions: newVersions } satisfies PackageOverview)
145
+ )
146
+ );
147
+ this.logger.info(`Done (${newVersions.length} records)`);
147
148
 
148
149
  // calculating all channels
149
150
  const allChannels = new Set<string>();
@@ -183,39 +184,47 @@ export class BlockRegistryV2 {
183
184
  }
184
185
 
185
186
  // writing global overview
186
- await this.storage.putFile(
187
- GlobalOverviewPath,
188
- Buffer.from(
189
- JSON.stringify({ schema: 'v2', packages: overviewPackages } satisfies GlobalOverviewReg)
190
- )
191
- );
192
- this.logger?.info(`Global overview updated (${overviewPackages.length} records)`);
187
+ if (!dryRun)
188
+ await this.storage.putFile(
189
+ GlobalOverviewPath,
190
+ Buffer.from(
191
+ JSON.stringify({ schema: 'v2', packages: overviewPackages } satisfies GlobalOverviewReg)
192
+ )
193
+ );
194
+ this.logger.info(`Global overview updated (${overviewPackages.length} records)`);
193
195
 
194
196
  // deleting seeds
195
- await this.storage.deleteFiles(...seedPaths.map((sp) => `${VersionUpdatesPrefix}${sp}`));
196
- this.logger?.info(`Version update requests cleared`);
197
+ if (!dryRun)
198
+ await this.storage.deleteFiles(...seedPaths.map((sp) => `${VersionUpdatesPrefix}${sp}`));
199
+ this.logger.info(`Version update requests cleared`);
197
200
  }
198
201
 
199
- public async updateIfNeeded(force: boolean = false): Promise<void> {
202
+ public async updateIfNeeded(mode: 'force' | 'normal' | 'dry-run' = 'normal'): Promise<void> {
200
203
  // implementation of main convergence algorithm
201
204
 
202
- this.logger?.info(`Checking if registry requires refresh...`);
205
+ this.logger.info(`Checking if registry requires refresh...`);
203
206
  const updateRequestSeed = await this.storage.getFile(GlobalUpdateSeedInFile);
204
207
  const currentUpdatedSeed = await this.storage.getFile(GlobalUpdateSeedOutFile);
205
- if (!force && updateRequestSeed === undefined && currentUpdatedSeed === undefined) return;
208
+ if (mode !== 'force' && updateRequestSeed === undefined && currentUpdatedSeed === undefined) {
209
+ this.logger.info(`No global seed files found, update not needed.`);
210
+ return;
211
+ }
206
212
  if (
207
- !force &&
213
+ mode !== 'force' &&
208
214
  updateRequestSeed !== undefined &&
209
215
  currentUpdatedSeed !== undefined &&
210
216
  updateRequestSeed.equals(currentUpdatedSeed)
211
- )
217
+ ) {
218
+ this.logger.info(`Registry is up to date.`);
212
219
  return;
220
+ }
213
221
 
214
- await this.updateRegistry();
222
+ await this.updateRegistry(mode === 'dry-run');
215
223
 
216
224
  if (updateRequestSeed) {
217
- await this.storage.putFile(GlobalUpdateSeedOutFile, updateRequestSeed);
218
- this.logger?.info(`Refresh finished`);
225
+ if (mode !== 'dry-run')
226
+ await this.storage.putFile(GlobalUpdateSeedOutFile, updateRequestSeed);
227
+ this.logger.info(`Refresh finished.`);
219
228
  }
220
229
  }
221
230
 
@@ -237,9 +246,9 @@ export class BlockRegistryV2 {
237
246
  // adding update seed
238
247
  const seed = randomUUID();
239
248
  const seedPath = packageUpdateSeedPath(id, seed);
240
- this.logger?.info(`Creating update seed at ${seedPath} ...`);
249
+ this.logger.info(`Creating update seed at ${seedPath} ...`);
241
250
  await this.storage.putFile(seedPath, Buffer.from(seed));
242
- this.logger?.info(`Touching global update seed ${GlobalUpdateSeedInFile} ...`);
251
+ this.logger.info(`Touching global update seed ${GlobalUpdateSeedInFile} ...`);
243
252
  await this.storage.putFile(GlobalUpdateSeedInFile, Buffer.from(seed));
244
253
  }
245
254
 
@@ -288,13 +297,13 @@ export class BlockRegistryV2 {
288
297
  );
289
298
 
290
299
  const dst = prefix + '/' + f.name;
291
- this.logger?.info(`Uploading ${f.name} -> ${dst} ...`);
300
+ this.logger.info(`Uploading ${f.name} -> ${dst} ...`);
292
301
  await this.storage.putFile(dst, bytes);
293
302
  }
294
303
 
295
304
  // uploading manifest as the last upload action
296
305
  const manifestDst = prefix + '/' + ManifestFileName;
297
- this.logger?.info(`Uploading manifest to ${manifestDst} ...`);
306
+ this.logger.info(`Uploading manifest to ${manifestDst} ...`);
298
307
  await this.storage.putFile(manifestDst, Buffer.from(JSON.stringify(manifest)));
299
308
 
300
309
  await this.marchChanged(manifest.description.id);