UNPKG

16.7 kBJavaScriptView Raw
1var Promise = require('promise');
2var FilesMapping = require("./js_diff/files-mapping");
3var consoleFileLogger = require("./sl-logger.js").consoleFileLogger;
4var version = require("../package.json").version;
5var utils = require('./utils.js');
6var os = require("os");
7var DefaultValuesResolver = require('./default-values-resolver');
8var fileAndFolderUtils = require("./file-and-folder-utils");
9var BrowserInstrumenter = require('./instrumentation/browser-instrumenter');
10var dvr = new DefaultValuesResolver();
11var SlMapper = require("./js_diff/sl-mapper").SlMapper;
12var ScmFilesContainer = require("./scm/scm-files-container");
13var SlJsInfra = require("sl-js-infra").SlJsInfra;
14var CiaEnvVars = SlJsInfra.SlEnvVars.CIA;
15var path = require("path");
16var fs = require("fs");
17
18function BuildDiffProcess(cfg, backendProxy, sourceConrolProviders, parsedDependencies, logger) {
19 var log = logger ? logger.child({
20 className: "BuildDiffProcess"
21 }) : consoleFileLogger("BuildDiffProcess");
22
23 function createBuildDiffPromiseChain(buildArguments) {
24 var handlerParams = {
25 buildArguments: buildArguments,
26 cfg: cfg,
27 finalOutput: {
28 meta: createMetaTag(buildArguments, cfg),
29 version: "2.0",
30 files: [],
31 dependencies: parsedDependencies || []
32 }
33 };
34
35 var scmInstance;
36
37 if (buildArguments.workspacepath) {
38 var scmType = sourceConrolProviders[buildArguments.scm];
39 if (scmType) {
40 scmInstance = new scmType(cfg, buildArguments.workspacePath);
41 handlerParams.finalOutput.meta.scm = buildArguments.scm;
42 log.info("Created an scmInstance of type '" + scmType.name + "'. Searching for a local repository at '" + buildArguments.workspacepath + "'.");
43 }else{
44 log.warn("Unsupported scmType: '" + scmType + "'.");
45 }
46 }
47
48 if (!buildArguments.commit && scmInstance && !scmInstance.detectCommitVersion) {
49 return Promise.reject("'commit' command-line argument is required, since automatic detection by the " + buildArguments.scm + " SCM is not supported");
50 }
51
52 var promiseChain = Promise.resolve();
53
54 if (buildArguments.workspacepath) {
55
56 //2. If there is a mapping, get the diffs
57 if (scmInstance) {
58 //2.1 Get repository url from the SCM
59 promiseChain = promiseChain.then(function (mapping) {
60 log.info("Getting repository URL.");
61 return getRepositoryUrl(handlerParams, scmInstance);
62 });
63
64 //2.2 Get all contributors from the scm
65 if(buildArguments.sendContributors){
66 promiseChain = promiseChain.then(function(mapping){
67 log.info("Getting contributors.");
68 return getContributors(handlerParams, scmInstance);
69 });
70 }
71
72 //2.3 Get branch history from the SCM
73 promiseChain = promiseChain.then(function (mapping) {
74 log.info("Loading branch history.");
75 return loadBranchHistory(handlerParams, scmInstance);
76 });
77
78 //2.4 Get all commits effected each file
79 if(buildArguments.sendContributors){
80 promiseChain= promiseChain.then(function(mapping){
81 log.info("Getting commits per file.");
82 return getCommitsPerFile(handlerParams, scmInstance);
83 });
84 }
85 //2.5 if commit was not specified, automatically detect it
86 if (!buildArguments.commit) {
87 promiseChain = promiseChain.then(function () {
88 log.info("Couldn't find a 'commit' on the 'buildArguments'. Trying to detect the commit version.");
89 return scmInstance.detectCommitVersion(handlerParams, log).then(function (commit) {
90 if (commit) {
91 handlerParams.finalOutput.meta.commit = commit;
92 }
93 });
94 });
95 };
96
97 //2.6 Find repository root directory
98 promiseChain = promiseChain.then(function () {
99 return scmInstance.getRootDirectory(handlerParams).then(function (rootDir) {
100 handlerParams.scmRootDir = rootDir;
101 })
102 })
103
104 //2.6 Get list of all files in git
105 promiseChain = promiseChain.then(function () {
106 return scmInstance.getFiles(handlerParams).then(function (scmFiles) {
107 if(scmFiles && Array.isArray(scmFiles)){
108 var scmFilesContainer = new ScmFilesContainer(logger);
109 scmFiles.forEach(function (file) {
110 scmFilesContainer.addFile(file);
111 })
112 handlerParams.scmFilesContainer = scmFilesContainer;
113 }
114 })
115 })
116 }
117
118 //3. Call JS mapping handler
119 var slMapper = null;
120 if(buildArguments.instrumentForBrowsers) {
121 slMapper = new SlMapper(CiaEnvVars.getSlMappingPath(), backendProxy, buildArguments.buildsessionid, logger);
122 }
123 promiseChain = promiseChain.then(function () {
124 log.info("Handling files and sending information in the new Build Scanner Format (with UniqueID).");
125 var filesMapping = new FilesMapping(handlerParams, slMapper, log);
126 return filesMapping.process();
127 });
128 };
129
130 //4. Submit the final output to the server
131 promiseChain = promiseChain.then(function () {
132 if (buildArguments.instrumentationOnly) {
133 log.info("No need to submit the files to server as the 'instrumentationOnly' flag is on.");
134 return Promise.resolve();
135 } else {
136 //TODO: [SLDEV-4708] When the call to the server fails, the agent is "silent" and not showing any error message.
137 return backendProxy.submitBuildMapping(handlerParams.finalOutput);
138 }
139 });
140
141 //5. Print the counters
142 promiseChain = promiseChain.then(function () {
143 var mapping = handlerParams.finalOutput;
144 if(mapping != null && mapping.counters !=null && mapping.counters.methods != null && mapping.counters.branches != null){
145 console.log("Reported " + mapping.counters.methods + " methods and " + mapping.counters.branches + " branches in " + mapping.files.length + " files.");
146 }
147 });
148
149 //6. Create instrumented browser files.
150 if (buildArguments.instrumentForBrowsers) {
151 promiseChain = promiseChain.then(function () {
152 return submitSlMapping(promiseChain, slMapper, logger);
153 })
154 promiseChain = promiseChain.then(function () {
155
156 if (handlerParams.finalOutput && handlerParams.finalOutput.files) {
157 delete handlerParams.finalOutput.files;
158 }
159 var promise = new Promise(function (resolve, reject) {
160 var resolveWithoutHash = true;
161 var delayShutdownInSeconds =buildArguments.delayShutdownInSeconds || 30;
162 var downloadAgent = buildArguments.downloadAgent != null ? buildArguments.downloadAgent : true;
163
164 var instrumentationConfig = {
165 appName: buildArguments.appname,
166 build: buildArguments.build,
167 customerId: cfg.customerId,
168 branch: buildArguments.branch,
169 sourceRoot: buildArguments.workspacepath,
170 files: getProcessedFiles(buildArguments, handlerParams.processedFiles, logger),
171 outputPath: buildArguments.outputpath,
172 copyAllFilesToOutput: buildArguments.copyAllFilesToOutput !== false,
173 buildsessionid: buildArguments.buildsessionid,
174 esModules: buildArguments["es-modules"],
175 server: handlerParams.cfg.server,
176 token: cfg.token,
177 instrumentationType: "browser",
178 resolveWithoutHash: resolveWithoutHash,
179 delayShutdownInSeconds: delayShutdownInSeconds,
180 downloadAgent: downloadAgent,
181 workspacepath: buildArguments.workspacepath,
182 folderToInstrument: buildArguments.folderToInstrument,
183 isInstrumentOriginals: !!buildArguments.folderToInstrument,
184 slMappingPath: CiaEnvVars.getSlMappingPath(),
185 slMappingUrl: CiaEnvVars.getSlMappingUrl() ||CiaEnvVars.getSlMappingPath()
186
187 };
188
189 log.info("'instrumentForBrowsers' flag is on. Starting instrumentation. Instrumentation config: ", JSON.stringify(instrumentationConfig));
190 var callback = function (err) {
191 if (err){
192 log.info("Finished the instrumentation with an error. Error:", err);
193 reject(err);
194 }
195 else{
196 log.info("Finished the instrumentation successfully");
197 return resolve();
198 }
199 };
200
201 runBrowserInstrumentation(log, instrumentationConfig, callback, slMapper);
202 });
203 return promise;
204 });
205 }
206
207 promiseChain = promiseChain.then(function () {
208 return Promise.resolve();
209 }).catch(function (err) {
210 return Promise.reject(err);
211 });
212
213 return promiseChain;
214 }
215
216 this.run = function run(buildArguments) {
217 return createBuildDiffPromiseChain(buildArguments);
218 }
219
220 function runBrowserInstrumentation(log, instrumentationConfig, callback, slMapper){
221 log.info("Running browser instrumentation.");
222 instrumentationConfig.extensionsToInstrument = dvr.getFileExtensions();
223 var bi = new BrowserInstrumenter(instrumentationConfig, log, slMapper);
224 bi.instrument(callback);
225 }
226
227 function loadBranchHistory(handlerParams, scmInstance) {
228 return scmInstance.getBranchHistory(handlerParams, log).then(function (gitLog) {
229 if (gitLog && gitLog.commitHistory && gitLog.commitHistory.length && gitLog.commitLog && gitLog.commitLog.length) {
230 log.info('Branch history loaded (' + gitLog.commitHistory.length + ' commits)');
231 handlerParams.finalOutput.meta.history = gitLog.commitHistory;
232 handlerParams.finalOutput.meta.commitLog = gitLog.commitLog;
233 } else {
234 logBranchHistoryNotFound(gitLog, log);
235 }
236 return loadCommitIndexMap(gitLog, handlerParams, log);
237 });
238 }
239
240 function getRepositoryUrl(handlerParams, scmInstance) {
241 return scmInstance.getRepositoryUrl(handlerParams, log).then(function (repositoryUrl) {
242 if (repositoryUrl) {
243 log.info('Repository Url loaded (' + repositoryUrl + ')');
244 handlerParams.finalOutput.meta.repositoryUrl = repositoryUrl;
245 }
246 return repositoryUrl;
247 });
248 }
249
250 function getContributors(handlerParams, scmInstance) {
251 return scmInstance.getContributors(handlerParams, log).then(function (contributorsLog) {
252 if (contributorsLog && contributorsLog.contributors && contributorsLog.emailToIndexMap) {
253 log.info('Contributors list loaded (' + contributorsLog.contributors.length + ' contributors)');
254 handlerParams.finalOutput.meta.contributors = contributorsLog.contributors;
255 handlerParams.emailToIndexMap = contributorsLog.emailToIndexMap;
256 }else{
257 logContributorsNotFound(contributorsLog, log);
258 }
259 return contributorsLog;
260 })
261 }
262
263 function getCommitsPerFile(handlerParams, scmInstance){
264 return scmInstance.getCommitsPerFile(handlerParams, log).then(function(fileToCommitsMap){
265 if(fileToCommitsMap != null){
266 log.info('File commit map loaded (' + Object.keys(fileToCommitsMap).length + ' records)');
267 handlerParams.fileToCommitsMap = fileToCommitsMap;
268 }else{
269 log.error("Commits map is null or undefined.")
270 }
271 return fileToCommitsMap;
272 })
273 }
274}
275
276function logContributorsNotFound(contributorsLog, log) {
277 var fieldsMap = {
278 contributorsLog: !contributorsLog,
279 contributors: contributorsLog && !contributorsLog.contributors,
280 emailToIndexMap: contributorsLog && !contributorsLog.emailToIndexMap
281 };
282 var missing = utils.getMissingProperties(fieldsMap)
283 log.error("Contributors list not loaded, missing fields: " + missing);
284}
285
286
287function logBranchHistoryNotFound(gitLog, log) {
288 var fieldsMap = {
289 gitLog: !gitLog,
290 commitHistory: gitLog && !gitLog.commitHistory,
291 commitHistoryLength: gitLog && gitLog.commitHistory && !gitLog.commitHistory.length,
292 commitLog: gitLog && !gitLog.commitLog,
293 commitLogLength: gitLog && gitLog.commitLog && !gitLog.commitLog.length
294 };
295 var missing = utils.getMissingProperties(fieldsMap)
296 log.error("Branch history not loaded, missing fields: " + missing);
297}
298
299function clone(o) {
300 //if (!o) return o; //Unreachable
301 return JSON.parse(JSON.stringify(o));
302}
303
304var getProcessedFiles =function (buildArguments, processedFiles, logger) {
305 var folderToScan = buildArguments.folderToInstrument || buildArguments.workspacepath;
306 return fileAndFolderUtils.scanDirRecursively(folderToScan, logger)
307}
308
309var loadCommitIndexMap = function (gitLog, handlerParams, log) {
310 if(!handlerParams.buildArguments.sendContributors){
311 return gitLog;
312 }
313 if (gitLog && gitLog.commitToIndexMap) {
314 handlerParams.commitToIndexMap = gitLog.commitToIndexMap;
315 } else {
316 log.error("Commit log index map not loaded")
317 }
318 return gitLog;
319};
320
321function createMetaTag(buildArguments, cfg){
322 return {
323 "generated": new Date().valueOf(),
324 "build": buildArguments.build,
325 "commit": buildArguments.commit,
326 "customerId": cfg.customerId,
327 "appName": buildArguments.appname,
328 //"technologies": "nodejs",
329 "technology": "nodejs",
330 "branch": buildArguments.branch,
331 "environment": {
332 agentVersion: version,
333 agentType: "nodeJsBuildScanner",
334 processArgv:process.argv,
335 machineName: os.hostname(),
336 platform: os.platform(),
337 os: os.type(),
338 osVersion: os.release(),
339 arch: os.arch(),
340 processId: process.pid,
341 ipAddress: clone(os.networkInterfaces()),
342 dependencies: clone(process.versions),
343 runtime: process.version
344 },
345 "authors": buildArguments.author,
346 "logsUrl": buildArguments.logsUrl,
347 "jobName": buildArguments.jobName,
348 "moduleName": buildArguments.uniqueModuleId, //Added for backward compatibility incase the server needs it.
349 "uniqueModuleId": buildArguments.uniqueModuleId,
350 "configurationData": buildArguments,
351 "scmProvider": buildArguments.scmProvider,
352 "scmVersion": buildArguments.scmVersion,
353 "scmBaseUrl": buildArguments.scmBaseUrl
354 }
355}
356
357function submitSlMapping(promiseChain, slMapper, logger){
358 return new Promise(function (resolve, reject) {
359 if(!CiaEnvVars.getSlMappingPath()) {
360 slMapper.postToServer().then(function () {
361 resolve()
362 }, function (err) {
363 reject(err);
364 });
365 }else {
366 logger.info("Sl mapping path was set to '%s', skipping post to server");
367 resolve();
368 }
369
370 })
371}
372
373
374module.exports.BuildDiffProcess = BuildDiffProcess;
375module.exports.sourceControlProviders = require("./source-control-providers.js");