def test_get_release_pr_no_pulls(): """If there is no release PR, an exception should be raised""" with pytest.raises(Exception) as ex, patch( 'lib.requests.get', return_value=Mock(json=Mock(return_value=FAKE_PULLS))): get_release_pr('org', 'repo', 'version') assert ex.value.args[0] == "No release pull request on server"
def test_too_many_releases(): """If there is no release PR, an exception should be raised""" pulls = [RELEASE_PR, RELEASE_PR] with pytest.raises(Exception) as ex, patch( 'lib.requests.get', return_value=Mock(json=Mock(return_value=pulls))): get_release_pr('org', 'repo', '0.53.3') assert ex.value.args[0] == "Too many release pull requests"
def test_no_release_wrong_repo(): """If there is no repo accessible, an exception should be raised""" response_404 = Response() response_404.status_code = 404 with pytest.raises(HTTPError) as ex, patch('github.requests.get', return_value=response_404): get_release_pr('access_token', 'org', 'repo') assert ex.value.response.status_code == 404
def test_too_many_releases(): """If there is no release PR, an exception should be raised""" pulls = [RELEASE_PR, RELEASE_PR] with pytest.raises(Exception) as ex, patch( 'github.requests.get', return_value=Mock(json=Mock(return_value=pulls))): get_release_pr('access_token', 'org', 'repo') assert ex.value.args[ 0] == "More than one pull request for the branch release-candidate"
async def release_command(self, command_args): """ Start a new release and wait for deployment Args: command_args (CommandArgs): The arguments for this command """ repo_info = command_args.repo_info version = command_args.args[0] repo_url = repo_info.repo_url channel_id = repo_info.channel_id org, repo = get_org_and_repo(repo_url) pr = get_release_pr(self.github_access_token, org, repo) if pr: raise ReleaseException( "A release is already in progress: {}".format(pr.url)) release( github_access_token=self.github_access_token, repo_url=repo_url, new_version=version, ) await self.say( channel_id=channel_id, text= "Behold, my new evil scheme - release {version} for {project}! Now deploying to RC..." .format( version=version, project=repo_info.name, ), ) await wait_for_deploy( github_access_token=self.github_access_token, repo_url=repo_url, hash_url=repo_info.rc_hash_url, watch_branch="release-candidate", ) unchecked_authors = get_unchecked_authors(self.github_access_token, org, repo) slack_usernames = self.translate_slack_usernames(unchecked_authors) pr = get_release_pr(self.github_access_token, org, repo) await self.say( channel_id=channel_id, text= "Release {version} for {project} was deployed! PR is up at {pr_url}." " These people have commits in this release: {authors}".format( version=version, authors=", ".join(slack_usernames), pr_url=pr.url, project=repo_info.name, )) await self.wait_for_checkboxes(repo_info, command_args.manager) command_args.loop.create_task(self.delay_message(repo_info))
async def wait_for_checkboxes(self, repo_info, manager): """ Poll the Release PR and wait until all checkboxes are checked off Args: repo_info (RepoInfo): Information for a repo manager (str): User id for the release manager """ channel_id = repo_info.channel_id await self.say( channel_id=channel_id, text= "Wait, wait. Time out. My evil plan for {project} isn't evil enough " "until all the checkboxes are checked...".format( project=repo_info.name, )) org, repo = get_org_and_repo(repo_info.repo_url) await wait_for_checkboxes(self.github_access_token, org, repo) pr = get_release_pr(self.github_access_token, org, repo) await self.say( channel_id=channel_id, text= "All checkboxes checked off. Release {version} is ready for the Merginator {name}!" .format(name=format_user_id(manager), version=pr.version), attachments=[{ "fallback": "Finish the release", "callback_id": FINISH_RELEASE_ID, "actions": [{ "name": "finish_release", "text": "Finish the release", "type": "button", }] }])
async def do_release(self, repo_info, version): """ Start a new release and wait for deployment Args: repo_info (RepoInfo): Information for a repo version (str): The version """ repo_url = repo_info.repo_url channel_id = repo_info.channel_id release(repo_url, version) await self.say( channel_id, "Behold, my new evil scheme - release {}! Now deploying to RC...". format(version)) await wait_for_deploy(repo_url, repo_info.rc_hash_url, "release-candidate") org, repo = get_org_and_repo(repo_url) unchecked_authors = get_unchecked_authors(org, repo, version) slack_usernames = self.translate_slack_usernames(unchecked_authors) await self.say( channel_id, "Release {version} was deployed! PR is up at <{pr_url}|Release {version}>." " These people have commits in this release: {authors}".format( version=version, authors=", ".join(slack_usernames), pr_url=get_release_pr(org, repo, version)['html_url'], ))
def test_get_release_pr_no_pulls(): """If there is no release PR it should return None""" with patch( 'github.requests.get', return_value=Mock(json=Mock(return_value=[OTHER_PR])) ): assert get_release_pr( github_access_token='access_token', org='org', repo='repo-missing', ) is None
async def _web_application_release(self, command_args): """Do a web application release""" repo_info = command_args.repo_info version = command_args.args[0] repo_url = repo_info.repo_url channel_id = repo_info.channel_id org, repo = get_org_and_repo(repo_url) release( github_access_token=self.github_access_token, repo_url=repo_url, new_version=version, ) await self.say( channel_id=channel_id, text="Behold, my new evil scheme - release {version} for {project}! Now deploying to RC...".format( version=version, project=repo_info.name, ), ) await wait_for_deploy( github_access_token=self.github_access_token, repo_url=repo_url, hash_url=repo_info.rc_hash_url, watch_branch="release-candidate", ) unchecked_authors = get_unchecked_authors( github_access_token=self.github_access_token, org=org, repo=repo, ) slack_usernames = self.translate_slack_usernames(unchecked_authors) pr = get_release_pr( github_access_token=self.github_access_token, org=org, repo=repo, ) await self.say( channel_id=channel_id, text="Release {version} for {project} was deployed! PR is up at {pr_url}." " These people have commits in this release: {authors}".format( version=version, authors=", ".join(slack_usernames), pr_url=pr.url, project=repo_info.name, ) ) await self.wait_for_checkboxes(repo_info, command_args.manager) command_args.loop.create_task(self.delay_message(repo_info))
async def finish_release(self, command_args): """ Merge the release candidate into the release branch, tag it, merge to master, and wait for deployment Args: command_args (CommandArgs): The arguments for this command """ repo_info = command_args.repo_info channel_id = repo_info.channel_id repo_url = repo_info.repo_url org, repo = get_org_and_repo(repo_url) pr = get_release_pr( github_access_token=self.github_access_token, org=org, repo=repo, ) if not pr: raise ReleaseException("No release currently in progress for {project}".format(project=repo_info.name)) version = pr.version finish_release( github_access_token=self.github_access_token, repo_url=repo_url, version=version, timezone=self.timezone ) await self.say( channel_id=channel_id, text="Merged evil scheme {version} for {project}! Now deploying to production...".format( version=version, project=repo_info.name, ), ) await wait_for_deploy( github_access_token=self.github_access_token, repo_url=repo_url, hash_url=repo_info.prod_hash_url, watch_branch="release", ) await self.say( channel_id=channel_id, text="My evil scheme {version} for {project} has been released to production. " "And by 'released', I mean completely...um...leased.".format( version=version, project=repo_info.name, ) )
def test_get_release_pr(): """get_release_pr should grab a release from GitHub's API""" org = 'org' repo = 'repo' version = '0.53.3' with patch( 'lib.requests.get', return_value=Mock(json=Mock(return_value=FAKE_PULLS))) as get_mock: pulls = get_release_pr(org, repo, version) get_mock.assert_called_once_with( "https://api.github.com/repos/{org}/{repo}/pulls".format( org=org, repo=repo, )) assert pulls == RELEASE_PR
def test_get_release_pr(): """get_release_pr should grab a release from GitHub's API""" org = 'org' repo = 'repo' access_token = 'access' with patch('github.requests.get', return_value=Mock(json=Mock(return_value=FAKE_PULLS))) as get_mock: pr = get_release_pr( github_access_token=access_token, org=org, repo=repo, ) get_mock.assert_called_once_with("https://api.github.com/repos/{org}/{repo}/pulls".format( org=org, repo=repo, ), headers=github_auth_headers(access_token)) assert pr.body == RELEASE_PR['body'] assert pr.url == RELEASE_PR['html_url'] assert pr.version == '0.53.3'
async def release_command(self, command_args): """ Start a new release and wait for deployment Args: command_args (CommandArgs): The arguments for this command """ repo_info = command_args.repo_info repo_url = repo_info.repo_url org, repo = get_org_and_repo(repo_url) pr = get_release_pr( github_access_token=self.github_access_token, org=org, repo=repo, ) if pr: raise ReleaseException("A release is already in progress: {}".format(pr.url)) if repo_info.project_type == LIBRARY_TYPE: await self._library_release(command_args) elif repo_info.project_type == WEB_APPLICATION_TYPE: await self._web_application_release(command_args) else: raise Exception("Configuration error: unknown project type {}".format(repo_info.project_type))