Exemplo n.º 1
0
 protected function setupCheckoutLocal(JobInterface $job, $details)
 {
     $job->getOutput()->writeln("<info>Entering setupCheckoutLocal().</info>");
     $srcdir = isset($details['srcdir']) ? $details['srcdir'] : './';
     $workingdir = $job->getWorkingDir();
     $checkoutdir = isset($details['checkout_dir']) ? $details['checkout_dir'] : $workingdir;
     // TODO: Ensure we don't end up with double slashes
     // Validate source directory
     $source = realpath($srcdir);
     if (empty($source)) {
         $job->errorOutput("Error", "The source directory <info>{$srcdir}</info> does not exist.");
         return;
     }
     // Validate target directory.  Must be within workingdir.
     if (!($directory = $this->validate_directory($job, $checkoutdir))) {
         // Invalidate checkout directory
         $job->errorOutput("Error", "The checkout directory <info>{$directory}</info> is invalid.");
         return;
     }
     $job->getOutput()->write("<comment>Copying files from <options=bold>{$srcdir}</options=bold> to the local checkout directory <options=bold>{$directory}</options=bold> ... </comment>");
     exec("cp -r {$srcdir}/* {$directory}", $cmdoutput, $result);
     if (is_null($result)) {
         $job->errorOutput("Failed", "Error encountered while attempting to copy code to the local checkout directory.");
         return;
     }
     $job->getOutput()->writeln("<comment>DONE</comment>");
 }
Exemplo n.º 2
0
 /**
  * {@inheritdoc}
  */
 public function run(JobInterface $job, $data)
 {
     // Data format:
     // i) array('patch_file' => '...', 'patch_dir' => '...')
     // or
     // iii) array(array(...), array(...))
     // Normalize data to the third format, if necessary
     $data = count($data) == count($data, COUNT_RECURSIVE) ? [$data] : $data;
     $job->getOutput()->writeln("<info>Entering setup_patch().</info>");
     foreach ($data as $key => $details) {
         if (empty($details['patch_file'])) {
             $job->errorOutput("Error", "No valid patch file provided for the patch command.");
             return;
         }
         $workingdir = realpath($job->getWorkingDir());
         $patchfile = $details['patch_file'];
         $patchdir = !empty($details['patch_dir']) ? $details['patch_dir'] : $workingdir;
         // Validate target directory.
         if (!($directory = $this->validate_directory($job, $patchdir))) {
             // Invalid checkout directory
             $job->errorOutput("Error", "The patch directory <info>{$directory}</info> is invalid.");
             return;
         }
         $cmd = "patch -p1 -i {$patchfile} -d {$directory}";
         exec($cmd, $cmdoutput, $result);
         if ($result !== 0) {
             // The command threw an error.
             $job->errorOutput("Patch failed", "The patch attempt returned an error.");
             $job->getOutput()->writeln($cmdoutput);
             // TODO: Pass on the actual return value for the patch attempt
             return;
         }
         $job->getOutput()->writeln("<comment>Patch <options=bold>{$patchfile}</options=bold> applied to directory <options=bold>{$directory}</options=bold></comment>");
     }
 }
