Skip to content

Commit 3bb0ed0

Browse files
committed
Added script to automatically copy files from PyPI to GitHub Releases.
1 parent c0accc9 commit 3bb0ed0

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

.ci/copy_pypi_2_github.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# stdlib
2+
import json
3+
import pathlib
4+
import sys
5+
import tempfile
6+
import urllib.parse
7+
import os
8+
9+
# 3rd party
10+
import github
11+
import requests
12+
13+
14+
def get_pypi_releases(project_name):
15+
16+
pypi_releases = {}
17+
18+
# Parse PyPI data
19+
r = requests.get(f"https://pypi.org/pypi/{project_name}/json")
20+
if r.status_code != 200:
21+
print(f"Unable to get package data from PyPI for '{project_name}'", file=sys.stderr)
22+
23+
else:
24+
pkg_info = json.loads(r.content)
25+
26+
for release, release_data in pkg_info["releases"].items():
27+
release_urls = []
28+
for file in release_data:
29+
release_urls.append(file["url"])
30+
pypi_releases[release] = release_urls
31+
32+
return pypi_releases
33+
34+
35+
def update_github_release(repo, tag_name, release_name, release_message):
36+
current_assets = []
37+
38+
try:
39+
release = repo.get_release(tag_name)
40+
41+
# Update existing release
42+
release.update_release(name=release_name, message=release_message)
43+
44+
# Get list of current assets for release
45+
for asset in release.get_assets():
46+
current_assets.append(asset.name)
47+
48+
except github.UnknownObjectException:
49+
50+
# Create the release
51+
release = repo.create_git_release(tag=tag_name, name=release_name, message=release_message)
52+
53+
return release, current_assets
54+
55+
56+
def get_file_from_pypi(url, tmpdir):
57+
filename = pathlib.PosixPath(urllib.parse.urlparse(url).path).name
58+
59+
r = requests.get(url)
60+
if r.status_code != 200:
61+
print(f"Unable to download '{filename}' from PyPI. Skipping.", file=sys.stderr)
62+
return False
63+
64+
(tmpdir / filename).write_bytes(r.content)
65+
66+
return True
67+
68+
69+
def copy_pypi_2_github(g, repo_name, github_username, *, release_message='', pypi_name=None):
70+
repo_name = str(repo_name)
71+
github_username = str(github_username)
72+
73+
if not pypi_name:
74+
pypi_name = repo_name
75+
pypi_name = str(pypi_name)
76+
77+
pypi_releases = get_pypi_releases(pypi_name)
78+
79+
repo = g.get_repo(f"{github_username}/{repo_name}")
80+
print(repo.name)
81+
82+
with tempfile.TemporaryDirectory() as tmpdir:
83+
tmpdir = pathlib.Path(tmpdir)
84+
85+
for tag in repo.get_tags():
86+
version = tag.name.lstrip("v")
87+
if version not in pypi_releases:
88+
sys.stdout.flush()
89+
print(f"No PyPI release found for tag '{tag.name}'. Skipping.", file=sys.stderr)
90+
sys.stderr.flush()
91+
continue
92+
93+
print(f"Processing release for {version}")
94+
release_name = f"Version {version}"
95+
release_message += f"""
96+
Automatically copied from PyPI.
97+
https://pypi.org/project/{pypi_name}/{version}
98+
"""
99+
100+
release, current_assets = update_github_release(repo, tag.name, release_name, release_message)
101+
102+
# pprint(pypi_releases[version])
103+
# Copy the files from PyPI
104+
105+
for pypi_url in pypi_releases[version]:
106+
filename = pathlib.PosixPath(urllib.parse.urlparse(pypi_url).path).name
107+
# print(filename)
108+
109+
if filename in current_assets:
110+
sys.stdout.flush()
111+
print(f"File '{filename}' already exists for release '{tag.name}'. Skipping.", file=sys.stderr)
112+
sys.stderr.flush()
113+
continue
114+
115+
if get_file_from_pypi(pypi_url, tmpdir):
116+
print(f"Copying {filename} from PyPi to GitHub Releases")
117+
release.upload_asset(str(tmpdir / filename))
118+
else:
119+
continue
120+
121+
122+
if __name__ == '__main__':
123+
gh_token = os.environ.get("GITHUB_TOKEN")
124+
if not gh_token:
125+
sys.stdout.flush()
126+
print("Please supply a GitHub token via the environment variable `GITHUB_TOKEN`.", file=sys.stderr)
127+
sys.stderr.flush()
128+
sys.exit(1)
129+
130+
g = github.Github(gh_token)
131+
132+
rate = g.get_rate_limit()
133+
remaining_requests = rate.core.remaining
134+
print(rate)
135+
136+
github_username = "domdfcoding"
137+
138+
copy_pypi_2_github(g, "domdf_python_tools", "", pypi_name="domdf_python_tools")
139+
140+
rate = g.get_rate_limit()
141+
used_requests = remaining_requests - rate.core.remaining
142+
print(f"Used {used_requests} requests. {rate.core.remaining} remaining. Resets at {rate.core.reset}")

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ install:
1212
- sudo apt-get update
1313

1414
- pip install rst2txt yolk3k
15+
- pip install PyGithub requests
1516
- pip install coveralls tox tox-travis
1617
- wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
1718
- bash miniconda.sh -b -p $HOME/miniconda
@@ -27,6 +28,7 @@ stages:
2728
- test
2829
- deploy_pypi
2930
- deploy_conda
31+
- deploy_releases
3032

3133
jobs:
3234
include:
@@ -50,3 +52,12 @@ jobs:
5052
repo: domdfcoding/domdf_python_tools
5153
provider: script
5254
script: .ci/travis_deploy_conda.sh || travis_terminate 1;
55+
56+
- stage: deploy_releases
57+
python: "3.6"
58+
script: skip
59+
deploy:
60+
on:
61+
repo: domdfcoding/domdf_python_tools
62+
provider: script
63+
script: python .ci/copy_pypi_2_github.py || travis_terminate 1;

0 commit comments

Comments
 (0)