/**
 * solution-project.js
 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jonghwan Park <iwin100.park@samsung.com>
 * Kitae Kim <kt920.kim@samsung.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 * - S-Core Co., Ltd
**/


var async = require('async');
var fs = require('fs');
var path = require('path');
var xmlParseString = require('xml2js').parseString;
var _ = require('underscore');

var dibs = require('../../core/dibs.js');
var DError = require('../../core/exception.js');
var Job = require('../dibs.model.common/job.js');
var Process = require('../dibs.core/process.js');
var Tutils = require('../org.tizen.common/tizen_utils.js');
var TizenGit = require('../org.tizen.projects/git-control.js');
var utils = require('../../lib/utils.js');
var vsCommon = require('./visualstudio_common.js');


module.exports.createJob = createJob;
module.exports.initializeJob = initializeJob;
module.exports.executeJob = executeJob;
module.exports.resumeJob = resumeJob;
module.exports.pendingJobHandler = pendingJobHandler;
module.exports.checkMutualExclusiveJob = vsCommon.checkMutualExclusiveJob;


function VisualStudioSolutionJob(baseJob) {
    Job.copy(this, baseJob);
    /**
     * package infos from pkginfo.manifest
     * @type {Array}
     */
    if (!this.options.packages) {
        this.options.packages = [];
    }
    /**
     * will have git repository path if succeeded
     * @type {Array}
     */
    this.gitRepo = null;
    /**
     * will have git commit id if succeeded
     * @type {string}
     */
    this.gitCommit = null;
    /**
     * will have visual studio solution path if succeeded
     * @type {string}
     */
    this.solutionPath = null;
    /**
     * @type {Array}
     *
     * vsixProject: @type {Object}
     * {
     *     csprojName: @type {String}
     *     vsixmanifestPath: @type {String}
     *     vsixmanifest: @type {Object}
     * }
     */
    this.vsixProjects = null;
    /**
     * snapshot infomation
     * @type {string}
     */
    this.snapshot = null;
    this.distribution = null;
    /**
     * tizen environments
     * @type {environment}
     */
    this.initEnvironments = dibs.projectTypes['visualstudio-solution'].environments;
}

/**
 * Create tizen git job instance
 * @function createJob
 * @param {string} userEmail - user email
 * @param {string} distName - distibution name
 * @param {string} prjName - project name
 * @param {string} prjType - project type
 * @param {string} environmentName - environment name
 * @param {string} parentId - parent Id
 * @param {string} distType - distibution type
 * @param {module:models/job.options} options - job options
 * @param {module:models/job~Job} baseJob - base job object
 * @memberOf module:models/tizen-project/git-project
 */

function createJob(userEmail, distName, prjName, prjType, environmentName, parentId, distType, options, callback) {
    Job.create(userEmail, distName, distType, prjName, prjType, environmentName, parentId, null, options,
        function (err, newJob) {
            if (err) {
                callback(err, null);
            } else {
                dibs.thisServer.log.info(newJob);
                vsCommon.checkReleasePhase(new VisualStudioSolutionJob(newJob), callback);
            }
        });
}


/**
 * Initialize Tizen Git job
 * @function initializeJob
 * @param {module:models/job~Job} job - job
 * @param {string} jobWorkPath - jobWorkPath
 * @param {module:core/base-server.BaseServer} server - server
 * @param {module:lib/monitor.monitor} monitor - monitor
 * @param {module:lib/utils.callback_error} callback - callback(error)
 * @memberOf module:models/tizen-project/git-project
 */
