-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathdo-fetch.js
More file actions
182 lines (158 loc) · 6.58 KB
/
do-fetch.js
File metadata and controls
182 lines (158 loc) · 6.58 KB
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
const core = require('@actions/core');
const axios = require('axios');
async function doFetch({
changeCreationStartTime,
instanceUrl,
toolId,
username,
passwd,
token,
jobname,
githubContextStr,
prevPollChangeDetails,
changeCreationTimeOut,
abortOnChangeCreationFailure
}) {
let githubContext = JSON.parse(githubContextStr);
const codesAllowedArr = '200,201,400,401,403,404,500'.split(',').map(Number);
const pipelineName = `${githubContext.repository}` + '/' + `${githubContext.workflow}`;
const buildNumber = `${githubContext.run_id}`;
const attemptNumber = `${githubContext.run_attempt}`;
let endpoint = '';
let httpHeaders = {};
let response = {};
let status = false;
let changeStatus = {};
let responseCode = 500;
try {
if (token !== '') {
endpoint = `${instanceUrl}/api/sn_devops/v2/devops/orchestration/changeStatus?toolId=${toolId}&stageName=${encodeURIComponent(jobname)}&pipelineName=${encodeURIComponent(pipelineName)}&buildNumber=${buildNumber}&attemptNumber=${attemptNumber}`;
const defaultHeadersForToken = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'sn_devops.DevOpsToken ' + `${toolId}:${token}`
};
httpHeaders = { headers: defaultHeadersForToken };
}
else {
endpoint = `${instanceUrl}/api/sn_devops/v1/devops/orchestration/changeStatus?toolId=${toolId}&stageName=${encodeURIComponent(jobname)}&pipelineName=${encodeURIComponent(pipelineName)}&buildNumber=${buildNumber}&attemptNumber=${attemptNumber}`;
const tokenBasicAuth = `${username}:${passwd}`;
const encodedTokenForBasicAuth = Buffer.from(tokenBasicAuth).toString('base64');
const defaultHeadersForBasicAuth = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + `${encodedTokenForBasicAuth}`
};
httpHeaders = { headers: defaultHeadersForBasicAuth };
}
response = await axios.get(endpoint, httpHeaders);
status = true;
} catch (err) {
if (!err.response) {
throw new Error("500");
}
if (!codesAllowedArr.includes(err.response.status)) {
throw new Error("500");
}
if (err.response.status == 500) {
throw new Error("500");
}
if (err.response.status == 400) {
let responseData = err.response.data;
if (responseData && responseData.result && responseData.result.errorMessage) {//Other technical error messages
let errMsg = responseData.result.errorMessage;
throw new Error(JSON.stringify({ "status": "error", "details": errMsg }));
}
throw new Error("400");
}
if (err.response.status == 401) {
throw new Error("401");
}
if (err.response.status == 403) {
throw new Error("403");
}
if (err.response.status == 404) {
throw new Error("404");
}
}
if (status) {
core.debug("[ServiceNow DevOps], Polling started to fetch change info.");
try {
responseCode = response.status;
} catch (error) {
core.setFailed('\nCould not read response code from API response: ' + error);
throw new Error("500");
}
try {
changeStatus = response.data.result;
} catch (error) {
core.setFailed('\nCould not read change status details from API response: ' + error);
throw new Error("500");
}
let currChangeDetails = changeStatus.details;
let changeState = currChangeDetails.status;
/**
* Check for changeCreationTimeOut.
* If changeCreationTimeOut happened and change doesnot get created, then we need to terminate the step based on abortOnChangeCreationFailure flag.
* */
if(Object.keys(currChangeDetails).length === 0) {
if ((+new Date() - changeCreationStartTime) > (changeCreationTimeOut * 1000)) {
if (abortOnChangeCreationFailure) {
let errMsg = `Timeout after ${changeCreationTimeOut} seconds.Workflow execution is aborted since abortOnChangeCreationFailure flag is true`;
throw new Error(JSON.stringify({ "status": "error", "details": errMsg }));
}
else {
console.error('\n \x1b[38;5;214m Timeout occured after '+changeCreationTimeOut+' seconds but pipeline will coninue since abortOnChangeCreationFailure flag is false \x1b[38;5;214m');
throw new Error("ChangeCreationFailure_DontFailTheStep");
}
}
}
if (currChangeDetails) {
if (currChangeDetails.number)
core.setOutput('change-request-number', currChangeDetails.number);
if (currChangeDetails.sys_id)
core.setOutput('change-request-sys-id', currChangeDetails.sys_id);
}
/**
* 1. incase of change not created
* 2. incase of change created and not in implement state
*/
if (responseCode == 201) {
if (changeState == "pending_decision") {
if (isChangeDetailsChanged(prevPollChangeDetails, currChangeDetails)) {
console.log('\n \x1b[1m\x1b[32m' + JSON.stringify(currChangeDetails) + '\x1b[0m\x1b[0m');
}
throw new Error(JSON.stringify({ "statusCode": "201", "details": currChangeDetails }));
} else if ((changeState == "failed") || (changeState == "error")) {
throw new Error(JSON.stringify({ "status": "error", "details": currChangeDetails.details }));
} else if (changeState == "rejected" || changeState == "canceled_by_user") {
if (isChangeDetailsChanged(prevPollChangeDetails, currChangeDetails)) {
console.log('\n \x1b[1m\x1b[32m' + JSON.stringify(currChangeDetails) + '\x1b[0m\x1b[0m');
}
throw new Error("202");
} else
throw new Error("201");
}
else if (responseCode == 200) { //incase of change created and in implemented state
if (isChangeDetailsChanged(prevPollChangeDetails, currChangeDetails)) {
console.log('\n \x1b[1m\x1b[32m' + JSON.stringify(currChangeDetails) + '\x1b[0m\x1b[0m');
}
console.log('\n****Change is Approved.');
}
}
else
throw new Error("500");
return true;
}
function isChangeDetailsChanged(prevPollChangeDetails, currChangeDetails) {
if (Object.keys(currChangeDetails).length !== Object.keys(prevPollChangeDetails).length) {
return true;
}
for (let field of Object.keys(currChangeDetails)) {
if (currChangeDetails[field] !== prevPollChangeDetails[field]) {
return true;
}
}
return false;
}
module.exports = { doFetch };