• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / jobs / 24850441053

23 Apr 2026 05:54PM UTC coverage: 52.404% (-1.5%) from 53.938%
24850441053

push

github

daycry
Fixes

104 of 219 new or added lines in 42 files covered. (47.49%)

14 existing lines in 9 files now uncovered.

1210 of 2309 relevant lines covered (52.4%)

4.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Commands/CronJobHistoryCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Queues.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Jobs\Commands;
15

16
use CodeIgniter\CLI\CLI;
17
use Throwable;
18

19
/**
20
 * Displays execution history for a specific cron job with filtering and formatting options.
21
 * Supports table or JSON output and optional payload inclusion.
22
 */
23
class CronJobHistoryCommand extends BaseJobsCommand
24
{
25
    protected $name        = 'jobs:cronjob:history';
26
    protected $description = 'Shows recent execution history for a cron job';
27
    protected $usage       = 'jobs:cronjob:history <jobName> [--limit n] [--status OK|ERROR] [--full] [--json] [--payload] [--extended]';
28
    protected $arguments   = [
29
        'jobName' => 'The job name as defined in the scheduler',
30
    ];
31
    protected $options = [
32
        '--limit'    => 'Maximum number of executions to show (default 5)',
33
        '--status'   => 'Filter by status OK or ERROR',
34
        '--full'     => 'Do not truncate output or error columns',
35
        '--json'     => 'Return raw JSON array instead of table',
36
        '--payload'  => 'Include payload column in table/JSON',
37
        '--extended' => 'Include extra fields (attempt, source, outputLength, payloadHash)',
38
    ];
39

40
    public function run(array $params): int
41
    {
42
        $this->getConfig();
×
43
        if (! $this->isActive()) {
×
44
            $this->tryToEnable();
×
45

NEW
46
            return self::FAILURE;
×
47
        }
48

49
        $jobName = $params[0] ?? null;
×
50
        if (! $jobName) {
×
51
            CLI::error('You must provide a jobName');
×
52
            CLI::write('Usage: ' . $this->usage);
×
53

NEW
54
            return self::FAILURE;
×
55
        }
56

57
        $limit = (int) (CLI::getOption('limit') ?? 5);
×
58
        if ($limit <= 0) {
×
59
            $limit = 5;
×
60
        }
61

62
        $filterStatus = CLI::getOption('status');
×
63
        if ($filterStatus !== null) {
×
64
            $filterStatus = strtoupper($filterStatus);
×
65
            if (! in_array($filterStatus, ['OK', 'ERROR'], true)) {
×
66
                CLI::error('Invalid --status value. Use OK or ERROR');
×
67

NEW
68
                return self::FAILURE;
×
69
            }
70
        }
71

72
        $noTruncate   = CLI::getOption('full') !== null; // presence flag
×
73
        $asJson       = CLI::getOption('json') !== null; // presence flag
×
74
        $showPayload  = CLI::getOption('payload') !== null; // presence flag
×
75
        $extendedMode = CLI::getOption('extended') !== null; // presence flag
×
76

77
        // Manual fallback parsing (useful in unit tests where CLI parser not engaged)
78
        if (! $extendedMode && in_array('--extended', $params, true)) {
×
79
            $extendedMode = true;
×
80
            // Remove the flag from params for cleanliness (doesn't impact further logic)
81
            $params = array_values(array_filter($params, static fn ($p) => $p !== '--extended'));
×
82
            // Re-evaluate jobName if it was first param
83
            $jobName = $params[0] ?? $jobName;
×
84
        }
85
        if (! $asJson && in_array('--json', $params, true)) {
×
86
            $asJson  = true;
×
87
            $params  = array_values(array_filter($params, static fn ($p) => $p !== '--json'));
×
88
            $jobName = $params[0] ?? $jobName;
×
89
        }
90

91
        // Instantiate logging handler like list command
92
        $handler = null;
×
93
        if (isset($this->config->loggers[$this->config->log])) {
×
94
            $class = $this->config->loggers[$this->config->log];
×
95
            if (class_exists($class)) {
×
96
                try {
97
                    $handler = new $class();
×
98
                } catch (Throwable) {
×
99
                    $handler = null;
×
100
                }
101
            }
102
        }
103

104
        if (! $handler || ! method_exists($handler, 'history')) {
×
105
            CLI::error('Logging handler does not support history or is not configured.');
×
106

NEW
107
            return self::FAILURE;
×
108
        }
109

110
        $history = $handler->history($jobName, $limit);
×
111
        if (empty($history)) {
×
112
            CLI::write('No history found for job: ' . $jobName);
×
113

NEW
114
            return self::SUCCESS;
×
115
        }
116

117
        $rows = [];
×
118

119
        foreach ($history as $row) {
×
120
            // Row may be stdClass (file) or entity/object (db) with properties
121
            $start    = $row->start_at ?? null;
×
122
            $end      = $row->end_at ?? null;
×
123
            $duration = $row->duration ?? null;
×
124
            $output   = $row->output ?? null;
×
125
            $error    = $row->error ?? null;
×
126
            $payload  = $row->payload ?? null;
×
127

128
            // Derive status
129
            $status = $error ? 'ERROR' : 'OK';
×
130

131
            // Shorten output & error for table unless --full
132
            $short = static function (?string $text) use ($noTruncate): ?string {
133
                if ($text === null) {
×
134
                    return null;
×
135
                }
136
                $text = trim($text);
×
137
                if ($noTruncate) {
×
138
                    return $text;
×
139
                }
140
                if (strlen($text) > 60) {
×
141
                    return substr($text, 0, 57) . '...';
×
142
                }
143

144
                return $text;
×
145
            };
146

147
            // Apply status filter early to avoid building unnecessary rows
148
            if ($filterStatus !== null && $filterStatus !== $status) {
×
149
                continue;
×
150
            }
151

152
            $rowData = [
×
153
                'start'    => $start,
×
154
                'end'      => $end,
×
155
                'duration' => $duration,
×
156
                'status'   => $status,
×
157
                'output'   => $short($output),
×
158
                'error'    => $short($error),
×
159
            ];
×
160
            if ($showPayload) {
×
NEW
161
                $rowData['payload'] = $noTruncate ? $payload : ($payload && strlen((string) $payload) > 60 ? substr((string) $payload, 0, 57) . '...' : $payload);
×
162
            }
163
            if ($extendedMode) {
×
164
                $rowData['attempt']      = $row->attempt ?? null;
×
165
                $rowData['source']       = $row->source ?? null;
×
166
                $rowData['outputLength'] = $row->outputLength ?? null;
×
167
                $rowData['hash']         = $row->payloadHash ?? null;
×
168
            }
169
            $rows[] = $rowData;
×
170
        }
171

172
        if ($asJson) {
×
173
            // In JSON mode we return raw values (including full hash) when extendedMode
174
            // For non-extended we preserve backward compatibility
175
            CLI::write(json_encode($rows, JSON_PRETTY_PRINT));
×
176

NEW
177
            return self::SUCCESS;
×
178
        }
179

180
        $headers = [
×
181
            'Start',
×
182
            'End',
×
183
            'Duration',
×
184
            'Status',
×
185
            $noTruncate ? 'Output' : 'Output (trimmed)',
×
186
            $noTruncate ? 'Error' : 'Error (trimmed)',
×
187
        ];
×
188
        if ($showPayload) {
×
189
            $headers[] = $noTruncate ? 'Payload' : 'Payload (trimmed)';
×
190
        }
191
        if ($extendedMode) {
×
192
            $headers[] = 'Attempt';
×
193
            $headers[] = 'Source';
×
194
            $headers[] = 'OutputLen';
×
195
            $headers[] = 'Hash';
×
196

197
            // Truncate hash display in table rows
198
            foreach ($rows as &$r) {
×
199
                if (isset($r['hash']) && is_string($r['hash']) && strlen($r['hash']) > 12) {
×
200
                    $r['hash'] = substr($r['hash'], 0, 12) . '…';
×
201
                }
202
            }
203
            unset($r);
×
204
        }
205

206
        CLI::table($rows, $headers);
×
207

NEW
208
        return self::SUCCESS;
×
209
    }
210
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc