diff --git a/src/Composer/DriverFactoryAwareInterface.php b/src/Composer/DriverFactoryAwareInterface.php new file mode 100644 index 00000000..2e8e13c6 --- /dev/null +++ b/src/Composer/DriverFactoryAwareInterface.php @@ -0,0 +1,10 @@ +githubNoApi) { // Disable API if used ssh key @@ -177,6 +181,6 @@ public function createRepository(string $url, ?IOInterface $io = null, ?Config $ $repoConfig['driver'] = $config->get('_driver'); } - return $this->repositoryFactory->create($repoConfig, $io, $config, $repoConfig['repoType'] ?? null); + return $this->repositoryFactory->create($repoConfig, $io, $config, $repoType); } } diff --git a/src/Composer/Repository/Vcs/AssetVcsDriver.php b/src/Composer/Repository/Vcs/AssetVcsDriver.php new file mode 100644 index 00000000..1268a1c1 --- /dev/null +++ b/src/Composer/Repository/Vcs/AssetVcsDriver.php @@ -0,0 +1,108 @@ +repoConfig; + $repoConfig['driver'] = 'vcs'; + $repoConfig['repoType'] = 'vcs'; + + $this->driver = $this->driverFactory->createDriver( + repoConfig: $repoConfig, + io: $this->io, + config: $this->config, + httpDownloader: $this->httpDownloader, + process: $this->process, + classOrType: $repoConfig['driver'], + options: ['url' => $repoConfig['url']], + ); + } + + public function getComposerInformation(string $identifier): ?array + { + $composer = $this->repoConfig['customComposerJson'] ?? []; + if ($this->repoConfig['packageName'] ?? null) { + $composer['name'] = $this->repoConfig['packageName']; + } + + if (empty($composer['time']) && null !== ($changeDate = $this->getChangeDate($identifier))) { + $composer['time'] = $changeDate->format(DATE_RFC3339); + } + + return $composer; + } + + public function getFileContent(string $file, string $identifier): ?string + { + return $this->driver->getFileContent($file, $identifier); + } + + public function getChangeDate(string $identifier): ?\DateTimeImmutable + { + return $this->driver->getChangeDate($identifier); + } + + public function getRootIdentifier(): string + { + return $this->driver->getRootIdentifier(); + } + + public function getBranches(): array + { + return $this->driver->getBranches(); + } + + public function getTags(): array + { + return $this->driver->getTags(); + } + + public function getDist(string $identifier): ?array + { + return $this->driver->getDist($identifier); + } + + public function getSource(string $identifier): array + { + return $this->driver->getSource($identifier); + } + + public function getUrl(): string + { + return $this->driver->getUrl(); + } + + public function hasComposerFile(string $identifier): bool + { + return true; + } + + public function cleanup(): void + { + $this->driver->cleanup(); + } + + public static function supports(IOInterface $io, Config $config, string $url, bool $deep = false): bool + { + return false; + } + + public function setDriverFactory(VcsDriverFactory $factory): void + { + $this->driverFactory = $factory; + } +} diff --git a/src/Composer/VcsDriverFactory.php b/src/Composer/VcsDriverFactory.php index bcc0dce2..88b6692e 100644 --- a/src/Composer/VcsDriverFactory.php +++ b/src/Composer/VcsDriverFactory.php @@ -6,6 +6,7 @@ use Composer\Config; use Composer\IO\IOInterface; +use Composer\Repository\Vcs\VcsDriver; use Composer\Util\HttpDownloader; use Composer\Util\ProcessExecutor; @@ -32,6 +33,7 @@ public function __construct(array $drivers = []) 'fossil' => 'Composer\Repository\Vcs\FossilDriver', // svn must be last because identifying a subversion server for sure is practically impossible 'svn' => 'Composer\Repository\Vcs\SvnDriver', + 'asset' => 'Packeton\Composer\Repository\Vcs\AssetVcsDriver', ]; } @@ -54,10 +56,11 @@ public function setDriverClass(string $type, string $class): void * @param string|null $classOrType * @param array $options * - * @return \Composer\Repository\Vcs\VcsDriver + * @return VcsDriver */ - public function createDriver(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, ProcessExecutor $process, ?string $classOrType = null, array $options = []) + public function createDriver(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, ProcessExecutor $process, ?string $classOrType = null, array $options = []): VcsDriver { + /** @var VcsDriver|null $driver */ $driver = null; if ($classOrType && class_exists($classOrType)) { $driver = new $classOrType($repoConfig, $io, $config, $process); @@ -91,6 +94,10 @@ public function createDriver(array $repoConfig, IOInterface $io, Config $config, throw new \UnexpectedValueException("VCS Driver not found for repository $repoUrl"); } + if ($driver instanceof DriverFactoryAwareInterface) { + $driver->setDriverFactory($this); + } + if (!($options['lazy'] ?? false)) { $driver->initialize(); } diff --git a/src/Entity/Package.php b/src/Entity/Package.php index 2544559b..482a6758 100644 --- a/src/Entity/Package.php +++ b/src/Entity/Package.php @@ -458,6 +458,7 @@ public function getRepoConfig(): array 'oauth2' => $this->integration, 'externalRef' => $this->externalRef, 'customVersions' => $this->getCustomVersions(), + 'customComposerJson' => $this->getCustomComposerJson(), 'packageName' => $this->name, ]; diff --git a/src/Entity/PackageSerializedTrait.php b/src/Entity/PackageSerializedTrait.php index 0c0fa3e4..a22145cd 100644 --- a/src/Entity/PackageSerializedTrait.php +++ b/src/Entity/PackageSerializedTrait.php @@ -199,6 +199,16 @@ public function setCustomVersions($versions): void $this->setSerialized('custom_versions', $versions); } + public function getCustomComposerJson(): array + { + return $this->getSerialized('custom_composer_json', 'array', []); + } + + public function setCustomComposerJson(?array $composer): void + { + $this->setSerialized('custom_composer_json', $composer); + } + public function isDisabledUpdate(): bool { return (bool) ($this->serializedFields['disabled_update'] ?? false); diff --git a/src/Form/Type/Package/AssetPackageType.php b/src/Form/Type/Package/AssetPackageType.php new file mode 100644 index 00000000..40079b84 --- /dev/null +++ b/src/Form/Type/Package/AssetPackageType.php @@ -0,0 +1,66 @@ +remove('pullRequestReview'); + + $builder + ->add('credentials', CredentialType::class) + ->add('repository', TextType::class, [ + 'label' => 'Repository URL (Git/Svn/Hg)', + 'attr' => [ + 'class' => 'package-repo-info', + 'placeholder' => 'e.g.: https://github.com/fullcalendar/fullcalendar', + ], + 'constraints' => [new NotBlank()], + ]) + ->add('name', TextType::class, [ + 'required' => true, + 'constraints' => [new NotBlank()], + 'attr' => ['class' => 'package-repo-info', 'placeholder' => 'npm-asset/select2'], + 'disabled' => false === $options['is_created'], + ]); + + $placeholder = [ + 'name' => 'npm-asset/select2', + 'description' => 'Select2 is a jQuery-based replacement for select boxes.', + 'require' => ['php' => '>8.1'], + 'autoload' => ['psr-4' => ['Packeton\\' => 'src/']] + ]; + + $builder + ->add('customComposerJson', JsonTextType::class, [ + 'required' => false, + 'label' => 'composer.json config', + 'attr' => ['rows' => 12, 'placeholder' => json_encode($placeholder, 448)] + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, $this->updateRepository(...), 255); + } + + public function getParent(): string + { + return BasePackageType::class; + } +} diff --git a/src/Form/Type/Package/BasePackageType.php b/src/Form/Type/Package/BasePackageType.php index f4c36b32..9094e05b 100644 --- a/src/Form/Type/Package/BasePackageType.php +++ b/src/Form/Type/Package/BasePackageType.php @@ -29,6 +29,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'Custom (JSON)' => RepTypes::CUSTOM, 'Proxy Repo' => RepTypes::PROXY, 'Virtual (only JSON metadata)' => RepTypes::VIRTUAL, + 'VCS (Asset + Custom JSON)' => RepTypes::ASSET, 'Satis / Packagist.com / VCS Import' => 'import', // only redirect ]; diff --git a/src/Form/Type/Package/PackageType.php b/src/Form/Type/Package/PackageType.php index 18b989be..43c66bf8 100644 --- a/src/Form/Type/Package/PackageType.php +++ b/src/Form/Type/Package/PackageType.php @@ -17,6 +17,8 @@ class PackageType extends AbstractType { + use VcsPackageTypeTrait; + /** * @var PackageManager */ @@ -57,17 +59,6 @@ public function getParent(): string return BasePackageType::class; } - /** - * @param FormEvent $event - */ - public function updateRepository(FormEvent $event): void - { - $package = $event->getData(); - if ($package instanceof Package) { - $this->packageManager->updatePackageUrl($package); - } - } - /** * {@inheritdoc} */ diff --git a/src/Form/Type/Package/VcsPackageTypeTrait.php b/src/Form/Type/Package/VcsPackageTypeTrait.php new file mode 100644 index 00000000..5cc0f88e --- /dev/null +++ b/src/Form/Type/Package/VcsPackageTypeTrait.php @@ -0,0 +1,19 @@ +getData(); + if ($package instanceof Package) { + $this->packageManager->updatePackageUrl($package); + } + } +} diff --git a/src/Package/RepTypes.php b/src/Package/RepTypes.php index b891d67d..dc99754b 100644 --- a/src/Package/RepTypes.php +++ b/src/Package/RepTypes.php @@ -5,6 +5,7 @@ namespace Packeton\Package; use Packeton\Form\Type\Package\ArtifactPackageType; +use Packeton\Form\Type\Package\AssetPackageType; use Packeton\Form\Type\Package\CustomPackageType; use Packeton\Form\Type\Package\IntegrationPackageType; use Packeton\Form\Type\Package\MonoRepoPackageType; @@ -20,8 +21,9 @@ class RepTypes public const CUSTOM = 'custom'; public const VIRTUAL = 'virtual'; public const PROXY = 'proxy'; + public const ASSET = 'asset'; - private static $types = [ + private static array $types = [ self::ARTIFACT, self::MONO_REPO, self::INTEGRATION, @@ -29,6 +31,7 @@ class RepTypes self::CUSTOM, self::VIRTUAL, self::PROXY, + self::ASSET ]; public static function getFormType(?string $type): string @@ -39,6 +42,7 @@ public static function getFormType(?string $type): string self::INTEGRATION => IntegrationPackageType::class, self::CUSTOM, self::VIRTUAL => CustomPackageType::class, self::PROXY => ProxyPackageType::class, + self::ASSET => AssetPackageType::class, default => PackageType::class, }; } @@ -74,7 +78,16 @@ public static function normalizeType(?string $type): string self::CUSTOM => self::CUSTOM, self::VIRTUAL => self::VIRTUAL, self::PROXY => self::PROXY, + self::ASSET => self::ASSET, default => self::VCS, }; } + + /** + * @return string[] + */ + public static function getAllTypes(): array + { + return self::$types; + } } diff --git a/src/Package/Updater.php b/src/Package/Updater.php index 5c6dc767..088228c6 100644 --- a/src/Package/Updater.php +++ b/src/Package/Updater.php @@ -109,7 +109,7 @@ public function setSerializerCachePath(?string $serializerCachePath): void */ public static function supportRepoTypes(): iterable { - return [RepTypes::VCS, RepTypes::ARTIFACT, RepTypes::INTEGRATION, RepTypes::CUSTOM, RepTypes::VIRTUAL, RepTypes::PROXY]; + return [RepTypes::VCS, RepTypes::ARTIFACT, RepTypes::INTEGRATION, RepTypes::CUSTOM, RepTypes::VIRTUAL, RepTypes::PROXY, RepTypes::ASSET]; } /**