bjira 0.0.15 → 0.0.19
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/LICENSE.md +1 -1
- package/README.md +5 -4
- package/package.json +1 -1
- package/src/ask.js +1 -1
- package/src/attachment.js +37 -0
- package/src/command.js +1 -1
- package/src/comment.js +1 -1
- package/src/create.js +13 -10
- package/src/errorhandler.js +6 -1
- package/src/field.js +112 -51
- package/src/index.js +3 -1
- package/src/init.js +1 -1
- package/src/issue.js +70 -7
- package/src/jira.js +17 -6
- package/src/preset.js +1 -1
- package/src/project.js +6 -1
- package/src/query.js +102 -13
- package/src/run.js +3 -2
- package/src/set.js +46 -16
- package/src/sprint.js +1 -1
- package/src/table.js +16 -5
- package/src/user.js +1 -1
- package/src/utils.js +1 -1
- package/aqtinstall.log +0 -0
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2021 Andrea Marchesini <baku@bnode.dev>
|
|
3
|
+
Copyright (c) 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -15,11 +15,11 @@ jira settings.
|
|
|
15
15
|
|
|
16
16
|
```
|
|
17
17
|
$ bjira init
|
|
18
|
-
? Provide your jira host: your-
|
|
18
|
+
? Provide your jira host: your-domain.atlassian.net
|
|
19
19
|
? Please provide your jira username: username
|
|
20
20
|
? API token: [hidden]
|
|
21
21
|
? Enable HTTPS Protocol? Yes
|
|
22
|
-
Config file succesfully created in: /home
|
|
22
|
+
Config file succesfully created in: /home/<username>/.bjira.json
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## How to use it
|
|
@@ -63,10 +63,11 @@ Jira is strongly configurable via custom fields. You can retrieve the list of cu
|
|
|
63
63
|
bjira field listall
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
If you want to see some of them in the issue report, add them:
|
|
66
|
+
If you want to see some of them in the issue report, add them for the project (FOO) and the issue type (Story):
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
bjira field add "Story Points"
|
|
69
|
+
bjira field add FOO Story "Story Points"
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Any custom fields added to the list will be shown in the issue report (See `bjira show`).
|
|
73
|
+
You can also set custom fields using `bira set custom `Story Points' ISSUE-ID`.
|
package/package.json
CHANGED
package/src/ask.js
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
import Command from './command.js';
|
|
6
|
+
import Field from './field.js';
|
|
7
|
+
import Issue from './issue.js';
|
|
8
|
+
import Jira from './jira.js';
|
|
9
|
+
import Utils from './utils.js';
|
|
10
|
+
|
|
11
|
+
class Attachment extends Command {
|
|
12
|
+
addOptions(program) {
|
|
13
|
+
const cmd = program.command('attachment')
|
|
14
|
+
.description('Play with attachments');
|
|
15
|
+
cmd.command('get')
|
|
16
|
+
.description('Get the attachment')
|
|
17
|
+
.argument('<issueID>', 'The issue ID')
|
|
18
|
+
.argument('<attachmentID>', 'The attachment ID')
|
|
19
|
+
.action(async (issueId, attachmentId) => {
|
|
20
|
+
const jira = new Jira(program);
|
|
21
|
+
|
|
22
|
+
const resultFields = await Field.listFields(jira);
|
|
23
|
+
|
|
24
|
+
const result = await jira.spin('Running query...', jira.api.findIssue(issueId));
|
|
25
|
+
const issue = Issue.replaceFields(result, resultFields);
|
|
26
|
+
|
|
27
|
+
const attachment = issue.fields['Attachment'].find(attachment => attachment.id === attachmentId);
|
|
28
|
+
const attachmentData = await jira.spin('Retriving attachment...', jira.api.downloadAttachment(attachment));
|
|
29
|
+
process.stdout.write(attachmentData);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// TODO: delete attachment
|
|
33
|
+
// TODO: upload attachment
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default Attachment;
|
package/src/command.js
CHANGED
package/src/comment.js
CHANGED
package/src/create.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -33,8 +33,8 @@ class Create extends Command {
|
|
|
33
33
|
}
|
|
34
34
|
})));
|
|
35
35
|
|
|
36
|
-
const meta = await
|
|
37
|
-
|
|
36
|
+
const meta = await Project.metadata(jira, project.key, issueType.name);
|
|
37
|
+
|
|
38
38
|
const newIssue = {
|
|
39
39
|
fields: {
|
|
40
40
|
project: {
|
|
@@ -58,11 +58,12 @@ class Create extends Command {
|
|
|
58
58
|
.issuetypes.find(i => i.name === issueType.name).fields;
|
|
59
59
|
const requiredFields = Object.keys(issueFields).filter(
|
|
60
60
|
key => issueFields[key].required &&
|
|
61
|
-
Field.isSupported(issueFields[key]
|
|
62
|
-
!["summary", "description", "project"].includes(key)).map(key => issueFields[key]);
|
|
61
|
+
Field.isSupported(issueFields[key]) &&
|
|
62
|
+
!["issuetype", "summary", "description", "project"].includes(key)).map(key => issueFields[key]);
|
|
63
63
|
|
|
64
64
|
for (const field of requiredFields) {
|
|
65
|
-
|
|
65
|
+
const fieldData = await Field.askFieldIfSupported(field);
|
|
66
|
+
newIssue.fields[fieldData.key] = fieldData.value;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
if (issueType.name !== 'Epic' &&
|
|
@@ -100,10 +101,12 @@ class Create extends Command {
|
|
|
100
101
|
await Set.setStatus(jira, issue.key);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
const customFields = jira.fields.filter(
|
|
105
|
+
field => field.projectName === project.key &&
|
|
106
|
+
field.issueTypeName === issueType.name);
|
|
107
|
+
if (customFields.length > 0 && await Ask.askBoolean('Do you want to set custom fields?')) {
|
|
108
|
+
for (let customField of customFields) {
|
|
109
|
+
await Set.setCustomField(jira, customField, issue.key);
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
|
package/src/errorhandler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -20,6 +20,11 @@ class ErrorHandler {
|
|
|
20
20
|
color: "blue",
|
|
21
21
|
text: error
|
|
22
22
|
}]));
|
|
23
|
+
} else if ("message" in e.error) {
|
|
24
|
+
table.addRow([{
|
|
25
|
+
color: "blue",
|
|
26
|
+
text: e.error.message
|
|
27
|
+
}]);
|
|
23
28
|
} else {
|
|
24
29
|
table.addRow([{
|
|
25
30
|
color: "blue",
|
package/src/field.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
5
|
+
import color from 'chalk';
|
|
6
|
+
|
|
5
7
|
import Ask from './ask.js';
|
|
6
8
|
import Command from './command.js';
|
|
7
9
|
import Jira from './jira.js';
|
|
10
|
+
import Project from './project.js';
|
|
8
11
|
import Table from './table.js';
|
|
9
12
|
|
|
10
13
|
class Field extends Command {
|
|
@@ -16,59 +19,76 @@ class Field extends Command {
|
|
|
16
19
|
.action(async () => {
|
|
17
20
|
const jira = new Jira(program);
|
|
18
21
|
|
|
19
|
-
const resultFields = await
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
const resultFields = await jira.spin('Retrieving the fields...',
|
|
23
|
+
jira.apiRequest('/issue/createmeta?expand=projects.issuetypes.fields'));
|
|
24
|
+
|
|
25
|
+
resultFields.projects.forEach(project => {
|
|
26
|
+
console.log(`\nProject: ${color.blue(project.name)} (${color.blue(project.key)})`);
|
|
27
|
+
project.issuetypes.forEach(issueType => {
|
|
28
|
+
console.log(`\nIssue type: ${color.yellow(issueType.name)}`);
|
|
29
|
+
|
|
30
|
+
const table = new Table({
|
|
31
|
+
head: ['Name', 'Supported', 'Type']
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
for (const fieldName in issueType.fields) {
|
|
35
|
+
const field = issueType.fields[fieldName];
|
|
36
|
+
const supported = Field.isSupported(field);
|
|
37
|
+
table.addRow([{
|
|
38
|
+
color: "blue",
|
|
39
|
+
text: field.name
|
|
40
|
+
}, supported, supported ? field.schema?.type : ""]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(table.toString());
|
|
44
|
+
});
|
|
31
45
|
});
|
|
32
|
-
console.log(table.toString());
|
|
33
46
|
});
|
|
34
47
|
|
|
35
48
|
cmd.command("add")
|
|
36
49
|
.description("Add a custom field to be shown")
|
|
50
|
+
.argument('<project>', 'The project name')
|
|
51
|
+
.argument('<issueType>', 'The issue type')
|
|
37
52
|
.argument('<field>', 'The field name')
|
|
38
|
-
.action(async fieldName => {
|
|
53
|
+
.action(async (projectName, issueTypeName, fieldName) => {
|
|
39
54
|
const jira = new Jira(program);
|
|
40
55
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!
|
|
45
|
-
console.log(
|
|
56
|
+
const meta = await Project.metadata(jira, projectName, issueTypeName);
|
|
57
|
+
const issueType = meta.projects.find(p => p.key === projectName)
|
|
58
|
+
.issuetypes.find(i => i.name === issueTypeName);
|
|
59
|
+
if (!issueType) {
|
|
60
|
+
console.log(`Issue type ${issueTypeName} does not exist.`);
|
|
46
61
|
return;
|
|
47
62
|
}
|
|
48
63
|
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
for (const name in issueType.fields) {
|
|
65
|
+
const field = issueType.fields[name];
|
|
66
|
+
if (field.name !== fieldName) continue;
|
|
67
|
+
|
|
68
|
+
if (!Field.isSupported(field)) {
|
|
69
|
+
console.log("Unsupported field.");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
jira.addField(projectName, issueTypeName, fieldName);
|
|
74
|
+
jira.syncConfig();
|
|
75
|
+
|
|
76
|
+
console.log('Config file succesfully updated');
|
|
51
77
|
return;
|
|
52
78
|
}
|
|
53
79
|
|
|
54
|
-
|
|
55
|
-
jira.syncConfig();
|
|
56
|
-
|
|
57
|
-
console.log('Config file succesfully updated');
|
|
80
|
+
console.log(`Field ${fieldName} does not exist in Issue type ${issueTypeName} for project ${projectName}`);
|
|
58
81
|
});
|
|
59
82
|
|
|
60
83
|
cmd.command("remove")
|
|
61
84
|
.description("Remove a custom field")
|
|
85
|
+
.argument('<project>', 'The project name')
|
|
86
|
+
.argument('<issueType>', 'The issue type')
|
|
62
87
|
.argument('<field>', 'The field name')
|
|
63
|
-
.action(async fieldName => {
|
|
88
|
+
.action(async (projectName, issueTypeName, fieldName) => {
|
|
64
89
|
const jira = new Jira(program);
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
console.log("Unknown field.");
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
jira.removeField(fieldName);
|
|
91
|
+
jira.removeField(projectName, issueTypeName, fieldName);
|
|
72
92
|
jira.syncConfig();
|
|
73
93
|
|
|
74
94
|
console.log('Config file succesfully updated');
|
|
@@ -80,12 +100,17 @@ class Field extends Command {
|
|
|
80
100
|
const jira = new Jira(program);
|
|
81
101
|
|
|
82
102
|
const table = new Table({
|
|
83
|
-
head: ['Name']
|
|
103
|
+
head: ['Project', 'Issue Type', 'Name']
|
|
84
104
|
});
|
|
85
105
|
|
|
86
|
-
jira.fields.forEach(
|
|
106
|
+
jira.fields.forEach(field => table.addRow([{
|
|
87
107
|
color: "blue",
|
|
88
|
-
text:
|
|
108
|
+
text: field.projectName,
|
|
109
|
+
}, {
|
|
110
|
+
color: "yellow",
|
|
111
|
+
text: field.issueTypeName
|
|
112
|
+
}, {
|
|
113
|
+
text: field.fieldName
|
|
89
114
|
}]));
|
|
90
115
|
console.log(table.toString());
|
|
91
116
|
});
|
|
@@ -95,24 +120,51 @@ class Field extends Command {
|
|
|
95
120
|
return await jira.spin('Retrieving the fields...', jira.api.listFields());
|
|
96
121
|
}
|
|
97
122
|
|
|
98
|
-
static isSupported(
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
static isSupported(fieldData) {
|
|
124
|
+
if (["string", "number"].includes(fieldData.schema?.type)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
101
127
|
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
if ("allowedValues" in fieldData) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
104
131
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (field.name === fieldName) fieldData = field;
|
|
108
|
-
});
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
109
134
|
|
|
110
|
-
|
|
111
|
-
|
|
135
|
+
static fieldValue(field, fieldData) {
|
|
136
|
+
if (!Field.isSupported(fieldData)) {
|
|
112
137
|
return null;
|
|
113
138
|
}
|
|
114
139
|
|
|
115
|
-
|
|
140
|
+
let type;
|
|
141
|
+
switch (fieldData.schema.type) {
|
|
142
|
+
case 'number':
|
|
143
|
+
return field;
|
|
144
|
+
case 'string':
|
|
145
|
+
return field;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return field.name;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static async fetchAndAskFieldIfSupported(jira, field) {
|
|
152
|
+
const meta = await Project.metadata(jira, field.projectName, field.issueTypeName);
|
|
153
|
+
const fields = meta.projects.find(p => p.key === field.projectName)
|
|
154
|
+
.issuetypes.find(i => i.name === field.issueTypeName).fields;
|
|
155
|
+
|
|
156
|
+
for (const name in fields) {
|
|
157
|
+
const fieldObj = fields[name];
|
|
158
|
+
if (fieldObj.name === field.fieldName) {
|
|
159
|
+
return Field.askFieldIfSupported(fieldObj);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
static async askFieldIfSupported(fieldData) {
|
|
167
|
+
if (!Field.isSupported(fieldData)) {
|
|
116
168
|
console.log("Unsupported field");
|
|
117
169
|
return null;
|
|
118
170
|
}
|
|
@@ -121,15 +173,24 @@ class Field extends Command {
|
|
|
121
173
|
switch (fieldData.schema.type) {
|
|
122
174
|
case 'number':
|
|
123
175
|
return {
|
|
124
|
-
value: await Ask.askNumber(`${
|
|
176
|
+
value: await Ask.askNumber(`${fieldData.name}:`), key: fieldData.key
|
|
125
177
|
};
|
|
126
178
|
case 'string':
|
|
127
179
|
return {
|
|
128
|
-
value: await Ask.askString(`${
|
|
180
|
+
value: await Ask.askString(`${fieldData.name}:`), key: fieldData.key
|
|
129
181
|
};
|
|
130
182
|
}
|
|
131
183
|
|
|
132
|
-
return
|
|
184
|
+
return {
|
|
185
|
+
key: fieldData.key,
|
|
186
|
+
value: await Ask.askList(`${fieldData.name}:`,
|
|
187
|
+
fieldData.allowedValues.map(value => ({
|
|
188
|
+
name: value.name,
|
|
189
|
+
value: {
|
|
190
|
+
id: value.id
|
|
191
|
+
}
|
|
192
|
+
})))
|
|
193
|
+
};
|
|
133
194
|
}
|
|
134
195
|
};
|
|
135
196
|
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
3
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
4
4
|
//
|
|
5
5
|
// SPDX-License-Identifier: MIT
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ import fs from 'fs';
|
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
|
|
12
|
+
import Attachment from './attachment.js';
|
|
12
13
|
import Comment from './comment.js';
|
|
13
14
|
import Create from './create.js';
|
|
14
15
|
import Field from './field.js';
|
|
@@ -24,6 +25,7 @@ import Sprint from './sprint.js';
|
|
|
24
25
|
const DEFAULT_CONFIG_FILE = path.join(os.homedir(), ".bjira.json")
|
|
25
26
|
|
|
26
27
|
const commands = [
|
|
28
|
+
new Attachment(),
|
|
27
29
|
new Comment(),
|
|
28
30
|
new Create(),
|
|
29
31
|
new Field(),
|
package/src/init.js
CHANGED
package/src/issue.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
5
5
|
import Command from './command.js';
|
|
6
6
|
import Field from './field.js';
|
|
7
7
|
import Jira from './jira.js';
|
|
8
|
+
import Project from './project.js';
|
|
9
|
+
import Query from './query.js';
|
|
8
10
|
import Table from './table.js';
|
|
9
11
|
|
|
10
12
|
const DEFAULT_QUERY_LIMIT = 20;
|
|
@@ -17,7 +19,9 @@ class Issue extends Command {
|
|
|
17
19
|
addOptions(program) {
|
|
18
20
|
const cmd = program.command('show')
|
|
19
21
|
.description('Show an issue')
|
|
22
|
+
.option('-a, --attachments', 'Show the attachments too')
|
|
20
23
|
.option('-C, --comments', 'Show the comments too')
|
|
24
|
+
.option('-s, --subissues', 'Show the comments too')
|
|
21
25
|
.argument('<id>', 'The issue ID')
|
|
22
26
|
.action(async id => {
|
|
23
27
|
const jira = new Jira(program);
|
|
@@ -64,9 +68,6 @@ class Issue extends Command {
|
|
|
64
68
|
[
|
|
65
69
|
'Assignee', Issue.showUser(issue.fields['Assignee'])
|
|
66
70
|
],
|
|
67
|
-
[
|
|
68
|
-
'Priority', issue.fields['Priority'].name
|
|
69
|
-
],
|
|
70
71
|
[
|
|
71
72
|
'Epic Link', {
|
|
72
73
|
color: "yellow",
|
|
@@ -84,7 +85,22 @@ class Issue extends Command {
|
|
|
84
85
|
]
|
|
85
86
|
]);
|
|
86
87
|
|
|
87
|
-
jira.fields.
|
|
88
|
+
const customFields = jira.fields.filter(
|
|
89
|
+
field => field.projectName === issue.fields['Project'].key &&
|
|
90
|
+
field.issueTypeName === issue.fields['Issue Type'].name);
|
|
91
|
+
if (customFields.length > 0) {
|
|
92
|
+
const meta = await Project.metadata(jira, issue.fields['Project'].key, issue.fields['Issue Type'].name);
|
|
93
|
+
customFields.forEach(field => {
|
|
94
|
+
const fields = meta.projects.find(p => p.key === field.projectName)
|
|
95
|
+
.issuetypes.find(i => i.name === field.issueTypeName).fields;
|
|
96
|
+
for (const name in fields) {
|
|
97
|
+
const fieldObj = fields[name];
|
|
98
|
+
if (fieldObj.name === field.fieldName) {
|
|
99
|
+
table.addRow([field.fieldName, Field.fieldValue(issue.fields[field.fieldName], fieldObj) || "unset"]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
88
104
|
|
|
89
105
|
table.addRows([
|
|
90
106
|
[
|
|
@@ -105,11 +121,45 @@ class Issue extends Command {
|
|
|
105
121
|
[
|
|
106
122
|
'', ''
|
|
107
123
|
],
|
|
124
|
+
[
|
|
125
|
+
'Attachments', issue.fields['Attachment'].length
|
|
126
|
+
],
|
|
108
127
|
[
|
|
109
128
|
'Comments', issue.fields['Comment'].total
|
|
110
|
-
]
|
|
129
|
+
],
|
|
111
130
|
]);
|
|
112
131
|
|
|
132
|
+
if (cmd.opts().attachments) {
|
|
133
|
+
issue.fields['Attachment'].forEach(attachment => {
|
|
134
|
+
table.addRows([
|
|
135
|
+
[
|
|
136
|
+
'', ''
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
'Attachment', {
|
|
140
|
+
color: "yellow",
|
|
141
|
+
text: attachment.id
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
'Filename', attachment.filename
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
'Author', Issue.showUser(attachment.author)
|
|
149
|
+
],
|
|
150
|
+
[
|
|
151
|
+
'Size', attachment.size
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
'Mime-type', attachment.mimeType
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
'Created on', attachment['Created']
|
|
158
|
+
],
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
113
163
|
if (cmd.opts().comments) {
|
|
114
164
|
issue.fields['Comment'].comments.forEach(comment => {
|
|
115
165
|
table.addRows([
|
|
@@ -133,12 +183,25 @@ class Issue extends Command {
|
|
|
133
183
|
],
|
|
134
184
|
[
|
|
135
185
|
'Body', comment.body
|
|
136
|
-
]
|
|
186
|
+
],
|
|
137
187
|
]);
|
|
138
188
|
});
|
|
139
189
|
}
|
|
140
190
|
|
|
141
191
|
console.log(table.toString());
|
|
192
|
+
|
|
193
|
+
if (cmd.opts().subissues) {
|
|
194
|
+
console.log("\nSub-issues:");
|
|
195
|
+
const children = await Query.runQuery(jira, `parent = "${id}"`, 999999);
|
|
196
|
+
await Query.showIssues(jira, children.issues, children.total, resultFields, false);
|
|
197
|
+
|
|
198
|
+
if (issue.fields['Issue Type'].name === 'Epic') {
|
|
199
|
+
console.log("\nEpic issues:");
|
|
200
|
+
const children = await jira.spin('Fetching child issues...', jira.api.getIssuesForEpic(id));
|
|
201
|
+
await Query.showIssues(jira, children.issues, children.total, resultFields, false);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
142
205
|
});
|
|
143
206
|
}
|
|
144
207
|
|
package/src/jira.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -31,16 +31,27 @@ class Jira {
|
|
|
31
31
|
this._config.latestProject = latestProject;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
addField(fieldName) {
|
|
34
|
+
addField(projectName, issueTypeName, fieldName) {
|
|
35
35
|
if (!Array.isArray(this._config.fields)) this._config.fields = [];
|
|
36
36
|
|
|
37
|
-
this._config.fields.
|
|
37
|
+
if (!this._config.fields.find(field => field.projectName === projectName &&
|
|
38
|
+
field.issueTypeName === issueTypeName && field.fieldName === fieldName)) {
|
|
39
|
+
this._config.fields.push({
|
|
40
|
+
projectName,
|
|
41
|
+
issueTypeName,
|
|
42
|
+
fieldName
|
|
43
|
+
});
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
removeField(fieldName) {
|
|
41
|
-
if (!Array.isArray(this._config.fields)
|
|
47
|
+
removeField(projectName, issueTypeName, fieldName) {
|
|
48
|
+
if (!Array.isArray(this._config.fields)) return;
|
|
42
49
|
|
|
43
|
-
this._config.fields.
|
|
50
|
+
const pos = this._config.fields.findIndex(field => field.projectName === projectName &&
|
|
51
|
+
field.issueTypeName === issueTypeName && field.fieldName === fieldName);
|
|
52
|
+
if (pos !== -1) {
|
|
53
|
+
this._config.fields.splice(pos, 1);
|
|
54
|
+
}
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
get fields() {
|
package/src/preset.js
CHANGED
package/src/project.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -73,6 +73,11 @@ class Project extends Command {
|
|
|
73
73
|
issueTypes: project.issuetypes,
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
static async metadata(jira, project, issueType) {
|
|
78
|
+
return await jira.spin('Retrieving the fields...',
|
|
79
|
+
jira.apiRequest(`/issue/createmeta?projectKeys=${project}&issuetypeNames=${issueType}&expand=projects.issuetypes.fields`));
|
|
80
|
+
}
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
export default Project;
|
package/src/query.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -21,6 +21,7 @@ class Query extends Command {
|
|
|
21
21
|
.option('-l, --limit <limit>',
|
|
22
22
|
`Set the query limit. Default ${DEFAULT_QUERY_LIMIT}`,
|
|
23
23
|
DEFAULT_QUERY_LIMIT)
|
|
24
|
+
.option('-g, --grouped', 'Group the issues by parenting')
|
|
24
25
|
.action(async query => {
|
|
25
26
|
const jira = new Jira(program);
|
|
26
27
|
const opts = cmd.opts();
|
|
@@ -28,32 +29,120 @@ class Query extends Command {
|
|
|
28
29
|
const resultFields = await Field.listFields(jira);
|
|
29
30
|
const result = await Query.runQuery(jira, query, opts.limit);
|
|
30
31
|
|
|
31
|
-
Query.showIssues(jira, result.issues, result.total, resultFields);
|
|
32
|
+
await Query.showIssues(jira, result.issues, result.total, resultFields, opts.grouped);
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
static showIssues(jira, issues, total, fields) {
|
|
36
|
+
static async showIssues(jira, issues, total, fields, grouped) {
|
|
36
37
|
console.log(`Showing ${color.bold(issues.length)} issues of ${color.bold(total)}`);
|
|
37
38
|
|
|
39
|
+
issues = issues.map(issue => Issue.replaceFields(issue, fields)).map(issue => ({
|
|
40
|
+
children: [],
|
|
41
|
+
issue
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const addIssueInTree = (issues, issue, parentId) => {
|
|
45
|
+
for (const existingIssue of issues) {
|
|
46
|
+
if (existingIssue.issue.key == parentId) {
|
|
47
|
+
existingIssue.children.push(issue);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (addIssueInTree(existingIssue.children, issue, parentId)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const computeIssueInTree = async (issues, newIssues, issue) => {
|
|
60
|
+
// Top level.
|
|
61
|
+
if (!issue.issue.fields['Epic Link'] && !issue.issue.fields['Parent']) {
|
|
62
|
+
newIssues.push(issue);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const parentId = issue.issue.fields['Epic Link'] || issue.issue.fields['Parent'].key;
|
|
67
|
+
|
|
68
|
+
// In the already processed issues
|
|
69
|
+
if (addIssueInTree(newIssues, issue, parentId)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// In the non-already processed issues
|
|
74
|
+
if (addIssueInTree(issues, issue, parentId)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const parentIssueResult = await jira.spin('Running query...', jira.api.findIssue(parentId));
|
|
79
|
+
const parentIssue = Issue.replaceFields(parentIssueResult, fields);
|
|
80
|
+
|
|
81
|
+
const parentIssueData = {
|
|
82
|
+
children: [issue],
|
|
83
|
+
incompleted: true,
|
|
84
|
+
issue: parentIssue
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
await computeIssueInTree(issues, newIssues, parentIssueData);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (grouped) {
|
|
91
|
+
const newIssues = [];
|
|
92
|
+
for (; issues.length; issues = issues.splice(1)) {
|
|
93
|
+
await computeIssueInTree(issues, newIssues, issues[0]);
|
|
94
|
+
}
|
|
95
|
+
issues = newIssues;
|
|
96
|
+
}
|
|
97
|
+
|
|
38
98
|
const table = new Table({
|
|
39
|
-
head: ['Key', 'Status', 'Type', 'Assignee', 'Summary']
|
|
99
|
+
head: ['Key', 'Status', 'Type', 'Assignee', 'Summary'],
|
|
100
|
+
unresizableColumns: [0],
|
|
40
101
|
});
|
|
41
102
|
|
|
42
|
-
|
|
103
|
+
const showIssue = (table, issue, nested) => {
|
|
104
|
+
let pre = "";
|
|
105
|
+
if (nested.length) {
|
|
106
|
+
pre += " ";
|
|
107
|
+
for (let i = 0; i < nested.length - 1; ++i) {
|
|
108
|
+
pre += (nested[i]) ? '│ ' : ' ';
|
|
109
|
+
}
|
|
110
|
+
pre += (nested[nested.length - 1]) ? "├─ " : "└─ ";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
table.addRow([{
|
|
43
114
|
color: "blue",
|
|
44
|
-
|
|
115
|
+
style: issue.incompleted ? "italic" : "normal",
|
|
116
|
+
text: pre + issue.issue.key
|
|
45
117
|
}, {
|
|
46
118
|
color: "green",
|
|
47
|
-
|
|
119
|
+
style: issue.incompleted ? "italic" : "normal",
|
|
120
|
+
text: issue.issue.fields['Status'].name
|
|
48
121
|
}, {
|
|
49
122
|
color: "green",
|
|
50
|
-
|
|
123
|
+
style: issue.incompleted ? "italic" : "normal",
|
|
124
|
+
text: issue.issue.fields['Issue Type'].name
|
|
51
125
|
}, {
|
|
52
126
|
color: "yellow",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
127
|
+
style: issue.incompleted ? "italic" : "normal",
|
|
128
|
+
text: Issue.showUser(issue.issue.fields['Assignee'])
|
|
129
|
+
}, {
|
|
130
|
+
style: issue.incompleted ? "italic" : "normal",
|
|
131
|
+
text: issue.issue.fields['Summary']
|
|
132
|
+
}]);
|
|
133
|
+
|
|
134
|
+
if (issue.children.length) {
|
|
135
|
+
const newNested = [];
|
|
136
|
+
nested.forEach(n => newNested.push(n));
|
|
137
|
+
newNested.push(false);
|
|
138
|
+
issue.children.forEach((subissue, pos) => {
|
|
139
|
+
newNested[nested.length] = (pos < issue.children.length - 1);
|
|
140
|
+
showIssue(table, subissue, newNested);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
issues.forEach(issue => showIssue(table, issue, []));
|
|
57
146
|
|
|
58
147
|
console.log(table.toString());
|
|
59
148
|
}
|
|
@@ -64,7 +153,7 @@ class Query extends Command {
|
|
|
64
153
|
while (issues.length < (expectedResult === undefined ? issues.length + 1 : expectedResult)) {
|
|
65
154
|
const result = await jira.spin('Running query...',
|
|
66
155
|
jira.api.searchJira(query, {
|
|
67
|
-
startAt: issues.
|
|
156
|
+
startAt: issues.length,
|
|
68
157
|
maxResults: expectedResult - issues.length
|
|
69
158
|
}));
|
|
70
159
|
|
package/src/run.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -19,6 +19,7 @@ class Run extends Command {
|
|
|
19
19
|
.option('-l, --limit <limit>',
|
|
20
20
|
`Set the query limit. Default ${DEFAULT_QUERY_LIMIT}`,
|
|
21
21
|
DEFAULT_QUERY_LIMIT)
|
|
22
|
+
.option('-g, --grouped', 'Group the issues by parenting')
|
|
22
23
|
.action(async name => {
|
|
23
24
|
const jira = new Jira(program);
|
|
24
25
|
const opts = cmd.opts();
|
|
@@ -46,7 +47,7 @@ class Run extends Command {
|
|
|
46
47
|
const resultFields = await Field.listFields(jira);
|
|
47
48
|
const result = await Query.runQuery(jira, query, opts.limit);
|
|
48
49
|
|
|
49
|
-
Query.showIssues(jira, result.issues, result.total, resultFields);
|
|
50
|
+
await Query.showIssues(jira, result.issues, result.total, resultFields, opts.grouped);
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
|
package/src/set.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
5
5
|
import Ask from './ask.js';
|
|
6
6
|
import Command from './command.js';
|
|
7
7
|
import Field from './field.js';
|
|
8
|
+
import Issue from './issue.js';
|
|
8
9
|
import Jira from './jira.js';
|
|
9
10
|
import User from './user.js';
|
|
10
11
|
|
|
@@ -14,7 +15,7 @@ class Set extends Command {
|
|
|
14
15
|
.description('Update fields in an issue');
|
|
15
16
|
setCmd.command('assignee')
|
|
16
17
|
.description('Assign the issue to somebody')
|
|
17
|
-
.argument('<
|
|
18
|
+
.argument('<ID>', 'The issue ID')
|
|
18
19
|
.action(async id => {
|
|
19
20
|
const jira = new Jira(program);
|
|
20
21
|
await Set.assignIssue(jira, id);
|
|
@@ -22,7 +23,7 @@ class Set extends Command {
|
|
|
22
23
|
|
|
23
24
|
setCmd.command('unassign')
|
|
24
25
|
.description('Unassign the issue')
|
|
25
|
-
.argument('<
|
|
26
|
+
.argument('<ID>', 'The issue ID')
|
|
26
27
|
.action(async id => {
|
|
27
28
|
const jira = new Jira(program);
|
|
28
29
|
|
|
@@ -34,12 +35,12 @@ class Set extends Command {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
await jira.spin(
|
|
38
|
+
await jira.spin(`Updating issue ${id}...`, jira.api.updateIssue(id, issue));
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
setCmd.command('status')
|
|
41
42
|
.description('Change the status')
|
|
42
|
-
.argument('<
|
|
43
|
+
.argument('<ID>', 'The issue ID')
|
|
43
44
|
.action(async id => {
|
|
44
45
|
const jira = new Jira(program);
|
|
45
46
|
await Set.setStatus(jira, id);
|
|
@@ -51,7 +52,21 @@ class Set extends Command {
|
|
|
51
52
|
.argument('<id>', 'The issue ID')
|
|
52
53
|
.action(async (fieldName, id) => {
|
|
53
54
|
const jira = new Jira(program);
|
|
54
|
-
|
|
55
|
+
|
|
56
|
+
const resultFields = await Field.listFields(jira);
|
|
57
|
+
const result = await jira.spin('Running query...', jira.api.findIssue(id));
|
|
58
|
+
const issue = Issue.replaceFields(result, resultFields);
|
|
59
|
+
|
|
60
|
+
const customField = jira.fields.find(
|
|
61
|
+
field => field.projectName === issue.fields['Project'].key &&
|
|
62
|
+
field.issueTypeName === issue.fields['Issue Type'].name &&
|
|
63
|
+
field.fieldName === fieldName);
|
|
64
|
+
if (!customField) {
|
|
65
|
+
console.log("Unknown custom field");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await Set.setCustomField(jira, customField, id);
|
|
55
70
|
});
|
|
56
71
|
}
|
|
57
72
|
|
|
@@ -72,12 +87,12 @@ class Set extends Command {
|
|
|
72
87
|
}
|
|
73
88
|
}
|
|
74
89
|
|
|
75
|
-
await jira.spin(
|
|
90
|
+
await jira.spin(`Updating issue ${id}...`, jira.api.updateIssue(id, issue));
|
|
76
91
|
}
|
|
77
92
|
|
|
78
|
-
static async setCustomField(jira,
|
|
79
|
-
const field = await Field.
|
|
80
|
-
if (
|
|
93
|
+
static async setCustomField(jira, customField, id) {
|
|
94
|
+
const field = await Field.fetchAndAskFieldIfSupported(jira, customField);
|
|
95
|
+
if (field === null) {
|
|
81
96
|
console.log("Unsupported field type");
|
|
82
97
|
return;
|
|
83
98
|
}
|
|
@@ -85,7 +100,7 @@ class Set extends Command {
|
|
|
85
100
|
const data = {};
|
|
86
101
|
data[field.key] = field.value;
|
|
87
102
|
|
|
88
|
-
await jira.spin(
|
|
103
|
+
await jira.spin(`Updating issue ${id}...`, jira.api.updateIssue(id, {
|
|
89
104
|
fields: {
|
|
90
105
|
...data
|
|
91
106
|
}
|
|
@@ -94,18 +109,33 @@ class Set extends Command {
|
|
|
94
109
|
|
|
95
110
|
static async setStatus(jira, id) {
|
|
96
111
|
const transitionList = await jira.spin('Retrieving transitions...', jira.api.listTransitions(id));
|
|
97
|
-
const
|
|
98
|
-
transitionList.transitions.map(transition => ({
|
|
112
|
+
const transitionData = await Ask.askList('Status:',
|
|
113
|
+
transitionList.transitions.filter(transition => transition.isAvailable).map(transition => ({
|
|
99
114
|
name: transition.name,
|
|
100
|
-
value: transition
|
|
115
|
+
value: transition
|
|
101
116
|
})));
|
|
117
|
+
|
|
102
118
|
const transition = {
|
|
103
119
|
transition: {
|
|
104
|
-
id:
|
|
120
|
+
id: transitionData.id
|
|
105
121
|
}
|
|
106
122
|
};
|
|
107
123
|
|
|
108
|
-
|
|
124
|
+
for (const field of Object.keys(transitionData.fields)) {
|
|
125
|
+
const fieldData = transitionData.fields[field];
|
|
126
|
+
|
|
127
|
+
if (!fieldData.required) continue;
|
|
128
|
+
|
|
129
|
+
if (!Field.isSupported(fieldData)) {
|
|
130
|
+
console.log(`Field ${field} is required but it's not supported`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const fieldValue = await Field.askFieldIfSupported(fieldData);
|
|
135
|
+
transition.transition[fieldValue.key] = fieldValue.value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await jira.spin(`Updating issue ${id}...`, jira.api.transitionIssue(id, transition));
|
|
109
139
|
}
|
|
110
140
|
};
|
|
111
141
|
|
package/src/sprint.js
CHANGED
package/src/table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2021 Andrea Marchesini <baku@bnode.dev>
|
|
1
|
+
// SPDX-FileCopyrightText: 2021-2022 Andrea Marchesini <baku@bnode.dev>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
4
|
|
|
@@ -12,6 +12,8 @@ class Table {
|
|
|
12
12
|
options.head?.forEach(head => {
|
|
13
13
|
this._columns.push(this._createColumn(head, 0));
|
|
14
14
|
});
|
|
15
|
+
|
|
16
|
+
this._unresizableColumns = options.unresizableColumns || [];
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
addRow(row) {
|
|
@@ -58,7 +60,7 @@ class Table {
|
|
|
58
60
|
const rowHeight = Math.max(...this._columns.map(column => this._computeRowHeight(column, row)));
|
|
59
61
|
|
|
60
62
|
for (let i = 0; i < rowHeight; ++i) {
|
|
61
|
-
lines.push(this._columns.map(column => this.
|
|
63
|
+
lines.push(this._columns.map(column => this._stylize(column.rows[row], this._toWidth(this._computeLine(column.rows[row], i), column.width))).join(" "));
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -118,7 +120,7 @@ class Table {
|
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
_maybeSplitRow(row, width) {
|
|
121
|
-
if (row.length
|
|
123
|
+
if (row.length <= width) return [row];
|
|
122
124
|
|
|
123
125
|
const rows = [];
|
|
124
126
|
let currentRow = "";
|
|
@@ -142,8 +144,9 @@ class Table {
|
|
|
142
144
|
|
|
143
145
|
_resizeWidthOfOne() {
|
|
144
146
|
const max = Math.max(...this._columns.map(column => column.width));
|
|
145
|
-
for (let
|
|
146
|
-
|
|
147
|
+
for (let columnId in this._columns) {
|
|
148
|
+
const column = this._columns[columnId];
|
|
149
|
+
if (!this._unresizableColumns.includes(columnId) && column.width === max) {
|
|
147
150
|
--column.width;
|
|
148
151
|
break;
|
|
149
152
|
}
|
|
@@ -154,6 +157,14 @@ class Table {
|
|
|
154
157
|
return str.slice(0, width);
|
|
155
158
|
}
|
|
156
159
|
|
|
160
|
+
_stylize(row, text) {
|
|
161
|
+
if (!("style" in row) || row.style === "normal") {
|
|
162
|
+
return this._colorize(row, text);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return color[row.style].apply(null, [this._colorize(row, text)]);
|
|
166
|
+
}
|
|
167
|
+
|
|
157
168
|
_colorize(row, text) {
|
|
158
169
|
if (!("color" in row)) {
|
|
159
170
|
return text;
|
package/src/user.js
CHANGED
package/src/utils.js
CHANGED
package/aqtinstall.log
DELETED
|
File without changes
|