@tolgee/cli 2.15.1 → 2.16.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/dist/cli.js +6 -1
- package/dist/client/errorFromLoadable.js +3 -0
- package/dist/commands/branch.js +94 -0
- package/dist/commands/merge.js +118 -0
- package/dist/commands/pull.js +3 -0
- package/dist/commands/push.js +3 -0
- package/dist/commands/sync/compare.js +5 -1
- package/dist/commands/sync/sync.js +9 -6
- package/dist/commands/tag.js +3 -1
- package/dist/config/tolgeerc.js +11 -5
- package/dist/options.js +1 -0
- package/dist/utils/branch.js +49 -0
- package/package.json +1 -1
- package/schema.json +5 -0
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import ansi from 'ansi-colors';
|
|
|
13
13
|
import { getApiKey, savePak, savePat } from './config/credentials.js';
|
|
14
14
|
import loadTolgeeRc from './config/tolgeerc.js';
|
|
15
15
|
import { setDebug, info, error, exitWithError } from './utils/logger.js';
|
|
16
|
-
import { API_KEY_OPT, API_URL_OPT, CONFIG_OPT, DEFAULT_NAMESPACE, EXTRACTOR, FILE_PATTERNS, FORMAT_OPT, STRICT_NAMESPACE, PARSER, PROJECT_ID_OPT, STRICT_NAMESPACE_NEGATION, VERBOSE, } from './options.js';
|
|
16
|
+
import { API_KEY_OPT, API_URL_OPT, CONFIG_OPT, DEFAULT_NAMESPACE, EXTRACTOR, FILE_PATTERNS, FORMAT_OPT, STRICT_NAMESPACE, PARSER, PROJECT_ID_OPT, PROJECT_BRANCH, STRICT_NAMESPACE_NEGATION, VERBOSE, } from './options.js';
|
|
17
17
|
import { API_KEY_PAK_PREFIX, API_KEY_PAT_PREFIX, DEFAULT_API_URL, VERSION, } from './constants.js';
|
|
18
18
|
import { Login, Logout } from './commands/login.js';
|
|
19
19
|
import PushCommand from './commands/push.js';
|
|
@@ -22,6 +22,8 @@ import ExtractCommand from './commands/extract.js';
|
|
|
22
22
|
import CompareCommand from './commands/sync/compare.js';
|
|
23
23
|
import SyncCommand from './commands/sync/sync.js';
|
|
24
24
|
import TagCommand from './commands/tag.js';
|
|
25
|
+
import BranchCommand from './commands/branch.js';
|
|
26
|
+
import MergeCommand from './commands/merge.js';
|
|
25
27
|
import { getSingleOption } from './utils/getSingleOption.js';
|
|
26
28
|
import { createTolgeeClient } from './client/TolgeeClient.js';
|
|
27
29
|
import { projectIdFromKey } from './client/ApiClient.js';
|
|
@@ -136,6 +138,7 @@ function run() {
|
|
|
136
138
|
program.addOption(API_URL_OPT.default((_a = config.apiUrl) !== null && _a !== void 0 ? _a : DEFAULT_API_URL));
|
|
137
139
|
program.addOption(API_KEY_OPT.default(config.apiKey));
|
|
138
140
|
program.addOption(PROJECT_ID_OPT.default((_b = config.projectId) !== null && _b !== void 0 ? _b : -1));
|
|
141
|
+
program.addOption(PROJECT_BRANCH.default(config.branch));
|
|
139
142
|
program.addOption(FORMAT_OPT.default((_c = config.format) !== null && _c !== void 0 ? _c : 'JSON_TOLGEE'));
|
|
140
143
|
program.addOption(EXTRACTOR.default(config.extractor));
|
|
141
144
|
program.addOption(FILE_PATTERNS.default(config.patterns));
|
|
@@ -152,6 +155,8 @@ function run() {
|
|
|
152
155
|
program.addCommand(CompareCommand(config).configureHelp({ showGlobalOptions: true }));
|
|
153
156
|
program.addCommand(SyncCommand(config).configureHelp({ showGlobalOptions: true }));
|
|
154
157
|
program.addCommand(TagCommand(config).configureHelp({ showGlobalOptions: true }));
|
|
158
|
+
program.addCommand(BranchCommand(config).configureHelp({ showGlobalOptions: true }));
|
|
159
|
+
program.addCommand(MergeCommand(config).configureHelp({ showGlobalOptions: true }));
|
|
155
160
|
yield program.parseAsync();
|
|
156
161
|
}
|
|
157
162
|
catch (e) {
|
|
@@ -27,6 +27,9 @@ export const errorFromLoadable = (loadable) => {
|
|
|
27
27
|
// Forbidden
|
|
28
28
|
case 403:
|
|
29
29
|
return `You are not allowed to perform this operation ${addErrorDetails(loadable)}`;
|
|
30
|
+
// Not found (e.g. branch in project)
|
|
31
|
+
case 404:
|
|
32
|
+
return `Requested data not found. Please check your inputs ${addErrorDetails(loadable)}`;
|
|
30
33
|
// Rate limited
|
|
31
34
|
case 429:
|
|
32
35
|
return `You've been rate limited. Please try again later ${addErrorDetails(loadable)}`;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Command, Option } from 'commander';
|
|
11
|
+
import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
12
|
+
import { fetchBranches, listBranches } from '../utils/branch.js';
|
|
13
|
+
import { error, exitWithError, loading, success } from '../utils/logger.js';
|
|
14
|
+
function resolveTargetNames(opts, createArg) {
|
|
15
|
+
var _a;
|
|
16
|
+
const createName = (_a = opts.create) !== null && _a !== void 0 ? _a : createArg;
|
|
17
|
+
const deleteName = opts.delete;
|
|
18
|
+
if (opts.create && createArg) {
|
|
19
|
+
exitWithError("error: use either the '[branch]' arg to create branch or the option '-c, --create <branch>'");
|
|
20
|
+
}
|
|
21
|
+
if (createArg && deleteName) {
|
|
22
|
+
exitWithError("error: '[branch]' arg to create branch cannot be used together with option '-d, --delete <branch>'");
|
|
23
|
+
}
|
|
24
|
+
// opts.create && opts.delete use is already sanitized by commander
|
|
25
|
+
return { createName, deleteName };
|
|
26
|
+
}
|
|
27
|
+
function resolveOriginId(opts, branches) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const originName = opts.origin;
|
|
30
|
+
if (originName) {
|
|
31
|
+
const origin = branches.find((b) => b.name === originName);
|
|
32
|
+
if (!origin) {
|
|
33
|
+
error(`Origin branch "${originName}" was not found.`);
|
|
34
|
+
listBranches(branches);
|
|
35
|
+
exitWithError('Use --origin <branch> to specify an existing base branch.');
|
|
36
|
+
}
|
|
37
|
+
return origin.id;
|
|
38
|
+
}
|
|
39
|
+
const defaultBranch = branches.find((b) => b.isDefault);
|
|
40
|
+
if (!defaultBranch) {
|
|
41
|
+
error('Cannot determine default branch for the project.');
|
|
42
|
+
listBranches(branches);
|
|
43
|
+
exitWithError('Specify --origin <branch>.');
|
|
44
|
+
}
|
|
45
|
+
return defaultBranch.id;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const branchHandler = (config) => function () {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
const opts = this.optsWithGlobals();
|
|
51
|
+
const createArg = this.processedArgs[0];
|
|
52
|
+
const { createName, deleteName } = resolveTargetNames(opts, createArg);
|
|
53
|
+
const branches = yield loading('Fetching project branches...', fetchBranches(opts));
|
|
54
|
+
if (!createName && !deleteName) {
|
|
55
|
+
listBranches(branches);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (createName) {
|
|
59
|
+
const originId = yield resolveOriginId(opts, branches);
|
|
60
|
+
const loadable = yield loading(`Creating branch "${createName}"...`, opts.client.POST('/v2/projects/{projectId}/branches', {
|
|
61
|
+
params: { path: { projectId: opts.client.getProjectId() } },
|
|
62
|
+
body: { name: createName, originBranchId: originId },
|
|
63
|
+
}));
|
|
64
|
+
handleLoadableError(loadable);
|
|
65
|
+
success(`Branch "${createName}" created.`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (deleteName) {
|
|
69
|
+
const target = branches.find((b) => b.name === deleteName);
|
|
70
|
+
if (!target) {
|
|
71
|
+
error(`Branch "${deleteName}" was not found.`);
|
|
72
|
+
listBranches(branches);
|
|
73
|
+
exitWithError('Specify an existing branch.');
|
|
74
|
+
}
|
|
75
|
+
const loadable = yield loading(`Deleting branch "${deleteName}"...`, opts.client.DELETE('/v2/projects/{projectId}/branches/{branchId}', {
|
|
76
|
+
params: {
|
|
77
|
+
path: {
|
|
78
|
+
projectId: opts.client.getProjectId(),
|
|
79
|
+
branchId: target.id,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
}));
|
|
83
|
+
handleLoadableError(loadable);
|
|
84
|
+
success(`Branch "${deleteName}" deleted.`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
export default (config) => new Command('branch')
|
|
89
|
+
.description('Create or delete project branches')
|
|
90
|
+
.argument('[branch]', 'Branch name to create')
|
|
91
|
+
.addOption(new Option('--create <branch>', 'create a new branch').conflicts('delete'))
|
|
92
|
+
.addOption(new Option('-d, --delete <branch>', 'delete an existing branch').conflicts('create'))
|
|
93
|
+
.addOption(new Option('-o, --origin <branch>', 'origin branch to fork from (defaults to project default branch)'))
|
|
94
|
+
.action(branchHandler(config));
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
12
|
+
import { fetchBranches, listBranches } from '../utils/branch.js';
|
|
13
|
+
import { error, exitWithError, info, loading, success, } from '../utils/logger.js';
|
|
14
|
+
function resolveBranchName(opts, branchArg, branchExplicit) {
|
|
15
|
+
if (branchArg && branchExplicit) {
|
|
16
|
+
exitWithError("error: use either the '[branch]' arg or the option '--branch <branch>'");
|
|
17
|
+
}
|
|
18
|
+
const branchName = branchArg !== null && branchArg !== void 0 ? branchArg : (branchExplicit ? opts.branch : undefined);
|
|
19
|
+
if (!branchName) {
|
|
20
|
+
exitWithError('Specify a branch to merge.');
|
|
21
|
+
}
|
|
22
|
+
return branchName;
|
|
23
|
+
}
|
|
24
|
+
function renderChangeType(change) {
|
|
25
|
+
switch (change.type) {
|
|
26
|
+
case 'ADD':
|
|
27
|
+
return '+';
|
|
28
|
+
case 'UPDATE':
|
|
29
|
+
return '~';
|
|
30
|
+
case 'DELETE':
|
|
31
|
+
return '-';
|
|
32
|
+
case 'CONFLICT':
|
|
33
|
+
return 'x';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function renderChange(change) {
|
|
37
|
+
var _a, _b, _c, _d, _e;
|
|
38
|
+
const keyName = (_d = (_b = (_a = change.sourceKey) === null || _a === void 0 ? void 0 : _a.keyName) !== null && _b !== void 0 ? _b : (_c = change.targetKey) === null || _c === void 0 ? void 0 : _c.keyName) !== null && _d !== void 0 ? _d : 'unknown';
|
|
39
|
+
const languages = ((_e = change.changedTranslations) === null || _e === void 0 ? void 0 : _e.length)
|
|
40
|
+
? ` (${change.changedTranslations.join(', ')})`
|
|
41
|
+
: '';
|
|
42
|
+
return `${renderChangeType(change)} ${keyName}${languages}`;
|
|
43
|
+
}
|
|
44
|
+
function buildMergeUrl(opts, mergeId) {
|
|
45
|
+
return new URL(`/projects/${opts.projectId}/branches/merge/${mergeId}`, opts.apiUrl // API and frontend URLs may differ, but commonly they are the same
|
|
46
|
+
).toString();
|
|
47
|
+
}
|
|
48
|
+
const mergeHandler = (config) => function () {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
51
|
+
const opts = this.optsWithGlobals();
|
|
52
|
+
const branchArg = this.processedArgs[0];
|
|
53
|
+
const branchExplicit = ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.getOptionValueSource('branch')) === 'cli';
|
|
54
|
+
const branchName = resolveBranchName(opts, branchArg, branchExplicit);
|
|
55
|
+
const branches = yield loading('Fetching project branches...', fetchBranches(opts));
|
|
56
|
+
const mergedBranch = branches.find((branch) => branch.name === branchName);
|
|
57
|
+
if (!mergedBranch) {
|
|
58
|
+
error(`Branch "${branchName}" was not found.`);
|
|
59
|
+
listBranches(branches);
|
|
60
|
+
exitWithError('Specify an existing branch to merge.');
|
|
61
|
+
}
|
|
62
|
+
if (mergedBranch.isDefault) {
|
|
63
|
+
exitWithError('Cannot merge the default branch.');
|
|
64
|
+
}
|
|
65
|
+
const previewLoadable = yield loading(`Preparing merge of "${branchName}"...`, opts.client.POST('/v2/projects/{projectId}/branches/merge/preview', {
|
|
66
|
+
params: { path: { projectId: opts.client.getProjectId() } },
|
|
67
|
+
body: { sourceBranchId: mergedBranch.id },
|
|
68
|
+
}));
|
|
69
|
+
handleLoadableError(previewLoadable);
|
|
70
|
+
const mergeRef = previewLoadable.data;
|
|
71
|
+
const refreshLoadable = yield loading(`Refreshing merge changes...`, opts.client.POST('/v2/projects/{projectId}/branches/merge/{mergeId}/refresh', {
|
|
72
|
+
params: {
|
|
73
|
+
path: {
|
|
74
|
+
projectId: opts.client.getProjectId(),
|
|
75
|
+
mergeId: mergeRef.id,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
}));
|
|
79
|
+
handleLoadableError(refreshLoadable);
|
|
80
|
+
const changesLoadable = yield loading(`Checking merge changes...`, opts.client.GET('/v2/projects/{projectId}/branches/merge/{mergeId}/changes', {
|
|
81
|
+
params: {
|
|
82
|
+
path: {
|
|
83
|
+
projectId: opts.client.getProjectId(),
|
|
84
|
+
mergeId: mergeRef.id,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
88
|
+
handleLoadableError(changesLoadable);
|
|
89
|
+
const changes = (_d = (_c = (_b = changesLoadable.data) === null || _b === void 0 ? void 0 : _b._embedded) === null || _c === void 0 ? void 0 : _c.branchMergeChanges) !== null && _d !== void 0 ? _d : [];
|
|
90
|
+
const totalChanges = (_g = (_f = (_e = changesLoadable.data) === null || _e === void 0 ? void 0 : _e.page) === null || _f === void 0 ? void 0 : _f.totalElements) !== null && _g !== void 0 ? _g : changes.length;
|
|
91
|
+
console.log('Changed keys:');
|
|
92
|
+
changes.forEach((change) => {
|
|
93
|
+
console.log(renderChange(change));
|
|
94
|
+
});
|
|
95
|
+
if (totalChanges > changes.length) {
|
|
96
|
+
console.log(`...and ${totalChanges - changes.length} more`);
|
|
97
|
+
}
|
|
98
|
+
if (((_j = (_h = refreshLoadable.data) === null || _h === void 0 ? void 0 : _h.keyUnresolvedConflictsCount) !== null && _j !== void 0 ? _j : changes.filter((change) => change.type === 'CONFLICT' && !change.resolution).length) > 0) {
|
|
99
|
+
error(`Unresolved merge conflicts detected between "${branchName}" and "${mergeRef.targetBranchName}".`);
|
|
100
|
+
info(`Finish merge in web app: ${buildMergeUrl(opts, mergeRef.id)}`);
|
|
101
|
+
exitWithError('Resolve changes before merging.');
|
|
102
|
+
}
|
|
103
|
+
const applyLoadable = yield loading(`Merging branch "${branchName}"...`, opts.client.POST('/v2/projects/{projectId}/branches/merge/{mergeId}/apply', {
|
|
104
|
+
params: {
|
|
105
|
+
path: {
|
|
106
|
+
projectId: opts.client.getProjectId(),
|
|
107
|
+
mergeId: mergeRef.id,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
111
|
+
handleLoadableError(applyLoadable);
|
|
112
|
+
success(`Branch "${branchName}" merged into "${mergeRef.targetBranchName}".`);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
export default (config) => new Command('merge')
|
|
116
|
+
.description('Merge a branch into its origin branch')
|
|
117
|
+
.argument('[branch]', 'Branch name to merge')
|
|
118
|
+
.action(mergeHandler(config));
|
package/dist/commands/pull.js
CHANGED
|
@@ -14,6 +14,7 @@ import { exitWithError, info, loading, success } from '../utils/logger.js';
|
|
|
14
14
|
import { checkPathNotAFile } from '../utils/checkPathNotAFile.js';
|
|
15
15
|
import { mapExportFormat } from '../utils/mapExportFormat.js';
|
|
16
16
|
import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
17
|
+
import { printBranchInfo } from '../utils/branch.js';
|
|
17
18
|
import { startWatching } from '../utils/pullWatch/watchHandler.js';
|
|
18
19
|
import { getETag } from '../utils/eTagStorage.js';
|
|
19
20
|
export default (config) => {
|
|
@@ -44,6 +45,7 @@ const pullHandler = () => function () {
|
|
|
44
45
|
exitWithError('Missing option --path <path> or `pull.path` in tolgee config');
|
|
45
46
|
}
|
|
46
47
|
yield checkPathNotAFile(opts.path);
|
|
48
|
+
printBranchInfo(opts.branch);
|
|
47
49
|
if (!opts.watch) {
|
|
48
50
|
yield doPull(opts);
|
|
49
51
|
success('Done!');
|
|
@@ -93,6 +95,7 @@ function fetchZipBlob(opts, ifNoneMatch) {
|
|
|
93
95
|
fileStructureTemplate: opts.fileStructureTemplate,
|
|
94
96
|
escapeHtml: false,
|
|
95
97
|
ifNoneMatch,
|
|
98
|
+
filterBranch: opts.branch,
|
|
96
99
|
});
|
|
97
100
|
handleLoadableError(loadable);
|
|
98
101
|
const etag = loadable.response
|
package/dist/commands/push.js
CHANGED
|
@@ -19,6 +19,7 @@ import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
|
19
19
|
import { findFilesByTemplate } from '../utils/filesTemplate.js';
|
|
20
20
|
import { valueToArray } from '../utils/valueToArray.js';
|
|
21
21
|
import { printUnresolvedConflicts } from '../utils/printFailedKeys.js';
|
|
22
|
+
import { printBranchInfo } from '../utils/branch.js';
|
|
22
23
|
function allInPattern(pattern) {
|
|
23
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24
25
|
const files = [];
|
|
@@ -126,6 +127,7 @@ const pushHandler = (config) => function () {
|
|
|
126
127
|
}
|
|
127
128
|
return true;
|
|
128
129
|
});
|
|
130
|
+
printBranchInfo(opts.branch);
|
|
129
131
|
const files = yield loading('Reading files...', readRecords(filteredMatchers));
|
|
130
132
|
if (files.length === 0) {
|
|
131
133
|
error('Nothing to import.');
|
|
@@ -149,6 +151,7 @@ const pushHandler = (config) => function () {
|
|
|
149
151
|
overrideKeyDescriptions: opts.overrideKeyDescriptions,
|
|
150
152
|
convertPlaceholdersToIcu: opts.convertPlaceholdersToIcu,
|
|
151
153
|
tagNewKeys: (_d = opts.tagNewKeys) !== null && _d !== void 0 ? _d : [],
|
|
154
|
+
branch: opts.branch,
|
|
152
155
|
overrideMode: (_e = opts.overrideMode) !== null && _e !== void 0 ? _e : 'RECOMMENDED',
|
|
153
156
|
fileMappings: files.map((f) => {
|
|
154
157
|
var _a;
|
|
@@ -14,14 +14,18 @@ import { extractKeysOfFiles, filterExtractionResult, } from '../../extractor/run
|
|
|
14
14
|
import { dumpWarnings } from '../../extractor/warnings.js';
|
|
15
15
|
import { loading } from '../../utils/logger.js';
|
|
16
16
|
import { handleLoadableError } from '../../client/TolgeeClient.js';
|
|
17
|
+
import { printBranchInfo } from '../../utils/branch.js';
|
|
17
18
|
const asyncHandler = (config) => function () {
|
|
18
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
20
|
var _a;
|
|
20
21
|
const opts = this.optsWithGlobals();
|
|
22
|
+
printBranchInfo(opts.branch);
|
|
21
23
|
const rawKeys = yield loading('Analyzing code...', extractKeysOfFiles(opts));
|
|
22
24
|
dumpWarnings(rawKeys);
|
|
23
25
|
const localKeys = filterExtractionResult(rawKeys);
|
|
24
|
-
const loadable = yield opts.client.GET('/v2/projects/{projectId}/all-keys', {
|
|
26
|
+
const loadable = yield loading('Fetching Tolgee keys...', opts.client.GET('/v2/projects/{projectId}/all-keys', {
|
|
27
|
+
params: Object.assign({ path: { projectId: opts.client.getProjectId() } }, (!!opts.branch && { query: { branch: opts.branch } })),
|
|
28
|
+
}));
|
|
25
29
|
handleLoadableError(loadable);
|
|
26
30
|
const remoteKeys = (_a = loadable.data._embedded.keys) !== null && _a !== void 0 ? _a : [];
|
|
27
31
|
const diff = compareKeys(localKeys, remoteKeys);
|
|
@@ -17,7 +17,8 @@ import { unzipBuffer } from '../../utils/zip.js';
|
|
|
17
17
|
import { askBoolean } from '../../utils/ask.js';
|
|
18
18
|
import { loading, exitWithError } from '../../utils/logger.js';
|
|
19
19
|
import { handleLoadableError, } from '../../client/TolgeeClient.js';
|
|
20
|
-
|
|
20
|
+
import { printBranchInfo } from '../../utils/branch.js';
|
|
21
|
+
function backup(client, dest, branch) {
|
|
21
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
23
|
const loadable = yield client.export.export({
|
|
23
24
|
format: 'JSON',
|
|
@@ -25,6 +26,7 @@ function backup(client, dest) {
|
|
|
25
26
|
filterState: ['UNTRANSLATED', 'TRANSLATED', 'REVIEWED'],
|
|
26
27
|
structureDelimiter: '',
|
|
27
28
|
escapeHtml: false,
|
|
29
|
+
filterBranch: branch,
|
|
28
30
|
});
|
|
29
31
|
handleLoadableError(loadable);
|
|
30
32
|
const blob = loadable.data;
|
|
@@ -49,6 +51,7 @@ const syncHandler = (config) => function () {
|
|
|
49
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
52
|
var _a, _b, _c, _d, _e, _f;
|
|
51
53
|
const opts = this.optsWithGlobals();
|
|
54
|
+
printBranchInfo(opts.branch);
|
|
52
55
|
const rawKeys = yield loading('Analyzing code...', extractKeysOfFiles(opts));
|
|
53
56
|
const warnCount = dumpWarnings(rawKeys);
|
|
54
57
|
if (!opts.continueOnWarning && warnCount) {
|
|
@@ -63,9 +66,9 @@ const syncHandler = (config) => function () {
|
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
|
-
const allKeysLoadable = yield opts.client.GET('/v2/projects/{projectId}/all-keys', {
|
|
67
|
-
params: { path: { projectId: opts.client.getProjectId() } },
|
|
68
|
-
});
|
|
69
|
+
const allKeysLoadable = yield loading('Fetching Tolgee keys...', opts.client.GET('/v2/projects/{projectId}/all-keys', {
|
|
70
|
+
params: Object.assign({ path: { projectId: opts.client.getProjectId() } }, (!!opts.branch && { query: { branch: opts.branch } })),
|
|
71
|
+
}));
|
|
69
72
|
handleLoadableError(allKeysLoadable);
|
|
70
73
|
let remoteKeys = (_e = (_d = (_c = allKeysLoadable.data) === null || _c === void 0 ? void 0 : _c._embedded) === null || _d === void 0 ? void 0 : _d.keys) !== null && _e !== void 0 ? _e : [];
|
|
71
74
|
if ((_f = opts.namespaces) === null || _f === void 0 ? void 0 : _f.length) {
|
|
@@ -92,7 +95,7 @@ const syncHandler = (config) => function () {
|
|
|
92
95
|
// Prepare backup
|
|
93
96
|
if (opts.backup) {
|
|
94
97
|
yield prepareDir(opts.backup, opts.yes);
|
|
95
|
-
yield loading('Backing up Tolgee project', backup(opts.client, opts.backup));
|
|
98
|
+
yield loading('Backing up Tolgee project...', backup(opts.client, opts.backup, opts.branch));
|
|
96
99
|
}
|
|
97
100
|
// Create new keys
|
|
98
101
|
if (diff.added.length) {
|
|
@@ -108,7 +111,7 @@ const syncHandler = (config) => function () {
|
|
|
108
111
|
tags: opts.tagNewKeys,
|
|
109
112
|
}));
|
|
110
113
|
const loadable = yield loading('Creating missing keys...', opts.client.POST('/v2/projects/{projectId}/keys/import', {
|
|
111
|
-
params: { path: { projectId: opts.client.getProjectId() } },
|
|
114
|
+
params: Object.assign({ path: { projectId: opts.client.getProjectId() } }, (!!opts.branch && { query: { branch: opts.branch } })),
|
|
112
115
|
body: { keys },
|
|
113
116
|
}));
|
|
114
117
|
handleLoadableError(loadable);
|
package/dist/commands/tag.js
CHANGED
|
@@ -11,9 +11,11 @@ import { Command, Option } from 'commander';
|
|
|
11
11
|
import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
12
12
|
import { exitWithError, loading, success } from '../utils/logger.js';
|
|
13
13
|
import { extractKeysOfFiles } from '../extractor/runner.js';
|
|
14
|
+
import { printBranchInfo } from '../utils/branch.js';
|
|
14
15
|
const tagHandler = (config) => function () {
|
|
15
16
|
return __awaiter(this, void 0, void 0, function* () {
|
|
16
17
|
const opts = this.optsWithGlobals();
|
|
18
|
+
printBranchInfo(opts.branch);
|
|
17
19
|
let extractedKeys;
|
|
18
20
|
if (opts.filterExtracted || opts.filterNotExtracted) {
|
|
19
21
|
if (opts.filterExtracted && opts.filterNotExtracted) {
|
|
@@ -27,7 +29,7 @@ const tagHandler = (config) => function () {
|
|
|
27
29
|
}));
|
|
28
30
|
}
|
|
29
31
|
const loadable = yield loading('Tagging...', opts.client.PUT('/v2/projects/{projectId}/tag-complex', {
|
|
30
|
-
params: { path: { projectId: opts.client.getProjectId() } },
|
|
32
|
+
params: Object.assign({ path: { projectId: opts.client.getProjectId() } }, (!!opts.branch && { query: { branch: opts.branch } })),
|
|
31
33
|
body: {
|
|
32
34
|
filterTag: opts.filterTag,
|
|
33
35
|
filterTagNot: opts.filterNoTag,
|
package/dist/config/tolgeerc.js
CHANGED
|
@@ -7,12 +7,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
10
|
+
import { cosmiconfig, defaultLoaders, } from 'cosmiconfig';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { readFile } from 'node:fs/promises';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
15
|
import { error, exitWithError } from '../utils/logger.js';
|
|
15
|
-
import { existsSync } from 'fs';
|
|
16
16
|
import { valueToArray } from '../utils/valueToArray.js';
|
|
17
17
|
import { Ajv } from 'ajv';
|
|
18
18
|
const explorer = cosmiconfig('tolgee', {
|
|
@@ -37,6 +37,12 @@ function parseConfig(input, configDir) {
|
|
|
37
37
|
throw new Error("Invalid config: 'projectId' should be an integer representing your project Id");
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
if (rc.branch !== undefined) {
|
|
41
|
+
if (typeof rc.branch !== 'string' || !rc.branch.trim().length) {
|
|
42
|
+
throw new Error("Invalid config: 'branch' should be a non-empty string representing your project branch");
|
|
43
|
+
}
|
|
44
|
+
rc.branch = rc.branch.trim();
|
|
45
|
+
}
|
|
40
46
|
// convert relative paths in config to absolute
|
|
41
47
|
if (rc.extractor !== undefined) {
|
|
42
48
|
rc.extractor = resolve(configDir, rc.extractor).replace(/\\/g, '/');
|
package/dist/options.js
CHANGED
|
@@ -26,6 +26,7 @@ function parsePath(v) {
|
|
|
26
26
|
export const API_KEY_OPT = new Option('-ak, --api-key <key>', 'Tolgee API Key. Can be a Project API Key or a Personal Access Token.').env('TOLGEE_API_KEY');
|
|
27
27
|
export const PROJECT_ID_OPT = new Option('-p, --project-id <id>', 'Project ID. Only required when using a Personal Access Token.').argParser(parseProjectId);
|
|
28
28
|
export const API_URL_OPT = new Option('-au, --api-url <url>', 'The url of Tolgee API.').argParser(parseUrlArgument);
|
|
29
|
+
export const PROJECT_BRANCH = new Option('-b, --branch <name>', 'Project branch. Use when branching enabled for the project.').env('TOLGEE_BRANCH');
|
|
29
30
|
export const EXTRACTOR = new Option('-e, --extractor <extractor>', `A path to a custom extractor to use instead of the default one.`).argParser(parsePath);
|
|
30
31
|
export const CONFIG_OPT = new Option('-c, --config [config]', 'A path to tolgeerc config file.').argParser(parsePath);
|
|
31
32
|
export const FORMAT_OPT = new Option('--format <format>', 'Localization files format.').choices([
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { handleLoadableError } from '../client/TolgeeClient.js';
|
|
11
|
+
import { info, success } from './logger.js';
|
|
12
|
+
export function printBranchInfo(branch) {
|
|
13
|
+
if (branch) {
|
|
14
|
+
info(`Using branch "${branch}"`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function fetchBranches(cmd) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
const loadable = yield cmd.client.GET('/v2/projects/{projectId}/branches', {
|
|
21
|
+
params: {
|
|
22
|
+
path: { projectId: cmd.client.getProjectId() },
|
|
23
|
+
query: { size: 10000 },
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
handleLoadableError(loadable);
|
|
27
|
+
return (_c = (_b = (_a = loadable.data) === null || _a === void 0 ? void 0 : _a._embedded) === null || _b === void 0 ? void 0 : _b.branches) !== null && _c !== void 0 ? _c : [];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function listBranches(branches) {
|
|
31
|
+
if (!branches.length) {
|
|
32
|
+
success('No branches found.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log('Branches:');
|
|
36
|
+
branches.forEach((b) => {
|
|
37
|
+
const markers = [];
|
|
38
|
+
if (b.isDefault)
|
|
39
|
+
markers.push('default');
|
|
40
|
+
if (b.isProtected)
|
|
41
|
+
markers.push('protected');
|
|
42
|
+
if (b.active === false)
|
|
43
|
+
markers.push('inactive');
|
|
44
|
+
if (b.merge)
|
|
45
|
+
markers.push('ongoing merge');
|
|
46
|
+
const suffix = markers.length ? ` (${markers.join(', ')})` : '';
|
|
47
|
+
console.log(`- ${b.name}${suffix}`);
|
|
48
|
+
});
|
|
49
|
+
}
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
"description": "Project ID. Only required when using a Personal Access Token.",
|
|
6
6
|
"type": ["number", "string"]
|
|
7
7
|
},
|
|
8
|
+
"branch": {
|
|
9
|
+
"description": "Project branch. Use when branching enabled for the project.",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1
|
|
12
|
+
},
|
|
8
13
|
"apiUrl": {
|
|
9
14
|
"description": "The url of Tolgee API.",
|
|
10
15
|
"type": "string"
|