UNPKG

8.06 kBJavaScriptView Raw
1import {cached, defineAssoc} from "./decorators.js";
2import {RallyBase, lib, Collection, AbortError} from "./rally-tools.js";
3import {configObject} from "./config.js";
4import Preset from "./preset.js";
5import Provider from "./providers.js";
6import Notification from "./notification.js";
7
8import {writeFileSync, readFileSync} from "./fswrap.js";
9import {join, resolve as pathResolve} from "path";
10
11class Rule extends RallyBase{
12 constructor({path, data, remote, subProject} = {}){
13 super();
14 if(path){
15 path = pathResolve(path);
16 try{
17 let f = readFileSync(path, "utf-8")
18 data = JSON.parse(readFileSync(path, "utf-8"));
19 }catch(e){
20 if(e.code === "ENOENT"){
21 if(configObject.ignoreMissing){
22 this.missing = true;
23 return undefined;
24 }else{
25 throw new AbortError("Could not load code of local file");
26 }
27 }else{
28 throw new AbortError(`Unreadable JSON in ${path}. ${e}`);
29 }
30 }
31 }
32 this.meta = {};
33 this.subproject = subProject;
34 if(!data){
35 data = Rule.newShell();
36 }
37 this.data = data;
38 this.remote = remote;
39 this.isGeneric = !this.remote;
40 }
41
42 static newShell(){
43 return {
44 "attributes": {
45 "description": "-",
46 "priority": "PriorityNorm",
47 "starred": false,
48 },
49 "relationships": {},
50 "type": "workflowRules",
51 };
52 }
53
54 async acclimatize(env){
55 this.remote = env;
56
57 let preset = await this.resolveField(Preset, "preset", false, "specific");
58 let pNext = await this.resolveField(Rule, "passNext", false, "specific");
59 let eNext = await this.resolveField(Rule, "errorNext", false, "specific");
60 let proType = await this.resolveField(Provider, "providerType", false, "specific");
61
62 let dynamicNexts = await this.resolveField(Rule, "dynamicNexts", true, "specific");
63
64 let enterNotif = await this.resolveField(Notification, "enterNotifications", true, "specific");
65 let errorNotif = await this.resolveField(Notification, "errorNotifications", true, "specific");
66 let passNotif = await this.resolveField(Notification, "passNotifications", true, "specific");
67 }
68 async saveA(env){
69 if(lib.isLocalEnv(env)) return;
70 return await this.createIfNotExist(env);
71 }
72 async saveB(env){
73 if(!this.isGeneric){
74 await this.resolve();
75 }
76 this.cleanup();
77 if(lib.isLocalEnv(env)){
78 log(chalk`Saving rule {green ${this.name}} to {blue ${lib.envName(env)}}.`)
79 writeFileSync(this.localpath, JSON.stringify(this.data, null, 4));
80 }else{
81 await this.acclimatize(env);
82 await this.uploadRemote(env);
83 }
84 }
85 get immutable(){
86 return false;
87 }
88 async createIfNotExist(env){
89 write(chalk`First pass rule {green ${this.name}} to {green ${env}}: `);
90
91 if(this.immutable){
92 log(chalk`{magenta IMMUTABLE}. Nothing to do.`);
93 return;
94 }
95
96 //First query the api to see if this already exists.
97 let remote = await Rule.getByName(env, this.name);
98
99 this.idMap = this.idMap || {};
100
101 if(remote){
102 this.idMap[env] = remote.id;
103 log(chalk`exists ${remote.chalkPrint(false)}`);
104 return;
105 }
106
107 //If it exists we can replace it
108 write("create, ");
109 let res = await lib.makeAPIRequest({
110 env, path: `/workflowRules`, method: "POST",
111 payload: {data: {attributes: {name: this.name}, type: "workflowRules"}},
112 });
113 this.idMap = this.idMap || {};
114 this.idMap[env] = res.data.id;
115 write("id ");
116 log(this.idMap[env]);
117 }
118
119 async patchStrip(){
120 delete this.data.attributes.createdAt;
121 delete this.data.attributes.starred;
122 delete this.data.attributes.updatedAt;
123
124 // TEMP FIX FOR BUG IN SDVI
125 if(this.relationships.passMetadata && this.relationships.passMetadata[0]){
126 log("HAS PASS");
127 log(this.name);
128 log("HAS PASS");
129 }
130 delete this.relationships.passMetadata;
131
132 if(this.relationships.errorMetadata && this.relationships.errorMetadata[0]){
133 log("HAS PASS");
134 log(this.name);
135 log("HAS PASS");
136 }
137 delete this.relationships.errorMetadata;
138
139 // This is commented out because it was fixed.
140 //for(let key in this.relationships){
141 //let relationship = this.relationships[key];
142 //if(!relationship.data || relationship.data instanceof Array && !relationship.data[0]){
143 //delete this.relationships[key];
144 //}
145 //}
146 }
147
148 async uploadRemote(env){
149 write(chalk`Uploading rule {green ${this.name}} to {green ${env}}: `);
150
151 if(this.immutable){
152 log(chalk`{magenta IMMUTABLE}. Nothing to do.`);
153 return;
154 }
155
156 if(this.idMap[env]){
157 this.remote = env;
158
159 await this.patchStrip();
160 this.data.id = this.idMap[env];
161 //If it exists we can replace it
162 write("replace, ");
163 let res = await lib.makeAPIRequest({
164 env, path: `/workflowRules/${this.idMap[env]}`, method: "PATCH",
165 payload: {data: this.data}, fullResponse: true,
166 });
167
168 log(chalk`response {yellow ${res.statusCode}}`);
169 if(res.statusCode !== 200){
170 log(res.body)
171 log(JSON.stringify(this.data, null, 4));
172 }
173 }else{
174 throw Error("Bad idmap!");
175 }
176 }
177
178 get localpath(){
179 return join(configObject.repodir, this.subproject || "", "silo-rules", this.name + ".json");
180 }
181
182 async resolve(){
183 let preset = await this.resolveField(Preset, "preset", false);
184 //log(preset);
185 let pNext = await this.resolveField(Rule, "passNext", false);
186 let eNext = await this.resolveField(Rule, "errorNext", false);
187 let proType = await this.resolveField(Provider, "providerType", false);
188
189 //log("Dynamic nexts")
190 let dynamicNexts = await this.resolveField(Rule, "dynamicNexts", true);
191 //log(dynamicNexts);
192
193 let enterNotif = await this.resolveField(Notification, "enterNotifications", true);
194 let errorNotif = await this.resolveField(Notification, "errorNotifications", true);
195 let passNotif = await this.resolveField(Notification, "passNotifications", true);
196
197 //TODO Unsupported
198 delete this.relationships["enterMetadata"]
199 delete this.relationships["errorMetadata"]
200
201 this.isGeneric = true;
202
203 return {
204 preset, proType,
205 pNext, eNext,
206 dynamicNexts,
207 errorNotif, enterNotif, passNotif,
208 };
209 }
210
211 chalkPrint(pad=true){
212 let id = String("R-" + (this.remote && this.remote + "-" + this.id || "LOCAL"))
213 let sub = "";
214 if(this.subproject){
215 sub = chalk`{yellow ${this.subproject}}`;
216 }
217 if(pad) id = id.padStart(10);
218 try{
219 return chalk`{green ${id}}: ${sub}{blue ${this.name}}`;
220 }catch(e){
221 return this.data;
222 }
223 }
224}
225
226defineAssoc(Rule, "name", "data.attributes.name");
227defineAssoc(Rule, "description", "data.attributes.description");
228defineAssoc(Rule, "id", "data.id");
229defineAssoc(Rule, "relationships", "data.relationships");
230defineAssoc(Rule, "isGeneric", "meta.isGeneric");
231defineAssoc(Rule, "remote", "meta.remote");
232defineAssoc(Rule, "subproject", "meta.project");
233defineAssoc(Rule, "idMap", "meta.idMap");
234Rule.endpoint = "workflowRules";
235
236export default Rule;