public function execute()
 {
     if (!class_exists(Validator::class)) {
         $this->error('The JsonSchema library cannot be found, please install it through composer.', 1);
     } elseif (!class_exists(SpdxLicenses::class)) {
         $this->error('The spdx-licenses library cannot be found, please install it through composer.', 1);
     }
     $path = $this->getArg(0);
     $data = json_decode(file_get_contents($path));
     if (!is_object($data)) {
         $this->error("{$path} is not a valid JSON file.", 1);
     }
     if (!isset($data->manifest_version)) {
         $this->output("Warning: No manifest_version set, assuming 1.\n");
         // For backwards-compatability assume 1
         $data->manifest_version = 1;
     }
     $version = $data->manifest_version;
     if ($version !== ExtensionRegistry::MANIFEST_VERSION) {
         $schemaPath = dirname(__DIR__) . "/docs/extension.schema.v{$version}.json";
     } else {
         $schemaPath = dirname(__DIR__) . '/docs/extension.schema.json';
     }
     if ($version < ExtensionRegistry::OLDEST_MANIFEST_VERSION || $version > ExtensionRegistry::MANIFEST_VERSION) {
         $this->error("Error: {$path} is using a non-supported schema version, it should use " . ExtensionRegistry::MANIFEST_VERSION, 1);
     } elseif ($version < ExtensionRegistry::MANIFEST_VERSION) {
         $this->output("Warning: {$path} is using a deprecated schema, and should be updated to " . ExtensionRegistry::MANIFEST_VERSION . "\n");
     }
     $licenseError = false;
     // Check if it's a string, if not, schema validation will display an error
     if (isset($data->{'license-name'}) && is_string($data->{'license-name'})) {
         $licenses = new SpdxLicenses();
         $valid = $licenses->validate($data->{'license-name'});
         if (!$valid) {
             $licenseError = '[license-name] Invalid SPDX license identifier, ' . 'see <https://spdx.org/licenses/>';
         }
     }
     $validator = new Validator();
     $validator->check($data, (object) ['$ref' => 'file://' . $schemaPath]);
     if ($validator->isValid() && !$licenseError) {
         $this->output("{$path} validates against the version {$version} schema!\n");
     } else {
         foreach ($validator->getErrors() as $error) {
             $this->output("[{$error['property']}] {$error['message']}\n");
         }
         if ($licenseError) {
             $this->output("{$licenseError}\n");
         }
         $this->error("{$path} does not validate.", 1);
     }
 }
 /**
  * @dataProvider providePassesValidation
  * @param string $path Path to thing's json file
  */
 public function testPassesValidation($path)
 {
     $data = json_decode(file_get_contents($path));
     $this->assertInstanceOf('stdClass', $data, "{$path} is not valid JSON");
     $this->assertObjectHasAttribute('manifest_version', $data, "{$path} does not have manifest_version set.");
     $version = $data->manifest_version;
     if ($version !== ExtensionRegistry::MANIFEST_VERSION) {
         $schemaPath = __DIR__ . "/../../../docs/extension.schema.v{$version}.json";
     } else {
         $schemaPath = __DIR__ . '/../../../docs/extension.schema.json';
     }
     // Not too old
     $this->assertTrue($version >= ExtensionRegistry::OLDEST_MANIFEST_VERSION, "{$path} is using a non-supported schema version");
     // Not too new
     $this->assertTrue($version <= ExtensionRegistry::MANIFEST_VERSION, "{$path} is using a non-supported schema version");
     $licenseError = false;
     if (class_exists(SpdxLicenses::class) && isset($data->{'license-name'}) && is_string($data->{'license-name'})) {
         $licenses = new SpdxLicenses();
         $valid = $licenses->validate($data->{'license-name'});
         if (!$valid) {
             $licenseError = '[license-name] Invalid SPDX license identifier, ' . 'see <https://spdx.org/licenses/>';
         }
     }
     $validator = new Validator();
     $validator->check($data, (object) ['$ref' => 'file://' . $schemaPath]);
     if ($validator->isValid() && !$licenseError) {
         // All good.
         $this->assertTrue(true);
     } else {
         $out = "{$path} did pass validation.\n";
         foreach ($validator->getErrors() as $error) {
             $out .= "[{$error['property']}] {$error['message']}\n";
         }
         if ($licenseError) {
             $out .= "{$licenseError}\n";
         }
         $this->assertTrue(false, $out);
     }
 }
