global$config; #!/usr/bin/env php $jiraUrl, 'headers' => [ 'Authorization' => 'Bearer ' . $apiToken, 'Accept' => 'application/json', ], ]); foreach ($teams as $team => $teamData) { echo "Расчет для команды {$team}\n"; $filename = "{$team}_tasks_{$startDate}_to_{$endDate}.csv"; // --- 3. Подготовка JQL-запроса --- // Запрос ищет задачи, у которых статус изменился на "Done" в указанный период. $jql = "project in (".$teamData['projects'].") AND issuetype in standardIssueTypes() AND issuetype not in (Epic, \"Admin work\") AND resolutiondate > \"{$startDate}\" AND resolutiondate < \"{$endDate}\""; $params = [ 'jql' => $jql, 'maxResults' => $maxResults, 'fields' => 'issuetype,key,summary,assignee,resolution,aggregatetimeoriginalestimate,aggregateprogress,resolutiondate', ]; try { // --- 4. Обработка пагинации --- // Если задач больше, чем maxResults, Jira вернет только часть. // Мы будем запрашивать страницы до тех пор, пока не получим все. $allIssues = []; $startAt = 0; $totalFetched = 0; do { $response = $client->get('rest/api/2/search', [ 'query' => $params + ['startAt' => $startAt] ]); $data = json_decode($response->getBody(), true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("Ошибка декодирования JSON-ответа от Jira."); } $issues = $data['issues'] ?? []; $allIssues = array_merge($allIssues, $issues); // Обновляем счетчики для следующей итерации $totalFetched += count($issues); $startAt += count($issues); echo "Получено задач: {$totalFetched} из {$data['total']}\n"; } while ($startAt < ($data['total'] ?? 0)); if (!empty($allIssues)) { // Убираем дубликаты, там где изменения не требуются $allIssues = filterByResolution($allIssues); // Убираем задачи, исполнители на которых не исполнители $allIssues = filterByExecutors($allIssues, array_keys($teamData['executors'])); //file_put_contents($filename.".json", json_encode($allIssues, JSON_PRETTY_PRINT));die(); echo "Убрали лишнее, осталось ".count($allIssues)."\n"; $task = null; foreach ($allIssues as $i => $issue) { $statuses = getStatusForIssue($issue['key'], $client); //$allIssues[$i]['countStatuses'] = $statuses; $firstDateInStatus = array_map(function($value) { return is_array($value) && count($value) > 1 ? $value[1] : null; }, $statuses); $countStatus = array_map(function($value) { return is_array($value) && count($value) > 1 ? $value[0] : null; }, $statuses); $task = new \Nechaev\Reports\Task( $issue["fields"]["issuetype"]["name"], $issue['key'], $issue["fields"]["summary"], $issue["fields"]["assignee"]["name"], $issue["fields"]["aggregatetimeoriginalestimate"], $issue["fields"]["aggregateprogress"]["progress"], StatusHelper::getDataByStatus($firstDateInStatus, StatusHelper::getInWorkStatuses()), $issue["fields"]["resolutiondate"], StatusHelper::getDataByStatus($countStatus, StatusHelper::getInReviewStatuses()), StatusHelper::getDataByStatus($countStatus, StatusHelper::getInTestingStatuses()), ); file_put_contents($filename, $task, FILE_APPEND | LOCK_EX); } // --- 5. Сохранение в файл --- echo "Данные успешно сохранены в файл: {$filename}\n"; } else { echo "За указанный период завершенных задач не найдено.\n"; } } catch (GuzzleException | Exception $e) { echo "Ошибка: " . $e->getMessage() . "\n"; } }