gt 2.11.2 → 2.11.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.11.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1133](https://github.com/generaltranslation/gt/pull/1133) [`4de22d7`](https://github.com/generaltranslation/gt/commit/4de22d7548b5d34c0d7e465132878d192c2f41e0) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Extending publish step to save-local and upload commands
8
+
3
9
  ## 2.11.2
4
10
 
5
11
  ### Patch Changes
@@ -6,4 +6,4 @@ import { FileReference } from 'generaltranslation/types';
6
6
  *
7
7
  * Must run before enqueueing new translations so rules are available to the generator.
8
8
  */
9
- export declare function collectAndSendUserEditDiffs(files: FileReference[], settings: Settings): Promise<void>;
9
+ export declare function collectAndSendUserEditDiffs(files: FileReference[], settings: Settings): Promise<boolean>;
@@ -26,7 +26,7 @@ const findLatestDownloadedVersion = (entryMap, fileId, locale) => {
26
26
  */
27
27
  export async function collectAndSendUserEditDiffs(files, settings) {
28
28
  if (!settings.files)
29
- return;
29
+ return false;
30
30
  const { resolvedPaths, placeholderPaths, transformPaths } = settings.files;
31
31
  const fileMapping = createFileMapping(resolvedPaths, placeholderPaths, transformPaths, settings.locales, settings.defaultLocale);
32
32
  const { entryMap } = readLockfile(settings);
@@ -153,4 +153,5 @@ export async function collectAndSendUserEditDiffs(files, settings) {
153
153
  if (collectedDiffs.length > 0) {
154
154
  await gt.submitUserEditDiffs({ diffs: collectedDiffs });
155
155
  }
156
+ return collectedDiffs.length > 0;
156
157
  }
@@ -5,6 +5,7 @@ import { BranchStep } from '../workflows/steps/BranchStep.js';
5
5
  import { logErrorAndExit } from '../console/logging.js';
6
6
  import { logger } from '../console/logger.js';
7
7
  import chalk from 'chalk';
8
+ import { runPublishWorkflow } from '../workflows/publish.js';
8
9
  /**
9
10
  * Uploads current source files to obtain file references, then collects and sends
10
11
  * diffs for all locales based on last downloaded versions. Does not enqueue translations.
@@ -13,7 +14,7 @@ export async function saveLocalEdits(settings) {
13
14
  if (!settings.files)
14
15
  return;
15
16
  // Collect current files from config
16
- const { files } = await aggregateFiles(settings);
17
+ const { files, publishMap } = await aggregateFiles(settings);
17
18
  if (!files.length)
18
19
  return;
19
20
  // run branch query to get branch id
@@ -33,6 +34,10 @@ export async function saveLocalEdits(settings) {
33
34
  }));
34
35
  const spinner = logger.createSpinner('dots');
35
36
  spinner.start('Saving local edits...');
36
- await collectAndSendUserEditDiffs(uploads, settings);
37
+ const hadDiffs = await collectAndSendUserEditDiffs(uploads, settings);
37
38
  spinner.stop(chalk.green('Local edits saved successfully'));
39
+ // Publish files to CDN if diffs were detected and publish config exists
40
+ if (hadDiffs) {
41
+ await runPublishWorkflow(files, publishMap, branchResult.currentBranch.id, settings);
42
+ }
38
43
  }
package/dist/cli/base.js CHANGED
@@ -121,7 +121,9 @@ export class BaseCLI {
121
121
  setupSendDiffsCommand() {
122
122
  attachSharedFlags(this.program
123
123
  .command('save-local')
124
- .description('Save local edits for all configured files by sending diffs (no translation enqueued)')).action(async (initOptions) => {
124
+ .description('Save local edits for all configured files by sending diffs (no translation enqueued)'))
125
+ .option('--publish', 'Publish translations to the CDN', false)
126
+ .action(async (initOptions) => {
125
127
  displayHeader('Saving local edits...');
126
128
  const settings = await generateSettings(initOptions);
127
129
  await saveLocalEdits(settings);
@@ -9,9 +9,7 @@ import processOpenApi from '../../utils/processOpenApi.js';
9
9
  import localizeStaticImports from '../../utils/localizeStaticImports.js';
10
10
  import { getDownloadedMeta } from '../../state/recentDownloads.js';
11
11
  import { persistPostProcessHashes } from '../../utils/persistPostprocessHashes.js';
12
- import { PublishStep } from '../../workflows/steps/PublishStep.js';
13
- import { gt } from '../../utils/gt.js';
14
- import { hasPublishConfig } from '../../utils/resolvePublish.js';
12
+ import { runPublishWorkflow } from '../../workflows/publish.js';
15
13
  // Downloads translations that were completed
16
14
  export async function handleTranslate(options, settings, fileVersionData, jobData, branchData, publishMap) {
17
15
  if (fileVersionData) {
@@ -30,19 +28,13 @@ export async function handleTranslate(options, settings, fileVersionData, jobDat
30
28
  forceDownload: options.forceDownload || options.force, // if force is true should also force download
31
29
  });
32
30
  // Publish/unpublish files after translations are downloaded
33
- if (publishMap && hasPublishConfig(settings)) {
34
- const allFileRefs = Object.entries(fileVersionData)
35
- .filter(([fileId]) => publishMap.has(fileId))
36
- .map(([fileId, data]) => ({
31
+ if (publishMap && branchData?.currentBranch.id) {
32
+ const files = Object.entries(fileVersionData).map(([fileId, data]) => ({
37
33
  fileId,
38
34
  versionId: data.versionId,
39
- branchId: branchData?.currentBranch.id,
40
- publish: publishMap.get(fileId),
41
35
  fileName: data.fileName,
42
36
  }));
43
- const publishStep = new PublishStep(gt);
44
- await publishStep.run(allFileRefs);
45
- await publishStep.wait();
37
+ await runPublishWorkflow(files, publishMap, branchData.currentBranch.id, settings);
46
38
  }
47
39
  }
48
40
  }
@@ -13,6 +13,8 @@ import { createFileMapping } from '../../formats/files/fileMapping.js';
13
13
  import parseYaml from '../../formats/yaml/parseYaml.js';
14
14
  import { hashStringSync } from '../../utils/hash.js';
15
15
  import { hasValidCredentials } from './utils/validation.js';
16
+ import { buildPublishMap } from '../../utils/resolvePublish.js';
17
+ import { runPublishWorkflow } from '../../workflows/publish.js';
16
18
  const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
17
19
  /**
18
20
  * Sends multiple files to the API for translation
@@ -180,7 +182,13 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
180
182
  });
181
183
  try {
182
184
  // Send all files in a single API call
183
- await runUploadFilesWorkflow({ files: uploadData, options: settings });
185
+ const { branchData } = await runUploadFilesWorkflow({
186
+ files: uploadData,
187
+ options: settings,
188
+ });
189
+ // Publish files to CDN if publish config exists
190
+ const publishMap = buildPublishMap(filePaths, settings);
191
+ await runPublishWorkflow(allFiles, publishMap, branchData.currentBranch.id, settings);
184
192
  }
185
193
  catch (error) {
186
194
  logErrorAndExit(`Error uploading files: ${error}`);
@@ -11,7 +11,7 @@ import { determineLibrary } from '../../fs/determineFramework/index.js';
11
11
  import { hashStringSync } from '../../utils/hash.js';
12
12
  import { preprocessContent } from './preprocessContent.js';
13
13
  import { parseKeyedMetadata, } from '../parseKeyedMetadata.js';
14
- import { shouldPublishFile } from '../../utils/resolvePublish.js';
14
+ import { buildPublishMap } from '../../utils/resolvePublish.js';
15
15
  /**
16
16
  * Checks if a file path is a metadata companion file (e.g. foo.metadata.json)
17
17
  * AND its corresponding source file (e.g. foo.json) exists in the file list.
@@ -29,32 +29,15 @@ export const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
29
29
  export async function aggregateFiles(settings) {
30
30
  // Aggregate all files to translate
31
31
  const files = [];
32
- const publishMap = new Map();
33
32
  if (!settings.files ||
34
33
  (Object.keys(settings.files.placeholderPaths).length === 1 &&
35
34
  settings.files.placeholderPaths.gt)) {
36
- return { files, publishMap };
35
+ return { files, publishMap: new Map() };
37
36
  }
38
37
  const { resolvedPaths: filePaths } = settings.files;
39
38
  const skipValidation = settings.options?.skipFileValidation;
40
39
  // Build publish map upfront from resolved paths.
41
- // Only include files that have an explicit publish config or when a global
42
- // publish flag is defined. Files without any config are left out of the map
43
- // so the publish endpoint is never called for them.
44
- const hasGlobalPublish = settings.publish !== undefined;
45
- for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
46
- if (filePaths[fileType]) {
47
- for (const absolutePath of filePaths[fileType]) {
48
- const hasExplicitConfig = settings.files.publishPaths?.has(absolutePath) ||
49
- settings.files.unpublishPaths?.has(absolutePath);
50
- if (hasGlobalPublish || hasExplicitConfig) {
51
- const relativePath = getRelative(absolutePath);
52
- const fileId = hashStringSync(relativePath);
53
- publishMap.set(fileId, shouldPublishFile(absolutePath, settings));
54
- }
55
- }
56
- }
57
- }
40
+ const publishMap = buildPublishMap(filePaths, settings);
58
41
  // Process JSON files
59
42
  if (filePaths.json) {
60
43
  const { library, additionalModules } = determineLibrary();
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.11.2";
1
+ export declare const PACKAGE_VERSION = "2.11.3";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.11.2';
2
+ export const PACKAGE_VERSION = '2.11.3';
@@ -1,4 +1,4 @@
1
- import { Settings } from '../types/index.js';
1
+ import { Settings, ResolvedFiles } from '../types/index.js';
2
2
  /**
3
3
  * Determines whether a file should be published based on the publish resolution logic:
4
4
  * - If the file is explicitly opted OUT (unpublishPaths), never publish
@@ -6,6 +6,13 @@ import { Settings } from '../types/index.js';
6
6
  * - Otherwise, fall back to the global publish setting
7
7
  */
8
8
  export declare function shouldPublishFile(resolvedPath: string, settings: Settings): boolean;
9
+ /**
10
+ * Builds a publish map from resolved file paths.
11
+ * Only includes files that have an explicit publish config or when a global
12
+ * publish flag is defined. Files without any config are left out of the map
13
+ * so the publish endpoint is never called for them.
14
+ */
15
+ export declare function buildPublishMap(filePaths: ResolvedFiles, settings: Settings): Map<string, boolean>;
9
16
  /**
10
17
  * Returns true if the user has any explicit publish configuration —
11
18
  * global flag, gt-specific flag, or per-file publish/unpublish patterns.
@@ -1,3 +1,6 @@
1
+ import { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';
2
+ import { getRelative } from '../fs/findFilepath.js';
3
+ import { hashStringSync } from './hash.js';
1
4
  /**
2
5
  * Determines whether a file should be published based on the publish resolution logic:
3
6
  * - If the file is explicitly opted OUT (unpublishPaths), never publish
@@ -11,6 +14,30 @@ export function shouldPublishFile(resolvedPath, settings) {
11
14
  return true;
12
15
  return settings.publish ?? false;
13
16
  }
17
+ /**
18
+ * Builds a publish map from resolved file paths.
19
+ * Only includes files that have an explicit publish config or when a global
20
+ * publish flag is defined. Files without any config are left out of the map
21
+ * so the publish endpoint is never called for them.
22
+ */
23
+ export function buildPublishMap(filePaths, settings) {
24
+ const publishMap = new Map();
25
+ const hasGlobalPublish = settings.publish !== undefined;
26
+ for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
27
+ if (filePaths[fileType]) {
28
+ for (const absolutePath of filePaths[fileType]) {
29
+ const hasExplicitConfig = settings.files.publishPaths?.has(absolutePath) ||
30
+ settings.files.unpublishPaths?.has(absolutePath);
31
+ if (hasGlobalPublish || hasExplicitConfig) {
32
+ const relativePath = getRelative(absolutePath);
33
+ const fileId = hashStringSync(relativePath);
34
+ publishMap.set(fileId, shouldPublishFile(absolutePath, settings));
35
+ }
36
+ }
37
+ }
38
+ }
39
+ return publishMap;
40
+ }
14
41
  /**
15
42
  * Returns true if the user has any explicit publish configuration —
16
43
  * global flag, gt-specific flag, or per-file publish/unpublish patterns.
@@ -0,0 +1,10 @@
1
+ import { Settings } from '../types/index.js';
2
+ /**
3
+ * Publishes files to the CDN if publish config exists and the publishMap is non-empty.
4
+ * Shared by translate, upload, and save-local commands.
5
+ */
6
+ export declare function runPublishWorkflow(files: {
7
+ fileId: string;
8
+ versionId: string;
9
+ fileName: string;
10
+ }[], publishMap: Map<string, boolean>, branchId: string, settings: Settings): Promise<void>;
@@ -0,0 +1,31 @@
1
+ import { PublishStep } from './steps/PublishStep.js';
2
+ import { gt } from '../utils/gt.js';
3
+ import { hasPublishConfig } from '../utils/resolvePublish.js';
4
+ import { logger } from '../console/logger.js';
5
+ /**
6
+ * Publishes files to the CDN if publish config exists and the publishMap is non-empty.
7
+ * Shared by translate, upload, and save-local commands.
8
+ */
9
+ export async function runPublishWorkflow(files, publishMap, branchId, settings) {
10
+ if (publishMap.size === 0 || !hasPublishConfig(settings))
11
+ return;
12
+ try {
13
+ const allFileRefs = files
14
+ .filter((file) => publishMap.has(file.fileId))
15
+ .map((file) => ({
16
+ fileId: file.fileId,
17
+ versionId: file.versionId,
18
+ branchId,
19
+ publish: publishMap.get(file.fileId),
20
+ fileName: file.fileName,
21
+ }));
22
+ if (allFileRefs.length === 0)
23
+ return;
24
+ const publishStep = new PublishStep(gt);
25
+ await publishStep.run(allFileRefs);
26
+ await publishStep.wait();
27
+ }
28
+ catch (error) {
29
+ logger.warn(`Failed to publish files: ${error instanceof Error ? error.message : String(error)}`);
30
+ }
31
+ }
@@ -1,10 +1,11 @@
1
1
  import { Settings } from '../types/index.js';
2
2
  import type { FileToUpload } from 'generaltranslation/types';
3
+ import { BranchData } from '../types/branch.js';
3
4
  /**
4
5
  * Uploads multiple files to the API using a workflow pattern
5
6
  * @param files - Array of file objects to upload
6
7
  * @param options - The options for the API call
7
- * @returns The uploaded content or version ID
8
+ * @returns The branch data resolved during the workflow
8
9
  */
9
10
  export declare function runUploadFilesWorkflow({ files, options, }: {
10
11
  files: {
@@ -12,4 +13,6 @@ export declare function runUploadFilesWorkflow({ files, options, }: {
12
13
  translations: FileToUpload[];
13
14
  }[];
14
15
  options: Settings;
15
- }): Promise<undefined>;
16
+ }): Promise<{
17
+ branchData: BranchData;
18
+ }>;
@@ -9,7 +9,7 @@ import { UploadTranslationsStep } from './steps/UploadTranslationsStep.js';
9
9
  * Uploads multiple files to the API using a workflow pattern
10
10
  * @param files - Array of file objects to upload
11
11
  * @param options - The options for the API call
12
- * @returns The uploaded content or version ID
12
+ * @returns The branch data resolved during the workflow
13
13
  */
14
14
  export async function runUploadFilesWorkflow({ files, options, }) {
15
15
  try {
@@ -40,6 +40,7 @@ export async function runUploadFilesWorkflow({ files, options, }) {
40
40
  await uploadTranslationsStep.wait();
41
41
  }
42
42
  logger.success('All files uploaded successfully');
43
+ return { branchData };
43
44
  }
44
45
  catch (error) {
45
46
  return logErrorAndExit('Failed to upload files. ' + error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.11.2",
3
+ "version": "2.11.3",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -110,8 +110,8 @@
110
110
  "unified": "^11.0.5",
111
111
  "unist-util-visit": "^5.0.0",
112
112
  "yaml": "^2.8.0",
113
- "@generaltranslation/python-extractor": "0.1.6",
114
113
  "generaltranslation": "8.1.20",
114
+ "@generaltranslation/python-extractor": "0.1.6",
115
115
  "gt-remark": "1.0.6"
116
116
  },
117
117
  "devDependencies": {