Exemplo n.º 3
0
 protected function validate_directory(JobInterface $job, $dir)
 {
     // Validate target directory.  Must be within workingdir.
     $working_dir = $job->getWorkingDir();
     $true_dir = realpath($dir);
     if (!empty($true_dir)) {
         if ($true_dir == realpath($working_dir)) {
             // Passed directory is the root working directory.
             return $true_dir;
         } elseif (strpos($true_dir, realpath($working_dir)) === 0) {
             // Passed directory is an existing subdirectory within the working path.
             return $true_dir;
         }
     }
     // Assume the Passed directory is a subdirectory of the working, without the working prefix.  Construct the full path.
     if (!(strpos($dir, realpath($working_dir)) === 0)) {
         $dir = $working_dir . "/" . $dir;
     }
     $directory = realpath($dir);
     // TODO: Ensure we don't have double slashes
     // Check whether this is a pre-existing directory
     if ($directory === FALSE) {
         // Directory doesn't exist. Create and then validate.
         mkdir($dir, 0777, TRUE);
         $directory = realpath($dir);
     }
     // Validate that resulting directory is still within the working directory path.
     if (!strpos(realpath($directory), realpath($working_dir)) === 0) {
         // Invalid checkout directory
         $job->errorOutput("Error", "The checkout directory <info>{$directory}</info> is invalid.");
         return FALSE;
     }
     // Return the updated directory value.
     return $directory;
 }
 protected function create_tempdir(JobInterface $job, $dir = NULL, $prefix = NULL)
 {
     // PHP seems to have trouble creating temporary unique directories with the appropriate permissions,
     // So we create a temp file to get the unique filename, then mkdir a directory in it's place.
     $prefix = empty($prefix) ? "drupalci-" : $prefix;
     $tmpdir = $dir && is_dir($dir) ? $dir : sys_get_temp_dir();
     $tempname = tempnam($tmpdir, $prefix);
     if (empty($tempname)) {
         // Unable to create temp filename
         $job->errorOutput("Error", "Unable to create temporary directory inside of {$tmpdir}.");
         return;
     }
     $tempdir = $tempname;
     unlink($tempname);
     if (mkdir($tempdir)) {
         return $tempdir;
     } else {
         // Unable to create temp directory
         $job->errorOutput("Error", "Error encountered while attempting to create temporary directory {$tempdir}.");
         return;
     }
 }
 public function validateImageNames($containers, JobInterface $job)
 {
     // Verify that the appropriate container images exist
     $job->getOutput()->writeln("<comment>Validating container images exist</comment>");
     $docker = $job->getDocker();
     $manager = $docker->getImageManager();
     foreach ($containers as $key => $image_name) {
         $name = $image_name['image'];
         try {
             $image = $manager->find($name);
         } catch (ImageNotFoundException $e) {
             $job->errorOutput("Failed", "Required container image <options=bold>'{$name}'</options=bold> not found.");
             // TODO: Robust error handling.
             return FALSE;
         }
         $id = substr($image->getID(), 0, 8);
         $job->getOutput()->writeln("<comment>Found image <options=bold>{$name}</options=bold> with ID <options=bold>{$id}</options=bold></comment>");
     }
     return TRUE;
 }
 /**
  * {@inheritdoc}
  */
 public function run(JobInterface $job, $data = NULL)
 {
     // TODO: Ensure that all 'required' arguments are defined
     $definition = $job->getDefinition();
     $failflag = FALSE;
     foreach ($job->getRequiredArguments() as $env_var => $yaml_loc) {
         if (!empty($job->getBuildVars()[$env_var])) {
             continue;
         } else {
             // Look for the appropriate array structure in the job definition file
             // eg: environment:db
             $keys = explode(":", $yaml_loc);
             $eval = $definition;
             foreach ($keys as $key) {
                 if (!empty($eval[$key])) {
                     // Check if the next level contains a numeric [0] key, indicating a
                     // nested array of parameters.  If found, skip this level of the
                     // array.
                     if (isset($eval[$key][0])) {
                         $eval = $eval[$key][0];
                     } else {
                         $eval = $eval[$key];
                     }
                 } else {
                     // Missing a required key in the array key chain
                     $failflag = TRUE;
                     break;
                 }
             }
             if (!$failflag) {
                 continue;
             }
         }
         // If processing gets to here, we're missing a required variable
         $job->errorOutput("Failed", "Required test parameter <options=bold>'{$env_var}'</options=bold> not found in environment variables, and <options=bold>'{$yaml_loc}'</options=bold> not found in job definition file.");
         // TODO: Graceful handling of failed exit states
         return FALSE;
     }
     // TODO: Strip out arguments which are not defined in the 'Available' arguments array
     return TRUE;
 }
