@shortcut-cli/shortcut-cli 3.4.0 → 3.6.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.
- package/README.md +25 -0
- package/build/_virtual/rolldown_runtime.js +25 -0
- package/build/bin/short-api.js +78 -0
- package/build/bin/short-create.js +52 -573
- package/build/bin/short-epics.js +31 -160
- package/build/bin/short-find.js +4 -588
- package/build/bin/short-install.js +37 -135
- package/build/bin/short-members.js +28 -134
- package/build/bin/short-projects.js +28 -136
- package/build/bin/short-search.js +46 -597
- package/build/bin/short-story.js +201 -737
- package/build/bin/short-workflows.js +27 -133
- package/build/bin/short-workspace.js +62 -648
- package/build/bin/short.js +7 -33
- package/build/lib/client.js +10 -103
- package/build/lib/configure.js +93 -126
- package/build/lib/spinner.js +14 -31
- package/build/lib/stories.js +295 -462
- package/build/package.js +18 -0
- package/package.json +15 -15
package/build/lib/stories.js
CHANGED
|
@@ -1,491 +1,324 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/lib/stories.ts
|
|
30
|
-
var stories_exports = {};
|
|
31
|
-
__export(stories_exports, {
|
|
32
|
-
default: () => stories_default
|
|
33
|
-
});
|
|
34
|
-
module.exports = __toCommonJS(stories_exports);
|
|
35
|
-
var import_child_process = require("child_process");
|
|
36
|
-
var import_chalk = __toESM(require("chalk"));
|
|
37
|
-
var import_debug = __toESM(require("debug"));
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
|
|
3
|
+
const require_lib_configure = require('./configure.js');
|
|
4
|
+
const require_lib_client = require('./client.js');
|
|
5
|
+
const debug = require_rolldown_runtime.__toESM(require("debug"));
|
|
6
|
+
const child_process = require_rolldown_runtime.__toESM(require("child_process"));
|
|
7
|
+
const chalk = require_rolldown_runtime.__toESM(require("chalk"));
|
|
38
8
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
var import_path = __toESM(require("path"));
|
|
44
|
-
var import_fs = __toESM(require("fs"));
|
|
45
|
-
var import_os = __toESM(require("os"));
|
|
46
|
-
function getConfigDir(suffix) {
|
|
47
|
-
const configBaseDir = process.env.XDG_CONFIG_HOME || import_path.default.resolve(process.env.XDG_DATA_HOME || import_os.default.homedir(), ".config");
|
|
48
|
-
return import_path.default.resolve(configBaseDir, suffix);
|
|
49
|
-
}
|
|
50
|
-
var configDir = getConfigDir("shortcut-cli");
|
|
51
|
-
var configFile = import_path.default.resolve(configDir, "config.json");
|
|
52
|
-
var legacyConfigDirs = [
|
|
53
|
-
getConfigDir("clubhouse-cli"),
|
|
54
|
-
import_path.default.resolve(import_os.default.homedir(), ".clubhouse-cli")
|
|
55
|
-
];
|
|
56
|
-
var CONFIG_CACHE = null;
|
|
57
|
-
var loadConfig = () => {
|
|
58
|
-
const config3 = loadCachedConfig();
|
|
59
|
-
if (!config3 || config3 === {} || !config3.token) {
|
|
60
|
-
console.error("Please run 'short install' to configure Shortcut API access.");
|
|
61
|
-
process.exit(11);
|
|
62
|
-
}
|
|
63
|
-
if (!config3.urlSlug) {
|
|
64
|
-
console.error(
|
|
65
|
-
"Your config must be updated with data from Shortcut. Please run 'short install --refresh'."
|
|
66
|
-
);
|
|
67
|
-
process.exit(12);
|
|
68
|
-
}
|
|
69
|
-
return config3;
|
|
70
|
-
};
|
|
71
|
-
var loadCachedConfig = () => {
|
|
72
|
-
if (CONFIG_CACHE) {
|
|
73
|
-
return { ...CONFIG_CACHE };
|
|
74
|
-
}
|
|
75
|
-
let config3 = {};
|
|
76
|
-
const token = process.env.SHORTCUT_API_TOKEN || process.env.CLUBHOUSE_API_TOKEN;
|
|
77
|
-
legacyConfigDirs.forEach((dir) => {
|
|
78
|
-
if (import_fs.default.existsSync(dir)) {
|
|
79
|
-
createConfigDir();
|
|
80
|
-
import_fs.default.renameSync(dir, configDir);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
if (import_fs.default.existsSync(configFile)) {
|
|
84
|
-
try {
|
|
85
|
-
config3 = JSON.parse(import_fs.default.readFileSync(configFile, "utf8"));
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.error(e);
|
|
88
|
-
process.exit(10);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (token) {
|
|
92
|
-
config3 = { token, ...config3 };
|
|
93
|
-
}
|
|
94
|
-
CONFIG_CACHE = { ...config3 };
|
|
95
|
-
return config3;
|
|
96
|
-
};
|
|
97
|
-
var createConfigDir = () => {
|
|
98
|
-
const dir = import_path.default.dirname(configDir);
|
|
99
|
-
if (!import_fs.default.existsSync(dir)) {
|
|
100
|
-
import_fs.default.mkdirSync(dir);
|
|
101
|
-
}
|
|
102
|
-
if (!import_fs.default.existsSync(configDir)) {
|
|
103
|
-
import_fs.default.mkdirSync(configDir);
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
// src/lib/client.ts
|
|
108
|
-
var config = loadConfig();
|
|
109
|
-
var client = new import_client.ShortcutClient(config.token);
|
|
110
|
-
var client_default = client;
|
|
111
|
-
|
|
112
|
-
// src/lib/stories.ts
|
|
113
|
-
var debug = (0, import_debug.default)("club");
|
|
114
|
-
var config2 = loadConfig();
|
|
115
|
-
var log = console.log;
|
|
9
|
+
//#region src/lib/stories.ts
|
|
10
|
+
const debug$1 = (0, debug.default)("club");
|
|
11
|
+
const config = require_lib_configure.loadConfig();
|
|
12
|
+
const log = console.log;
|
|
116
13
|
async function fetchEntities() {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
14
|
+
const [projectsById, statesById, membersById, groupsById, epicsById, iterationsById, labels] = await Promise.all([
|
|
15
|
+
require_lib_client.default.listProjects().then((r) => r.data).then(mapByItemId),
|
|
16
|
+
require_lib_client.default.listWorkflows().then((r) => r.data).then((wfs) => wfs.reduce((states, wf) => states.concat(wf.states), [])).then(mapByItemId),
|
|
17
|
+
require_lib_client.default.listMembers(null).then((r) => r.data).then(mapByItemStringId),
|
|
18
|
+
require_lib_client.default.listGroups().then((r) => r.data).then(mapByItemStringId),
|
|
19
|
+
require_lib_client.default.listEpics(null).then((r) => r.data).then(mapByItemId),
|
|
20
|
+
require_lib_client.default.listIterations(null).then((r) => r.data).then(mapByItemId),
|
|
21
|
+
require_lib_client.default.listLabels(null).then((r) => r.data)
|
|
22
|
+
]).catch((err) => {
|
|
23
|
+
log(`Error fetching workflows: ${err}`);
|
|
24
|
+
process.exit(2);
|
|
25
|
+
});
|
|
26
|
+
debug$1("response workflows, members, groups, projects, epics, iterations");
|
|
27
|
+
return {
|
|
28
|
+
projectsById,
|
|
29
|
+
statesById,
|
|
30
|
+
membersById,
|
|
31
|
+
groupsById,
|
|
32
|
+
epicsById,
|
|
33
|
+
iterationsById,
|
|
34
|
+
labels
|
|
35
|
+
};
|
|
131
36
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
37
|
+
const listStories = async (program) => {
|
|
38
|
+
debug$1("request workflows, members, projects, epics");
|
|
39
|
+
const entities = await fetchEntities();
|
|
40
|
+
const stories = await fetchStories(program, entities);
|
|
41
|
+
debug$1("filtering stories");
|
|
42
|
+
return filterStories(program, stories, entities).sort(sortStories(program));
|
|
138
43
|
};
|
|
139
44
|
function mapByItemId(items) {
|
|
140
|
-
|
|
45
|
+
return items.reduce((map, obj) => map.set(obj.id, obj), /* @__PURE__ */ new Map());
|
|
141
46
|
}
|
|
142
47
|
function mapByItemStringId(items) {
|
|
143
|
-
|
|
48
|
+
return items.reduce((map, obj) => map.set(obj.id, obj), /* @__PURE__ */ new Map());
|
|
144
49
|
}
|
|
145
50
|
async function fetchStories(program, entities) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
debug("request all stories for project(s)", projectIds.map((p) => p.name).join(", "));
|
|
156
|
-
return Promise.all(projectIds.map((p) => client_default.listStories(p.id, null))).then(
|
|
157
|
-
(projectStories) => projectStories.reduce((acc, stories) => acc.concat(stories.data), [])
|
|
158
|
-
);
|
|
51
|
+
if ((program.args || []).length) {
|
|
52
|
+
debug$1("using the search endpoint");
|
|
53
|
+
return searchStories(program);
|
|
54
|
+
}
|
|
55
|
+
debug$1("filtering projects");
|
|
56
|
+
const regexProject = new RegExp(program.project, "i");
|
|
57
|
+
const projectIds = [...entities.projectsById.values()].filter((p) => !!(p.id + p.name).match(regexProject));
|
|
58
|
+
debug$1("request all stories for project(s)", projectIds.map((p) => p.name).join(", "));
|
|
59
|
+
return Promise.all(projectIds.map((p) => require_lib_client.default.listStories(p.id, null))).then((projectStories) => projectStories.reduce((acc, stories) => acc.concat(stories.data), []));
|
|
159
60
|
}
|
|
160
61
|
async function searchStories(program) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
62
|
+
const query = program.args.join(" ").replace("%self%", config.mentionName);
|
|
63
|
+
let result = await require_lib_client.default.searchStories({ query });
|
|
64
|
+
let stories = result.data.data.map(storySearchResultToStory);
|
|
65
|
+
while (result.data.next) {
|
|
66
|
+
const nextCursor = new URLSearchParams(result.data.next).get("next");
|
|
67
|
+
result = await require_lib_client.default.searchStories({
|
|
68
|
+
query,
|
|
69
|
+
next: nextCursor
|
|
70
|
+
});
|
|
71
|
+
stories = stories.concat(result.data.data.map(storySearchResultToStory));
|
|
72
|
+
}
|
|
73
|
+
return stories;
|
|
170
74
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
75
|
+
const storySearchResultToStory = (storySearchResult) => {
|
|
76
|
+
return {
|
|
77
|
+
...storySearchResult,
|
|
78
|
+
description: storySearchResult.description || "",
|
|
79
|
+
linked_files: storySearchResult.linked_files || [],
|
|
80
|
+
comments: storySearchResult.comments || [],
|
|
81
|
+
branches: storySearchResult.branches || [],
|
|
82
|
+
tasks: storySearchResult.tasks || [],
|
|
83
|
+
pull_requests: storySearchResult.pull_requests || [],
|
|
84
|
+
commits: storySearchResult.commits || [],
|
|
85
|
+
files: storySearchResult.files || []
|
|
86
|
+
};
|
|
183
87
|
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
88
|
+
const hydrateStory = (entities, story) => {
|
|
89
|
+
debug$1("hydrating story");
|
|
90
|
+
const augmented = story;
|
|
91
|
+
augmented.project = entities.projectsById.get(story.project_id);
|
|
92
|
+
augmented.state = entities.statesById.get(story.workflow_state_id);
|
|
93
|
+
augmented.epic = entities.epicsById.get(story.epic_id);
|
|
94
|
+
augmented.iteration = entities.iterationsById.get(story.iteration_id);
|
|
95
|
+
augmented.owners = story.owner_ids.map((id) => entities.membersById.get(id));
|
|
96
|
+
augmented.requester = entities.membersById.get(story.requested_by_id);
|
|
97
|
+
augmented.group = entities.groupsById.get(story.group_id);
|
|
98
|
+
debug$1("hydrated story");
|
|
99
|
+
return augmented;
|
|
196
100
|
};
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return entities.get(Number(id.toString()));
|
|
204
|
-
}
|
|
205
|
-
const match = new RegExp(`${id}`, "i");
|
|
206
|
-
return Object.values(entities).filter((s) => !!s.name.match(match))[0];
|
|
101
|
+
const isNumber = (val) => !!(val || val === 0) && !isNaN(Number(val.toString()));
|
|
102
|
+
const findEntity = (entities, id) => {
|
|
103
|
+
if (entities.get(id)) return entities.get(id);
|
|
104
|
+
if (isNumber(id) && Number(id.toString())) return entities.get(Number(id.toString()));
|
|
105
|
+
const match = new RegExp(`${id}`, "i");
|
|
106
|
+
return Array.from(entities.values()).filter((s) => !!s.name.match(match))[0];
|
|
207
107
|
};
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
108
|
+
const findProject = (entities, project) => findEntity(entities.projectsById, project);
|
|
109
|
+
const findGroup = (entities, group) => findEntity(entities.groupsById, group);
|
|
110
|
+
const findState = (entities, state) => findEntity(entities.statesById, state);
|
|
111
|
+
const findEpic = (entities, epicName) => findEntity(entities.epicsById, epicName);
|
|
112
|
+
const findIteration = (entities, iterationName) => findEntity(entities.statesById, iterationName);
|
|
113
|
+
const findOwnerIds = (entities, owners) => {
|
|
114
|
+
const ownerMatch = new RegExp(owners.split(",").join("|"), "i");
|
|
115
|
+
return Array.from(entities.membersById.values()).filter((m) => !!`${m.id} ${m.profile.name} ${m.profile.mention_name}`.match(ownerMatch)).map((m) => m.id);
|
|
216
116
|
};
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
117
|
+
const findLabelNames = (entities, label) => {
|
|
118
|
+
const labelMatch = new RegExp(label.split(",").join("|"), "i");
|
|
119
|
+
return entities.labels.filter((m) => !!`${m.id} ${m.name}`.match(labelMatch)).map((m) => ({ name: m.name }));
|
|
220
120
|
};
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (!(s.epic_id + " " + (s.epic || {}).name).match(regexEpic)) {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
if (!(s.iteration_id + " " + (s.iteration || {}).name).match(
|
|
257
|
-
regexIteration
|
|
258
|
-
)) {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
if (program.owner) {
|
|
262
|
-
const owned = s.owners.filter((o) => {
|
|
263
|
-
return !!`${o.profile.name} ${o.profile.mention_name}`.match(regexOwner);
|
|
264
|
-
}).length > 0;
|
|
265
|
-
if (!owned) return false;
|
|
266
|
-
}
|
|
267
|
-
if (!s.name.match(regexText)) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
if (!s.story_type.match(regexType)) {
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
if (created_at && !created_at(s.created_at)) {
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
if (updated_at && !updated_at(s.updated_at)) {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
return !(estimate && !estimate(s.estimate));
|
|
280
|
-
});
|
|
121
|
+
const filterStories = (program, stories, entities) => {
|
|
122
|
+
let created_at;
|
|
123
|
+
if (program.created) created_at = parseDateComparator(program.created);
|
|
124
|
+
let updated_at;
|
|
125
|
+
if (program.updated) updated_at = parseDateComparator(program.updated);
|
|
126
|
+
let estimate;
|
|
127
|
+
if (program.estimate) estimate = parseNumberComparator(program.estimate);
|
|
128
|
+
const regexLabel = new RegExp(program.label, "i");
|
|
129
|
+
const regexState = new RegExp(program.state, "i");
|
|
130
|
+
const regexOwner = new RegExp(program.owner, "i");
|
|
131
|
+
const regexText = new RegExp(program.text, "i");
|
|
132
|
+
const regexType = new RegExp(program.type, "i");
|
|
133
|
+
const regexEpic = new RegExp(program.epic, "i");
|
|
134
|
+
const regexIteration = new RegExp(program.iteration, "i");
|
|
135
|
+
return stories.map((story) => hydrateStory(entities, story)).filter((s) => {
|
|
136
|
+
if (!program.archived && s.archived) return false;
|
|
137
|
+
if (!(s.labels.map((l) => `${l.id},${l.name}`).join(",") + "").match(regexLabel)) return false;
|
|
138
|
+
if (!(s.workflow_state_id + " " + (s.state || {}).name).match(regexState)) return false;
|
|
139
|
+
if (!(s.epic_id + " " + (s.epic || {}).name).match(regexEpic)) return false;
|
|
140
|
+
if (!(s.iteration_id + " " + (s.iteration || {}).name).match(regexIteration)) return false;
|
|
141
|
+
if (program.owner) {
|
|
142
|
+
const owned = s.owners.filter((o) => {
|
|
143
|
+
return !!`${o.profile.name} ${o.profile.mention_name}`.match(regexOwner);
|
|
144
|
+
}).length > 0;
|
|
145
|
+
if (!owned) return false;
|
|
146
|
+
}
|
|
147
|
+
if (!s.name.match(regexText)) return false;
|
|
148
|
+
if (!s.story_type.match(regexType)) return false;
|
|
149
|
+
if (created_at && !created_at(s.created_at)) return false;
|
|
150
|
+
if (updated_at && !updated_at(s.updated_at)) return false;
|
|
151
|
+
return !(estimate && !estimate(s.estimate));
|
|
152
|
+
});
|
|
281
153
|
};
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}, 0);
|
|
305
|
-
};
|
|
154
|
+
const sortStories = (program) => {
|
|
155
|
+
const fields = (program.sort || "").split(",").map((s) => {
|
|
156
|
+
return s.split(":").map((ss) => ss.split("."));
|
|
157
|
+
});
|
|
158
|
+
const pluck = (acc, val) => {
|
|
159
|
+
if (acc[val] === void 0) return {};
|
|
160
|
+
return acc[val];
|
|
161
|
+
};
|
|
162
|
+
debug$1("sorting stories");
|
|
163
|
+
return (a, b) => {
|
|
164
|
+
return fields.reduce((acc, field) => {
|
|
165
|
+
if (acc !== 0) return acc;
|
|
166
|
+
const ap = field[0].reduce(pluck, a);
|
|
167
|
+
const bp = field[0].reduce(pluck, b);
|
|
168
|
+
if (ap === bp) return 0;
|
|
169
|
+
const direction = (field[1] || [""])[0].match(/des/i) ? 1 : -1;
|
|
170
|
+
if (ap > bp) {
|
|
171
|
+
if (direction > 0) return -1;
|
|
172
|
+
} else if (direction < 0) return -1;
|
|
173
|
+
return 1;
|
|
174
|
+
}, 0);
|
|
175
|
+
};
|
|
306
176
|
};
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
177
|
+
const printFormattedStory = (program) => {
|
|
178
|
+
return (story) => {
|
|
179
|
+
var _story$group;
|
|
180
|
+
const defaultFormat = `#%id %t
|
|
181
|
+
\tType: %y/%e
|
|
182
|
+
\tTeam: %T
|
|
183
|
+
\tProject: %p
|
|
184
|
+
\tEpic: %epic
|
|
185
|
+
\tIteration: %i
|
|
186
|
+
\tRequester: %r
|
|
187
|
+
\tOwners: %o
|
|
188
|
+
\tState: %s
|
|
189
|
+
\tLabels: %l
|
|
190
|
+
\tURL: %u
|
|
191
|
+
\tCreated: %c
|
|
192
|
+
\tUpdated: %updated
|
|
193
|
+
\tArchived: %a
|
|
323
194
|
`;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
).replace(/%e/, `${story.estimate || "_"}`).replace(
|
|
336
|
-
/%i/,
|
|
337
|
-
story.iteration_id ? `${(story.iteration || {}).name} (#${story.iteration_id})` : "_"
|
|
338
|
-
).replace(/%p/, project).replace(/%T/, story.group?.name || "_").replace(/%o/, owners.join(", ") || "_").replace(
|
|
339
|
-
/%r/,
|
|
340
|
-
// eslint-disable-next-line no-constant-binary-expression
|
|
341
|
-
`${story.requester.profile.name} (${story.requester.profile.mention_name})` || "_"
|
|
342
|
-
).replace(
|
|
343
|
-
/%s/,
|
|
344
|
-
`${(story.state || {}).name} (#${story.workflow_state_id})`
|
|
345
|
-
).replace(/%c/, `${story.created_at}`).replace(
|
|
346
|
-
/%updated/,
|
|
347
|
-
`${story.updated_at !== story.created_at ? story.updated_at : "_"}`
|
|
348
|
-
).replace(/%u/, url).replace(/%a/, `${story.archived}`).replace(
|
|
349
|
-
/%gbs/,
|
|
350
|
-
`${buildStoryBranch(story, `${config2.mentionName}/sc-${story.id}/`)}`
|
|
351
|
-
).replace(/%gb/, `${buildStoryBranch(story)}`)
|
|
352
|
-
);
|
|
353
|
-
return story;
|
|
354
|
-
};
|
|
195
|
+
const format = program.format || defaultFormat;
|
|
196
|
+
const labels = story.labels.map((l) => `${l.name} (#${l.id})`);
|
|
197
|
+
const owners = story.owners.map((o) => `${o.profile.name} (${o.profile.mention_name})`);
|
|
198
|
+
const url = `https://app.shortcut.com/story/${story.id}`;
|
|
199
|
+
const project = story.project ? `${story.project.name} (#${story.project.id})` : "None";
|
|
200
|
+
log(format.replace(/%j/, JSON.stringify({
|
|
201
|
+
...story,
|
|
202
|
+
url
|
|
203
|
+
}, null, 2)).replace(/%id/, chalk.default.blue.bold(`${story.id}`)).replace(/%t/, chalk.default.blue(`${story.name}`)).replace(/%d/, story.description || "").replace(/%y/, story.story_type).replace(/%l/, labels.join(", ") || "_").replace(/%epic/, story.epic_id ? `${(story.epic || {}).name} (#${story.epic_id})` : "_").replace(/%e/, `${story.estimate || "_"}`).replace(/%i/, story.iteration_id ? `${(story.iteration || {}).name} (#${story.iteration_id})` : "_").replace(/%p/, project).replace(/%T/, ((_story$group = story.group) === null || _story$group === void 0 ? void 0 : _story$group.name) || "_").replace(/%o/, owners.join(", ") || "_").replace(/%r/, `${story.requester.profile.name} (${story.requester.profile.mention_name})` || "_").replace(/%s/, `${(story.state || {}).name} (#${story.workflow_state_id})`).replace(/%c/, `${story.created_at}`).replace(/%updated/, `${story.updated_at !== story.created_at ? story.updated_at : "_"}`).replace(/%u/, url).replace(/%a/, `${story.archived}`).replace(/%gbs/, `${buildStoryBranch(story, `${config.mentionName}/sc-${story.id}/`)}`).replace(/%gb/, `${buildStoryBranch(story)}`));
|
|
204
|
+
return story;
|
|
205
|
+
};
|
|
355
206
|
};
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
207
|
+
const buildURL = (...segments) => {
|
|
208
|
+
return [
|
|
209
|
+
"https://app.shortcut.com",
|
|
210
|
+
config.urlSlug,
|
|
211
|
+
...segments.map((item) => item.toString())
|
|
212
|
+
].join("/");
|
|
362
213
|
};
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (story.completed) {
|
|
409
|
-
log(import_chalk.default.bold("Completed: ") + import_chalk.default.bold(`${story.completed_at}`));
|
|
410
|
-
}
|
|
411
|
-
story.tasks.map((c) => {
|
|
412
|
-
log(
|
|
413
|
-
import_chalk.default.bold("Task: ") + (c.complete ? "[X]" : "[ ]") + " " + formatLong(c.description)
|
|
414
|
-
);
|
|
415
|
-
return c;
|
|
416
|
-
});
|
|
417
|
-
story.comments.filter((comment) => !comment.deleted).map((c) => {
|
|
418
|
-
const author = entities.membersById.get(c.author_id);
|
|
419
|
-
log(import_chalk.default.bold("Comment:") + ` ${formatLong(c.text)}`);
|
|
420
|
-
log(` ${author.profile.name} ` + import_chalk.default.bold("at:") + ` ${c.updated_at}`);
|
|
421
|
-
return c;
|
|
422
|
-
});
|
|
423
|
-
story.files.map((file) => {
|
|
424
|
-
log(import_chalk.default.bold("File:") + ` ${file.name}`);
|
|
425
|
-
log(` ${file.url}`);
|
|
426
|
-
return file;
|
|
427
|
-
});
|
|
428
|
-
log();
|
|
214
|
+
const storyURL = (story) => buildURL("story", story.id);
|
|
215
|
+
const printDetailedStory = (story, entities = {}) => {
|
|
216
|
+
var _story$group2;
|
|
217
|
+
const labels = story.labels.map((l) => {
|
|
218
|
+
return chalk.default.bold(`#${l.id}`) + ` ${l.name}`;
|
|
219
|
+
});
|
|
220
|
+
const owners = story.owners.map((o) => {
|
|
221
|
+
const mentionName = chalk.default.bold(`${o.profile.mention_name}`);
|
|
222
|
+
return `${o.profile.name} (${mentionName})`;
|
|
223
|
+
});
|
|
224
|
+
log(chalk.default.blue.bold(`#${story.id}`) + chalk.default.blue(` ${story.name}`));
|
|
225
|
+
log(chalk.default.bold("Desc:") + ` ${formatLong(story.description || "_")}`);
|
|
226
|
+
log(chalk.default.bold("Team:") + ` ${((_story$group2 = story.group) === null || _story$group2 === void 0 ? void 0 : _story$group2.name) || "_"}`);
|
|
227
|
+
log(chalk.default.bold("Owners:") + ` ${owners.join(", ") || "_"}`);
|
|
228
|
+
log(chalk.default.bold("Requester:") + ` ${story.requester.profile.name} (${story.requester.profile.mention_name})`);
|
|
229
|
+
log(chalk.default.bold("Type:") + ` ${story.story_type}/${story.estimate || "_"}`);
|
|
230
|
+
log(chalk.default.bold("Label:") + ` ${labels.join(", ") || "_"}`);
|
|
231
|
+
if (story.project) log(chalk.default.bold("Project:") + chalk.default.bold(` #${story.project_id} `) + story.project.name);
|
|
232
|
+
if (story.group) log(chalk.default.bold("Team:") + chalk.default.bold(` #${story.group_id} `) + story.group.name);
|
|
233
|
+
if (story.epic) log(chalk.default.bold("Epic:") + chalk.default.bold(` #${story.epic_id} `) + story.epic.name);
|
|
234
|
+
else log(chalk.default.bold("Epic:") + " _");
|
|
235
|
+
if (story.iteration) log(chalk.default.bold("Iteration:") + chalk.default.bold(` #${story.iteration_id} `) + story.iteration.name);
|
|
236
|
+
else log(chalk.default.bold("Iteration:") + " _");
|
|
237
|
+
log(chalk.default.bold("State:") + chalk.default.bold(` #${story.workflow_state_id} `) + story.state.name);
|
|
238
|
+
log(chalk.default.bold("Created:") + ` ${story.created_at}`);
|
|
239
|
+
if (story.created_at !== story.updated_at) log(chalk.default.bold("Updated:") + ` ${story.updated_at}`);
|
|
240
|
+
log(chalk.default.bold("URL:") + ` ${storyURL(story)}`);
|
|
241
|
+
if (story.archived) log(chalk.default.bold("Archived: ") + chalk.default.bold(`${story.archived}`));
|
|
242
|
+
if (story.completed) log(chalk.default.bold("Completed: ") + chalk.default.bold(`${story.completed_at}`));
|
|
243
|
+
story.tasks.map((c) => {
|
|
244
|
+
log(chalk.default.bold("Task: ") + (c.complete ? "[X]" : "[ ]") + " " + formatLong(c.description));
|
|
245
|
+
return c;
|
|
246
|
+
});
|
|
247
|
+
story.comments.filter((comment) => !comment.deleted).map((c) => {
|
|
248
|
+
const author = entities.membersById.get(c.author_id);
|
|
249
|
+
log(chalk.default.bold("Comment:") + ` ${formatLong(c.text)}`);
|
|
250
|
+
log(` ${author.profile.name} ` + chalk.default.bold("at:") + ` ${c.updated_at}`);
|
|
251
|
+
return c;
|
|
252
|
+
});
|
|
253
|
+
story.files.map((file) => {
|
|
254
|
+
log(chalk.default.bold("File:") + ` ${file.name}`);
|
|
255
|
+
log(` ${file.url}`);
|
|
256
|
+
return file;
|
|
257
|
+
});
|
|
258
|
+
log();
|
|
429
259
|
};
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
260
|
+
const formatLong = (str) => str.split("\n").join("\n ");
|
|
261
|
+
const parseDateComparator = (arg) => {
|
|
262
|
+
const match = arg.match(/[0-9].*/) || {
|
|
263
|
+
index: 0,
|
|
264
|
+
"0": { length: 30 }
|
|
265
|
+
};
|
|
266
|
+
const parsedDate = new Date(arg.slice(match.index));
|
|
267
|
+
const comparator = arg.slice(0, match.index);
|
|
268
|
+
return (date) => {
|
|
269
|
+
switch (comparator) {
|
|
270
|
+
case "<": return new Date(date) < parsedDate;
|
|
271
|
+
case ">": return new Date(date) > parsedDate;
|
|
272
|
+
case "=":
|
|
273
|
+
default: return new Date(date.slice(0, match[0].length)).getTime() === parsedDate.getTime();
|
|
274
|
+
}
|
|
275
|
+
};
|
|
446
276
|
};
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
277
|
+
const parseNumberComparator = (arg) => {
|
|
278
|
+
const match = arg.match(/[0-9].*/) || {
|
|
279
|
+
index: 0,
|
|
280
|
+
"0": { length: 30 }
|
|
281
|
+
};
|
|
282
|
+
const parsedNumber = Number(arg.slice(match.index));
|
|
283
|
+
const comparator = arg.slice(0, match.index).trimRight();
|
|
284
|
+
return (n) => {
|
|
285
|
+
switch (comparator) {
|
|
286
|
+
case "<": return Number(n) < parsedNumber;
|
|
287
|
+
case ">": return Number(n) > parsedNumber;
|
|
288
|
+
case "=":
|
|
289
|
+
default: return Number(n) === parsedNumber;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
462
292
|
};
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
293
|
+
const buildStoryBranch = (story, prefix = "") => {
|
|
294
|
+
prefix = prefix || `${config.mentionName}/sc-${story.id}/${story.story_type}-`;
|
|
295
|
+
const slug = story.name.toLowerCase().replace(/\W/g, "-").replace(/[^a-z0-9-]/g, "").slice(0, 30).replace(/-$/, "");
|
|
296
|
+
return `${prefix}${slug}`;
|
|
467
297
|
};
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
298
|
+
const checkoutStoryBranch = (story, prefix = "") => {
|
|
299
|
+
const branch = buildStoryBranch(story, prefix);
|
|
300
|
+
debug$1("checking out git branch: " + branch);
|
|
301
|
+
(0, child_process.execSync)(`git checkout ${branch} 2> /dev/null || git checkout -b ${branch}`);
|
|
472
302
|
};
|
|
473
|
-
|
|
303
|
+
const fileURL = (file) => `${file.url}?token=${config.token}`;
|
|
474
304
|
var stories_default = {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
305
|
+
listStories,
|
|
306
|
+
printFormattedStory,
|
|
307
|
+
printDetailedStory,
|
|
308
|
+
checkoutStoryBranch,
|
|
309
|
+
fetchEntities,
|
|
310
|
+
hydrateStory,
|
|
311
|
+
findProject,
|
|
312
|
+
findGroup,
|
|
313
|
+
findState,
|
|
314
|
+
findEpic,
|
|
315
|
+
findIteration,
|
|
316
|
+
findOwnerIds,
|
|
317
|
+
findLabelNames,
|
|
318
|
+
fileURL,
|
|
319
|
+
storyURL,
|
|
320
|
+
buildURL
|
|
491
321
|
};
|
|
322
|
+
|
|
323
|
+
//#endregion
|
|
324
|
+
exports.default = stories_default;
|