예제 #1
1
파일: Api.php 프로젝트: martinsv/bart
 /**
  * @param array $conf Configurations for reaching Gerrit server
  */
 public function __construct()
 {
     /** @var \Bart\Configuration\GerritConfig $config */
     $config = Diesel::create('Bart\\Configuration\\GerritConfig');
     /** @var \Bart\SshWrapper $ssh */
     $ssh = Diesel::create('Bart\\SshWrapper', $config->host(), $config->sshPort());
     $ssh->setCredentials($config->sshUser(), $config->sshKeyFile());
     $this->ssh = $ssh;
     $this->config = $config;
     $this->logger = Log4PHP::getLogger(__CLASS__);
     $this->logger->trace("Configured Gerrit API using ssh {$ssh}");
 }
예제 #2
0
파일: GitTest.php 프로젝트: martinsv/bart
 /**
  * Register a mock shell instance with Diesel
  */
 protected function registerMockShell($mockShell = null)
 {
     if (!$mockShell) {
         $mockShell = $this->getMock('Bart\\Shell');
     }
     Diesel::registerInstantiator('Bart\\Shell', $mockShell, true);
 }
예제 #3
0
파일: Git.php 프로젝트: martinsv/bart
 /**
  * @param string $dir The git directory of interest
  * @param string $origin Upstream origin name
  * @maintenance Migrate over to GitCommit and Bart\Git namespace
  */
 public function __construct($dir = '.git', $origin = 'origin')
 {
     $this->dir = $dir;
     $this->git = "git --git-dir={$dir}";
     $this->origin = $origin;
     $this->shell = Diesel::singleton('Bart\\Shell');
 }
예제 #4
0
 /**
  * @param array $hookConf Configuration for this hook type
  * @param string $repo Name of the repository
  */
 public function __construct(array $hookConf, $gitDir, $repo)
 {
     $this->hookConf = $hookConf;
     $this->repo = $repo;
     $this->logger = Log4PHP::getLogger(get_called_class());
     /** @var \Bart\Git git handle to current project */
     $this->git = Diesel::create('Bart\\Git', $gitDir);
 }
예제 #5
0
파일: TestBase.php 프로젝트: martinsv/bart
 /**
  * Register a git stub with Diesel
  * @return \Bart\Git git stub that was registered
  */
 public function getGitStub()
 {
     // mock git and method get change id to return $repo
     $gitStub = $this->getMock('\\Bart\\Git', array(), array(), '', false);
     Diesel::registerInstantiator('Bart\\Git', function () use($gitStub) {
         return $gitStub;
     });
     return $gitStub;
 }
예제 #6
0
 /**
  * Register our mock soap instance with local Diesel
  */
 private function register_soap_with_diesel()
 {
     $phpu = $this;
     Diesel::registerInstantiator('\\SoapClient', function ($wsdl, $options) use($phpu) {
         $phpu->assertEquals($phpu->opts['wsdl'], $wsdl, 'wsdl');
         $phpu->assertEquals($phpu->opts['key'], $options['key'], 'opts');
         return $phpu->soap;
     });
 }
예제 #7
0
 public function __construct(array $conf, $gitDir, $repo)
 {
     $stl_conf = $conf['jenkins'];
     if (!array_key_exists('job_name', $stl_conf)) {
         // Default to the repo for convenience
         $stl_conf['job_name'] = $repo;
     }
     parent::__construct($stl_conf, $gitDir, $repo);
     $this->job = Diesel::create('Bart\\Jenkins\\Job', $stl_conf['host'], $stl_conf['job_name']);
 }
예제 #8
0
파일: Ssh.php 프로젝트: martinsv/bart
 public function __construct($server)
 {
     if (!is_string($server)) {
         throw new \Exception("Invalid server {$server}");
     }
     $this->server = $server;
     $this->ssh_user = get_current_user();
     $this->shell = Diesel::create('Bart\\Shell');
     $this->conf = Diesel::create('Bart\\Config_Parser');
 }
예제 #9
0
 /**
  * Configure Job for injection of stub Curl with $json
  * @param string $url Expected Jenkins URL
  * @param JSON $json
  */
 private function configure_diesel($url, $json)
 {
     $mock_curl = $this->getMock('\\Bart\\Curl', array(), array(), '', false);
     $mock_curl->expects($this->once())->method('get')->with($this->equalTo(''), $this->equalTo(array()))->will($this->returnValue(array('content' => $json)));
     $phpu = $this;
     Diesel::registerInstantiator('Bart\\Curl', function ($urlParam, $portParam) use($phpu, $url, $mock_curl) {
         $phpu->assertEquals($url, $urlParam, 'url');
         $phpu->assertEquals(8080, $portParam, 'port');
         return $mock_curl;
     });
 }
예제 #10
0
파일: Client.php 프로젝트: martinsv/bart
 /**
  *
  * @param string $usename Jira username
  * @param string $password Jira password
  * @param array $options Generic soap options hash. Must, at the least, specify the WSDL to
  * your Jira SOAP, which can be a local or remote resource. It typically is available at
  * http://$your-jira-server/rpc/soap/jirasoapservice-v2?wsdl'
  */
 public function __construct($username, $password, $options)
 {
     $wsdl = $options['wsdl'];
     unset($options['wsdl']);
     $this->soap = Diesel::create('\\SoapClient', $wsdl, $options);
     try {
         $this->token = $this->soap->login($username, $password);
     } catch (\SoapFault $f) {
         throw new Soap_Exception($f, 'Authentication failed');
     }
 }
예제 #11
0
 /**
  * @param string $revision
  * @return bool
  */
 private function isChangeFeatureFlip($revision)
 {
     /** @var Git $git */
     $git = Diesel::create('\\Bart\\Git');
     $fileList = $git->get_file_list($revision);
     foreach ($fileList as $file) {
         if ($file == 'conf_override/features.conf') {
             return true;
         }
     }
     return false;
 }
예제 #12
0
 private function configure_for($conf, $is_healthy, $job_name)
 {
     $mock_job = $this->getMock('\\Bart\\Jenkins\\Job', array(), array(), '', false);
     $mock_job->expects($this->once())->method('is_healthy')->will($this->returnValue($is_healthy));
     $gitStub = $this->getGitStub();
     $phpu = $this;
     Diesel::registerInstantiator('Bart\\Jenkins\\Job', function ($host, $jobNameParam) use($phpu, $conf, $job_name, $mock_job) {
         $phpu->assertEquals($job_name, $jobNameParam, 'Jenkins job name');
         $phpu->assertEquals($conf['jenkins']['host'], $host, 'Jenkins host');
         return $mock_job;
     });
     return array('stl' => new StopTheLineJenkins($conf, '', 'Gorg'), 'git' => $gitStub);
 }
예제 #13
0
 public function testConstructor()
 {
     $conf = array();
     // mock git and method get_change_id to return $repo
     $mock_git = $this->getMock('\\Bart\\Git', array(), array(), '', false);
     $mock_git->expects($this->once())->method('get_change_id')->will($this->returnValue('grinder'));
     $phpu = $this;
     Diesel::registerInstantiator('Bart\\Git', function ($gitDir) use($mock_git, $phpu) {
         $phpu->assertEquals('.git', $gitDir, 'Expected constructor to get git dir');
         return $mock_git;
     });
     $hook = new TestGitHookAction($conf, '.git', 'grinder');
     $hook->run($this);
 }
예제 #14
0
 /**
  * @integrationTest
  */
 public function testRawFileContentsReal()
 {
     // Let's make sure the command we're running is legit
     $expectedContents = trim(shell_exec('git show HEAD:composer.json'));
     // Replicate the actual shell invocation that would take place
     Diesel::registerInstantiator('Bart\\Shell\\Command', function () {
         $shell = new Shell();
         $args = func_get_args();
         return call_user_func_array([$shell, 'command'], $args);
     });
     $commit = new Commit(new GitRoot(BART_DIR . '/.git'), 'HEAD');
     $actualContents = trim($commit->rawFileContents('composer.json'));
     $this->assertEquals($expectedContents, $actualContents, 'Raw file contents');
 }
