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