jira-sprinter 2.1.1 → 2.3.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 +9 -5
- package/dist/main.js +70 -29
- package/package.json +1 -1
- package/src/auto.ts +77 -17
- package/src/cli.ts +7 -7
- package/src/jira.ts +12 -6
package/README.md
CHANGED
|
@@ -76,20 +76,24 @@ Options:
|
|
|
76
76
|
-h, --help display help for command
|
|
77
77
|
|
|
78
78
|
Commands:
|
|
79
|
-
auto [options] Automatically manages split tasks (
|
|
80
|
-
|
|
81
|
-
status
|
|
79
|
+
auto [options] Automatically manages split tasks (Preliminary
|
|
80
|
+
Testing and QE) based on ticket state and status
|
|
82
81
|
```
|
|
83
82
|
|
|
84
83
|
### `auto` command
|
|
85
84
|
|
|
86
|
-
The `auto` command automates the
|
|
85
|
+
The `auto` command automates the management of split tasks based on ticket state and status. It performs the following actions:
|
|
86
|
+
|
|
87
|
+
- **Preliminary Testing Requested**: Scans the board for issues where Preliminary Testing is marked as "Requested" and creates the corresponding split task if one does not already exist (or was previously closed).
|
|
88
|
+
- **Preliminary Testing Failed**: When testing has failed, automatically closes the linked Preliminary Testing split task.
|
|
89
|
+
- **Integration without QE Task**: Finds issues in "Integration" status that lack an open QE Task and creates one automatically.
|
|
90
|
+
- **Release Pending with QE Task**: When an issue moves to "Release Pending" status, automatically closes the linked QE Task if it is still open.
|
|
87
91
|
|
|
88
92
|
```md
|
|
89
93
|
$ jira-sprinter auto --help
|
|
90
94
|
Usage: jira-sprinter auto [options]
|
|
91
95
|
|
|
92
|
-
Automatically manages split tasks (
|
|
96
|
+
Automatically manages split tasks (Preliminary Testing and QE) based on ticket
|
|
93
97
|
state and status
|
|
94
98
|
|
|
95
99
|
Options:
|
package/dist/main.js
CHANGED
|
@@ -47713,7 +47713,9 @@ var Jira = class {
|
|
|
47713
47713
|
}
|
|
47714
47714
|
async getlinkedTasks(issue2, expectedTasks) {
|
|
47715
47715
|
if (this.dry) {
|
|
47716
|
-
this.logger.log(
|
|
47716
|
+
this.logger.log(
|
|
47717
|
+
` ${source_default.dim(`Fetching linked tasks for ${issue2} (dry-run)`)}`
|
|
47718
|
+
);
|
|
47717
47719
|
return [
|
|
47718
47720
|
{
|
|
47719
47721
|
key: "RHEL-1234",
|
|
@@ -47752,11 +47754,13 @@ var Jira = class {
|
|
|
47752
47754
|
async createTasks(issue2, tasks) {
|
|
47753
47755
|
if (this.dry) {
|
|
47754
47756
|
this.logger.log(
|
|
47755
|
-
`
|
|
47757
|
+
` ${source_default.dim(`Creating tasks ${tasks.join(", ")} for ${issue2} (dry-run)`)}`
|
|
47756
47758
|
);
|
|
47757
47759
|
return;
|
|
47758
47760
|
}
|
|
47759
|
-
this.logger.log(
|
|
47761
|
+
this.logger.log(
|
|
47762
|
+
` ${source_default.cyan(`Creating tasks ${tasks.join(", ")} for ${issue2}`)}`
|
|
47763
|
+
);
|
|
47760
47764
|
await this.api.issues.editIssue({
|
|
47761
47765
|
issueIdOrKey: issue2,
|
|
47762
47766
|
fields: {
|
|
@@ -47767,10 +47771,10 @@ var Jira = class {
|
|
|
47767
47771
|
}
|
|
47768
47772
|
async closeTask(issue2) {
|
|
47769
47773
|
if (this.dry) {
|
|
47770
|
-
this.logger.log(`
|
|
47774
|
+
this.logger.log(` ${source_default.dim(`Closing task ${issue2} (dry-run)`)}`);
|
|
47771
47775
|
return;
|
|
47772
47776
|
}
|
|
47773
|
-
this.logger.log(`Closing task
|
|
47777
|
+
this.logger.log(` ${source_default.cyan(`Closing task ${issue2}`)}`);
|
|
47774
47778
|
await this.api.issues.doTransition({
|
|
47775
47779
|
issueIdOrKey: issue2,
|
|
47776
47780
|
transition: {
|
|
@@ -47800,7 +47804,7 @@ var Jira = class {
|
|
|
47800
47804
|
assignee
|
|
47801
47805
|
);
|
|
47802
47806
|
const version2 = await instance.getVersion();
|
|
47803
|
-
|
|
47807
|
+
logger.log(source_default.dim(`JIRA v${version2}`));
|
|
47804
47808
|
return instance;
|
|
47805
47809
|
}
|
|
47806
47810
|
};
|
|
@@ -47826,9 +47830,12 @@ var Logger = class _Logger {
|
|
|
47826
47830
|
async function runAuto(options) {
|
|
47827
47831
|
const logger = new Logger(!!options.nocolor);
|
|
47828
47832
|
const jira = await Jira.getInstance(options.dry, logger, options.assignee);
|
|
47833
|
+
logger.log(
|
|
47834
|
+
`${source_default.cyan(`Verifying issues in board ${options.board} - team: ${options.team}`)}`
|
|
47835
|
+
);
|
|
47829
47836
|
const boardIssues = await jira.getBoardIssues(
|
|
47830
47837
|
options.board,
|
|
47831
|
-
`project = RHEL and issuetype in (Bug, Story, Vulnerability) and
|
|
47838
|
+
`project = RHEL and issuetype in (Bug, Story, Vulnerability) and status != Closed`
|
|
47832
47839
|
);
|
|
47833
47840
|
const preliminaryTestingRequested = boardIssues.filter(
|
|
47834
47841
|
(issue2) => issue2.fields?.[jira.fields.preliminaryTesting]?.value === "Requested" && !issue2.fields?.issuelinks?.some(
|
|
@@ -47837,9 +47844,6 @@ async function runAuto(options) {
|
|
|
47837
47844
|
) && l.outwardIssue?.fields?.status.name !== "Closed"
|
|
47838
47845
|
)
|
|
47839
47846
|
);
|
|
47840
|
-
logger.log(
|
|
47841
|
-
`${source_default.green("Preliminary Testing Requested")} - ${preliminaryTestingRequested.length}`
|
|
47842
|
-
);
|
|
47843
47847
|
const preliminaryTestingFailed = boardIssues.filter(
|
|
47844
47848
|
(issue2) => issue2.fields?.[jira.fields.preliminaryTesting]?.value === "Fail" && issue2.fields?.issuelinks?.some(
|
|
47845
47849
|
(l) => l.type?.outward === "split to" && l.outwardIssue?.fields?.summary.startsWith(
|
|
@@ -47847,13 +47851,36 @@ async function runAuto(options) {
|
|
|
47847
47851
|
) && l.outwardIssue?.fields?.status.name !== "Closed"
|
|
47848
47852
|
)
|
|
47849
47853
|
);
|
|
47850
|
-
|
|
47851
|
-
|
|
47854
|
+
const issuesInIntegration = boardIssues.filter(
|
|
47855
|
+
(issue2) => issue2.fields?.status.name === "Integration" && !issue2.fields?.issuelinks?.some(
|
|
47856
|
+
(l) => l.type?.outward === "split to" && l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) && l.outwardIssue?.fields?.status.name !== "Closed"
|
|
47857
|
+
)
|
|
47852
47858
|
);
|
|
47853
|
-
|
|
47854
|
-
|
|
47855
|
-
|
|
47856
|
-
)
|
|
47859
|
+
const issuesInReleasePending = boardIssues.filter(
|
|
47860
|
+
(issue2) => issue2.fields?.status.name === "Release Pending" && issue2.fields?.issuelinks?.some(
|
|
47861
|
+
(l) => l.type?.outward === "split to" && l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) && l.outwardIssue?.fields?.status.name !== "Closed"
|
|
47862
|
+
)
|
|
47863
|
+
);
|
|
47864
|
+
const summary = [
|
|
47865
|
+
{
|
|
47866
|
+
label: "Preliminary Testing Requested",
|
|
47867
|
+
count: preliminaryTestingRequested.length
|
|
47868
|
+
},
|
|
47869
|
+
{
|
|
47870
|
+
label: "Preliminary Testing Failed",
|
|
47871
|
+
count: preliminaryTestingFailed.length
|
|
47872
|
+
},
|
|
47873
|
+
{ label: "Integration w/o QE Task", count: issuesInIntegration.length },
|
|
47874
|
+
{
|
|
47875
|
+
label: "Release Pending w/ QE Task",
|
|
47876
|
+
count: issuesInReleasePending.length
|
|
47877
|
+
}
|
|
47878
|
+
].filter((entry) => entry.count > 0);
|
|
47879
|
+
for (const { label, count } of summary) {
|
|
47880
|
+
logger.log(` ${source_default.cyan(label)}: ${source_default.bold(count)}`);
|
|
47881
|
+
}
|
|
47882
|
+
if (summary.length === 0) {
|
|
47883
|
+
logger.log(` ${source_default.green("Nothing to do")}`);
|
|
47857
47884
|
}
|
|
47858
47885
|
for (const issue2 of preliminaryTestingRequested) {
|
|
47859
47886
|
if (!issue2.key) {
|
|
@@ -47861,11 +47888,6 @@ async function runAuto(options) {
|
|
|
47861
47888
|
}
|
|
47862
47889
|
await jira.createTasks(issue2.key, [jira.preliminaryTestingTask.value]);
|
|
47863
47890
|
}
|
|
47864
|
-
if (preliminaryTestingFailed.length > 0) {
|
|
47865
|
-
logger.log(
|
|
47866
|
-
`${source_default.red("Closing Preliminary Testing Task - Testing Failed...")}`
|
|
47867
|
-
);
|
|
47868
|
-
}
|
|
47869
47891
|
for (const issue2 of preliminaryTestingFailed) {
|
|
47870
47892
|
if (!issue2.key) {
|
|
47871
47893
|
continue;
|
|
@@ -47877,12 +47899,31 @@ async function runAuto(options) {
|
|
|
47877
47899
|
);
|
|
47878
47900
|
if (!preliminaryTestingTask || !preliminaryTestingTask.outwardIssue?.key) {
|
|
47879
47901
|
logger.log(
|
|
47880
|
-
|
|
47902
|
+
` ${source_default.red("Preliminary Testing Task not found")} - ${issue2.key}`
|
|
47881
47903
|
);
|
|
47882
47904
|
continue;
|
|
47883
47905
|
}
|
|
47884
47906
|
await jira.closeTask(preliminaryTestingTask.outwardIssue?.key);
|
|
47885
47907
|
}
|
|
47908
|
+
for (const issue2 of issuesInIntegration) {
|
|
47909
|
+
if (!issue2.key) {
|
|
47910
|
+
continue;
|
|
47911
|
+
}
|
|
47912
|
+
await jira.createTasks(issue2.key, [jira.qeTask.value]);
|
|
47913
|
+
}
|
|
47914
|
+
for (const issue2 of issuesInReleasePending) {
|
|
47915
|
+
if (!issue2.key) {
|
|
47916
|
+
continue;
|
|
47917
|
+
}
|
|
47918
|
+
const qeTask = issue2.fields?.issuelinks?.find(
|
|
47919
|
+
(l) => l.type?.outward === "split to" && l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) && l.outwardIssue?.fields?.status.name !== "Closed"
|
|
47920
|
+
);
|
|
47921
|
+
if (!qeTask || !qeTask.outwardIssue?.key) {
|
|
47922
|
+
logger.log(` ${source_default.red("QE Task not found")} - ${issue2.key}`);
|
|
47923
|
+
continue;
|
|
47924
|
+
}
|
|
47925
|
+
await jira.closeTask(qeTask.outwardIssue?.key);
|
|
47926
|
+
}
|
|
47886
47927
|
process.exit(0);
|
|
47887
47928
|
}
|
|
47888
47929
|
|
|
@@ -47989,10 +48030,10 @@ var issueStatusSchema = external_exports.union([
|
|
|
47989
48030
|
// src/cli.ts
|
|
47990
48031
|
function cli() {
|
|
47991
48032
|
const program2 = new Command();
|
|
47992
|
-
program2.name("jira-sprinter").description("\u{1F3C3} Small CLI tool to manage sprints in JIRA Board").version("2.
|
|
48033
|
+
program2.name("jira-sprinter").description("\u{1F3C3} Small CLI tool to manage sprints in JIRA Board").version("2.3.0");
|
|
47993
48034
|
program2.addCommand(
|
|
47994
48035
|
new Command("auto").description(
|
|
47995
|
-
"Automatically manages split tasks (
|
|
48036
|
+
"Automatically manages split tasks (Preliminary Testing and QE) based on ticket state and status"
|
|
47996
48037
|
).option("-b, --board [board]", "Jira Board ID", getDefaultValue("BOARD")).requiredOption(
|
|
47997
48038
|
"-t, --team [assigned team]",
|
|
47998
48039
|
"Jira Assigned Team",
|
|
@@ -48049,7 +48090,7 @@ var runProgram = async () => {
|
|
|
48049
48090
|
issues = await jira.getIssuesInSprint(sprintOrBacklog, options.assignee);
|
|
48050
48091
|
}
|
|
48051
48092
|
if (issues.length === 0) {
|
|
48052
|
-
logger.log(
|
|
48093
|
+
logger.log(source_default.green("No issues found"));
|
|
48053
48094
|
process.exit(0);
|
|
48054
48095
|
}
|
|
48055
48096
|
for (const issue2 of issues) {
|
|
@@ -48109,7 +48150,7 @@ ${issueTypeSchema.parse(issue2.fields?.issuetype.name)} ${issue2.key} - ${source
|
|
|
48109
48150
|
);
|
|
48110
48151
|
if (Array.isArray(tasks) && tasks.length >= answer.length) break;
|
|
48111
48152
|
if (attempt < 10) {
|
|
48112
|
-
logger.log(
|
|
48153
|
+
logger.log(source_default.dim("Waiting for tasks to be created..."));
|
|
48113
48154
|
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
48114
48155
|
}
|
|
48115
48156
|
}
|
|
@@ -48117,7 +48158,7 @@ ${issueTypeSchema.parse(issue2.fields?.issuetype.name)} ${issue2.key} - ${source
|
|
|
48117
48158
|
if (task.fields.summary.includes("QE Task")) {
|
|
48118
48159
|
continue;
|
|
48119
48160
|
}
|
|
48120
|
-
logger.log(
|
|
48161
|
+
logger.log(source_default.italic(task.fields.summary));
|
|
48121
48162
|
let storyPointsAnswer;
|
|
48122
48163
|
let addToSprintAnswer;
|
|
48123
48164
|
if (!options.yolo) {
|
|
@@ -48172,7 +48213,7 @@ ${issueTypeSchema.parse(issue2.fields?.issuetype.name)} ${issue2.key} - ${source
|
|
|
48172
48213
|
storyPointsAnswer = issue2.fields?.[jira.fields.storyPoints];
|
|
48173
48214
|
addToSprintAnswer = sprintOrBacklog != -1;
|
|
48174
48215
|
logger.log(
|
|
48175
|
-
`
|
|
48216
|
+
` ${source_default.cyan("Story points")}: ${colorSizeSchema.parse(storyPointsAnswer)}, ${source_default.cyan("Sprint")}: ${addToSprintAnswer ? source_default.green("yes") : source_default.red("no")}`
|
|
48176
48217
|
);
|
|
48177
48218
|
}
|
|
48178
48219
|
await jira.setValues(task.key, {
|
|
@@ -48182,7 +48223,7 @@ ${issueTypeSchema.parse(issue2.fields?.issuetype.name)} ${issue2.key} - ${source
|
|
|
48182
48223
|
});
|
|
48183
48224
|
}
|
|
48184
48225
|
logger.log(
|
|
48185
|
-
`
|
|
48226
|
+
`${source_default.dim(`Resetting ${issue2.key} \u2014 story points \u2192 0, removing from sprint`)}`
|
|
48186
48227
|
);
|
|
48187
48228
|
await jira.setValues(issue2.key, { size: 0, sprint: null });
|
|
48188
48229
|
}
|
package/package.json
CHANGED
package/src/auto.ts
CHANGED
|
@@ -9,9 +9,13 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
9
9
|
|
|
10
10
|
const jira = await Jira.getInstance(options.dry, logger, options.assignee);
|
|
11
11
|
|
|
12
|
+
logger.log(
|
|
13
|
+
`${chalk.cyan(`Verifying issues in board ${options.board} - team: ${options.team}`)}`
|
|
14
|
+
);
|
|
15
|
+
|
|
12
16
|
const boardIssues = await jira.getBoardIssues(
|
|
13
17
|
options.board,
|
|
14
|
-
`project = RHEL and issuetype in (Bug, Story, Vulnerability) and
|
|
18
|
+
`project = RHEL and issuetype in (Bug, Story, Vulnerability) and status != Closed`
|
|
15
19
|
);
|
|
16
20
|
|
|
17
21
|
const preliminaryTestingRequested = boardIssues.filter(
|
|
@@ -26,9 +30,6 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
26
30
|
l.outwardIssue?.fields?.status.name !== 'Closed'
|
|
27
31
|
)
|
|
28
32
|
);
|
|
29
|
-
logger.log(
|
|
30
|
-
`${chalk.green('Preliminary Testing Requested')} - ${preliminaryTestingRequested.length}`
|
|
31
|
-
);
|
|
32
33
|
|
|
33
34
|
const preliminaryTestingFailed = boardIssues.filter(
|
|
34
35
|
issue =>
|
|
@@ -42,14 +43,51 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
42
43
|
l.outwardIssue?.fields?.status.name !== 'Closed'
|
|
43
44
|
)
|
|
44
45
|
);
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
const issuesInIntegration = boardIssues.filter(
|
|
48
|
+
issue =>
|
|
49
|
+
issue.fields?.status.name === 'Integration' &&
|
|
50
|
+
!issue.fields?.issuelinks?.some(
|
|
51
|
+
l =>
|
|
52
|
+
l.type?.outward === 'split to' &&
|
|
53
|
+
l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) &&
|
|
54
|
+
l.outwardIssue?.fields?.status.name !== 'Closed'
|
|
55
|
+
)
|
|
47
56
|
);
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
const issuesInReleasePending = boardIssues.filter(
|
|
59
|
+
issue =>
|
|
60
|
+
issue.fields?.status.name === 'Release Pending' &&
|
|
61
|
+
issue.fields?.issuelinks?.some(
|
|
62
|
+
l =>
|
|
63
|
+
l.type?.outward === 'split to' &&
|
|
64
|
+
l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) &&
|
|
65
|
+
l.outwardIssue?.fields?.status.name !== 'Closed'
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const summary = [
|
|
70
|
+
{
|
|
71
|
+
label: 'Preliminary Testing Requested',
|
|
72
|
+
count: preliminaryTestingRequested.length,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'Preliminary Testing Failed',
|
|
76
|
+
count: preliminaryTestingFailed.length,
|
|
77
|
+
},
|
|
78
|
+
{ label: 'Integration w/o QE Task', count: issuesInIntegration.length },
|
|
79
|
+
{
|
|
80
|
+
label: 'Release Pending w/ QE Task',
|
|
81
|
+
count: issuesInReleasePending.length,
|
|
82
|
+
},
|
|
83
|
+
].filter(entry => entry.count > 0);
|
|
84
|
+
|
|
85
|
+
for (const { label, count } of summary) {
|
|
86
|
+
logger.log(` ${chalk.cyan(label)}: ${chalk.bold(count)}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (summary.length === 0) {
|
|
90
|
+
logger.log(` ${chalk.green('Nothing to do')}`);
|
|
53
91
|
}
|
|
54
92
|
|
|
55
93
|
for (const issue of preliminaryTestingRequested) {
|
|
@@ -60,12 +98,6 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
60
98
|
await jira.createTasks(issue.key, [jira.preliminaryTestingTask.value]);
|
|
61
99
|
}
|
|
62
100
|
|
|
63
|
-
if (preliminaryTestingFailed.length > 0) {
|
|
64
|
-
logger.log(
|
|
65
|
-
`${chalk.red('Closing Preliminary Testing Task - Testing Failed...')}`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
101
|
for (const issue of preliminaryTestingFailed) {
|
|
70
102
|
if (!issue.key) {
|
|
71
103
|
continue;
|
|
@@ -82,7 +114,7 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
82
114
|
|
|
83
115
|
if (!preliminaryTestingTask || !preliminaryTestingTask.outwardIssue?.key) {
|
|
84
116
|
logger.log(
|
|
85
|
-
|
|
117
|
+
` ${chalk.red('Preliminary Testing Task not found')} - ${issue.key}`
|
|
86
118
|
);
|
|
87
119
|
continue;
|
|
88
120
|
}
|
|
@@ -90,5 +122,33 @@ export async function runAuto(options: OptionValues): Promise<void> {
|
|
|
90
122
|
await jira.closeTask(preliminaryTestingTask.outwardIssue?.key);
|
|
91
123
|
}
|
|
92
124
|
|
|
125
|
+
for (const issue of issuesInIntegration) {
|
|
126
|
+
if (!issue.key) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await jira.createTasks(issue.key, [jira.qeTask.value]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const issue of issuesInReleasePending) {
|
|
134
|
+
if (!issue.key) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const qeTask = issue.fields?.issuelinks?.find(
|
|
139
|
+
l =>
|
|
140
|
+
l.type?.outward === 'split to' &&
|
|
141
|
+
l.outwardIssue?.fields?.summary.startsWith(jira.qeTask.summary) &&
|
|
142
|
+
l.outwardIssue?.fields?.status.name !== 'Closed'
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (!qeTask || !qeTask.outwardIssue?.key) {
|
|
146
|
+
logger.log(` ${chalk.red('QE Task not found')} - ${issue.key}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await jira.closeTask(qeTask.outwardIssue?.key);
|
|
151
|
+
}
|
|
152
|
+
|
|
93
153
|
process.exit(0);
|
|
94
154
|
}
|
package/src/cli.ts
CHANGED
|
@@ -24,12 +24,12 @@ export function cli(): Command {
|
|
|
24
24
|
program
|
|
25
25
|
.name('jira-sprinter')
|
|
26
26
|
.description('🏃 Small CLI tool to manage sprints in JIRA Board')
|
|
27
|
-
.version('2.
|
|
27
|
+
.version('2.3.0');
|
|
28
28
|
|
|
29
29
|
program.addCommand(
|
|
30
30
|
new Command('auto')
|
|
31
31
|
.description(
|
|
32
|
-
'Automatically manages split tasks (
|
|
32
|
+
'Automatically manages split tasks (Preliminary Testing and QE) based on ticket state and status'
|
|
33
33
|
)
|
|
34
34
|
.option('-b, --board [board]', 'Jira Board ID', getDefaultValue('BOARD'))
|
|
35
35
|
.requiredOption(
|
|
@@ -106,7 +106,7 @@ const runProgram = async () => {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
if (issues.length === 0) {
|
|
109
|
-
logger.log(
|
|
109
|
+
logger.log(chalk.green('No issues found'));
|
|
110
110
|
process.exit(0);
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -179,7 +179,7 @@ const runProgram = async () => {
|
|
|
179
179
|
|
|
180
180
|
if (Array.isArray(tasks) && tasks.length >= answer.length) break;
|
|
181
181
|
if (attempt < 10) {
|
|
182
|
-
logger.log(
|
|
182
|
+
logger.log(chalk.dim('Waiting for tasks to be created...'));
|
|
183
183
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
184
184
|
}
|
|
185
185
|
}
|
|
@@ -190,7 +190,7 @@ const runProgram = async () => {
|
|
|
190
190
|
continue;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
logger.log(
|
|
193
|
+
logger.log(chalk.italic(task.fields.summary));
|
|
194
194
|
|
|
195
195
|
let storyPointsAnswer: Size | undefined;
|
|
196
196
|
let addToSprintAnswer: boolean | undefined;
|
|
@@ -248,7 +248,7 @@ const runProgram = async () => {
|
|
|
248
248
|
storyPointsAnswer = issue.fields?.[jira.fields.storyPoints];
|
|
249
249
|
addToSprintAnswer = sprintOrBacklog != -1;
|
|
250
250
|
logger.log(
|
|
251
|
-
`
|
|
251
|
+
` ${chalk.cyan('Story points')}: ${colorSizeSchema.parse(storyPointsAnswer)}, ${chalk.cyan('Sprint')}: ${addToSprintAnswer ? chalk.green('yes') : chalk.red('no')}`
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
254
|
|
|
@@ -263,7 +263,7 @@ const runProgram = async () => {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
logger.log(
|
|
266
|
-
`
|
|
266
|
+
`${chalk.dim(`Resetting ${issue.key} — story points → 0, removing from sprint`)}`
|
|
267
267
|
);
|
|
268
268
|
await jira.setValues(issue.key!, { size: 0, sprint: null });
|
|
269
269
|
}
|
package/src/jira.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { AgileClient, Version3Client } from 'jira.js';
|
|
|
2
2
|
import { SearchResults, Sprint } from 'jira.js/dist/esm/types/agile/models';
|
|
3
3
|
import { Issue } from 'jira.js/dist/esm/types/version3/models/issue';
|
|
4
4
|
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
|
|
5
7
|
import { raise, tokenUnavailable } from './util';
|
|
6
8
|
import { Size } from './schema/jira';
|
|
7
9
|
import { Logger } from './logger';
|
|
@@ -194,7 +196,9 @@ export class Jira {
|
|
|
194
196
|
|
|
195
197
|
async getlinkedTasks(issue: string, expectedTasks: string[]) {
|
|
196
198
|
if (this.dry) {
|
|
197
|
-
this.logger.log(
|
|
199
|
+
this.logger.log(
|
|
200
|
+
` ${chalk.dim(`Fetching linked tasks for ${issue} (dry-run)`)}`
|
|
201
|
+
);
|
|
198
202
|
return [
|
|
199
203
|
{
|
|
200
204
|
key: 'RHEL-1234',
|
|
@@ -237,12 +241,14 @@ export class Jira {
|
|
|
237
241
|
async createTasks(issue: string, tasks: string[]) {
|
|
238
242
|
if (this.dry) {
|
|
239
243
|
this.logger.log(
|
|
240
|
-
`
|
|
244
|
+
` ${chalk.dim(`Creating tasks ${tasks.join(', ')} for ${issue} (dry-run)`)}`
|
|
241
245
|
);
|
|
242
246
|
return;
|
|
243
247
|
}
|
|
244
248
|
|
|
245
|
-
this.logger.log(
|
|
249
|
+
this.logger.log(
|
|
250
|
+
` ${chalk.cyan(`Creating tasks ${tasks.join(', ')} for ${issue}`)}`
|
|
251
|
+
);
|
|
246
252
|
await this.api.issues.editIssue({
|
|
247
253
|
issueIdOrKey: issue,
|
|
248
254
|
fields: {
|
|
@@ -254,11 +260,11 @@ export class Jira {
|
|
|
254
260
|
|
|
255
261
|
async closeTask(issue: string) {
|
|
256
262
|
if (this.dry) {
|
|
257
|
-
this.logger.log(`
|
|
263
|
+
this.logger.log(` ${chalk.dim(`Closing task ${issue} (dry-run)`)}`);
|
|
258
264
|
return;
|
|
259
265
|
}
|
|
260
266
|
|
|
261
|
-
this.logger.log(`Closing task
|
|
267
|
+
this.logger.log(` ${chalk.cyan(`Closing task ${issue}`)}`);
|
|
262
268
|
|
|
263
269
|
await this.api.issues.doTransition({
|
|
264
270
|
issueIdOrKey: issue,
|
|
@@ -310,7 +316,7 @@ export class Jira {
|
|
|
310
316
|
);
|
|
311
317
|
|
|
312
318
|
const version = await instance.getVersion();
|
|
313
|
-
|
|
319
|
+
logger.log(chalk.dim(`JIRA v${version}`));
|
|
314
320
|
|
|
315
321
|
return instance;
|
|
316
322
|
}
|