예제 #15
0
 /**
  * Basic, shared setup for the Build_In_Jenkins hook
  *
  * @param array $conf Configurations for the hook
  * @param string $commit_msg The commit message for the hook
  * @param string $job_name The name of the job to be built
  * @return array The git hook and the git stub
  */
 private function configure_for(array $conf, $commit_msg, $job_name)
 {
     $hash = 'HEAD';
     $info = array('author' => self::$author, 'subject' => '', 'message' => $commit_msg);
     $mock_git = $this->getGitStub();
     $mock_git->expects($this->once())->method('get_pretty_email')->with($this->equalTo($hash))->will($this->returnValue($info));
     $phpu = $this;
     $mock_job = $this->getMock('\\Bart\\Jenkins\\Job', array(), array(), '', false);
     Diesel::registerInstantiator('Bart\\Jenkins\\Job', function ($host, $name) use($phpu, $conf, $job_name, $mock_job) {
         $phpu->assertEquals($job_name, $name, 'Jenkins job name did not match');
         $phpu->assertEquals($conf['jenkins']['host'], $host, 'Expected host to match conf');
         return $mock_job;
     });
     return array('j' => new BuildInJenkins($conf, '', self::$repo), 'git' => $mock_git, 'job' => $mock_job);
 }
예제 #16
0
 public function testUnderscoresSupported()
 {
     Diesel::registerInstantiator('\\Bart\\Shell', function () {
         // Actually want to see how this works with a real Shell
         return new Shell();
     });
     $this->doStuffWithTempDir(function (BaseTestCase $phpu, $dirName) {
         Configuration::configure($dirName);
         // Copy sample INI file to path Configuration will look for TestConfig INI
         copy(BART_DIR . '/test/etc/conf-parser.conf', $dirName . '/test_underscore.conf');
         $configs = new Test_Underscore_Config(false);
         $phpu->assertEquals(42, $configs->number(), 'Underscore Configs number');
         $phpu->assertEquals('Quail', $configs->wildGame(), 'Underscore Configs wildGame');
     });
 }
예제 #17
0
 public function __construct()
 {
     parent::__construct();
     /** @var JenkinsConfig $jenkinsConfig */
     $jenkinsConfig = Diesel::create('\\Bart\\Jenkins\\JenkinsConfig');
     /** @var Connection $connection */
     $connection = Diesel::create('\\Bart\\Jenkins\\Connection', $jenkinsConfig->domain(), $jenkinsConfig->protocol(), $jenkinsConfig->port());
     $user = $jenkinsConfig->user();
     $token = $jenkinsConfig->token();
     if ($user !== null && $token !== null) {
         $connection->setAuth($user, $token);
     }
     /** @var Job job */
     $this->job = Diesel::create('\\Bart\\Jenkins\\Job', $connection, $jenkinsConfig->jobLocation());
 }
예제 #18
0
 public function testBasicCommandExec()
 {
     $root = new GitRoot();
     $command = CommandTest::withStubbedResult($this, ['a57a266'], 0);
     Diesel::registerInstantiator('Bart\\Shell\\Command', function ($fmt, $dir, $limit, $author, $pretty) use($command) {
         // Assert that GitRoot sends expected parameters to create the Command
         $this->assertEquals('git --git-dir=%s log %s --author=%s --format:%s', $fmt, 'command arg 0');
         $this->assertEquals('.git', $dir);
         $this->assertEquals('-1', $limit, 'Limit of commits');
         $this->assertEquals('jbraynard', $author);
         $this->assertEquals('%h', $pretty, 'pretty format');
         return $command;
     });
     // Throw something together with a few args interspersed
     $result = $root->getCommandResult('log %s --author=%s --format:%s', '-1', 'jbraynard', '%h');
     $this->assertEquals('a57a266', $result->getOutput(true), 'git log');
 }
