Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a8a7118
WIP
vovayatsyuk Sep 16, 2026
434bf24
WIP
vovayatsyuk Sep 16, 2026
3c3f3b1
Add swissup:update command
vovayatsyuk Sep 16, 2026
e4017ca
Array offset cannot be null
vovayatsyuk Sep 18, 2026
e857e37
Remove useless comment
vovayatsyuk Sep 18, 2026
48a0078
Update command descriptions
vovayatsyuk Sep 18, 2026
69fcf13
Use `swissup.extra` params as primary source
vovayatsyuk Sep 18, 2026
1e3a63c
Repo => Channel to match old command
vovayatsyuk Sep 18, 2026
9ffeb44
WIP
vovayatsyuk Sep 18, 2026
553041a
Allow passing package names to swissup:package:update
vovayatsyuk Sep 18, 2026
d6d0174
WIP
vovayatsyuk Sep 18, 2026
42c579c
Copy Marketplace Installer engine
vovayatsyuk Sep 18, 2026
c094016
Installer command
vovayatsyuk Sep 18, 2026
8d38226
Require and then install in one shot
vovayatsyuk Sep 18, 2026
6623443
Use constructor property promotion in installer classes
vovayatsyuk Sep 18, 2026
9e58a3a
Ready for psr/log
vovayatsyuk Sep 18, 2026
2db1054
Keep installer classes in Installer folder
vovayatsyuk Sep 18, 2026
dc009f3
WIP
vovayatsyuk Sep 18, 2026
975f93b
Update deps
vovayatsyuk Sep 18, 2026
f375c19
Use psr/log dependency
vovayatsyuk Sep 18, 2026
cc0b306
Fixed failing ci.swissuplabs tests
vovayatsyuk Sep 18, 2026
9015f97
Cleanup terminal composer output keeping installation info
vovayatsyuk Sep 21, 2026
d6dc01e
WIP
vovayatsyuk Sep 21, 2026
04c1c09
Remove swissup_core_module table, model and collection
vovayatsyuk Sep 21, 2026
c57ea46
Fix outdated urls in comments
vovayatsyuk Sep 21, 2026
5feae95
swissup:auth:check command
vovayatsyuk Sep 21, 2026
f212452
Key components by package name instead of module code
vovayatsyuk Sep 21, 2026
3903135
Rework auth:show and auth:check output
vovayatsyuk Sep 21, 2026
ad254be
Offer to remove duplicate access keys in auth:check
vovayatsyuk Sep 21, 2026
4bd0dea
Update Readme
vovayatsyuk Sep 21, 2026
8d0f803
Explain why the installer re-run passes --no-download
vovayatsyuk Sep 21, 2026
f44d35f
Better actions dropdown
vovayatsyuk Sep 21, 2026
607252b
Address review comments
vovayatsyuk Sep 22, 2026
16207b9
Fixed date attribute creation inside collection command
vovayatsyuk Sep 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 0 additions & 115 deletions Api/Data/ModuleInterface.php

This file was deleted.

56 changes: 56 additions & 0 deletions Console/Command/Installer/AuthAddCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
namespace Swissup\Core\Console\Command\Installer;

use Magento\Framework\Console\Cli;
use Swissup\Core\Model\Installer\ComposerRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class AuthAddCommand extends Command
{
const INPUT_ARGUMENT_KEY = 'key';

public function __construct(private ComposerRepository $repository)
{
parent::__construct();
}

protected function configure()
{
$this->setName('swissup:auth:add')
->setDescription('Add SwissupLabs access key')
->addArgument(self::INPUT_ARGUMENT_KEY, InputArgument::REQUIRED, 'Access key');
parent::configure();
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$key = trim($input->getArgument(self::INPUT_ARGUMENT_KEY));

try {
if (in_array($key, $this->repository->getKeys(), true)) {
$output->writeln('<comment>This key is already added</comment>');
return Cli::RETURN_SUCCESS;
}

$packages = $this->repository->addKey($key);
$output->writeln(sprintf(
'<info>Key accepted. Packages available with this key: %d</info>',
count($packages)
));

if (!$this->repository->isEnabled()) {
$output->writeln(
'<comment>SwissupLabs repository is not enabled. Run bin/magento swissup:channel:enable</comment>'
);
}
} catch (\Exception $e) {
$output->writeln('<error>' . $e->getMessage() . '</error>');
return Cli::RETURN_FAILURE;
}

return Cli::RETURN_SUCCESS;
}
}
140 changes: 140 additions & 0 deletions Console/Command/Installer/AuthCheckCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php
namespace Swissup\Core\Console\Command\Installer;