Exemplo n.º 7
0
 /**
  * {@inheritdoc}
  */
 public function run(JobInterface $job, $data)
 {
     // Data format:
     // i) array('url' => '...', 'fetch_dir' => '...')
     // or
     // iii) array(array(...), array(...))
     // Normalize data to the third format, if necessary
     $data = count($data) == count($data, COUNT_RECURSIVE) ? [$data] : $data;
     $job->getOutput()->writeln("<info>Entering setup_fetch().</info>");
     foreach ($data as $key => $details) {
         // URL and target directory
         // TODO: Ensure $details contains all required parameters
         if (empty($details['url'])) {
             $job->errorOutput("Error", "No valid target file provided for fetch command.");
             return;
         }
         $url = $details['url'];
         $workingdir = realpath($job->getWorkingDir());
         $fetchdir = !empty($details['fetch_dir']) ? $details['fetch_dir'] : $workingdir;
         if (!($directory = $this->validate_directory($job, $fetchdir))) {
             // Invalid checkout directory
             $job->errorOutput("Error", "The fetch directory <info>{$directory}</info> is invalid.");
             return;
         }
         $info = pathinfo($url);
         $destfile = $directory . "/" . $info['basename'];
         $contents = file_get_contents($url);
         if ($contents === FALSE) {
             $job->errorOutput("Error", "An error was encountered while attempting to fetch <info>{$url}</info>.");
             return;
         }
         if (file_put_contents($destfile, $contents) === FALSE) {
             $job->errorOutput("Error", "An error was encountered while attempting to write <info>{$url}</info> to <info>{$directory}</info>");
             return;
         }
         $job->getOutput()->writeln("<comment>Fetch of <options=bold>{$url}</options=bold> to <options=bold>{$destfile}</options=bold> complete.</comment>");
     }
 }
 /**
  * {@inheritdoc}
  */
 public function run(JobInterface $job, $data)
 {
     // Data format: 'command [arguments]' or array('command [arguments]', 'command [arguments]')
     // $data May be a string if one version required, or array if multiple
     // Normalize data to the array format, if necessary
     $data = is_array($data) ? $data : [$data];
     $docker = $job->getDocker();
     $manager = $docker->getContainerManager();
     if (!empty($data)) {
         // Check that we have a container to execute on
         $configs = $job->getExecContainers();
         foreach ($configs as $type => $containers) {
             foreach ($containers as $container) {
                 $id = $container['id'];
                 $instance = $manager->find($id);
                 $short_id = substr($id, 0, 8);
                 $job->getOutput()->writeln("<info>Executing on container instance {$short_id}:</info>");
                 foreach ($data as $cmd) {
                     $job->getOutput()->writeln("<fg=magenta>{$cmd}</fg=magenta>");
                     $exec = explode(" ", $cmd);
                     $exec_id = $manager->exec($instance, $exec, TRUE, TRUE, TRUE, TRUE);
                     $job->getOutput()->writeln("<info>Command created as exec id " . substr($exec_id, 0, 8) . "</info>");
                     $result = $manager->execstart($exec_id, function ($output, $type) use($job) {
                         if ($type === 1) {
                             $job->getOutput()->writeln("<info>{$output}</info>");
                         } else {
                             $job->errorOutput('Error', $output);
                         }
                     });
                     //Response stream is never read you need to simulate a wait in order to get output
                     $result->getBody()->getContents();
                     $job->getOutput()->writeln((string) $result);
                 }
             }
         }
     }
 }
 /**
  * {@inheritdoc}
  */
 public function run(JobInterface $job, $data = NULL)
 {
     // Get and parse test definitions
     // DrupalCI jobs are controlled via a hierarchy of configuration settings, which define the behaviour of the platform while running DrupalCI jobs.  This hierarchy is defined as follows, which each level overriding the previous:
     // 1. Out-of-the-box DrupalCI defaults
     // 2. Local overrides defined in ~/.drupalci/config
     // 3. 'DCI_' namespaced environment variable overrides
     // 4. Test-specific overrides passed inside a DrupalCI test definition (e.g. .drupalci.yml)
     // 5. Custom overrides located inside a test definition defined via the $source variable when calling this function.
     $confighelper = new ConfigHelper();
     // Load job defaults
     $platform_args = $job->getPlatformDefaults();
     $default_args = $job->getDefaultArguments();
     if (!empty($default_args)) {
         $job->getOutput()->writeln("<comment>Loading build variables for this job type.</comment>");
     }
     // Load DrupalCI local config overrides
     $local_args = $confighelper->getCurrentConfigSetParsed();
     if (!empty($local_args)) {
         $job->getOutput()->writeln("<comment>Loading build variables from DrupalCI local config overrides.</comment>");
     }
     // Load "DCI_ namespaced" environment variable overrides
     $environment_args = $confighelper->getCurrentEnvVars();
     if (!empty($environment_args)) {
         $job->getOutput()->writeln("<comment>Loading build variables from namespaced environment variable overrides.</comment>");
     }
     // Load command line arguments
     // TODO: Routine for loading command line arguments.
     // TODO: How do we pull arguments off the drupalci command, when in a job class?
     // $cli_args = $somehelper->loadCLIargs();
     $cli_args = array();
     if (!empty($cli_args)) {
         $job->getOutput()->writeln("<comment>Loading test parameters from command line arguments.</comment>");
     }
     // Create temporary config array to use in determining the definition file source
     $config = $cli_args + $environment_args + $local_args + $default_args + $platform_args;
     // Load any build vars defined in the job definition file
     // Retrieve test definition file
     if (isset($source)) {
         $config['explicit_source'] = $source;
     }
     $definition_file = $this->getDefinitionFile($config);
     $definition_args = array();
     // Load test definition file
     if (!empty($definition_file)) {
         $job->getOutput()->writeln("<comment>Loading test parameters from build file: </comment><info>{$definition_file}</info>");
         $jobdef = new JobDefinition();
         $result = $jobdef->load($definition_file);
         if ($result == -1) {
             // Error loading definition file.
             $job->errorOutput("Failed", "Unable to parse build file.");
             // TODO: Robust error handling
             return;
         }
         $job_definition = $jobdef->getParameters();
         if (empty($job_definition)) {
             $job_definition = array();
             $definition_args = array();
         } else {
             $definition_args = !empty($job_definition['build_vars']) ? $job_definition['build_vars'] : array();
         }
         $job->setDefinition($job_definition);
     }
     $config = $cli_args + $definition_args + $environment_args + $local_args + $default_args + $platform_args;
     // Set initial build variables
     $buildvars = $job->getBuildVars();
     $job->setBuildVars($buildvars + $config);
     // Map relevant build variables into the job definition array
     // $this->buildvarsToDefinition($job);
     return;
 }