function initializeJob(job, options, callback) {

    if ((job.status !== 'INITIALIZING')) {
        return callback(new DError('TIZENJOB008', {
            jobId: job.id
        }), job);
    }

    var monitor = options.monitor;

    async.waterfall([
        // git clone
        function (cb) {
            monitor.updateProgress('Preparing source code... ' + job.options.GIT_REPO, cb);
        },
        function (cb) {
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'git clone'
            });
            // git-control in Tizen uses source cache login
            TizenGit.getSourceCode(job, options, cb);
        },
        // set info paths
        function (srcPathInfo, cb) {
            monitor.updateProgress('get source info ' + srcPathInfo);

            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'git clone done'
            });

            job.solutionPath = path.join(srcPathInfo, job.options.SOLUTION_PATH);
            fs.exists(job.solutionPath, function (exists) {
                cb(((!exists) ? new DError('VSJOB001') : null));
            });
        },
        function (cb) {
            monitor.updateProgress('Preparing source code is done!', cb);
        },
        function (cb) {
            var solutionDir = path.dirname(job.solutionPath);
            utils.findFilesInDir(solutionDir, /source.extension.vsixmanifest$/, function (err, results) {
                if (!err) {
                    var vsixProjects = [];
                    _.each(results, function (res) {
                        vsixProjects.push({
                            csprojName: path.basename(path.dirname(res)),
                            vsixmanifestPath: res
                        });
                    });

                    job.vsixProjects = vsixProjects;

                    monitor.updateProgress(' - vsixmanifest path: [' + job.vsixProjects.map(function (e) {
                        return e.vsixmanifestPath;
                    }).join(',') + ']');
                }
                cb(err);
            });
        },
        // parse source.extension.vsixmanifest
        function (cb) {
            monitor.updateProgress('Parsing VSIX manifest...', cb);
        },
        function (cb) {
            var vsixProjects = [];

            async.map(_.clone(job.vsixProjects), function (project, cb1) {
                parseVSIXManifestFile(project, monitor, function (err1, result) {
                    if (err1) {
                        cb1(err1, {});
                    } else {
                        project.vsixmanifest = result;
                        vsixProjects.push(_.clone(project));

                        var metadata = result.PackageManifest.Metadata[0];
                        var pkg = {
                            name: metadata.DisplayName[0],
                            version: metadata.Identity[0]['$'].Version
                        };
                        cb1(err1, pkg);
                    }
                });
            },
            function (err1, pkgs) {
                job.vsixProjects = vsixProjects;
                cb(err1, pkgs);
            });
        },
        function (pkgs, cb) {
            /*
             * FORCE_REBUILD: flag for rebuild without increasing version
             * UPLOAD_TEMP: flag for test build
             */
            if (job.options.FORCE_REBUILD || job.options.UPLOAD_TEMP) {
                cb(null, pkgs);
            } else {
                monitor.updateProgress('Checking package information...');
                checkPackageInfo(job, pkgs, function (err) {
                    cb(err, pkgs);
                });
            }
        },
        function (pkgs, cb) {
            monitor.updateProgress(' - [' + _.uniq(_.map(pkgs, function (pkg) {
                return pkg.name;
            })).toString() + ']', cb);
        },
        function (cb) {
            monitor.updateProgress('Checking build server information...', cb);
        },
        function (cb) {
            //*** job.execEnvironments ***
            job.execEnvironments = Tutils.getEnvironmentIds('visualstudio-solution');
            job.options.packages.push({ name: job.projectName, os: job.environmentName });

            if (isServerPrepared(dibs.getAllServers(), job.execEnvironments)) {
                cb(null);
            } else {
                cb(new DError('VSJOB007', {
                    envName: job.execEnvironments.join(',')
                }));
            }
        }
    ],
    function (err) {
        if (err) {
            finalize(err, job, monitor, callback);
        } else {
            callback(err, job);
        }
    });
}


function parseVSIXManifestFile(vsixProject, monitor, callback) {
    async.waterfall([
        function (cb) {
            monitor.updateProgress('Read VSIX manifest...', cb);
        },
        function (cb) {
            fs.readFile(vsixProject.vsixmanifestPath, function (err, data) {
                if (err) {
                    cb(new DError('VSJOB002'));
                } else {
                    cb(err, data);
                }
            });
        },
        function (data, cb) {
            monitor.updateProgress('Parse VSIX manifest as JSON format...');
            xmlParseString(data.toString(), function (err, result) {
                if (err) {
                    cb(err, {});
                } else {
                    cb(err, result);
                }
            });
        }
    ],
    function (err, result) {
        callback(err, result);
    });
}


function isServerPrepared(servers, envNames) {
    return (_.select(servers, function (svr) {
        var envs = _.map(svr.environments, function (e) {
            return e.id;
        });

        return (svr.type === 'builder' &&
            svr.status === 'RUNNING' &&
            envNames &&
            _.intersection(envNames, envs).length > 0);
    }).length > 0);
}


