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, agentEventsController, 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, agentEventsController, 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["es6Modules"],
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 slMappingPath: CiaEnvVars.getSlMappingPath(),
183 slMappingUrl: CiaEnvVars.getSlMappingUrl() ||CiaEnvVars.getSlMappingPath(),
184 labId: buildArguments.labid
185
186 };
187
188 log.info("'instrumentForBrowsers' flag is on. Starting instrumentation. Instrumentation config: ", JSON.stringify(instrumentationConfig));
189 var callback = function (err) {
190 if (err){
191 log.info("Finished the instrumentation with an error. Error:", err);
192 reject(err);
193 }
194 else{
195 log.info("Finished the instrumentation successfully");
196 return resolve();
197 }
198 };
199
200 runBrowserInstrumentation(log, instrumentationConfig, callback, slMapper);
201 });
202 return promise;
203 });
204 }
205
206 promiseChain = promiseChain.then(function () {
207 return Promise.resolve();
208 }).catch(function (err) {
209 return Promise.reject(err);
210 });
211
212 return promiseChain;
213 }
214
215 this.run = function run(buildArguments) {
216 return createBuildDiffPromiseChain(buildArguments);
217 }
218
219 function runBrowserInstrumentation(log, instrumentationConfig, callback, slMapper){
220 log.info("Running browser instrumentation.");
221 instrumentationConfig.extensionsToInstrument = dvr.getFileExtensions();
222 var bi = new BrowserInstrumenter(instrumentationConfig, log, slMapper);
223 bi.instrument(callback);
224 }
225
226 function loadBranchHistory(handlerParams, scmInstance) {
227 return scmInstance.getBranchHistory(handlerParams, log).then(function (gitLog) {
228 if (gitLog && gitLog.commitHistory && gitLog.commitHistory.length && gitLog.commitLog && gitLog.commitLog.length) {
229 log.info('Branch history loaded (' + gitLog.commitHistory.length + ' commits)');
230 handlerParams.finalOutput.meta.history = gitLog.commitHistory;
231 handlerParams.finalOutput.meta.commitLog = gitLog.commitLog;
232 } else {
233 logBranchHistoryNotFound(gitLog, log);
234 }
235 return loadCommitIndexMap(gitLog, handlerParams, log);
236 });
237 }
238
239 function getRepositoryUrl(handlerParams, scmInstance) {
240 return scmInstance.getRepositoryUrl(handlerParams, log).then(function (repositoryUrl) {
241 if (repositoryUrl) {
242 log.info('Repository Url loaded (' + repositoryUrl + ')');
243 handlerParams.finalOutput.meta.repositoryUrl = repositoryUrl;
244 }
245 return repositoryUrl;
246 });
247 }
248
249 function getContributors(handlerParams, scmInstance) {
250 return scmInstance.getContributors(handlerParams, log).then(function (contributorsLog) {
251 if (contributorsLog && contributorsLog.contributors && contributorsLog.emailToIndexMap) {
252 log.info('Contributors list loaded (' + contributorsLog.contributors.length + ' contributors)');
253 handlerParams.finalOutput.meta.contributors = contributorsLog.contributors;
254 handlerParams.emailToIndexMap = contributorsLog.emailToIndexMap;
255 }else{
256 logContributorsNotFound(contributorsLog, log);
257 }
258 return contributorsLog;
259 })
260 }
261
262 function getCommitsPerFile(handlerParams, scmInstance){
263 return scmInstance.getCommitsPerFile(handlerParams, log).then(function(fileToCommitsMap){
264 if(fileToCommitsMap != null){
265 log.info('File commit map loaded (' + Object.keys(fileToCommitsMap).length + ' records)');
266 handlerParams.fileToCommitsMap = fileToCommitsMap;
267 }else{
268 log.error("Commits map is null or undefined.")
269 }
270 return fileToCommitsMap;
271 })
272 }
273}
274
275function logContributorsNotFound(contributorsLog, log) {
276 var fieldsMap = {
277 contributorsLog: !contributorsLog,
278 contributors: contributorsLog && !contributorsLog.contributors,
279 emailToIndexMap: contributorsLog && !contributorsLog.emailToIndexMap
280 };
281 var missing = utils.getMissingProperties(fieldsMap)
282 log.error("Contributors list not loaded, missing fields: " + missing);
283}
284
285
286function logBranchHistoryNotFound(gitLog, log) {
287 var fieldsMap = {
288 gitLog: !gitLog,
289 commitHistory: gitLog && !gitLog.commitHistory,
290 commitHistoryLength: gitLog && gitLog.commitHistory && !gitLog.commitHistory.length,
291 commitLog: gitLog && !gitLog.commitLog,
292 commitLogLength: gitLog && gitLog.commitLog && !gitLog.commitLog.length
293 };
294 var missing = utils.getMissingProperties(fieldsMap)
295 log.error("Branch history not loaded, missing fields: " + missing);
296}
297
298function clone(o) {
299 //if (!o) return o; //Unreachable
300 return JSON.parse(JSON.stringify(o));
301}
302
303var getProcessedFiles =function (buildArguments, processedFiles, logger) {
304 var folderToScan = buildArguments.workspacepath;
305 return fileAndFolderUtils.scanDirRecursively(folderToScan, logger)
306}
307
308var loadCommitIndexMap = function (gitLog, handlerParams, log) {
309 if(!handlerParams.buildArguments.sendContributors){
310 return gitLog;
311 }
312 if (gitLog && gitLog.commitToIndexMap) {
313 handlerParams.commitToIndexMap = gitLog.commitToIndexMap;
314 } else {
315 log.error("Commit log index map not loaded")
316 }
317 return gitLog;
318};
319
320function createMetaTag(buildArguments, cfg){
321 return {
322 "generated": new Date().valueOf(),
323 "build": buildArguments.build,
324 "commit": buildArguments.commit,
325 "customerId": cfg.customerId,
326 "appName": buildArguments.appname,
327 //"technologies": "nodejs",
328 "technology": "nodejs",
329 "branch": buildArguments.branch,
330 "environment": {
331 agentVersion: version,
332 agentType: "nodeJsBuildScanner",
333 processArgv:process.argv,
334 machineName: os.hostname(),
335 platform: os.platform(),
336 os: os.type(),
337 osVersion: os.release(),
338 arch: os.arch(),
339 processId: process.pid,
340 ipAddress: clone(os.networkInterfaces()),
341 dependencies: clone(process.versions),
342 runtime: process.version
343 },
344 "authors": buildArguments.author,
345 "logsUrl": buildArguments.logsUrl,
346 "jobName": buildArguments.jobName,
347 "moduleName": buildArguments.uniqueModuleId, //Added for backward compatibility incase the server needs it.
348 "uniqueModuleId": buildArguments.uniqueModuleId,
349 "configurationData": buildArguments,
350 "scmProvider": buildArguments.scmProvider,
351 "scmVersion": buildArguments.scmVersion,
352 "scmBaseUrl": buildArguments.scmBaseUrl,
353 "buildSessionId": buildArguments.buildsessionid
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");