1 | var Promise = require('promise');
|
2 | var FilesMapping = require("./js_diff/files-mapping");
|
3 | var consoleFileLogger = require("./sl-logger.js").consoleFileLogger;
|
4 | var version = require("../package.json").version;
|
5 | var utils = require('./utils.js');
|
6 | var os = require("os");
|
7 | var DefaultValuesResolver = require('./default-values-resolver');
|
8 | var fileAndFolderUtils = require("./file-and-folder-utils");
|
9 | var BrowserInstrumenter = require('./instrumentation/browser-instrumenter');
|
10 | var dvr = new DefaultValuesResolver();
|
11 | var SlMapper = require("./js_diff/sl-mapper").SlMapper;
|
12 | var ScmFilesContainer = require("./scm/scm-files-container");
|
13 | var SlJsInfra = require("sl-js-infra").SlJsInfra;
|
14 | var CiaEnvVars = SlJsInfra.SlEnvVars.CIA;
|
15 | var path = require("path");
|
16 | var fs = require("fs");
|
17 |
|
18 | function 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 |
|
57 | if (scmInstance) {
|
58 |
|
59 | promiseChain = promiseChain.then(function (mapping) {
|
60 | log.info("Getting repository URL.");
|
61 | return getRepositoryUrl(handlerParams, scmInstance);
|
62 | });
|
63 |
|
64 |
|
65 | if(buildArguments.sendContributors){
|
66 | promiseChain = promiseChain.then(function(mapping){
|
67 | log.info("Getting contributors.");
|
68 | return getContributors(handlerParams, scmInstance);
|
69 | });
|
70 | }
|
71 |
|
72 |
|
73 | promiseChain = promiseChain.then(function (mapping) {
|
74 | log.info("Loading branch history.");
|
75 | return loadBranchHistory(handlerParams, scmInstance);
|
76 | });
|
77 |
|
78 |
|
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 |
|
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 |
|
98 | promiseChain = promiseChain.then(function () {
|
99 | return scmInstance.getRootDirectory(handlerParams).then(function (rootDir) {
|
100 | handlerParams.scmRootDir = rootDir;
|
101 | })
|
102 | })
|
103 |
|
104 |
|
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 |
|
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 |
|
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 |
|
137 | return backendProxy.submitBuildMapping(handlerParams.finalOutput);
|
138 | }
|
139 | });
|
140 |
|
141 |
|
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 |
|
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 |
|
275 | function 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 |
|
286 | function 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 |
|
298 | function clone(o) {
|
299 |
|
300 | return JSON.parse(JSON.stringify(o));
|
301 | }
|
302 |
|
303 | var getProcessedFiles =function (buildArguments, processedFiles, logger) {
|
304 | var folderToScan = buildArguments.workspacepath;
|
305 | return fileAndFolderUtils.scanDirRecursively(folderToScan, logger)
|
306 | }
|
307 |
|
308 | var 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 |
|
320 | function 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 |
|
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,
|
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 |
|
357 | function 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 |
|
374 | module.exports.BuildDiffProcess = BuildDiffProcess;
|
375 | module.exports.sourceControlProviders = require("./source-control-providers.js");
|