/**
 * Execute tizen git job
 * - it include build, packaging and upload
 * @function executeJob
 * @param {module:models/job~Job} job - job
 * @param {string} jobWorkPath - jobWorkPath
 * @param {module:core/base-server.BaseServer} server - server
 * @param {module:lib/utils.callback_error} callback - callback(error)
 * @memberOf module:models/tizen-project/git-project
 */
function executeJob(job, options, callback) {
    var jobSvc = options.jobSvc;
    var parentServerId = options.parentServerId;
    var server = dibs.getServer(parentServerId);

    var monitor = options.monitor;
    var jobWorkPath = options.jobWorkPath;
    var srcPath = path.join(jobWorkPath, 'source');

    async.waterfall([
        // get latest snapshots of repository
        function (cb) {
            monitor.updateProgress('Getting the latest snapshot of repository ...');
            if (job.snapshot && job.snapshot.distName && job.snapshot.options) {
                monitor.updateProgress(' - ' + job.snapshot.name);
                cb(null);
            } else {
                job.board.push({
                    type: 'STAMP',
                    time: utils.getTimeString(),
                    name: 'get repository'
                });

                dibs.rpc.repo.searchSnapshots({
                    name: null,
                    type: 'tizen-visualstudio',
                    distName: job.distName
                },
                function (err, snapshots) {
                    job.board.push({
                        type: 'STAMP',
                        time: utils.getTimeString(),
                        name: 'get repository done'
                    });
                    if (!err && snapshots.length > 0) {
                        job.snapshot = snapshots[0];
                        monitor.updateProgress(' - ' + job.snapshot.name);
                        job.snapshot.distName = job.distName;
                    }
                    cb(err);
                });
            }
        },
        function (cb) {
            monitor.updateProgress('Checking initialization server matched...', cb);
        },
        // check
        function (cb) {
            if (job.initServerId !== parentServerId) {
                monitor.updateProgress(' - build server is different from init server');
                monitor.updateProgress(' - preparing source code...' + job.options.GIT_REPO);
                job.board.push({
                    type: 'STAMP',
                    time: utils.getTimeString(),
                    name: 'git clone'
                });
                TizenGit.getSourceCode(job, options, function (err) {
                    job.board.push({
                        type: 'STAMP',
                        time: utils.getTimeString(),
                        name: 'git clone done'
                    });
                    cb(err);
                });
            } else {
                monitor.updateProgress(' - build server is same as init server', cb);
            }
        },
        function (cb) {
            monitor.updateProgress('Checking build options...', cb);
        },
        // check compatible OS packages
        function (cb) {
            monitor.updateProgress('Start building project...');
            buildGitProject(job, options, cb);
        },
        function (cb) {
            monitor.updateProgress('Preparing to upload result files...');
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'prepare to upload'
            });

            var outputPath = path.join(path.dirname(job.solutionPath), 'bin');
            var vsixmanifest = job.vsixProjects[0].vsixmanifest;
            var metadata = vsixmanifest.PackageManifest.Metadata[0];

            var outputFilePattens = _.compact([
                /.vsix$/,
                metadata.Icon ? new RegExp(metadata.Icon[0]) : null,
                metadata.PreviewImage ? new RegExp(metadata.PreviewImage[0]) : null
            ]);

            prepareToUpload(server, outputPath, outputFilePattens, monitor, function (err, results) {
                if (!err) {
                    job.resultFiles = results.dfs;
                }
                job.board.push({
                    type: 'STAMP',
                    time: utils.getTimeString(),
                    name: 'prepare to upload done '
                });
                cb(err, results.fileInfos);
            });
        },
        function (dfsFileInfos, cb) {
            monitor.updateProgress('Collecting build information...');
            job.buildInfo = [];

            /*
             * job.vsixProjects
             *  - include csproject name and vsixmanifest path.
             */
            var vsixmanifest = job.vsixProjects[0].vsixmanifest;
            var metadata = vsixmanifest.PackageManifest.Metadata[0];
            var fileInfos = [];

            _.each(job.resultFiles, function (rpath) {
                var basename = path.basename(rpath);
                var type = basename.split('.').pop();

                var fileInfo = { name: basename, type: type, dfs: rpath };
                if (metadata.Icon && basename === metadata.Icon[0]) {
                    fileInfo.element = 'Icon';
                } else if (metadata.PreviewImage && basename === metadata.PreviewImage[0]) {
                    fileInfo.element = 'PreviewImage';
                }

                var info = _.findWhere(dfsFileInfos, { name: fileInfo.name });
                fileInfo.size = info.size;
                fileInfo.checksum = info.checksum;

                fileInfos.push(fileInfo);
            });

            var buildInfo = {
                identity: metadata.Identity[0]['$'].Id,
                name: metadata.DisplayName[0],
                version: metadata.Identity[0]['$'].Version,
                publisher: metadata.Identity[0]['$'].Publisher,
                published: new Date().toISOString(),
                manifest: vsixmanifest,
                files: fileInfos,
                projectType: job.projectType,
                projectName: job.projectName,
                gitCommitID: job.options.GIT_CURRENT_COMMIT,
                gitRepo: job.options.GIT_REPO,
                gitBranch: job.options.GIT_BRANCH
            };

            job.buildInfo.push(buildInfo);

            // save build informations for recover
            job.options.buildInfo = job.buildInfo;
            job.options.VERSION = metadata.Identity[0]['$'].Version;
            job.options.PACKAGES = _.map(fileInfos, function (fileInfo) {
                return fileInfo.name;
            });
            cb(null);
        },
        function (cb) {
            // set job info with git commit id and so on
            monitor.updateProgress('Setting the lastest source info...', cb);
        },
        function (cb) {
            vsCommon.set_commit_to_jobinfo(job, srcPath, cb);
        },
        function (cb) {
            monitor.updateProgress('Checking uploading...');
            vsCommon.binaryUploadApprovalProcess(jobSvc, job, monitor, cb);
        }
    ],
    function (err, job1) {
        job1 = job1 || job;

        if (!err && job1.status === 'PENDING') {
            return callback(null, job1);
        }

        finalizeBuild(err, job1, monitor, callback);
    });
}


