Check the release pull request before release

[MAILPOET-2004]
This commit is contained in:
Pavel Dohnal
2019-05-23 14:32:00 +02:00
committed by M. Shull
parent b47484ee3c
commit 32a739eba5
2 changed files with 85 additions and 0 deletions

View File

@ -613,6 +613,9 @@ class RoboFile extends \Robo\Tasks {
public function releasePublish($version = null) {
$version = $this->releaseVersionGetNext($version);
return $this->collectionBuilder()
->addCode(function () use ($version) {
return $this->releaseCheckPullRequest($version);
})
->addCode(function () {
return $this->releaseDownloadZip();
})
@ -640,6 +643,11 @@ class RoboFile extends \Robo\Tasks {
->run();
}
public function releaseCheckPullRequest($version) {
$this->createGitHubController()
->checkReleasePullRequestPassed($version);
}
public function releaseVersionGetNext($version = null) {
if (!$version) {
$version = $this->getReleaseVersionController()

View File

@ -22,6 +22,9 @@ class GitHubController {
/** @var HttpClient */
private $http_client;
/** @var HttpClient */
private $http_client_no_base;
public function __construct($username, $token, $project) {
$this->zip_filename = $project === self::PROJECT_MAILPOET ? self::FREE_ZIP_FILENAME : self::PREMIUM_ZIP_FILENAME;
$github_path = $project === self::PROJECT_MAILPOET ? 'mailpoet' : 'mailpoet-premium';
@ -32,6 +35,12 @@ class GitHubController {
],
'base_uri' => "https://api.github.com/repos/mailpoet/$github_path/",
]);
$this->http_client_no_base = new Client([
'auth' => [$username, $token],
'headers' => [
'Accept' => 'application/vnd.github.v3+json',
],
]);
}
public function createReleasePullRequest($version) {
@ -59,6 +68,74 @@ class GitHubController {
]);
}
public function checkReleasePullRequestPassed($version) {
$response = $this->http_client->get('pulls', [
'query' => [
'state' => 'all',
'head' => self::RELEASE_SOURCE_BRANCH,
'base' => 'master',
'direction' => 'desc',
]
]);
$response = json_decode($response->getBody()->getContents(), true);
if (sizeof($response) === 0) {
throw new \Exception('Failed to load release pull requests');
}
$response = array_filter($response, function ($pull_request) use ($version) {
return strpos($pull_request['title'], 'Release ' . $version) !== false;
});
if (sizeof($response) === 0) {
throw new \Exception('Release pull request not found');
}
$release_pull_request = reset($response);
if ($release_pull_request['state'] !== 'closed') {
throw new \Exception('Release pull request is still opened.');
}
if (!$release_pull_request['merged']) {
throw new \Exception('Release pull request has not been merged.');
}
$this->checkPullRequestChecks($release_pull_request['statuses_url']);
$pull_request_number = $release_pull_request['number'];
$this->checkPullRequestReviews($pull_request_number);
}
private function checkPullRequestChecks($statuses_url) {
$response = $this->http_client_no_base->get($statuses_url);
$response = json_decode($response->getBody()->getContents(), true);
// Find checks. Statuses are returned in reverse chronological order. We need to get the first of each type
$latest_statuses = [];
foreach ($response as $status) {
if (!isset($latest_statuses[$status['context']])) {
$latest_statuses[$status['context']] = $status;
}
}
$failed = [];
foreach ($latest_statuses as $status) {
if ($status['state'] !== 'success') {
$failed[] = $status['context'];
}
}
if (!empty($failed)) {
throw new \Exception('Release pull request build failed. Failed jobs: ' . join(', ', $failed));
}
}
private function checkPullRequestReviews($pull_request_number) {
$response = $this->http_client->get("pulls/$pull_request_number/reviews");
$response = json_decode($response->getBody()->getContents(), true);
$approved = 0;
foreach ($response as $review) {
if (strtolower($review['state']) === 'approved') {
$approved++;
}
}
if ($approved === 0) {
throw new \Exception('Pull Request has not been approved');
}
}
public function publishRelease($version, $changelog, $release_zip_path) {
$this->ensureNoDraftReleaseExists();
$this->ensureReleaseDoesNotExistYet($version);