예제 #19
0
 /**
  * Fails if review is not approved & verified in Gerrit
  * @param Commit $commit A git commit with a Change-Id
  * @throws GitHookException If Change-Id not found or the review is not approved or verified
  */
 public function run(Commit $commit)
 {
     try {
         $changeId = $commit->gerritChangeId();
     } catch (GitException $e) {
         $this->logger->warn("{$e->getMessage()}. Skipping commit.");
         throw new GitHookException("Couldn't get Change-Id for {$commit}", $e->getCode(), $e);
     }
     /** @var \Bart\Gerrit\Change $change */
     $change = Diesel::create('\\Bart\\Gerrit\\Change', $changeId);
     if (!$change->isReviewedAndVerified()) {
         $msg = "Could not find an approved & verified change in Gerrit for change {$changeId} in commit {$commit}";
         $this->logger->info($msg);
         throw new GitHookException($msg);
     }
     $this->logger->info('Gerrit approved.');
 }
예제 #20
0
 /**
  * Add a comment in JIRA with the commit hash
  * @param Commit $commit The commit for which we're running the Git Hook
  * @throws GitHookException if requirement fails
  */
 public function run(Commit $commit)
 {
     /** @var \Bart\GitHook\GitHookConfig $hConfigs */
     $hConfigs = Diesel::create('\\Bart\\GitHook\\GitHookConfig', $commit);
     // Apply template to produce desired comment for JIRA issue
     $template = $hConfigs->jiraCommentTemplate();
     $count = preg_match_all('/\\%s/', $template);
     $this->logger->debug("Loaded jira template --{$template}-- and found {$count} token(s)");
     $vsprintf_args = [];
     if ($count !== false) {
         $vsprintf_args = array_fill(0, $count, $commit->revision());
     }
     $comment = vsprintf($template, $vsprintf_args);
     $jiraIssues = $commit->jiras();
     $this->logger->debug('Found ' . count($jiraIssues) . " jira issue(s) in {$commit}");
     foreach ($jiraIssues as $jira) {
         $this->logger->debug("Adding comment to jira {$jira}");
         $this->jiraClient->addComment($jira->id(), $comment);
     }
 }
예제 #21
0
 /**
  * Curl Jenkins JSON API
  *
  * NOTE: This method is not meant to be used on its own. It is used by other classes,
  * e.g. \Bart\Jenkins\Job, to make API calls against Jenkins.
  *
  * @param string $apiPath The full API path to curl against. For example, to do a
  * simple GET against the Jenkins Job 'Example', the full path, 'job/Example/api/json'
  * must be passed in.
  * @param array $postData if null, then curl uses GET, otherwise POSTs data
  * @return array JSON data decoded as PHP array
  * @throws JenkinsApiException
  */
 public function curlJenkinsApi($apiPath, array $postData = null)
 {
     if (!Strings::startsWith($apiPath, '/')) {
         $apiPath = "/{$apiPath}";
     }
     $fullUrl = "{$this->baseUrl}{$apiPath}";
     $isPost = $postData !== null;
     $this->logger->debug('Curling ' . ($isPost ? 'POST ' : 'GET ') . $fullUrl);
     /** @var \Bart\Curl $curl */
     $curl = Diesel::create('\\Bart\\Curl', $fullUrl, $this->port);
     if ($this->curlOptions !== []) {
         $curl->setPhpCurlOpts($this->curlOptions);
     }
     $response = $isPost ? $curl->post('', [], $postData) : $curl->get('', []);
     $httpCode = $response['info']['http_code'];
     $content = $response['content'];
     if ($httpCode !== 200 && $httpCode !== 201 && $httpCode !== 202) {
         throw new JenkinsApiException("The Jenkins API call returned a {$httpCode}, " . "with the following content: {$content}");
     }
     return JSON::decode($content);
 }