function finalizeBuild(err, job, monitor, callback) {
    async.series([
        function (cb) {
            if (job.options.UPLOAD) {
                updateProjectBuildInfo(job, cb);
            } else {
                cb(null);
            }
        },
        function (cb) {
            finalize(err, job, monitor, cb);
        }
    ], function (err) {
        callback(err, job);
    });
}


function finalize(err, job, monitor, callback) {
    // NOTE. MUST strip unnecessary information for reducing object size
    //       if not, DNODE RPC cannnot receive callback
    vsCommon.stripJob(job);

    if (dibs.getServersByType('messenger')[0] && job.parentId === null && job.userEmail !== 'admin@user') {
        monitor.updateProgress('sending email');
        vsCommon.sendEmail(err, job, monitor, function (error) {
            if (error) {
                monitor.updateProgress('sending email failed');
                monitor.updateProgress('error: ' + error.message);
            }
            callback(err, job);
        });
    } else {
        monitor.updateProgress('ignore sending email');
        callback(err, job);
    }
}


function pendingJobHandler(job, callback) {
    vsCommon.pendingJobHandler(job, callback);
}


function resumeJob(job, options, callback) {
    var jobSvc = options.jobSvc;
    var monitor = options.monitor;
    var resumeOptions = options.resumeOptions;

    // recover build information
    job.buildInfo = job.options.buildInfo;

    vsCommon.resumeJob(jobSvc, job, resumeOptions, monitor, function (err) {
        finalizeBuild(err, job, monitor, callback);
    });

}


