Skip to content
This repository has been archived by the owner on Jun 23, 2020. It is now read-only.

Commit

Permalink
Create a release after uploading (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
brettcannon authored Apr 5, 2020
1 parent 9fd4968 commit 52460ac
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 82 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,3 @@ Finally, when everything is live, create a release on GitHub to both tag the rel

#### TODO
- [Upload release artifacts](https://developer.github.com/v3/repos/releases/#upload-a-release-asset)
- Customization of the release name?
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ inputs:
runs:
using: 'docker'
image: 'Dockerfile'
args: ['--changelog-path', '${{ inputs.changelog-path }}', '--pypi-token', '${{ inputs.pypi-token }}']
args: ['--changelog-path', '${{ inputs.changelog-path }}', '--pypi-token', '${{ inputs.pypi-token }}', '--github-token', '${{ inputs.github-token }}']
290 changes: 231 additions & 59 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ license = "MIT"

[tool.poetry.dependencies]
python = "^3.8"
gidgethub = "^4.0"

gidgethub = "^4.0" # Really want 'gidgethub[httpx]', but Poetry doesn't support extras.
httpx = ">=0.12.1"
packaging = "^20.3"
pep517 = "^0.8.1"
tomlkit = "^0.5.11"
trio = "^0.13.0"
twine = "^3.1.1"

[tool.poetry.dev-dependencies]
Expand Down
62 changes: 42 additions & 20 deletions release_often/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,43 @@
import subprocess
import sys

from gidgethub import actions
import gidgethub.actions
import gidgethub.httpx
import httpx
import pep517.envbuild
import trio

from . import changelog
from . import release
from . import version


def error(message):
actions.command("error", message)
actions.actions.command("error", message)
sys.exit(1)


def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--changelog-path", dest="changelog_path")
parser.add_argument("--pypi-token", dest="pypi_token")
parser.add_argument("--github-token", dest="github_token")
return parser.parse_args()


def update_version():
build_tool, version_file = version.find_details(actions.workspace())
build_tool, version_file = version.find_details(gidgethub.actions.workspace())
if build_tool is None:
error("build tool not detected; unable to update version")
else:
tool_name = build_tool.__name__.rpartition(".")[-1]
actions.command("debug", f"Build tool is {tool_name}")
actions.command("debug", f"Version found in {version_file}")
gidgethub.actions.command("debug", f"Build tool is {tool_name}")
gidgethub.actions.command("debug", f"Version found in {version_file}")
file_contents = version_file.read_text(encoding="utf-8")
current_version = build_tool.read_version(file_contents)
actions.command("debug", f"Current/old version is {current_version}")
new_version = version.bump_by_label(actions.event(), current_version)
actions.command("debug", f"New version is {new_version}")
gidgethub.actions.command("debug", f"Current/old version is {current_version}")
new_version = version.bump_by_label(gidgethub.actions.event(), current_version)
gidgethub.actions.command("debug", f"New version is {new_version}")
new_contents = build_tool.change_version(
file_contents, current_version, new_version
)
Expand All @@ -46,30 +51,30 @@ def update_version():
def update_changelog(path, new_version):
if not path.exists():
error(f"The path to the changelog does not exist: {path}")
actions.command("debug", f"Changelog file path is {path}")
new_entry = changelog.entry(path.suffix, new_version, actions.event())
gidgethub.actions.command("debug", f"Changelog file path is {path}")
new_entry = changelog.entry(path.suffix, new_version, gidgethub.actions.event())
current_changelog = path.read_text(encoding="utf-8")
path.write_text(new_entry + current_changelog, encoding="utf-8")


def build():
source_dir = actions.workspace()
source_dir = gidgethub.actions.workspace()
output_dir = source_dir / "dist"
actions.command("debug", f"Writing build artifacts to {output_dir}")
gidgethub.actions.command("debug", f"Writing build artifacts to {output_dir}")
for builder in (pep517.envbuild.build_sdist, pep517.envbuild.build_wheel):
builder(source_dir, output_dir)
# https://github.com/python-poetry/poetry/issues/769
check_result = subprocess.run(["twine", "check", f"{output_dir}/*"])
if check_result.returncode:
actions.command("warning", "`twine check` had a non-zero exit code")
gidgethub.actions.command("warning", "`twine check` had a non-zero exit code")
return output_dir


GIT = "/usr/bin/git"


def commit(new_version):
os.chdir(actions.workspace())
os.chdir(gidgethub.actions.workspace())
subprocess.run(
[GIT, "config", "--local", "user.email", "action@github.com"], check=True,
)
Expand All @@ -89,20 +94,37 @@ def upload(output_dir, pypi_token):
)


async def make_release(releases_url, version, changelog_entry, *, oauth_token):
async with gidgethub.httpx.AsyncClient() as client:
gh = gidgethub.httpx.GitHubAPI(
client, "brettcannon/release_often", oauth_token=oauth_token
)
return await release.create(gh, releases_url, version, changelog_entry)


def create_release(version, changelog_entry, *, oauth_token):
event = gidgethub.actions.event()
releases_url = event["pull_request"]["repository"]["releases_url"]
return trio.run(
make_release, releases_url, version, changelog_entry, oauth_token=oauth_token
)


if __name__ == "__main__":
args = parse_args()
new_version = update_version()
if new_version is None:
actions.command("debug", "No version update requested")
gidgethub.actions.command("debug", "No version update requested")
sys.exit()
changelog_entry = update_changelog(pathlib.Path(args.changelog_path), new_version)
output_dir = build()
commit(new_version)
if args.pypi_token != "-":
upload(output_dir, args.pypi_token)
else:
actions.command("debug", "PyPI uploading skipped; no API token provided")
# XXX Create a release on GitHub
# https://developer.github.com/v3/repos/releases/
# release(new_version, changelog_entry, output_dir)
pass
gidgethub.actions.command(
"debug", "PyPI uploading skipped; no API token provided"
)
upload_url = create_release(
new_version, changelog_entry, oauth_token=args.github_token
)
12 changes: 12 additions & 0 deletions release_often/release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
async def create(gh, releases_url, version, body):
# https://developer.github.com/v3/repos/releases/#create-a-release
details = {"tag_name": f"v{version}", "body": body}
result = await gh.post(releases_url, data=details)
return result["upload_url"]


async def add_artifact(gh, artifact_path):
# XXX https://developer.github.com/v3/repos/releases/#upload-a-release-asset
# XXX Requires changes to gidgethub for content-type upload
# XXX application/gzip, application/zip
...
41 changes: 41 additions & 0 deletions tests/data/create_release.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"url": "https://api.github.com/repos/octocat/Hello-World/releases/1",
"html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0",
"assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets",
"upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
"tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0",
"zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0",
"id": 1,
"node_id": "MDc6UmVsZWFzZTE=",
"tag_name": "v1.0.0",
"target_commitish": "master",
"name": "v1.0.0",
"body": "Description of the release",
"draft": false,
"prerelease": false,
"created_at": "2013-02-27T19:35:32Z",
"published_at": "2013-02-27T19:35:32Z",
"author": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"assets": [

]
}
33 changes: 33 additions & 0 deletions tests/test_release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import json

import trio

from release_often import release
from . import data


class MockGitHubAPI:
def __init__(self, to_return):
self.to_return = to_return

async def post(self, url, *, data):
self.url = url
self.data = data
return self.to_return


def test_create(data_path):
webhook_event_path = data_path / "create_release.json"
release_payload = webhook_event_path.read_text(encoding="utf-8")
to_return = json.loads(release_payload)
releases_url = "https://url/to/create/release"
mock_gh = MockGitHubAPI(to_return)
version = "1.2.3"
body = "body of things"
result = trio.run(release.create, mock_gh, releases_url, version, body)
assert (
result
== "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}"
)
assert mock_gh.url == releases_url
assert mock_gh.data == {"tag_name": "v1.2.3", "body": body}

0 comments on commit 52460ac

Please sign in to comment.