예제 #22
0
 /**
  * Stub the expected configuration
  * @param bool $buildHealth
  */
 private function mockJenkinsJobWithDependencies($buildHealth = true)
 {
     $this->shmockAndDieselify('\\Bart\\Jenkins\\JenkinsConfig', function ($jConfigs) {
         $jConfigs->domain()->once()->return_value('jenkins.example.com');
         $jConfigs->port()->once()->return_value('8080');
         $jConfigs->protocol()->once()->return_value('http');
         $jConfigs->user()->once()->return_value('user');
         $jConfigs->token()->once()->return_value('token');
         $jConfigs->jobLocation()->once()->return_value('job/Base/job/Build');
     }, true);
     $mockConnection = $this->shmockAndDieselify('\\Bart\\Jenkins\\Connection', function ($connection) {
         $connection->setAuth()->once();
     }, true);
     $mockJob = $this->shmock('\\Bart\\Jenkins\\Job', function ($jobStub) use($buildHealth) {
         $jobStub->isHealthy()->once()->return_value($buildHealth);
     }, true);
     Diesel::registerInstantiator('\\Bart\\Jenkins\\Job', function ($connection) use($mockJob, $mockConnection) {
         $this->assertEquals($mockConnection, $connection, '\\Bart\\Jenkins\\Connection object');
         return $mockJob;
     });
 }
예제 #23
0
 public function run($commitHash)
 {
     $info = $this->git->get_pretty_email($commitHash);
     $msg = $info['subject'] . PHP_EOL . $info['message'];
     if (preg_match('/\\{nobuild\\:\\s(\\".+?\\")\\}/', $msg, $matches) > 0) {
         $reason = $matches[1];
         $this->logger->debug('Skipping build with message: ' . $reason);
         return;
     }
     $jobName = $this->hookConf['job_name'];
     // Default parameters that all jobs may use, but may otherwise ignore
     $params = array('GIT_HASH' => $commitHash, 'Project_Name' => $this->repo, 'Requested_By' => $info['author']);
     if (preg_match('/\\{deploy\\}/', $msg, $matches) > 0) {
         // Submit a deploy job for repo
         $jobName = $this->hookConf['deploy-job'];
         // For repos whose deploy job is one and the same as the integration job
         $params['DEPLOY'] = 'true';
     }
     /** @var \Bart\Jenkins\Job $job */
     $job = Diesel::create('Bart\\Jenkins\\Job', $this->hookConf['host'], $jobName);
     $job->start($params);
 }
예제 #24
0
 /**
  * Run each revision against current hook
  */
 private function processRevisions()
 {
     /** @var \Bart\Git $git */
     $git = Diesel::create('\\Bart\\Git', $this->gitDir);
     /** @var \Bart\Shell $shell */
     $shell = Diesel::create('\\Bart\\Shell');
     // TODO This will need to change to support the 'update' hook
     $stdin = $shell->std_in();
     foreach ($stdin as $rangeAndRef) {
         list($startHash, $endHash, $ref) = explode(" ", $rangeAndRef);
         $endCommit = Diesel::create('\\Bart\\Git\\Commit', $this->gitRoot, $endHash);
         /** @var \Bart\GitHook\GitHookConfig $configs */
         $configs = Diesel::create('\\Bart\\GitHook\\GitHookConfig', $endCommit);
         $validRefs = $configs->getValidRefs();
         // Check whether current ref should have git hooks run or not
         if (!in_array($ref, $validRefs)) {
             $this->logger->info('Skipping hooks on ref ' . $ref);
             continue;
         }
         // TODO should this be reversed?
         // TODO This list could be massive for branches, should we have some config for how deep to go?
         $revisions = $git->getRevList($startHash, $endHash);
         $this->logger->debug('Found ' . count($revisions) . ' revision(s)');
         foreach ($revisions as $revision) {
             $commit = Diesel::create('\\Bart\\Git\\Commit', $this->gitRoot, $revision);
             // Allow a backdoor in case of emergency or broken hook configuration
             if ($this->shouldSkip($commit, $configs)) {
                 continue;
             }
             $hookRunner = $this->createHookRunner($commit);
             $this->logger->debug("Created {$hookRunner}");
             $this->logger->debug("Verifying all configured hook actions against {$revision}");
             // Let any failures bubble up to caller
             $hookRunner->runAllActions();
         }
     }
 }