Example #3
0
 /**
  * Validates the config, and returns the result.
  *
  * @param string $file                       The path to the file
  * @param int    $arrayLoaderValidationFlags Flags for ArrayLoader validation
  *
  * @return array a triple containing the errors, publishable errors, and warnings
  */
 public function validate($file, $arrayLoaderValidationFlags = ValidatingArrayLoader::CHECK_ALL)
 {
     $errors = array();
     $publishErrors = array();
     $warnings = array();
     // validate json schema
     $laxValid = false;
     try {
         $json = new JsonFile($file, null, $this->io);
         $manifest = $json->read();
         $json->validateSchema(JsonFile::LAX_SCHEMA);
         $laxValid = true;
         $json->validateSchema();
     } catch (JsonValidationException $e) {
         foreach ($e->getErrors() as $message) {
             if ($laxValid) {
                 $publishErrors[] = $message;
             } else {
                 $errors[] = $message;
             }
         }
     } catch (\Exception $e) {
         $errors[] = $e->getMessage();
         return array($errors, $publishErrors, $warnings);
     }
     // validate actual data
     if (!empty($manifest['license'])) {
         // strip proprietary since it's not a valid SPDX identifier, but is accepted by composer
         if (is_array($manifest['license'])) {
             foreach ($manifest['license'] as $key => $license) {
                 if ('proprietary' === $license) {
                     unset($manifest['license'][$key]);
                 }
             }
         }
         $licenseValidator = new SpdxLicenses();
         if ('proprietary' !== $manifest['license'] && array() !== $manifest['license'] && !$licenseValidator->validate($manifest['license'])) {
             $warnings[] = sprintf('License %s is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.' . "\nIf the software is closed-source, you may use \"proprietary\" as license.", json_encode($manifest['license']));
         }
     } else {
         $warnings[] = 'No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.';
     }
     if (isset($manifest['version'])) {
         $warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.';
     }
     if (!empty($manifest['name']) && preg_match('{[A-Z]}', $manifest['name'])) {
         $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']);
         $suggestName = strtolower($suggestName);
         $publishErrors[] = sprintf('Name "%s" does not match the best practice (e.g. lower-cased/with-dashes). We suggest using "%s" instead. As such you will not be able to submit it to Packagist.', $manifest['name'], $suggestName);
     }
     if (!empty($manifest['type']) && $manifest['type'] == 'composer-installer') {
         $warnings[] = "The package type 'composer-installer' is deprecated. Please distribute your custom installers as plugins from now on. See https://getcomposer.org/doc/articles/plugins.md for plugin documentation.";
     }
     // check for require-dev overrides
     if (isset($manifest['require']) && isset($manifest['require-dev'])) {
         $requireOverrides = array_intersect_key($manifest['require'], $manifest['require-dev']);
         if (!empty($requireOverrides)) {
             $plural = count($requireOverrides) > 1 ? 'are' : 'is';
             $warnings[] = implode(', ', array_keys($requireOverrides)) . " {$plural} required both in require and require-dev, this can lead to unexpected behavior";
         }
     }
     // check for commit references
     $require = isset($manifest['require']) ? $manifest['require'] : array();
     $requireDev = isset($manifest['require-dev']) ? $manifest['require-dev'] : array();
     $packages = array_merge($require, $requireDev);
     foreach ($packages as $package => $version) {
         if (preg_match('/#/', $version) === 1) {
             $warnings[] = sprintf('The package "%s" is pointing to a commit-ref, this is bad practice and can cause unforeseen issues.', $package);
         }
     }
     // check for empty psr-0/psr-4 namespace prefixes
     if (isset($manifest['autoload']['psr-0'][''])) {
         $warnings[] = "Defining autoload.psr-0 with an empty namespace prefix is a bad idea for performance";
     }
     if (isset($manifest['autoload']['psr-4'][''])) {
         $warnings[] = "Defining autoload.psr-4 with an empty namespace prefix is a bad idea for performance";
     }
     try {
         $loader = new ValidatingArrayLoader(new ArrayLoader(), true, null, $arrayLoaderValidationFlags);
         if (!isset($manifest['version'])) {
             $manifest['version'] = '1.0.0';
         }
         if (!isset($manifest['name'])) {
             $manifest['name'] = 'dummy/dummy';
         }
         $loader->load($manifest);
     } catch (InvalidPackageException $e) {
         $errors = array_merge($errors, $e->getErrors());
     }
     $warnings = array_merge($warnings, $loader->getWarnings());
     return array($errors, $publishErrors, $warnings);
 }
