/** * {@inheritdoc} */ public function request($method, $uri, $body, $headers = [], array $options = []) { $this->log->begin("{$method} {$uri}"); try { $response = parent::request($method, $uri, $body, $headers, $options); } catch (\Exception $ex) { $this->log->endError($ex->getCode()); throw $ex; } $this->log->endHttpStatus($response->getStatusCode()); return $response; }
public function syncMilestones($state = 'open', $autoClose = false) { $this->log->begin("Synchronizing milestones from {$this->fromRepo} to {$this->toRepo}"); $fromMilestones = $this->getMilestones($this->getFromRepo(), $state); $toMilestones = $this->getMilestones($this->getToRepo(), 'all'); // Add the new milestones. $addMilestones = array_udiff($fromMilestones, $toMilestones, function ($from, $to) use($toMilestones) { $titleDiff = strcasecmp($to['title'], $from['title']); $title1 = $from['title']; $title2 = $to['title']; if ($titleDiff === 0 || empty($to['due_on']) || empty($from['due_on'])) { return $titleDiff; } // Milestones due on the same day are considered the same if there isn't another milestone of the same name. if ($to['due_on'] === $from['due_on'] && !array_key_exists(strtolower($from['title']), $toMilestones)) { return 0; } return $titleDiff; }); foreach ($addMilestones as $milestone) { $this->log->begin("Add {$milestone['title']}"); $r = $this->api()->post("/repos/{$this->toRepo}/milestones", ['title' => $milestone['title'], 'description' => $milestone['description'], 'due_on' => $milestone['due_on']]); $this->log->endHttpStatus($r->getStatusCode(), true); } // Update the existing milestones. $updateMilestones = array_uintersect($toMilestones, $fromMilestones, function ($to, $from) use($toMilestones) { $toTitle = strtolower($to['title']); $fromTitle = strtolower($from['title']); $titleDiff = strcmp($toTitle, $fromTitle); if ($toTitle === $fromTitle || empty($to['due_on']) || empty($from['due_on'])) { return $titleDiff; } elseif ($to['due_on'] === $from['due_on'] && !array_key_exists($fromTitle, $toMilestones)) { // The milestone has the same date and there isn't another one with the same name. return 0; } else { return $titleDiff; } }); $updateMilestones = array_filter($updateMilestones, function ($to) use($fromMilestones) { if (array_key_exists(strtolower($to['title']), $fromMilestones)) { $from = $fromMilestones[strtolower($to['title'])]; } else { $from = $this->findMilestone($to, $fromMilestones); } if (!$from) { // Something is wrong with our code. throw new \Exception("Oops. Something went wrong.", 500); } if ($from['title'] !== $to['title'] || $from['description'] !== $to['description'] || $from['due_on'] !== $to['due_on']) { return true; } return false; }); foreach ($updateMilestones as $milestone) { $from = $this->findMilestone($milestone, $fromMilestones); if (empty($from)) { throw new \Exception("Oops. Something went wrong.", 500); } $this->log->begin("Update {$milestone['title']}"); $r = $this->api()->patch("/repos/{$this->toRepo}/milestones/{$milestone['number']}", ['title' => $from['title'], 'description' => $from['description'], 'due_on' => $from['due_on']]); $this->log->endHttpStatus($r->getStatusCode(), true); } // Check for auto-closing milestones. if ($autoClose) { foreach ($toMilestones as $milestone) { if ($milestone['state'] !== 'open' || $milestone['open_issues'] > 0 || empty($milestone['due_on'])) { continue; } $dueOn = new \DateTime($milestone['due_on']); $diff = $dueOn->diff(new \DateTime()); if ($diff->days > 0 && $diff->invert === 0) { $this->log->begin("Close {$milestone['title']}"); // The milestone is overdue and complete and can be closed. $r = $this->api()->patch("/repos/{$this->toRepo}/milestones/{$milestone['number']}", ['state' => 'closed']); $this->log->endHttpStatus($r->getStatusCode(), true); } } } $this->log->end('Done'); }