예제 #25
0
 /**
  * Mocks out the Diesel Curl class
  * @param callable $configure
  * @param string $expectedProtocol
  * @param string $expectedPort
  * @throws \Bart\DieselException
  */
 private function mockCurl($configure, $expectedProtocol = 'http', $expectedPort = '8080')
 {
     $fullUrl = "{$expectedProtocol}://" . self::$fakeDomain . ":{$expectedPort}/" . self::$fakeApiPath;
     $mockCurl = $this->shmock('\\Bart\\Curl', function ($curlStub) use($configure) {
         $configure($curlStub);
     }, true);
     Diesel::registerInstantiator('\\Bart\\Curl', function ($url, $port) use($mockCurl, $fullUrl, $expectedPort) {
         $this->assertEquals($fullUrl, $url, 'Full Jenkins REST API URL');
         $this->assertEquals($expectedPort, $port, 'Port');
         return $mockCurl;
     });
 }
예제 #26
0
파일: ApiTest.php 프로젝트: martinsv/bart
 /**
  * @param String $remoteGerritCmd
  * @param \PHPUnit_Framework_MockObject_Stub $will
  * @return Api
  */
 private function configureApiForCmd($remoteGerritCmd, $will)
 {
     $ssh = $this->getMock('\\Bart\\SshWrapper', array(), array(), '', false);
     $ssh->expects($this->once())->method('exec')->with($this->equalTo($remoteGerritCmd))->will($will);
     $gerritConfigs = $this->gerritConfigs;
     Diesel::registerInstantiator('Bart\\Configuration\\GerritConfig', function () use($gerritConfigs) {
         return $gerritConfigs;
     });
     $phpu = $this;
     Diesel::registerInstantiator('Bart\\SshWrapper', function ($server, $port) use($ssh, $phpu) {
         $phpu->assertEquals('gerrit.example.com', $server, 'gerrit server');
         $phpu->assertEquals(29418, $port, 'gerrit ssh port');
         return $ssh;
     });
     return new Api();
 }
예제 #27
0
파일: Change.php 프로젝트: martinsv/bart
 /**
  * @param string $changeId Gerrit Change-Id key
  */
 public function __construct($changeId)
 {
     $this->api = Diesel::create('\\Bart\\Gerrit\\Api');
     $this->changeId = $changeId;
     $this->logger = Log4PHP::getLogger(__CLASS__);
 }
예제 #28
0
 /**
  * @param $pidFileLocation string Full path to where the pid file should be located, e.g. '/var/run/my-process.pid'
  */
 public function __construct($pidFileLocation)
 {
     $this->pidFileLocation = $pidFileLocation;
     $this->shell = Diesel::create('\\Bart\\Shell');
     $this->logger = Log4PHP::getLogger(__CLASS__);
 }
예제 #29
0
 /**
  * @abstract
  * @param string $filePath Absolute path to file containing configurations
  * @param string $subclass Name of the configuration class
  * @return array Contents of configuration parsed as INI with sections
  * @throws ConfigurationException
  */
 protected function loadParsedIni($filePath, $subclass)
 {
     /** @var \Bart\Shell $shell */
     $shell = Diesel::create('\\Bart\\Shell');
     if (!$shell->file_exists($filePath)) {
         throw new ConfigurationException("No configuration file found for {$subclass} at {$filePath}");
     }
     // @NOTE we're not using the ConfigResolver to resolve environment
     // ...distinctions by default. To add this ability, a new method should
     // ...be added to this base to resolve and then reset @configurations
     return $shell->parse_ini_file($filePath, true);
 }
예제 #30
0
 /**
  * Instantiate a new hook action
  * @param string $fqcn Name of GitHookAction class
  * @return \Bart\GitHook\GitHookAction
  * @throws GitHookException If class DNE
  */
 private function createHookActionFor($fqcn)
 {
     if ($fqcn === '') {
         throw new GitHookException('Got empty string for GitHookAction FQCN');
     }
     if (!class_exists($fqcn)) {
         throw new GitHookException("No such hook action ({$fqcn})");
     }
     return Diesel::create($fqcn);
 }