Example #4
0
 /**
  * Prints the licenses of a package with metadata
  *
  * @param CompletePackageInterface $package
  */
 protected function printLicenses(CompletePackageInterface $package)
 {
     $spdxLicenses = new SpdxLicenses();
     $licenses = $package->getLicense();
     $io = $this->getIO();
     foreach ($licenses as $licenseId) {
         $license = $spdxLicenses->getLicenseByIdentifier($licenseId);
         // keys: 0 fullname, 1 osi, 2 url
         if (!$license) {
             $out = $licenseId;
         } else {
             // is license OSI approved?
             if ($license[1] === true) {
                 $out = sprintf('%s (%s) (OSI approved) %s', $license[0], $licenseId, $license[2]);
             } else {
                 $out = sprintf('%s (%s) %s', $license[0], $licenseId, $license[2]);
             }
         }
         $io->write('<info>license</info>  : ' . $out);
     }
 }
Example #5
0
 /**
  * Compiles composer into a single phar file
  *
  * @param  string            $pharFile The full path to the file to create
  * @throws \RuntimeException
  */
 public function compile($pharFile = 'composer.phar')
 {
     if (file_exists($pharFile)) {
         unlink($pharFile);
     }
     $process = new Process('git log --pretty="%H" -n1 HEAD', __DIR__);
     if ($process->run() != 0) {
         throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.');
     }
     $this->version = trim($process->getOutput());
     $process = new Process('git log -n1 --pretty=%ci HEAD', __DIR__);
     if ($process->run() != 0) {
         throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.');
     }
     $this->versionDate = new \DateTime(trim($process->getOutput()));
     $this->versionDate->setTimezone(new \DateTimeZone('UTC'));
     $process = new Process('git describe --tags --exact-match HEAD');
     if ($process->run() == 0) {
         $this->version = trim($process->getOutput());
     } else {
         // get branch-alias defined in composer.json for dev-master (if any)
         $localConfig = __DIR__ . '/../../composer.json';
         $file = new JsonFile($localConfig);
         $localConfig = $file->read();
         if (isset($localConfig['extra']['branch-alias']['dev-master'])) {
             $this->branchAliasVersion = $localConfig['extra']['branch-alias']['dev-master'];
         }
     }
     $phar = new \Phar($pharFile, 0, 'composer.phar');
     $phar->setSignatureAlgorithm(\Phar::SHA1);
     $phar->startBuffering();
     $finderSort = function ($a, $b) {
         return strcmp(strtr($a->getRealPath(), '\\', '/'), strtr($b->getRealPath(), '\\', '/'));
     };
     $finder = new Finder();
     $finder->files()->ignoreVCS(true)->name('*.php')->notName('Compiler.php')->notName('ClassLoader.php')->in(__DIR__ . '/..')->sort($finderSort);
     foreach ($finder as $file) {
         $this->addFile($phar, $file);
     }
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/Autoload/ClassLoader.php'), false);
     $finder = new Finder();
     $finder->files()->name('*.json')->in(__DIR__ . '/../../res')->in(SpdxLicenses::getResourcesDir())->sort($finderSort);
     foreach ($finder as $file) {
         $this->addFile($phar, $file, false);
     }
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/seld/cli-prompt/res/hiddeninput.exe'), false);
     $finder = new Finder();
     $finder->files()->ignoreVCS(true)->name('*.php')->name('LICENSE')->exclude('Tests')->exclude('tests')->exclude('docs')->in(__DIR__ . '/../../vendor/symfony/')->in(__DIR__ . '/../../vendor/seld/jsonlint/')->in(__DIR__ . '/../../vendor/seld/cli-prompt/')->in(__DIR__ . '/../../vendor/justinrainbow/json-schema/')->in(__DIR__ . '/../../vendor/composer/spdx-licenses/')->in(__DIR__ . '/../../vendor/composer/semver/')->sort($finderSort);
     foreach ($finder as $file) {
         $this->addFile($phar, $file);
     }
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/autoload.php'));
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_namespaces.php'));
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_psr4.php'));
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_classmap.php'));
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_real.php'));
     if (file_exists(__DIR__ . '/../../vendor/composer/include_paths.php')) {
         $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/include_paths.php'));
     }
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/ClassLoader.php'));
     $this->addComposerBin($phar);
     // Stubs
     $phar->setStub($this->getStub());
     $phar->stopBuffering();
     // disabled for interoperability with systems without gzip ext
     // $phar->compressFiles(\Phar::GZ);
     $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../LICENSE'), false);
     unset($phar);
     // re-sign the phar with reproducible timestamp / signature
     $util = new Timestamps($pharFile);
     $util->updateTimestamps($this->versionDate);
     $util->save($pharFile, \Phar::SHA1);
 }