fix(commands): surface core fetch errors, run post-install in the project, exit 1 on invalid project command; document compat flow
This commit is contained in:
+22
-8
@@ -233,6 +233,19 @@ Nunca bloquea: se confirma con =--yes=. Al core se le sigue la pista por sus
|
|||||||
tags semver (=vX.Y.Z=, empezando por =v0.1.0=); si no hay tags, la versión es
|
tags semver (=vX.Y.Z=, empezando por =v0.1.0=); si no hay tags, la versión es
|
||||||
desconocida y se fija por commit.
|
desconocida y se fija por commit.
|
||||||
|
|
||||||
|
Los valores =tested= de los manifiestos no son decorativos: los escribe sólo
|
||||||
|
quien corrió el *barrido de compatibilidad* (=make compat=), que monta un
|
||||||
|
proyecto temporal por paquete contra el core real publicado y lo ejercita por
|
||||||
|
HTTP (migraciones sobre sqlite, runner phpunit real; los clientes con servicio
|
||||||
|
externo — =aria2=, =proxy=, =compreFace= — sólo a nivel de carga/instantiación,
|
||||||
|
consignado así en =tests/compat/report.json=). Cualquier
|
||||||
|
=Deprecated=/=Warning=/=Notice= durante el barrido cuenta como fallo.
|
||||||
|
Un test de la suite (=group11=) exige que cada =tested= declarado tenga su =ok=
|
||||||
|
en ese reporte y que no se estampen componentes deliberadamente sin datos
|
||||||
|
(=commands:cli=/=commands:toolbox=, que son el instalador y no consumen el
|
||||||
|
core). Al aparecer un tag nuevo del core, el ritual es: =make compat= → arreglar
|
||||||
|
lo que falle → estampar → =make release=.
|
||||||
|
|
||||||
* Versionado y releases
|
* Versionado y releases
|
||||||
|
|
||||||
Hay *dos* sistemas de versión y no hay que confundirlos:
|
Hay *dos* sistemas de versión y no hay que confundirlos:
|
||||||
@@ -265,14 +278,15 @@ Hay *dos* sistemas de versión y no hay que confundirlos:
|
|||||||
|
|
||||||
=make help= lista los objetivos:
|
=make help= lista los objetivos:
|
||||||
|
|
||||||
| Objetivo | Qué hace |
|
| Objetivo | Qué hace |
|
||||||
|---------------+------------------------------------------------------------|
|
|--------------+-------------------------------------------------------------------------------------------|
|
||||||
| =make test= | Corre la suite (=php tests/run.php=). En verde antes de commitear. |
|
| =make test= | Corre la suite (=php tests/run.php=). En verde antes de commitear. |
|
||||||
| =make build= | Genera =dist/duckbrain.phar= + =dist/duckbrain.phar.sha256=. |
|
| =make build= | Genera =dist/duckbrain.phar= + =dist/duckbrain.phar.sha256=. |
|
||||||
| =make release= | Asistente interactivo de releases de paquetes (=ARGS="pkg minor --yes"= para modo directo). |
|
| =make compat= | Barrido de compatibilidad contra el core real (=scripts/compat-sweep=); requiere red. =ARGS="--only pkg"= para un paquete. |
|
||||||
| =make publish= | =build= + publica la release =v$(Config::VERSION)= con los assets. Requiere =FORGEJO_TOKEN=. |
|
| =make release= | Asistente interactivo de releases de paquetes (=ARGS="pkg minor --yes"= para modo directo). |
|
||||||
| =make check= | =self-update --check= contra el servidor: =actual/disponible=, exit 1 si hay nuevo. |
|
| =make publish= | =build= + publica la release =v$(Config::VERSION)= con los assets. Requiere =FORGEJO_TOKEN=. |
|
||||||
| =make clean= | Borra =dist/=. |
|
| =make check= | =self-update --check= contra el servidor: =actual/disponible=, exit 1 si hay nuevo. |
|
||||||
|
| =make clean= | Borra =dist/=. |
|
||||||
|
|
||||||
El token para publicar es un token personal de la API de Forgejo
|
El token para publicar es un token personal de la API de Forgejo
|
||||||
(*Ajustes → Aplicaciones*, scope =write:repository=, con caducidad y revocable).
|
(*Ajustes → Aplicaciones*, scope =write:repository=, con caducidad y revocable).
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ if ($command === null || in_array($command, $toolboxCommands, true)) {
|
|||||||
$coreCommand = 'Commands\\' . ucfirst($command);
|
$coreCommand = 'Commands\\' . ucfirst($command);
|
||||||
|
|
||||||
if (!class_exists($coreCommand) && !file_exists(ROOT_CORE . '/Commands/' . ucfirst($command) . '.php')) {
|
if (!class_exists($coreCommand) && !file_exists(ROOT_CORE . '/Commands/' . ucfirst($command) . '.php')) {
|
||||||
exit("Invalid command.\n");
|
fwrite(STDERR, "Invalid command.\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cli = new $coreCommand();
|
$cli = new $coreCommand();
|
||||||
@@ -36,5 +37,6 @@ $cli = new $coreCommand();
|
|||||||
if ($cli instanceof Interfaces\CommandInterface) {
|
if ($cli instanceof Interfaces\CommandInterface) {
|
||||||
call_user_func_array([$cli, 'run'], array_slice($argv, 2));
|
call_user_func_array([$cli, 'run'], array_slice($argv, 2));
|
||||||
} else {
|
} else {
|
||||||
exit("Invalid command.\n");
|
fwrite(STDERR, "La clase $coreCommand no implementa CommandInterface.\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,35 @@
|
|||||||
{
|
{
|
||||||
"name": "commands",
|
"name": "commands",
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"description": "CLI y migraciones para Duckbrain",
|
"description": "CLI y migraciones para Duckbrain",
|
||||||
"components": {
|
"components": {
|
||||||
"cli": {
|
"cli": {
|
||||||
"files": [
|
"files": [
|
||||||
"duckbrain",
|
"duckbrain",
|
||||||
"src/Interfaces/CommandInterface.php"
|
"src/Interfaces/CommandInterface.php"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"migration": {
|
|
||||||
"files": [
|
|
||||||
"src/Commands/Migration.php",
|
|
||||||
"src/Libs/Migration.php"
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"commands:cli": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"toolbox": {
|
|
||||||
"files": [
|
|
||||||
"src/Toolbox"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"default": [
|
"migration": {
|
||||||
"cli",
|
"files": [
|
||||||
"migration"
|
"src/Commands/Migration.php",
|
||||||
]
|
"src/Libs/Migration.php"
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"commands:cli": "*"
|
||||||
|
},
|
||||||
|
"core": {
|
||||||
|
"requires": ">=0.1",
|
||||||
|
"tested": "0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"toolbox": {
|
||||||
|
"files": [
|
||||||
|
"src/Toolbox"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": [
|
||||||
|
"cli",
|
||||||
|
"migration"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ final class CoreProvider
|
|||||||
throw new ToolboxException('No se pudo clonar el core: ' . implode("\n", $out));
|
throw new ToolboxException('No se pudo clonar el core: ' . implode("\n", $out));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
exec('git -C ' . escapeshellarg($dir) . ' fetch -q --tags 2>&1');
|
exec('git -C ' . escapeshellarg($dir) . ' remote set-url origin ' . escapeshellarg($url) . ' 2>&1');
|
||||||
|
$out = [];
|
||||||
|
exec('git -C ' . escapeshellarg($dir) . ' fetch -q --tags 2>&1', $out, $code);
|
||||||
|
if ($code !== 0) {
|
||||||
|
throw new ToolboxException('No se pudo actualizar el core: ' . implode("\n", $out));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$provider = new self($dir);
|
$provider = new self($dir);
|
||||||
|
|||||||
@@ -191,7 +191,8 @@ final class Installer
|
|||||||
$manifest->postInstall,
|
$manifest->postInstall,
|
||||||
$this->console,
|
$this->console,
|
||||||
(bool) ($options['yes'] ?? false),
|
(bool) ($options['yes'] ?? false),
|
||||||
$options['postRunner'] ?? null
|
$options['postRunner'] ?? null,
|
||||||
|
$this->root,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,35 +11,51 @@ final class PostInstall
|
|||||||
/**
|
/**
|
||||||
* @param list<string> $commands
|
* @param list<string> $commands
|
||||||
* @param callable(string):int|null $runner
|
* @param callable(string):int|null $runner
|
||||||
|
* @param string|null $cwd Directorio de trabajo del proyecto: los
|
||||||
|
* comandos se ejecutan alli, no donde arranco
|
||||||
|
* el instalador.
|
||||||
* @return list<string> comandos ejecutados
|
* @return list<string> comandos ejecutados
|
||||||
*/
|
*/
|
||||||
public static function run(
|
public static function run(
|
||||||
array $commands,
|
array $commands,
|
||||||
Console $console,
|
Console $console,
|
||||||
bool $assumeYes = false,
|
bool $assumeYes = false,
|
||||||
?callable $runner = null
|
?callable $runner = null,
|
||||||
|
?string $cwd = null
|
||||||
): array {
|
): array {
|
||||||
$executed = [];
|
$executed = [];
|
||||||
|
$previous = null;
|
||||||
|
|
||||||
foreach ($commands as $command) {
|
if ($cwd !== null && is_dir($cwd)) {
|
||||||
$console->out(' post-install: ' . $command);
|
$previous = getcwd();
|
||||||
|
chdir($cwd);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$console->confirm(' ¿Ejecutar?', $assumeYes)) {
|
try {
|
||||||
$console->warn('post-install omitido: ' . $command);
|
foreach ($commands as $command) {
|
||||||
|
$console->out(' post-install: ' . $command);
|
||||||
|
|
||||||
continue;
|
if (!$console->confirm(' ¿Ejecutar?', $assumeYes)) {
|
||||||
}
|
$console->warn('post-install omitido: ' . $command);
|
||||||
|
|
||||||
if ($runner !== null) {
|
continue;
|
||||||
$runner($command);
|
|
||||||
} else {
|
|
||||||
passthru($command, $code);
|
|
||||||
if (($code ?? 0) !== 0) {
|
|
||||||
throw new ToolboxException("post-install falló: {$command}");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$executed[] = $command;
|
if ($runner !== null) {
|
||||||
|
$runner($command);
|
||||||
|
} else {
|
||||||
|
passthru($command, $code);
|
||||||
|
if (($code ?? 0) !== 0) {
|
||||||
|
throw new ToolboxException("post-install falló: {$command}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$executed[] = $command;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if ($previous !== null) {
|
||||||
|
chdir($previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $executed;
|
return $executed;
|
||||||
|
|||||||
Reference in New Issue
Block a user