feat(pijul-qol:move-to-zero): two new commands, to try make intent-tag discovery easier
Dependencies
- [2]
32ICZXL4init laravel zero for fun - [3]
3JSFZAT5bit of copilot proofreading and editing - [4]
ZHWYHIOHfeat(pijul-qol): have copilot make script to show change messages beside changes, in pijul credit output - [5]
F435FWSFfeat(pijul-qol:move-to-zero): move to laravel zero, why not?
Change contents
- file addition: PijulSearchIntentTagsCommandTest.php[2.1888]
<?phpuse Illuminate\Process\PendingProcess;use Illuminate\Support\Facades\Process;it('searches intent tags using the list command logic and passes through the limit', function () {Process::fake(function (PendingProcess $process) {return match ($process->command) {['pijul', 'log', '--output-format', 'json', '--limit', '50'] => Process::result(json_encode([['message' => 'feat(pijul-qol): first'],['message' => 'feat(pijul-qol:move-to-zero): second'],['message' => 'fix(cli): third'],], JSON_THROW_ON_ERROR)),default => Process::result('', 'Unexpected command.', 1),};});$this->artisan('pijul:search-intent-tags', ['query' => 'zero','--limit' => '50',])->expectsOutput('feat(pijul-qol:move-to-zero)')->assertExitCode(0);Process::assertRanTimes(fn (PendingProcess $process) => $process->command === ['pijul','log','--output-format','json','--limit','50',], 1);});it('can search for an exact tag match', function () {Process::fake(function (PendingProcess $process) {return match ($process->command) {['pijul', 'log', '--output-format', 'json'] => Process::result(json_encode([['message' => 'feat(pijul-qol): first'],['message' => 'feat(pijul-qol:move-to-zero): second'],], JSON_THROW_ON_ERROR)),default => Process::result('', 'Unexpected command.', 1),};});$this->artisan('pijul:search-intent-tags', ['query' => 'feat(pijul-qol)','--exact' => true,])->expectsOutput('feat(pijul-qol)')->assertExitCode(0);}); - replacement in tests/Feature/PijulRecordWithIntentTagsCommandTest.php at line 9
['pijul', 'log', '--limit', '500', '--output-format', 'json'] => Process::result(json_encode([['pijul', 'log', '--output-format', 'json', '--limit', '500'] => Process::result(json_encode([ - replacement in tests/Feature/PijulRecordWithIntentTagsCommandTest.php at line 31
['pijul', 'log', '--limit', '500', '--output-format', 'json'] => Process::result(json_encode([['pijul', 'log', '--output-format', 'json', '--limit', '500'] => Process::result(json_encode([ - replacement in tests/Feature/PijulRecordWithIntentTagsCommandTest.php at line 50
['pijul', 'log', '--limit', '500', '--output-format', 'json'] => Process::result(json_encode([['pijul', 'log', '--output-format', 'json', '--limit', '500'] => Process::result(json_encode([ - file addition: PijulListIntentTagsCommandTest.php[2.1888]
<?phpuse Illuminate\Process\PendingProcess;use Illuminate\Support\Facades\Process;it('lists unique intent tags and respects the limit option', function () {Process::fake(function (PendingProcess $process) {return match ($process->command) {['pijul', 'log', '--output-format', 'json', '--limit', '2'] => Process::result(json_encode([['message' => 'feat(pijul-qol): first'],['message' => 'feat(init): second'],['message' => 'feat(pijul-qol): duplicate'],['message' => 'plain message'],], JSON_THROW_ON_ERROR)),default => Process::result('', 'Unexpected command.', 1),};});$this->artisan('pijul:list-intent-tags', ['--limit' => '2'])->expectsOutput('feat(pijul-qol)')->expectsOutput('feat(init)')->assertExitCode(0);}); - file addition: PijulSearchIntentTagsCommand.php[2.310659]
<?phpnamespace App\Commands;use LaravelZero\Framework\Commands\Command;class PijulSearchIntentTagsCommand extends Command{/*** @var string*/protected $signature = 'pijul:search-intent-tags{query? : Text to search for in intent tags}{--limit= : Number of recent log entries to scan}{--exact : Match the whole tag instead of a substring}{--repository= : Work with the repository at PATH}{--channel= : Work with CHANNEL instead of the current channel}{--no-prompt : Abort rather than prompt for input}';/*** @var string*/protected $description = 'Search intent tags extracted from pijul log messages';/*** @var array<int, string>*/protected $aliases = ['pijul-search-intent-tags'];public function handle(PijulListIntentTagsCommand $listIntentTags): int{$query = trim((string) ($this->argument('query') ?? ''));if ($query === '' && $this->input->isInteractive()) {$query = trim((string) $this->ask('Search query'));}if ($query === '') {$this->error('Please provide a search query.');return self::FAILURE;}$tags = $listIntentTags->resolveTags(limit: $this->option('limit'),repository: $this->option('repository'),channel: $this->option('channel'),noPrompt: (bool) $this->option('no-prompt'),);$matches = array_values(array_filter($tags,fn (string $tag): bool => $this->matchesQuery($tag, $query),));if ($matches === []) {$this->warn('No matching intent tags found.');return self::SUCCESS;}foreach ($matches as $match) {$this->line($match);}return self::SUCCESS;}private function matchesQuery(string $tag, string $query): bool{if ($this->option('exact')) {return strcasecmp($tag, $query) === 0;}return str_contains(strtolower($tag), strtolower($query));}} - edit in app/Commands/PijulRecordWithIntentTagsCommand.php at line 6
use JsonException; - replacement in app/Commands/PijulRecordWithIntentTagsCommand.php at line 44
/*** @throws JsonException*/public function handle(): intpublic function handle(PijulListIntentTagsCommand $listIntentTags): int - replacement in app/Commands/PijulRecordWithIntentTagsCommand.php at line 46
$tags = $this->collectIntentTags();$tags = $listIntentTags->resolveTags(limit: (string) $this->option('tag-limit'),repository: $this->option('repository'),channel: $this->option('channel'),noPrompt: (bool) $this->option('no-prompt'),); - edit in app/Commands/PijulRecordWithIntentTagsCommand.php at line 95
/*** @return list<string>** @throws JsonException*/private function collectIntentTags(): array{$arguments = ['log','--limit',(string) $this->option('tag-limit'),'--output-format','json',]; - edit in app/Commands/PijulRecordWithIntentTagsCommand.php at line 96
foreach (['repository', 'channel'] as $option) {$value = $this->option($option);if ($value !== null) {$arguments[] = sprintf('--%s', $option);$arguments[] = (string) $value;}}if ($this->option('no-prompt')) {$arguments[] = '--no-prompt';}$result = $this->runPijul($arguments);$changes = json_decode($result->output(), true, 512, JSON_THROW_ON_ERROR);$tags = [];foreach ($changes as $change) {$message = $change['message'] ?? null;if (! is_string($message) || preg_match('/^([A-Za-z0-9_-]+\([^)]*\))/', $message, $matches) !== 1) {continue;}$tags[$matches[1]] = true;}return array_keys($tags);} - file addition: PijulListIntentTagsCommand.php[2.310659]
<?phpnamespace App\Commands;use App\Commands\Concerns\InteractsWithPijul;use JsonException;use LaravelZero\Framework\Commands\Command;class PijulListIntentTagsCommand extends Command{use InteractsWithPijul;/*** @var string*/protected $signature = 'pijul:list-intent-tags{--limit= : Number of recent log entries to scan}{--repository= : Work with the repository at PATH}{--channel= : Work with CHANNEL instead of the current channel}{--no-prompt : Abort rather than prompt for input}';/*** @var string*/protected $description = 'List unique intent tags from pijul log messages';/*** @var array<int, string>*/protected $aliases = ['pijul-list-intent-tags'];/*** @throws JsonException*/public function handle(): int{foreach ($this->resolveTags(limit: $this->option('limit'),repository: $this->option('repository'),channel: $this->option('channel'),noPrompt: (bool) $this->option('no-prompt'),) as $tag) {$this->line($tag);}return self::SUCCESS;}/*** @return list<string>** @throws JsonException*/public function resolveTags(?string $limit = null,?string $repository = null,?string $channel = null,bool $noPrompt = false,): array {$arguments = ['log', '--output-format', 'json'];if ($limit !== null && $limit !== '') {$arguments[] = '--limit';$arguments[] = $limit;}if ($repository !== null && $repository !== '') {$arguments[] = '--repository';$arguments[] = $repository;}if ($channel !== null && $channel !== '') {$arguments[] = '--channel';$arguments[] = $channel;}if ($noPrompt) {$arguments[] = '--no-prompt';}$changes = json_decode($this->runPijul($arguments)->output(),true,512,JSON_THROW_ON_ERROR,);$tags = [];foreach ($changes as $change) {$message = $change['message'] ?? null;if (! is_string($message) || preg_match('/^([A-Za-z0-9_-]+\([^)]*\))/', $message, $matches) !== 1) {continue;}$tags[$matches[1]] = true;}return array_keys($tags);}} - edit in README.md at line 32
## Pijul intent tag listing and searchUse `./pijultester pijul:list-intent-tags` to print one unique intent tag per line, which makes it easy to pipe into shell tools.Use `./pijultester pijul:search-intent-tags` for built-in substring search over those tags.Examples: - edit in README.md at line 41
```bash./pijultester pijul:list-intent-tags./pijultester pijul:list-intent-tags --limit=50 | fzf./pijultester pijul:search-intent-tags zero --limit=50./pijultester pijul:search-intent-tags 'feat(pijul-qol)' --exact```