diff --git a/.github/issues.json b/.github/issues.json index 9bc53e3..d256d3c 100644 --- a/.github/issues.json +++ b/.github/issues.json @@ -1,7 +1,12 @@ [ { - "title": "Test", - "body": "Testing auto issue creation", - "labels": ["documentation"] + "title": "(refactor): Return types and throwing exceptions", + "body": "Its necessary to update the return types of the use case and its input, as well as to throw exceptions for invalid input. This will improve the robustness and clarity of the code.", + "labels": ["refactor"] + }, + { + "title": "(refactor): Command structure", + "body": "Update the command structure to something more clear and abstract, too many information in one single command can be overwhelming and hard to maintain. Consider breaking it down into smaller, more focused commands or methods.", + "labels": ["refactor"] } ] \ No newline at end of file diff --git a/.github/workflows/auto-issue.yml b/.github/workflows/auto-issue.yml index 9f3c157..dc4a740 100644 --- a/.github/workflows/auto-issue.yml +++ b/.github/workflows/auto-issue.yml @@ -1,21 +1,33 @@ name: Auto Issue Creator on: - schedule: - - cron: '0 9 * * 1' - workflow_dispatch: + push: + branches: + - '**' jobs: create-issues: runs-on: ubuntu-latest + permissions: + issues: write steps: - uses: actions/checkout@v4 - - name: Create Weekly TODO Issues + - name: Auto create issues from .github/issues.json uses: actions/github-script@v7 with: script: | const todos = require('.github/issues.json'); + const existing = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'all' + }); + + const existingTitles = existing.data.map(i => i.title); + for (const todo of todos) { + if (existingTitles.includes(todo.title)) continue; + await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.vscode/settings.json b/.vscode/settings.json index dbafcfb..2e771c2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,7 @@ "cmd": "${workspaceFolder}/vendor/bin/mago format ${file}" } ] - } -} \ No newline at end of file + }, + "terminal.integrated.defaultProfile.linux": "zsh", + "terminal.integrated.shellIntegration.enabled": true +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..73de7f0 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Composer Test", + "type": "shell", + "command": "composer test", + "presentation": { + "reveal": "always", + "panel": "new", + "group": "tests" + }, + "runOptions": { + "runOn": "folderOpen" + } + }, + { + "label": "MAGO Analyse", + "type": "shell", + "command": "mago analyse", + "presentation": { + "reveal": "always", + "panel": "new", + "group": "analysis" + }, + "runOptions": { + "runOn": "folderOpen" + } + } + ] +} \ No newline at end of file diff --git a/obsidian/.obsidian/workspace.json b/obsidian/.obsidian/workspace.json index 152251f..c78aaaa 100644 --- a/obsidian/.obsidian/workspace.json +++ b/obsidian/.obsidian/workspace.json @@ -76,7 +76,8 @@ } ], "direction": "horizontal", - "width": 233.5 + "width": 233.5, + "collapsed": true }, "right": { "id": "7ca2f4f0bbdfa382", @@ -184,15 +185,15 @@ }, "active": "ca2d8013c7331e8e", "lastOpenFiles": [ - "Process.md", - "Idea.md", - "Design.md", - "TODO.md", - "Excalidraw/Overall.md", - "Domain/Characters.md", "Domain/Dice.md", "Domain/Session.md", + "Design.md", + "Idea.md", + "Process.md", + "TODO.md", "Domain/World.md", + "Domain/Characters.md", + "Excalidraw/Overall.md", "Domain/NPC.md", "Excalidraw/Drawing 2026-03-02 14.34.45.excalidraw.md", "Sem título", diff --git a/obsidian/Design.md b/obsidian/Design.md index 0a30f61..fd74e95 100644 --- a/obsidian/Design.md +++ b/obsidian/Design.md @@ -1,8 +1,8 @@ # Purpose Hub of creative creation involving RPG, making easy to create histories and managing parties. ## Anchors +[[Session]] [[Dice]] [[World]] -[[Characters]] -[[NPC]] + diff --git a/obsidian/Domain/Characters.md b/obsidian/Domain/Characters.md deleted file mode 100644 index 21ef479..0000000 --- a/obsidian/Domain/Characters.md +++ /dev/null @@ -1 +0,0 @@ -## Attributess diff --git a/src/Application/UseCase/Dice/RollDice/RollDiceUseCase.php b/src/Application/UseCase/Dice/RollDice/RollDiceUseCase.php index c764789..52e0234 100644 --- a/src/Application/UseCase/Dice/RollDice/RollDiceUseCase.php +++ b/src/Application/UseCase/Dice/RollDice/RollDiceUseCase.php @@ -30,7 +30,7 @@ public function run(RollDiceUseCaseInput $input): Result foreach ($this->generateChunks($multiplier, 250_000) as $chunkSize) { $awaitables[] = Async\run(function () use ($chunkSize, $dice): int { $sum = 0; - for ($i = 0; $i < $chunkSize; $i++) { + for ($i = 0; $i < (int) $chunkSize; $i++) { $sum += RollDiceAction::roll($dice); } return $sum; @@ -73,6 +73,7 @@ public function run(RollDiceUseCaseInput $input): Result } } + /** @return \Generator */ private function generateChunks(int $multiplier, int $chunkSize): \Generator { $remaining = $multiplier; diff --git a/src/Application/UseCase/Session/StartSession/StartSessionUseCase.php b/src/Application/UseCase/Session/StartSession/StartSessionUseCase.php index e6bac22..3fd417b 100644 --- a/src/Application/UseCase/Session/StartSession/StartSessionUseCase.php +++ b/src/Application/UseCase/Session/StartSession/StartSessionUseCase.php @@ -12,7 +12,7 @@ final class StartSessionUseCase { /** - * @return Result + * @return Result */ public function run(StartSessionUseCaseInput $input): Result { @@ -27,8 +27,8 @@ public function run(StartSessionUseCaseInput $input): Result 'Session (' . $resultStartSession->session->identifier->value . ') started successfully.', $resultStartSession, ); - } catch (\Exception $e) { - return Result::error(message: 'Failed to start session: ' . $e->getMessage()); + } catch (\InvalidArgumentException $e) { + return Result::error('Failed to start session' . $e->getMessage()); } } } diff --git a/src/Application/UseCase/Session/StartSession/StartSessionUseCaseInput.php b/src/Application/UseCase/Session/StartSession/StartSessionUseCaseInput.php index e9c5c64..ce20884 100644 --- a/src/Application/UseCase/Session/StartSession/StartSessionUseCaseInput.php +++ b/src/Application/UseCase/Session/StartSession/StartSessionUseCaseInput.php @@ -6,6 +6,10 @@ final class StartSessionUseCaseInput { + /** + * @param string $name The name of the session to be started + * @throws \InvalidArgumentException if the name is empty + */ public function __construct( public string $name, ) { diff --git a/src/Domain/Entities/Session.php b/src/Domain/Entities/Session.php index 033aa3f..d857f91 100644 --- a/src/Domain/Entities/Session.php +++ b/src/Domain/Entities/Session.php @@ -8,6 +8,12 @@ final class Session { + /** + * @param string $name The name of the session + * @param Identifier $identifier The unique identifier for the session + * @param \DateTime $createdAt The date and time when the session was created + * @throws \InvalidArgumentException if the session name is empty + */ public function __construct( public readonly string $name, public readonly Identifier $identifier, diff --git a/src/Domain/ValueObjects/Utils/Result.php b/src/Domain/ValueObjects/Utils/Result.php index e61c9e5..62bafdf 100644 --- a/src/Domain/ValueObjects/Utils/Result.php +++ b/src/Domain/ValueObjects/Utils/Result.php @@ -24,7 +24,7 @@ private function __construct( /** * @template TValue * @param TValue $data - * @return self + * @return self */ public static function success(string $message, mixed $data = null): self { diff --git a/src/Infrastructure/EntryPoints/Console/Dice/RollDiceCommand.php b/src/Infrastructure/EntryPoints/Console/Dice/RollDiceCommand.php index 0ca1098..f47f856 100644 --- a/src/Infrastructure/EntryPoints/Console/Dice/RollDiceCommand.php +++ b/src/Infrastructure/EntryPoints/Console/Dice/RollDiceCommand.php @@ -4,6 +4,7 @@ namespace RPGPlayground\Infrastructure\EntryPoints\Console\Dice; +use Monolog\Level; use RPGPlayground\Application\UseCase\Dice\RollDice\RollDiceUseCase; use RPGPlayground\Application\UseCase\Dice\RollDice\RollDiceUseCaseInput; use RPGPlayground\Domain\ValueObjects\App\Dice; @@ -138,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int padding: true, ); - LogHandler::dispatch('info', 'Rolled dice', [ + LogHandler::dispatch(Level::Info, 'Rolled dice', [ 'dice_params' => $diceParams, 'roll_value' => $resultRollValue->rollValue, ]); @@ -147,7 +148,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } catch (\InvalidArgumentException $e) { $io = new SymfonyStyle($input, $output); $io->error($e->getMessage()); - LogHandler::dispatch('error', 'Roll dice command', ['exception' => $e->getMessage()]); + LogHandler::dispatch(Level::Error, 'Roll dice command', ['exception' => $e->getMessage()]); return Command::FAILURE; } } diff --git a/src/Infrastructure/EntryPoints/Console/Session/StartSessionCommand.php b/src/Infrastructure/EntryPoints/Console/Session/StartSessionCommand.php index c6d49a0..f037548 100644 --- a/src/Infrastructure/EntryPoints/Console/Session/StartSessionCommand.php +++ b/src/Infrastructure/EntryPoints/Console/Session/StartSessionCommand.php @@ -4,6 +4,7 @@ namespace RPGPlayground\Infrastructure\EntryPoints\Console\Session; +use Monolog\Level; use RPGPlayground\Application\UseCase\Session\StartSession\StartSessionUseCase; use RPGPlayground\Application\UseCase\Session\StartSession\StartSessionUseCaseInput; use RPGPlayground\Infrastructure\Handler\LogHandler; @@ -71,6 +72,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $resultStartSession = $useCase->run(new StartSessionUseCaseInput(name: $name)); + if (!isset($resultStartSession)) { + $io->error('An unexpected error occurred while starting the session.'); + LogHandler::dispatch(Level::Error, 'Start session command', ['error' => 'Result is null']); + return Command::FAILURE; + } + if ($resultStartSession->isError()) { $io->error($resultStartSession->getMessage()); return Command::FAILURE; @@ -78,8 +85,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $resultStartSession = $resultStartSession->getData(); - if (!$resultStartSession) { + if (!isset($resultStartSession)) { $io->error('An unexpected error occurred while starting the session.'); + LogHandler::dispatch(Level::Error, 'Start session command', ['error' => 'Result data is null']); return Command::FAILURE; } @@ -96,14 +104,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int padding: true, ); - LogHandler::dispatch('info', 'Started session', [ + LogHandler::dispatch(Level::Info, 'Started session', [ 'session_id' => $resultStartSession->session->identifier->value, ]); return Command::SUCCESS; } catch (\InvalidArgumentException $e) { $io = new SymfonyStyle($input, $output); $io->error($e->getMessage()); - LogHandler::dispatch('error', 'Start session command', ['exception' => $e->getMessage()]); + LogHandler::dispatch(Level::Error, 'Start session command', ['exception' => $e->getMessage()]); return Command::FAILURE; } } diff --git a/src/Infrastructure/Handler/LogHandler.php b/src/Infrastructure/Handler/LogHandler.php index aabe024..2ad2679 100644 --- a/src/Infrastructure/Handler/LogHandler.php +++ b/src/Infrastructure/Handler/LogHandler.php @@ -5,24 +5,45 @@ namespace RPGPlayground\Infrastructure\Handler; use Monolog\Handler\StreamHandler; +use Monolog\Level; use Monolog\Logger; final class LogHandler { private static ?Logger $instance = null; + /** + * Bind a logger instance to the LogHandler. + * @param Logger $logger The logger instance to bind + * @return void + */ public static function bind(Logger $logger): void { self::$instance = $logger; } + /** + * Add a log handler to the logger instance. + * @param StreamHandler $streamHandler The log handler to add + * @return void + */ public static function stream(StreamHandler $streamHandler): void { self::$instance?->pushHandler($streamHandler); } - public static function dispatch(string $level, string $message, array $context = []): void + /** + * @param Level $level The log level (e.g., Level::Error, Level::Info) + * @param string $message The log message + * @param array $context Additional context for the log entry + */ + public static function dispatch(Level $level, string $message, array $context = []): void { - self::$instance?->log($level, $message, $context); + try { + self::$instance?->log($level, $message, $context); + } catch (\Throwable $e) { + // Handle logging errors gracefully, e.g., by writing to a fallback log file + error_log('Logging error: ' . $e->getMessage()); + } } }