-
Notifications
You must be signed in to change notification settings - Fork 0
/
projectTree.js
241 lines (241 loc) · 8.75 KB
/
projectTree.js
1
2
3
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
41
42
43
44
45
46
47
48
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// Serves the change-project report page.
const serveProjectReport = (
op, projectWhich, projectRelease, projectReleaseRef, projectIteration, projectIterationRef
) => {
const {
err,
fs,
globals,
reportPrep,
reportScriptPrep,
servePage
} = op;
fs.readFile('projectReport.html', 'utf8')
.then(
htmlContent => {
fs.readFile('report.js', 'utf8')
.then(
jsContent => {
const newJSContent = reportScriptPrep(jsContent, '/projecttally', [
'total',
'storyTotal',
'caseTotal',
'changes',
'projectChanges',
'releaseChanges',
'iterationChanges',
'error'
]);
const newContent = reportPrep(htmlContent, newJSContent)
.replace('__projectWhich__', projectWhich)
.replace('__projectRef__', globals.projectRef)
.replace('__projectRelease__', projectRelease || 'N.A.')
.replace('__projectReleaseRef__', projectReleaseRef || 'N.A.')
.replace('__projectIteration__', projectIteration || 'N.A.')
.replace('__projectIterationRef__', projectIterationRef || 'N.A.');
servePage(newContent, true);
},
error => err(error, 'reading report script')
);
},
error => err(error, 'reading projectReport page')
);
};
// Handles project change requests.
const projectHandle = (op, bodyObject) => {
const {
err,
getGlobalNameRef,
getProjectNameRef,
globals
} = op;
const {projectWhich, projectRelease, projectIteration} = bodyObject;
// Get a reference to the named project.
getGlobalNameRef(projectWhich, 'project', 'Name')
.then(
// When it arrives:
ref => {
if (! globals.isError) {
// Set its global variable.
globals.projectRef = ref;
// Get a reference to the named release.
getProjectNameRef(globals.projectRef, 'release', projectRelease, 'project change')
.then(
// When it arrives:
ref => {
if (! globals.isError) {
// Set its global variable.
globals.projectReleaseRef = ref || null;
// Get a reference to the named iteration.
getProjectNameRef(
globals.projectRef, 'iteration', projectIteration, 'project change'
)
.then(
// When it arrives:
ref => {
if (! globals.isError) {
// Set its global variable.
globals.projectIterationRef = ref || null;
// Serve a report identifying the project, release, and iteration.
serveProjectReport(
op,
projectWhich,
projectRelease,
globals.projectReleaseRef,
projectIteration,
ref
);
}
},
error => err(error, 'getting reference to iteration')
);
}
},
error => err(error, 'getting reference to release')
);
}
},
error => err(error, 'getting reference to new project')
);
};
// Recursively changes project affiliations of an array of test cases.
const projectCases = (op, caseRefs) => {
const {globals, err, shorten, report} = op;
if (caseRefs.length) {
// Change the project of the first test case.
const firstRef = shorten('testcase', 'testcase', caseRefs[0]);
if (! globals.isError) {
return globals.restAPI.update({
ref: firstRef,
data: {
Project: globals.projectRef
}
})
.then(
// When it has been changed:
() => {
report([['changes'], ['projectChanges']]);
// Change the projects of the remaining test cases.
return projectCases(op, caseRefs.slice(1));
},
error => err(error, 'changing project of test case')
);
}
else {
return Promise.resolve('');
}
}
else {
return Promise.resolve('');
}
};
/*
Recursively changes project affiliations and optionally releases and/or iterations of
user stories, and project affiliations of test cases, in a tree or subtree.
*/
const projectTree = (op, storyRefs) => {
const {globals, err, shorten, report, getItemData, getCollectionData} = op;
if (storyRefs.length && ! globals.isError) {
const firstRef = shorten('userstory', 'hierarchicalrequirement', storyRefs[0]);
if (! globals.isError) {
// Get data on the first user story.
return getItemData(
firstRef,
['FormattedID', 'Project', 'Release', 'Iteration'],
['Children', 'TestCases']
)
.then(
// When the data arrive:
data => {
const oldProjectRef = shorten('project', 'project', data.project);
if (! globals.isError) {
// Initialize a configuration object for an update to the user story.
const config = {};
// Initialize an array of events reportable for the user story.
const events = [['total'], ['storyTotal']];
// Add necessary events to the configuration and array.
if (oldProjectRef && oldProjectRef !== globals.projectRef || ! oldProjectRef) {
config.Project = globals.projectRef;
events.push(['changes'], ['projectChanges']);
}
if (data.release !== globals.projectReleaseRef && ! data.children.count) {
config.Release = globals.projectReleaseRef;
events.push(['changes'], ['releaseChanges']);
}
if (data.iteration !== globals.projectIterationRef && ! data.children.count) {
config.Iteration = globals.projectIterationRef;
events.push(['changes'], ['iterationChanges']);
}
// Report progress in the console if requested.
if (globals.debug) {
console.log(`Processing ${data.formattedID}`);
}
// Update the user story if necessary.
return (events.length > 1 ? globals.restAPI.update({
ref: firstRef,
data: config
}) : Promise.resolve(''))
.then(
// When the update, if any, has been made:
() => {
events.length > 1 && report(events);
// Get data on the user story’s test cases, if any.
return getCollectionData(
data.testCases.count ? data.testCases.ref : '', ['Project'], []
)
.then(
// When the data, if any, arrive:
cases => {
cases.length && report([['total', cases.length], ['caseTotal', cases.length]]);
// Process sequentially the test cases needing a project change.
return projectCases(
op, cases.filter(
testCase => shorten('project', 'project', testCase.project) !== globals.projectRef
)
.map(testCase => testCase.ref)
)
.then(
// When they have been processed:
() => {
// Get data on the user story’s child user stories.
return getCollectionData(data.children.ref, [], [])
.then(
// When the data arrive:
children => {
// Process the children sequentially.
return projectTree(op, children.map(child => child.ref))
.then(
// When they have been processed, process the remaining user stories.
() => projectTree(op, storyRefs.slice(1)),
error => err(error, 'changing project of children of user story')
);
},
error => err(error, 'getting data on children of user story')
);
},
error => err(error, 'changing projects of test cases')
);
},
error => err(error, 'getting data on test cases')
);
},
error => err(error, 'changing project of user story')
);
}
else {
return '';
}
},
error => err(error, 'getting data on user story')
);
}
else {
return Promise.resolve('');
}
}
else {
return Promise.resolve('');
}
};
exports.projectHandle = projectHandle;
exports.projectTree = projectTree;