function buildGitProject(job, options, callback) {
    var jobWorkPath = options.jobWorkPath;
    var monitor = options.monitor;

    var srcPath = path.join(jobWorkPath, 'source');
    var outDir = path.join(path.dirname(job.solutionPath), 'bin');

    /*
     * build steps
     * 1. nuget local all -clear
     * 2. nuget restore ".sln" "NuGet.config"
     * 3. MSBUILD ".sln" "{Optional Configuration}" "/p:OutDir={OUTDIR}"
     */
    async.waterfall([
        function (cb) {
            monitor.updateProgress(' - clear nuget cache in local', cb);
        },
        function (cb) {
            launchCommand('nuget local all -clear', srcPath, monitor, cb);
        },
        function (cb) {
            monitor.updateProgress(' - restore packages using nuget', cb);
        },
        function (cb) {
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'restore packages'
            });
            launchCommand('nuget restore ' + job.solutionPath, srcPath, monitor, cb);
        },
        function (cb) {
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'restore packages done'
            });
            monitor.updateProgress(' - restoring packages is done', cb);
        },
        // build
        function (cb) {
            monitor.updateProgress('Building source project is started... ', cb);
        },
        function (cb) {
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'build'
            });

            var buildConf = ' /p:OutDir=' + outDir;
            buildConf += ' ' + job.options.MSBUILD_OPTION;

            launchCommand('msbuild ' + job.solutionPath + buildConf, path.dirname(job.solutionPath), monitor, cb);
        },
        function (cb) {
            job.board.push({
                type: 'STAMP',
                time: utils.getTimeString(),
                name: 'build done'
            });
            monitor.updateProgress('Building source project is done', cb);
        }
    ], function (err) {
        callback(err);
    });
}


function launchCommand(args, workdir, monitor, callback) {
    monitor.updateProgress('Start executing ' + args.split(' ')[0] + ' ...');

    var script = Process.create('cmd',
        ['/C', args],
        {
            cwd: workdir,
            env: process.env
        },
        {
            onStdout: function (line) {
                monitor.updateProgress('   ' + line);
            },
            onStderr: function (line) {
                monitor.updateProgress('   ' + line);
            },
            onExit: function (code) {
                if (code !== 0) {
                    var error;
                    if (monitor.isCancel()) {
                        error = new Error('cancel');
                        monitor.updateProgress({
                            log: ' - cmd execution failed by cancel',
                            logType: 'error'
                        });
                    } else {
                        error = new Error(' - running ' + args.split(' ')[0] + ' failed with exit code ' + code);
                        monitor.updateProgress({
                            log: ' - cmd execution failed with code : ' + code,
                            logType: 'error'
                        });
                    }
                    callback(error);
                } else {
                    monitor.updateProgress(' - running ' + args.split(' ')[0] + ' succeeded', callback);
                }
            }
        });
    monitor.addProcess(script);
}


function prepareToUpload(server, outputPath, outputFilePattens, monitor, callback) {
    var outputFilesPath = null;
    var results = {};

    async.waterfall([
        function (cb) {
            fs.readdir(outputPath, function (err, files) {
                cb(err, files);
            });
        },
        function (files, cb) {
            var outputFiles = [];
            _.each(outputFilePattens, function (regexp) {
                _.each(files, function (file) {
                    var match = regexp.exec(file);
                    if (match) {
                        outputFiles.push(file);
                    }
                });
            });

            outputFilesPath = _.map(outputFiles, function (file) {
                return path.join(outputPath, file);
            });

            outputFilesPath.push(path.join(outputPath, 'extension.vsixmanifest'));

            monitor.updateProgress(' - [' + outputFilesPath.map(function (e) {
                return path.basename(e);
            }).join(',') + ']');

            cb(null);
        },
        function (cb) {
            addToDFS(server, outputFilesPath, function (err, dfs) {
                results.dfs = dfs;
                cb(err);
            });
        },
        function (cb) {
            var fileInfos = [];

            async.each(outputFilesPath, function (file, cb1) {
                var fileInfo = { name: path.basename(file) };

                async.series([
                    function (cb2) {
                        utils.getCheckSum(file, function (err2, checksum) {
                            fileInfo.checksum = checksum;
                            cb2(err2);
                        });
                    },
                    function (cb2) {
                        fs.stat(file, function (err2, stat) {
                            fileInfo.size = stat.size;
                            cb2(err2);
                        });
                    }
                ],
                function (err1) {
                    fileInfos.push(fileInfo);
                    cb1(err1);
                });
            },
            function (err) {
                results.fileInfos = fileInfos;
                cb(err);
            });
        }
    ],
    function (err) {
        if (err) {
            monitor.updateProgress(' - ' + err.message);
        } else {
            monitor.updateProgress(' - done ');
        }
        callback(err, results);
    });
}