use Magento\Framework\Console\Cli;
use Swissup\Core\Model\ComponentList\Loader\Remote;
use Swissup\Core\Model\Installer\ComposerRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

class AuthCheckCommand extends Command
{
public function __construct(
private ComposerRepository $repository,
private Remote $remote
) {
parent::__construct();
}

protected function configure()
{
$this->setName('swissup:auth:check')
->setDescription('Display SwissupLabs access keys with the number of packages available');
parent::configure();
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
try {
$keys = $this->repository->getKeys();

if (!$keys) {
$output->writeln('<comment>No access keys found. Run bin/magento swissup:auth:add {key} to add one.</comment>');
return Cli::RETURN_SUCCESS;
}

$username = $this->repository->getUsername();
$latest = $this->remote->getComponentsInfo();
$packages = $this->repository->getPackagesBatch($username, $keys);

$table = new Table($output);
$table->setHeaders(['Username', 'Key', 'Provider', 'Packages']);

foreach ($keys as $i => $key) {
$summary = $packages[$key] instanceof \Exception
? '<error>' . $packages[$key]->getMessage() . '</error>'
: $this->summarize($packages[$key], $latest);

$table->addRow([
$i ? '' : $username,
$key,
$this->repository->getKeyDomain($key) ?: '',
$summary,
]);
}

$table->render();

$this->cleanup($input, $output, $username, $keys);
} catch (\Exception $e) {
$output->writeln('<error>' . $e->getMessage() . '</error>');
return Cli::RETURN_FAILURE;
}

return Cli::RETURN_SUCCESS;
}

/**
* Offer to drop the duplicates from the saved credentials
*
* @param InputInterface $input
* @param OutputInterface $output
* @param string $username
* @param string[] $keys
* @return void
* @throws \RuntimeException
*/
private function cleanup(InputInterface $input, OutputInterface $output, $username, array $keys)
{
$unique = array_unique($keys);
$duplicates = count($keys) - count($unique);

if (!$duplicates) {
return;
}

$question = new ConfirmationQuestion(
sprintf('%d duplicate key(s) found. Remove duplicates? [Y/n] ', $duplicates),
true
);

if (!$this->getHelper('question')->ask($input, $output, $question)) {
return;
}

$this->repository->saveCredentials($username, implode(' ', $unique));
$output->writeln('<info>Duplicate keys were removed</info>');
}

/**
* @param array $packages
* @param array $latest
* @return string
*/
private function summarize(array $packages, array $latest)
{
$outdated = 0;

foreach ($packages as $name => $versions) {
if (empty($latest[$name]['version'])) {
continue;
}

$version = $this->getLatestVersion(array_keys($versions));
if ($version && version_compare($version, $latest[$name]['version'], '<')) {
$outdated++;
}
}

if (!$outdated) {
return (string) count($packages);
}

return sprintf('%d (<comment>%d requires renewal</comment>)', count($packages), $outdated);
}

/**
* @param string[] $versions
* @return string
*/
private function getLatestVersion(array $versions)
{
$versions = array_filter($versions, fn ($version) => strpos($version, 'dev-') !== 0);
usort($versions, 'version_compare');

return (string) end($versions);
}
}
49 changes: 49 additions & 0 deletions Console/Command/Installer/AuthRemoveCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
namespace Swissup\Core\Console\Command\Installer;

use Magento\Framework\Console\Cli;
use Swissup\Core\Model\Installer\ComposerRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class AuthRemoveCommand extends Command
{
const INPUT_ARGUMENT_KEY = 'key';

public function __construct(private ComposerRepository $repository)
{
parent::__construct();
}

protected function configure()
{
$this->setName('swissup:auth:remove')
->setDescription('Remove SwissupLabs access key')
->addArgument(self::INPUT_ARGUMENT_KEY, InputArgument::REQUIRED, 'Access key');
parent::configure();
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$key = trim($input->getArgument(self::INPUT_ARGUMENT_KEY));

try {
if (!$this->repository->removeKey($key)) {
$output->writeln(sprintf(
'<comment>The key is saved in global composer auth.json. Remove it with:%s</comment>',
"\n composer config --global --unset http-basic." . ComposerRepository::HOSTNAME
));
return Cli::RETURN_FAILURE;
}

$output->writeln('<info>The key was removed</info>');
} catch (\Exception $e) {
$output->writeln('<error>' . $e->getMessage() . '</error>');
return Cli::RETURN_FAILURE;
}

return Cli::RETURN_SUCCESS;
}
}
Loading
Loading