From 1adcac8383d87d1d6f02d12ed793ffe297684a4d Mon Sep 17 00:00:00 2001 From: brendt Date: Wed, 21 Jan 2026 13:02:02 +0100 Subject: [PATCH 1/5] wip --- app/TempestReleaseCommand.php | 17 +++++++++++++++++ app/TempestSubsplitCommand.php | 17 +++++++++++++++++ composer.json | 1 + tempest | 7 +++---- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 app/TempestReleaseCommand.php create mode 100644 app/TempestSubsplitCommand.php diff --git a/app/TempestReleaseCommand.php b/app/TempestReleaseCommand.php new file mode 100644 index 000000000..2c172d2f1 --- /dev/null +++ b/app/TempestReleaseCommand.php @@ -0,0 +1,17 @@ +info('Todo'); + } +} \ No newline at end of file diff --git a/app/TempestSubsplitCommand.php b/app/TempestSubsplitCommand.php new file mode 100644 index 000000000..e97fe35dd --- /dev/null +++ b/app/TempestSubsplitCommand.php @@ -0,0 +1,17 @@ +info('Todo'); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 70449dbeb..482128c50 100644 --- a/composer.json +++ b/composer.json @@ -202,6 +202,7 @@ }, "autoload-dev": { "psr-4": { + "App\\": "app/", "Tempest\\Auth\\Tests\\": "packages/auth/tests", "Tempest\\Cache\\Tests\\": "packages/cache/tests", "Tempest\\Clock\\Tests\\": "packages/clock/tests", diff --git a/tempest b/tempest index 8fac46cc1..7da332190 100755 --- a/tempest +++ b/tempest @@ -7,8 +7,7 @@ use Tempest\Discovery\DiscoveryLocation; require_once getcwd() . '/vendor/autoload.php'; ConsoleApplication::boot(discoveryLocations: [ - new DiscoveryLocation('Tests\\Tempest\\Fixtures\\', getcwd() . '/tests/Fixtures/'), - new DiscoveryLocation('Tests\\Tempest\\Integration\\Console\\Fixtures', getcwd() . '/tests/Integration/Console/Fixtures'), +// new DiscoveryLocation('Tests\\Tempest\\Fixtures\\', getcwd() . '/tests/Fixtures/'), +// new DiscoveryLocation('Tests\\Tempest\\Integration\\Console\\Fixtures', getcwd() . '/tests/Integration/Console/Fixtures'), + new DiscoveryLocation('App', __DIR__ . '/app/'), ])->run(); - -exit; From 0e63edfa02a22992864a8482ebaf45692d30ab8b Mon Sep 17 00:00:00 2001 From: brendt Date: Wed, 21 Jan 2026 13:03:39 +0100 Subject: [PATCH 2/5] wip --- app/TempestReleaseCommand.php | 2 ++ app/TempestSubsplitCommand.php | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/app/TempestReleaseCommand.php b/app/TempestReleaseCommand.php index 2c172d2f1..b337ff62f 100644 --- a/app/TempestReleaseCommand.php +++ b/app/TempestReleaseCommand.php @@ -12,6 +12,8 @@ final class TempestReleaseCommand #[ConsoleCommand] public function __invoke(): void { + // Move all logic of the `bin/release` script into here + $this->info('Todo'); } } \ No newline at end of file diff --git a/app/TempestSubsplitCommand.php b/app/TempestSubsplitCommand.php index e97fe35dd..2271c37a2 100644 --- a/app/TempestSubsplitCommand.php +++ b/app/TempestSubsplitCommand.php @@ -12,6 +12,14 @@ final class TempestSubsplitCommand #[ConsoleCommand] public function __invoke(): void { + // Similarly to the release command, write all subsplit logic here + $this->info('Todo'); + + // 1. Copy each package to some kind of "dist" folder + // 2. Init their git repo if it doesn't exist yet + // 3. Do checks on composer versions etc + // 4. Replace dependency versions + // 5. Commit and push to each repo } } \ No newline at end of file From ad9292f149da275e593d119d30cc9379c7b03357 Mon Sep 17 00:00:00 2001 From: brendt Date: Wed, 21 Jan 2026 14:49:00 +0100 Subject: [PATCH 3/5] wip --- app/Git/FakeGitClient.php | 54 ++++++++++ app/Git/Git.php | 22 ++++ app/Git/GitClient.php | 101 ++++++++++++++++++ app/Git/GitOperationFailed.php | 10 ++ app/Subsplit/Package.php | 41 +++++++ app/Subsplit/TempestSubsplitCommand.php | 90 ++++++++++++++++ app/TempestSubsplitCommand.php | 25 ----- packages/container/src/AutowireDiscovery.php | 10 +- packages/container/src/GenericContainer.php | 6 +- .../App/TempestSubsplitCommandTest.php | 17 +++ .../FrameworkIntegrationTestCase.php | 1 + 11 files changed, 345 insertions(+), 32 deletions(-) create mode 100644 app/Git/FakeGitClient.php create mode 100644 app/Git/Git.php create mode 100644 app/Git/GitClient.php create mode 100644 app/Git/GitOperationFailed.php create mode 100644 app/Subsplit/Package.php create mode 100644 app/Subsplit/TempestSubsplitCommand.php delete mode 100644 app/TempestSubsplitCommand.php create mode 100644 tests/Integration/App/TempestSubsplitCommandTest.php diff --git a/app/Git/FakeGitClient.php b/app/Git/FakeGitClient.php new file mode 100644 index 000000000..08b7d0357 --- /dev/null +++ b/app/Git/FakeGitClient.php @@ -0,0 +1,54 @@ +commands[] = 'git init'; + } + + public function checkoutBranch(string $branch): void + { + $this->branch = $branch; + $this->commands[] = 'git checkout -b ' . $branch; + } + + public function pull(): void + { + $this->commands[] = 'git pull origin ' . $this->getCurrentBranch(); + } + + public function push(): void + { + $this->commands[] = 'git push origin ' . $this->getCurrentBranch(); + } + + public function getCurrentBranch(): string + { + return 'test'; + } + + public function status(): string + { + return ''; + } + + public function commit(string $message): void + { + $this->commands[] = 'git add . && git commit -m "' . $message . '"'; + } +} \ No newline at end of file diff --git a/app/Git/Git.php b/app/Git/Git.php new file mode 100644 index 000000000..8175cfe8d --- /dev/null +++ b/app/Git/Git.php @@ -0,0 +1,22 @@ +path . '/.git/')); + } + + public function tryInit(string $remote): void + { + if ($this->isInitialized()) { + return; + } + + exec("cd {$this->path}; git init && git remote add origin {$remote};", result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to initialize git repository.'); + } + } + + public function checkoutBranch(string $branch): void + { + exec("cd {$this->path}; git checkout -b {$branch} &> /dev/null", result_code: $result); + + if ($result === 0) { + return; + } + + exec("cd {$this->path}; git checkout &> {$branch}", result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to checkout branch.'); + } + } + + public function pull(): void + { + exec("cd {$this->path}; git pull origin {$this->getCurrentBranch()} &> /dev/null", result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to pull changes from remote.'); + } + } + + public function push(): void + { + exec("cd {$this->path}; git push origin {$this->getCurrentBranch()} &> /dev/null", result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to push changes to remote.'); + } + } + + public function getCurrentBranch(): string + { + exec("cd {$this->path}; git branch --show-current", output: $output, result_code: $result); + + if ($result !== 0 || $output === []) { + throw new GitOperationFailed('Failed get current branch.'); + } + + return $output[0]; + } + + public function status(): string + { + exec("cd {$this->path}; git status" , output: $output, result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to get git status.'); + } + + return implode(PHP_EOL, $output); + } + + public function commit(string $message): void + { + if (str_contains($this->status(), 'nothing to commit')) { + return; + } + + exec("cd {$this->path}; git add . && git commit -m \"{$message}\"" , result_code: $result); + + if ($result !== 0) { + throw new GitOperationFailed('Failed to commit changes.'); + } + } +} \ No newline at end of file diff --git a/app/Git/GitOperationFailed.php b/app/Git/GitOperationFailed.php new file mode 100644 index 000000000..99a3d8136 --- /dev/null +++ b/app/Git/GitOperationFailed.php @@ -0,0 +1,10 @@ + "git@github.com:tempestphp/tempest-{$this->name}.git"; + } + + public string $buildPath { + get => __DIR__ . '/../../build/packages/' . $this->name . '/'; + } + + public string $sourcePath { + get => __DIR__ . '/../../packages/' . $this->name . '/'; + } + + /** @return ImmutableArray */ + public static function all(): ImmutableArray + { + return arr(glob(__DIR__ . '/../../packages/*')) + ->map(fn (string $path) => self::fromPath($path)); + } + + public static function fromPath(string $path): self + { + return new self( + path: $path, + name: pathinfo($path, PATHINFO_FILENAME), + ); + } +} \ No newline at end of file diff --git a/app/Subsplit/TempestSubsplitCommand.php b/app/Subsplit/TempestSubsplitCommand.php new file mode 100644 index 000000000..1a6a0b257 --- /dev/null +++ b/app/Subsplit/TempestSubsplitCommand.php @@ -0,0 +1,90 @@ +container->get(Git::class, path: root_path())); + + + $packages = Package::all(); + + if ($package) { + $packages = $packages->filter(fn (Package $search) => $search->name === $package)->values(); + } + + if ($packages->isEmpty()) { + $this->error('No packages found'); + return; + } + + $total = $packages->count(); + + $currentBranch = $this->container->get(Git::class, path: root_path())->getCurrentBranch(); + ld($currentBranch); + + $this->confirm("Subsplitting on `{$currentBranch}`, continue?"); + + foreach ($packages as $i => $package) { + $this->info("{$i}/{$total} tempest/{$package->name}"); + + try { + $git = new GitClient($package->buildPath); + + Filesystem\ensure_directory_exists($package->buildPath); + + if ( ! $git->isInitialized()) { + $git->tryInit($package->remote); + $this->writeln(' - New remote initialized'); + } + + $this->writeln(" - Checking out {$currentBranch} branch"); + $git->checkoutBranch($currentBranch); + + $this->writeln(' - Pulling latest changes'); + + try { + $git->pull(); + } catch (GitOperationFailed) { + // Remote branch does not exist yet + } + + // Don't we have a recursive directory copy function somewhere?? + exec("cp -R {$package->sourcePath} {$package->buildPath}"); + $this->writeln(" - Copied updated contents from {$package->sourcePath} to {$package->buildPath}"); + + // TODO: Validate composer, LICENSE, README, and what else? + + $this->writeln(" - Committing changes"); + $git->commit("chore: subsplit"); + + $this->writeln(" - Pushing changes"); + $git->push(); + + $this->success('Done'); + } catch (GitOperationFailed $e) { + $this->error($e->getMessage()); + continue; + } + } + } +} \ No newline at end of file diff --git a/app/TempestSubsplitCommand.php b/app/TempestSubsplitCommand.php deleted file mode 100644 index 2271c37a2..000000000 --- a/app/TempestSubsplitCommand.php +++ /dev/null @@ -1,25 +0,0 @@ -info('Todo'); - - // 1. Copy each package to some kind of "dist" folder - // 2. Init their git repo if it doesn't exist yet - // 3. Do checks on composer versions etc - // 4. Replace dependency versions - // 5. Commit and push to each repo - } -} \ No newline at end of file diff --git a/packages/container/src/AutowireDiscovery.php b/packages/container/src/AutowireDiscovery.php index efdf7dedc..ee57b42b7 100644 --- a/packages/container/src/AutowireDiscovery.php +++ b/packages/container/src/AutowireDiscovery.php @@ -28,13 +28,13 @@ public function discover(DiscoveryLocation $location, ClassReflector $class): vo return; } - $this->discoveryItems->add($location, [$class, $autowire]); + $this->discoveryItems->add($location, [$class, $autowire, $class->getAttribute(Singleton::class)]); } public function apply(): void { - foreach ($this->discoveryItems as [$class, $autowire]) { - if ($autowire !== null) { + foreach ($this->discoveryItems as [$class, $autowire, $singleton]) { + if ($singleton !== null) { $this->discoverAsSingleton($class); } else { $this->discoverAsDefinition($class); @@ -49,7 +49,7 @@ private function discoverAsSingleton(ClassReflector $class): void foreach ($interfaces as $interface) { $this->container->singleton( $interface, - static fn (Container $container) => $container->get($class->getName()), + static fn (Container $container, mixed ...$params) => $container->get($class->getName(), ...$params), ); } } @@ -61,7 +61,7 @@ private function discoverAsDefinition(ClassReflector $class): void foreach ($interfaces as $interface) { $this->container->register( $interface, - static fn (Container $container) => $container->get($class->getName()), + static fn (Container $container, mixed ...$params) => $container->get($class->getName(), ...$params), ); } } diff --git a/packages/container/src/GenericContainer.php b/packages/container/src/GenericContainer.php index 2483f0640..11c6eaa9d 100644 --- a/packages/container/src/GenericContainer.php +++ b/packages/container/src/GenericContainer.php @@ -341,7 +341,8 @@ private function resolveDependency(string $className, null|string|UnitEnum $tag // Check if the class has been registered as a singleton. if ($instance = $this->singletons[$dependencyName] ?? null) { if ($instance instanceof Closure) { - $instance = $instance($this); + // TODO: test + $instance = $instance($this, ...$params); $this->singletons[$className] = $instance; } @@ -354,7 +355,8 @@ private function resolveDependency(string $className, null|string|UnitEnum $tag if ($definition = $this->definitions[$dependencyName] ?? null) { $this->resolveChain()->add(new FunctionReflector($definition)); - return $definition($this); + // TODO: test + return $definition($this, ...$params); } // Next we check if any of our default initializers can initialize this class. diff --git a/tests/Integration/App/TempestSubsplitCommandTest.php b/tests/Integration/App/TempestSubsplitCommandTest.php new file mode 100644 index 000000000..270888992 --- /dev/null +++ b/tests/Integration/App/TempestSubsplitCommandTest.php @@ -0,0 +1,17 @@ +console + ->call('tempest:subsplit') + ->assertSuccess(); + } +} \ No newline at end of file diff --git a/tests/Integration/FrameworkIntegrationTestCase.php b/tests/Integration/FrameworkIntegrationTestCase.php index 87ce6e656..0f6f72c8f 100644 --- a/tests/Integration/FrameworkIntegrationTestCase.php +++ b/tests/Integration/FrameworkIntegrationTestCase.php @@ -21,6 +21,7 @@ protected function discoverTestLocations(): array return [ new DiscoveryLocation('Tests\\Tempest\\Integration\\Console\\Fixtures', __DIR__ . '/Console/Fixtures'), new DiscoveryLocation('Tests\\Tempest\\Fixtures', __DIR__ . '/../Fixtures'), + new DiscoveryLocation('App\\', __DIR__ . '/../../app'), ]; } From 571225bf0ef4de587295437f307717cd66f61f22 Mon Sep 17 00:00:00 2001 From: brendt Date: Wed, 21 Jan 2026 14:50:15 +0100 Subject: [PATCH 4/5] wip --- app/Git/{FakeGitClient.php => FakeGit.php} | 2 +- app/Git/{GitClient.php => GenericGit.php} | 2 +- app/Subsplit/TempestSubsplitCommand.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename app/Git/{FakeGitClient.php => FakeGit.php} (96%) rename app/Git/{GitClient.php => GenericGit.php} (98%) diff --git a/app/Git/FakeGitClient.php b/app/Git/FakeGit.php similarity index 96% rename from app/Git/FakeGitClient.php rename to app/Git/FakeGit.php index 08b7d0357..648528f9c 100644 --- a/app/Git/FakeGitClient.php +++ b/app/Git/FakeGit.php @@ -2,7 +2,7 @@ namespace App\Git; -final class FakeGitClient implements Git +final class FakeGit implements Git { public array $commands = []; private string $branch = 'test'; diff --git a/app/Git/GitClient.php b/app/Git/GenericGit.php similarity index 98% rename from app/Git/GitClient.php rename to app/Git/GenericGit.php index 23ebdbd59..47c8a4973 100644 --- a/app/Git/GitClient.php +++ b/app/Git/GenericGit.php @@ -7,7 +7,7 @@ use Tempest\Support\Filesystem; #[Autowire] -final readonly class GitClient implements Git +final readonly class GenericGit implements Git { public function __construct( private string $path, diff --git a/app/Subsplit/TempestSubsplitCommand.php b/app/Subsplit/TempestSubsplitCommand.php index 1a6a0b257..013fefc75 100644 --- a/app/Subsplit/TempestSubsplitCommand.php +++ b/app/Subsplit/TempestSubsplitCommand.php @@ -9,7 +9,7 @@ use Tempest\Console\Middleware\ForceMiddleware; use Tempest\Container\Container; use Tempest\Support\Filesystem; -use App\Git\GitClient; +use App\Git\GenericGit; use function Tempest\root_path; final class TempestSubsplitCommand @@ -48,7 +48,7 @@ public function __invoke(?string $package = null): void $this->info("{$i}/{$total} tempest/{$package->name}"); try { - $git = new GitClient($package->buildPath); + $git = new GenericGit($package->buildPath); Filesystem\ensure_directory_exists($package->buildPath); From 5528b22e18115d5be16c252b0621b94d489c9b9f Mon Sep 17 00:00:00 2001 From: brendt Date: Wed, 21 Jan 2026 14:51:12 +0100 Subject: [PATCH 5/5] wip --- app/Subsplit/TempestSubsplitCommand.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/Subsplit/TempestSubsplitCommand.php b/app/Subsplit/TempestSubsplitCommand.php index 013fefc75..2007a11c9 100644 --- a/app/Subsplit/TempestSubsplitCommand.php +++ b/app/Subsplit/TempestSubsplitCommand.php @@ -23,9 +23,6 @@ public function __construct( #[ConsoleCommand(middleware: [ForceMiddleware::class])] public function __invoke(?string $package = null): void { - ld($this->container->get(Git::class, path: root_path())); - - $packages = Package::all(); if ($package) { @@ -40,7 +37,6 @@ public function __invoke(?string $package = null): void $total = $packages->count(); $currentBranch = $this->container->get(Git::class, path: root_path())->getCurrentBranch(); - ld($currentBranch); $this->confirm("Subsplitting on `{$currentBranch}`, continue?"); @@ -48,7 +44,7 @@ public function __invoke(?string $package = null): void $this->info("{$i}/{$total} tempest/{$package->name}"); try { - $git = new GenericGit($package->buildPath); + $git = $this->container->get(Git::class, path: $package->buildPath); Filesystem\ensure_directory_exists($package->buildPath);