function addToDFS(server, lpaths, callback) {
    if (lpaths.length === 0) {
        callback(null, []); return;
    }
    async.mapSeries(lpaths,
        function (lpath, cb) {
            server.dfsAddFile(null, lpath, {
                lifetime: 60 * 60 * 1000
            }, cb);
        },
        function (err, result) {
            callback(err, result);
        });
}


function updateProjectBuildInfo(job, callback) {
    async.waterfall([
        // search project
        function (cb) {
            dibs.rpc.datamgr.searchProjects({
                name: job.projectName,
                distName: job.distName
            },
            function (err, results) {
                if (!err) {
                    if (results.length > 0) {
                        cb(null, results[0]);
                    } else {
                        cb(new Error('Job\'s environment not found!'), null);
                    }
                } else {
                    cb(err, null);
                }
            });
        },
        // save build info
        function (prj, cb) {
            if (!prj.options.LAST_BUILD_INFO) {
                prj.options.LAST_BUILD_INFO = {};
            }

            prj.options.LAST_BUILD_INFO[job.environmentName] = {
                version: job.options.VERSION,
                gitRepo: job.options.GIT_REPO,
                gitCommit: job.options.GIT_CURRENT_COMMIT,
                solutionPath: job.options.SOLUTION_PATH,
                packageNames: job.options.PACKAGES
            };

            dibs.rpc.datamgr.updateProject(prj, function (err) {
                cb(err);
            });

        }
    ],
    function (err) {
        callback(err);
    });
}


function checkPackageInfo(job, pkgs, callback) {
    if (pkgs.length === 0) {
        callback(new DError('VSJOB002'));
        return;
    }

    async.series([
        // check package version
        function (cb) {
            dibs.rpc.repo.searchSnapshots({
                name: null,
                type: 'tizen-visualstudio',
                distName: job.distName
            }, function (err, snaps) {
                if (err) {
                    cb(err);
                } else {
                    if (snaps.length === 0) {
                        cb(null);
                    } else {
                        var artifacts = snaps[0].artifacts;
                        _.each(pkgs, function (pkg) {
                            var oldPkg = _.findWhere(artifacts, { name: pkg.name });
                            if (oldPkg && utils.compareVersion(pkg.version, oldPkg.version) <= 0) {
                                cb(new DError('VSJOB003', {
                                    name: pkg.name,
                                    version: pkg.version,
                                    oldVersion: oldPkg.version
                                }));
                                return;
                            }
                        });
                        cb(null);
                    }
                }
            });
        },
        // check package commit
        function (cb) {
            dibs.rpc.datamgr.searchProjects({
                name: job.projectName,
                distName: job.distName
            },
            function (err, prjs) {
                if (err) {
                    cb(err);
                } else {
                    if (prjs.length === 0) {
                        cb(new DError('VSJOB004', {
                            name: job.projectName,
                            distName: job.distName
                        }));
                    } else if (!prjs[0].options.LAST_BUILD_INFO) {
                        cb(null);
                    } else {
                        var lastBuildInfos = prjs[0].options.LAST_BUILD_INFO;
                        for (var os in lastBuildInfos) {
                            var bInfo = lastBuildInfos[os];
                            if (!bInfo.version || bInfo.version !== pkgs[0].version) {
                                continue;
                            }

                            if (bInfo.gitRepo && bInfo.gitRepo !== job.gitRepo) {
                                cb(new DError('VSJOB005', {
                                    repo: job.gitRepo,
                                    oldRepo: bInfo.gitRepo
                                }));
                                return;
                            }
                            if (bInfo.gitCommit && bInfo.gitCommit !== job.gitCommit) {
                                cb(new DError('VSJOB006', {
                                    commit: job.gitCommit,
                                    oldCommit: bInfo.gitCommit
                                }));
                                return;
                            }
                        }
                        cb(null);
                    }
                }
            });
        }
    ],
    function (err) {
        callback(err);
    });
}
