Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • composer/plugin/dorgflow
  • felixhaeberle/dorgflow
2 results
Select Git revision
Show changes
Commits on Source (45)
ahoyapi: v2
commands:
dorgflow:
imports:
- ahoy.yml
usage: Dorgflow settings and updates
......@@ -12,6 +12,3 @@ indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{composer.json,composer.lock}]
indent_size = 4
vendor
composer.lock
/vendor/
/.env
/composer.lock
/.ahoy.l3d
/.ahoy.yml
Deploy:
script:
- curl -XPOST -H'content-type:application/json' "https://packagist.org/api/update-package?username=${PACKAGIST_USERNAME}&apiToken=${PACKAGIST_API_TOKEN}" -d'{"repository":{"url":"'${CI_PROJECT_URL}'"}}'
include:
- project: 'gitlab-ci-cd/drupal'
ref: main
file: '/private-modules.yml'
# DorgFlow Composer Plugin
This is a composer plugin which prepares some of your projects in a composer base Drupal installation for drupal-org contributions powered by [Dorgflow](https://github.com/joachim-n/dorgflow).
You can keep your composer.json as is and only define the dev modules in the extra section such that this plugin can clone those projects for you from drupal.org so that you can immediately start using `dorgflow`.
Here is a sample of what to add to your composer.json:
```json
{
"extra": {
"dorgflow": {
"projects": {
"drupal/colorbox_field_formatter": "8.x-1.x",
"drupal/dimension": "8.x-1.x",
"drupal/drd": "8.x-3.x",
"drupal/drd_agent": "8.x-3.x"
}
}
}
}
```
Then, to get it to work, simply call `composer require lakedrops/dorgflow` and everything will be traken care off for you automatically - even if you update your Drupal project at any time in the future, the development environments for your defined projects will be kept in place and properly configured.
ahoyapi: v2
commands:
update:
cmd: composer lakedrops:dorgflow "$@"
usage: Update DorgFlow setup in project
on:
cmd: |
DORGFLOW=1
echo "DORGFLOW=1" >>.env
env -i $(cat .env | xargs) >.env
composer lakedrops:dorgflow --no-interaction
usage: Turn on dorgflow
off:
cmd: |
DORGFLOW=0
echo "DORGFLOW=0" >>.env
env -i $(cat .env | xargs) >.env
composer lakedrops:dorgflow --no-interaction
usage: Turn off dorgflow
issue:
cmd: composer lakedrops:issuefork "$@" --no-interaction
usage: Load an issue fork for a specific project from drupal.org
{
"name": "lakedrops/dorgflow",
"description": "Composer Plugin for development environments",
"type": "composer-plugin",
"keywords": ["Development"],
"homepage": "https://gitlab.lakedrops.com/composer/plugin/dorgflow",
"license": "GPL-2.0+",
"authors": [
{
"name": "Jürgen Haas",
"email": "juergen@paragon-es.de",
"homepage": "https://www.paragon-es.de",
"role": "Drupal Expert"
},
{
"name": "Richard Papp",
"email": "richard.papp@boromino.com",
"homepage": "http://www.boromino.com",
"role": "Drupal Expert"
}
],
"support": {
"issues": "https://gitlab.lakedrops.com/composer/plugin/dorgflow/issues",
"source": "https://gitlab.lakedrops.com/composer/plugin/dorgflow/tree/master"
"name": "lakedrops/dorgflow",
"description": "Composer Plugin for development environments",
"type": "composer-plugin",
"keywords": [
"Development"
],
"homepage": "https://gitlab.lakedrops.com/composer/plugin/dorgflow",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Jürgen Haas",
"email": "juergen.haas@lakedrops.com",
"homepage": "https://www.lakedrops.com",
"role": "Drupal Expert"
},
"require": {
"composer-plugin-api": "^1.0.0",
"cypresslab/gitelephant": "~1.0",
"lakedrops/dotenv": "^0.1",
"php": ">=5.6"
{
"name": "Daniel Speicher",
"email": "daniel.speicher@lakedrops.com",
"homepage": "https://www.lakedrops.com",
"role": "Drupal Expert"
},
"require-dev": {
"composer/composer": "^1.5.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"drupal/coder": "^8.2",
"phpunit/phpunit": "^4.8.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"LakeDrops\\DorgFlow\\": "src/"
}
},
"extra": {
"class": "LakeDrops\\DorgFlow\\Plugin"
{
"name": "Richard Papp",
"email": "richard.papp@lakedrops.com",
"homepage": "https://www.lakedrops.com",
"role": "Drupal Expert"
}
],
"support": {
"issues": "https://gitlab.lakedrops.com/composer/plugin/dorgflow/issues",
"source": "https://gitlab.lakedrops.com/composer/plugin/dorgflow/tree/main",
"docs": "https://devops-tools.docs.lakedrops.com/composer/plugin/dorgflow/"
},
"require": {
"php": ">=8.1",
"composer-plugin-api": "^2",
"cypresslab/gitelephant": "^2.0|^4.0",
"lakedrops/composer-json-utils": "^2.5||dev-develop"
},
"require-dev": {
"composer/composer": "^2",
"roave/security-advisories": "dev-latest"
},
"autoload": {
"psr-4": {
"LakeDrops\\DorgFlow\\": "src/"
}
},
"extra": {
"class": "LakeDrops\\DorgFlow\\Plugin"
}
}
parameters:
level: 6
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
treatPhpDocTypesAsCertain: false
<?php
namespace LakeDrops\DorgFlow;
use Composer\Plugin\Capability\CommandProvider as CommandProviderCapability;
/**
* Composer Command Provider for DorgFlow.
*
* @package LakeDrops\DorgFlow
*/
class CommandProvider implements CommandProviderCapability {
/**
* {@inheritdoc}
*/
public function getCommands(): array {
return [
new PrepareCommand(),
new IssueForkCommand(),
];
}
}
......@@ -2,123 +2,109 @@
namespace LakeDrops\DorgFlow;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Script\Event;
use GitElephant\Repository;
use LakeDrops\Component\Dotenv\Dotenv;
use LakeDrops\Component\Composer\BaseHandler;
use Symfony\Component\Filesystem\Filesystem;
/**
* Class Handler.
* Handler class for the Dorgflow plugin.
*
* @package LakeDrops\DorgFlow
*/
class Handler {
class Handler extends BaseHandler {
/**
* The composer object of this session.
*
* @var \Composer\Composer
*/
protected $composer;
/**
* The input-output object of the composer session.
*
* @var \Composer\IO\IOInterface
* {@inheritdoc}
*/
protected $io;
/**
* Handler constructor.
*
* @param \Composer\Composer $composer
* The composer object of this session.
* @param \Composer\IO\IOInterface $io
* The input-output object of the composer session.
*/
public function __construct(Composer $composer, IOInterface $io) {
$this->composer = $composer;
$this->io = $io;
public function configId(): string {
return 'dorgflow';
}
/**
* Retrieve a package from the current composer process.
*
* @param string $name
* Name of the package to get from the current composer installation.
*
* @return \Composer\Package\PackageInterface
* The package.
* {@inheritdoc}
*/
protected function getPackage($name) {
return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*');
protected function configDefault(): array {
return [
'projects' => [],
'drupalspoons' => [],
];
}
/**
* Post install/update event to prepare projects for development.
*
* @param \Composer\Script\Event $event
* The event that triggered the call of this function.
*/
public function prepareDevProjects(Event $event) {
public function prepareDevProjects(): void {
// We only do the fancy stuff for developers.
if (!$event->isDevMode()) {
if (!$this->isDevMode() || $this->isCiContext()) {
return;
}
$options = $this->getOptions();
if (empty($options['projects'])) {
$this->init();
$dorgflow = $this->env->receiveGlobal('DORGFLOW', 'Dorgflow', '0');
if (empty($dorgflow)) {
return;
}
$this->io->write('Dorgflow: Preparing drupol.org packages for development', TRUE);
$installationManager = $this->composer->getInstallationManager();
foreach ($options['projects'] as $project => $version) {
$package = $this->getPackage($project);
if (empty($package)) {
foreach ([
'projects' => 'git.drupal.org:project',
'drupalspoons' => 'gitlab.com:drupalspoons',
'selfhosted' => FALSE,
] as $type => $url) {
if ($this->config->readValue($type) === NULL) {
continue;
}
$path = $installationManager->getInstallPath($package);
$this->io->write("- $project => $path", TRUE);
$this->prepareWorkingDirectory($path, $project, $version, $options['username']);
if ($url === FALSE) {
$url = $this->config->readValue([$type, 'url']);
$projects = $this->config->readValue([$type, 'projects']);
$simpleMode = FALSE;
}
else {
$projects = $this->config->readValue($type);
$simpleMode = TRUE;
}
$this->io->write('Dorgflow: Preparing ' . $url . ' packages for development', TRUE);
foreach ($projects as $project => $specification) {
[, $projectname] = explode('/', $project);
if (!$simpleMode) {
$fullUrl = $url . ':' . $specification['path'];
$version = $specification['version'];
if (isset($specification['name'])) {
$projectname = $specification['name'];
}
}
else {
$fullUrl = $url;
$version = $specification;
}
$package = $this->getPackage($project);
if ($package === NULL) {
continue;
}
$path = $installationManager->getInstallPath($package);
$this->io->write("- $project => $path", TRUE);
$this->keepObjects($project);
$this->prepareWorkingDirectory($path, $projectname, $version, $fullUrl);
$this->restoreObjects($project);
}
}
}
/**
* Retrieve options from composer.json "extra" configuration.
*
* @return array
* The options.
*/
protected function getOptions() {
$env = new Dotenv('dorgflow', $this->io);
$extra = $this->composer->getPackage()->getExtra() + ['dorgflow' => []];
$options = $extra['dorgflow'] + [
'projects' => [],
'username' => $env->receive('drupal_org_username', 'Drupal.org username', getenv('USER')),
];
return $options;
}
/**
* Prepare the working directory of a git based package for dorgflow.
*
* @param string $path
* Name of the working directory.
* @param string $project
* @param string $projectname
* Name of the project.
* @param string $version
* Version to checkout.
* @param string $username
* Username on drupal.org.
* @param string $url
* Base URL to checkout from.
*/
protected function prepareWorkingDirectory($path, $project, $version, $username) {
list(, $projectname) = explode('/', $project);
$uri = $username . '@git.drupal.org:project/' . $projectname . '.git';
protected function prepareWorkingDirectory(string $path, string $projectname, string $version, string $url): void {
$uri = 'git@' . $url . '/' . $projectname . '.git';
// Git Clone the repository into the working directory.
$repository = Repository::open($path);
......@@ -126,7 +112,7 @@ class Handler {
try {
$origin = $repository->getRemote('origin', FALSE);
if ($origin && $origin->getFetchURL() == $uri) {
if ($origin->getFetchURL() === $uri) {
// Already setup correctly.
return;
}
......@@ -142,9 +128,104 @@ class Handler {
$repository->addRemote('origin', $uri);
$repository->fetch();
if ($repository->isDirty()) {
$this->io->write(' - directory dirty, can NOT checkout branch ' . $version, TRUE);
return;
}
$repository->checkout($version);
$repository->getCaller()->execute('branch --set-upstream-to origin/' . $version . ' ' . $version);
$this->io->write(" - completed", TRUE);
$this->io->write(' - completed', TRUE);
}
/**
* Load an issue fork for a specific project from drupal.org.
*/
public function loadIssueFork(string $project, string $issue): void {
// We only do the fancy stuff for developers.
if (!$this->isDevMode() || $this->isCiContext()) {
return;
}
$this->init();
$dorgflow = $this->env->receiveGlobal('DORGFLOW', 'Dorgflow', '0');
if (empty($dorgflow)) {
$this->io->write('ERROR: Dorgflow is not enabled.', TRUE);
return;
}
$installationManager = $this->composer->getInstallationManager();
$package = $this->getPackage('drupal/' . $project);
if ($package === NULL) {
$this->io->write('ERROR: Project not installed.', TRUE);
return;
}
$path = $installationManager->getInstallPath($package);
if (!file_exists($path)) {
$this->io->write('ERROR: Installation path not found: ' . $path, TRUE);
return;
}
$projects = $this->config->readValue('projects');
if (empty($projects['drupal/' . $project])) {
$this->io->write('ERROR: Project not configured for dorgflow.', TRUE);
return;
}
if (!file_exists($path . '/.git')) {
$this->prepareDevProjects();
}
$uri = 'git@git.drupal.org:issue/' . $project . '-' . $issue . '.git';
$remote = $project . '-issue-' . $issue;
$repository = Repository::open($path);
try {
$origin = $repository->getRemote($remote, FALSE);
if ($origin->getFetchURL() === $uri) {
// Already setup correctly.
$this->io->write('Already available.');
return;
}
}
catch (\Exception $ex) {
// Ignore the exception and conitue setup.
}
$repository->addRemote($remote, $uri);
$repository->fetch($remote);
$this->io->write('Successfully added issue fork.');
}
/**
* Move files and directories to keep to the /tmp directory.
*
* @param string $project
* The project name.
*/
private function keepObjects(string $project): void {
if ($objects = $this->config->readValue(['keep', $project])) {
$fs = new Filesystem();
foreach ($objects as $id => $object) {
if (file_exists($object)) {
$this->io->write(' - keeping ' . $object);
$fs->rename($object, '/tmp/dorgflow-keep-' . $id, TRUE);
}
}
}
}
/**
* Move files and directories to keep from the /tmp directory.
*
* @param string $project
* The project name.
*/
private function restoreObjects(string $project): void {
if ($objects = $this->config->readValue(['keep', $project])) {
$fs = new Filesystem();
foreach ($objects as $id => $object) {
if (file_exists('/tmp/dorgflow-keep-' . $id)) {
$this->io->write(' - restoring ' . $object);
$fs->rename('/tmp/dorgflow-keep-' . $id, $object, TRUE);
}
}
}
}
}
<?php
namespace LakeDrops\DorgFlow;
use LakeDrops\Component\Composer\BaseCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Composer Issue Fork Command for DorgFlow.
*
* @package LakeDrops\DorgFlow
*/
class IssueForkCommand extends BaseCommand {
/**
* {@inheritdoc}
*/
protected function configure(): void {
parent::configure();
$this
->setName('lakedrops:issuefork')
->addArgument('Project', InputArgument::REQUIRED, 'Name of the project, e.g. core')
->addArgument('Issue', InputArgument::REQUIRED, 'Number fo the issue')
->setDescription('Load an issue fork for a specific project from drupal.org.');
}
/**
* {@inheritdoc}
*/
public function getHandlerClass(): string {
return Handler::class;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
parent::execute($input, $output);
/** @var Handler $handler */
$handler = $this->handler;
$handler->loadIssueFork($input->getArgument('Project'), $input->getArgument('Issue'));
return 0;
}
}
......@@ -2,40 +2,40 @@
namespace LakeDrops\DorgFlow;
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Plugin\Capability\CommandProvider as ComposerCommandProvider;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use LakeDrops\Component\Composer\BasePlugin;
/**
* Composer plugin for preparing Drupal project for development with dorgflow.
*/
class Plugin implements PluginInterface, EventSubscriberInterface {
class Plugin extends BasePlugin {
/**
* The handler object to configure the project for dorgflow.
*
* @var \LakeDrops\DorgFlow\Handler
* {@inheritdoc}
*/
protected $handler;
public function getHandlerClass(): string {
return Handler::class;
}
/**
* {@inheritdoc}
*/
public function activate(Composer $composer, IOInterface $io) {
$this->handler = new Handler($composer, $io);
public function getCapabilities(): array {
return [
ComposerCommandProvider::class => CommandProvider::class,
];
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return array(
public static function getSubscribedEvents(): array {
return [
ScriptEvents::POST_INSTALL_CMD => 'prepareDevProjects',
ScriptEvents::POST_UPDATE_CMD => 'prepareDevProjects',
);
];
}
/**
......@@ -44,19 +44,11 @@ class Plugin implements PluginInterface, EventSubscriberInterface {
* @param \Composer\Script\Event $event
* The event that triggered the call of this function.
*/
public function prepareDevProjects(Event $event) {
$this->handler->prepareDevProjects($event);
}
/**
* Script callback for putting in composer scripts to prepare the project.
*
* @param \Composer\Script\Event $event
* The event that triggered the call of this function.
*/
public static function prepare(Event $event) {
$handler = new Handler($event->getComposer(), $event->getIO());
$handler->prepareDevProjects($event);
public function prepareDevProjects(Event $event): void {
/** @var \LakeDrops\DorgFlow\Handler $handler */
$handler = $this->handler;
$handler->setEvent($event);
$handler->prepareDevProjects();
}
}
<?php
namespace LakeDrops\DorgFlow;
use LakeDrops\Component\Composer\BaseCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Composer Prepare Command for DorgFlow.
*
* @package LakeDrops\DorgFlow
*/
class PrepareCommand extends BaseCommand {
/**
* {@inheritdoc}
*/
protected function configure(): void {
parent::configure();
$this
->setName('lakedrops:dorgflow')
->setDescription('Prepare drupal.org projects for dorgflow utility.');
}
/**
* {@inheritdoc}
*/
public function getHandlerClass(): string {
return Handler::class;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
parent::execute($input, $output);
/** @var Handler $handler */
$handler = $this->handler;
$handler->prepareDevProjects();
return 0;
}
}