Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 8 additions & 3 deletions .github/issues.json
Original file line number Diff line number Diff line change
@@ -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"]
}
]
20 changes: 16 additions & 4 deletions .github/workflows/auto-issue.yml
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@
"cmd": "${workspaceFolder}/vendor/bin/mago format ${file}"
}
]
}
}
},
"terminal.integrated.defaultProfile.linux": "zsh",
"terminal.integrated.shellIntegration.enabled": true
}
31 changes: 31 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
]
}
15 changes: 8 additions & 7 deletions obsidian/.obsidian/workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
}
],
"direction": "horizontal",
"width": 233.5
"width": 233.5,
"collapsed": true
},
"right": {
"id": "7ca2f4f0bbdfa382",
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions obsidian/Design.md
Original file line number Diff line number Diff line change
@@ -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]]


1 change: 0 additions & 1 deletion obsidian/Domain/Characters.md

This file was deleted.

3 changes: 2 additions & 1 deletion src/Application/UseCase/Dice/RollDice/RollDiceUseCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -73,6 +73,7 @@ public function run(RollDiceUseCaseInput $input): Result
}
}

/** @return \Generator<int, int, never, void> */
private function generateChunks(int $multiplier, int $chunkSize): \Generator
{
$remaining = $multiplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
final class StartSessionUseCase
{
/**
* @return Result<StartSessionUseCaseOutput>
* @return Result<StartSessionUseCaseOutput|null>
*/
public function run(StartSessionUseCaseInput $input): Result
{
Expand All @@ -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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
Expand Down
6 changes: 6 additions & 0 deletions src/Domain/Entities/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/Domain/ValueObjects/Utils/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private function __construct(
/**
* @template TValue
* @param TValue $data
* @return self<TValue|null>
* @return self<TValue>
*/
public static function success(string $message, mixed $data = null): self
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
]);
Expand All @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -71,15 +72,22 @@ 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;
}

$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;
}

Expand All @@ -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;
}
}
Expand Down
25 changes: 23 additions & 2 deletions src/Infrastructure/Handler/LogHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, mixed> $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());
}
}
}