Skip to content

Commit 3017689

Browse files
ci(pypi): Re-enable PyPI releases (#2825)
Revert the changes from #2668 and #2680 to re-enable PyPI releases, as our [project limit has been increased](pypi/support#7043)
1 parent 2cf0990 commit 3017689

File tree

6 files changed

+277
-1
lines changed

6 files changed

+277
-1
lines changed

.craft.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ targets:
9595
checksums:
9696
- algorithm: sha256
9797
format: hex
98+
- name: pypi
99+
- name: sentry-pypi
100+
internalPypiRepo: getsentry/pypi
98101
- name: docker
99102
id: Docker Hub (release)
100103
source: ghcr.io/getsentry/sentry-cli
@@ -115,3 +118,5 @@ requireNames:
115118
- /^sentry-cli-Windows-i686.exe$/
116119
- /^sentry-cli-Windows-x86_64.exe$/
117120
- /^sentry-cli-Windows-aarch64.exe$/
121+
- /^sentry_cli-.*.tar.gz$/
122+
- /^sentry_cli-.*.whl$/

.github/workflows/build.yml

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,49 @@ jobs:
248248
path: '*.tgz'
249249
if-no-files-found: 'error'
250250

251+
python-base:
252+
name: python (base)
253+
runs-on: ubuntu-24.04
254+
steps:
255+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0
256+
- name: Add Rustup Target
257+
run: rustup target add x86_64-unknown-linux-musl
258+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # 5.6.0
259+
with:
260+
python-version: '3.11'
261+
- run: python3 -m pip install build && python3 -m build
262+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
263+
with:
264+
name: python-base
265+
path: dist/*
266+
if-no-files-found: 'error'
267+
268+
python:
269+
name: python
270+
runs-on: ubuntu-24.04
271+
needs: [linux, sign-macos-binaries, windows, python-base]
272+
steps:
273+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0
274+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # 5.6.0
275+
with:
276+
python-version: '3.11'
277+
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # 5.0.0
278+
with:
279+
pattern: artifact-bin-*
280+
merge-multiple: true
281+
path: binaries
282+
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # 5.0.0
283+
with:
284+
name: python-base
285+
merge-multiple: true
286+
path: python-base
287+
- run: scripts/wheels --binaries binaries --base python-base --dest dist
288+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
289+
with:
290+
name: artifact-pkg-python
291+
path: dist/*
292+
if-no-files-found: 'error'
293+
251294
npm-distributions:
252295
name: 'Build NPM distributions'
253296
runs-on: ubuntu-24.04
@@ -350,7 +393,7 @@ jobs:
350393
merge:
351394
name: Create Release Artifact
352395
runs-on: ubuntu-24.04
353-
needs: [linux, sign-macos-binaries, windows, npm-distributions, node]
396+
needs: [linux, sign-macos-binaries, windows, npm-distributions, node, python]
354397
steps:
355398
- uses: actions/upload-artifact/merge@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
356399
with:

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build-system]
2+
requires = ["setuptools", "wheel", "setuptools-rust"]

scripts/wheels

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import base64
4+
import hashlib
5+
import os.path
6+
import shutil
7+
import tempfile
8+
import zipfile
9+
from typing import NamedTuple
10+
11+
12+
class Wheel(NamedTuple):
13+
src: str
14+
plat: str
15+
exe: str = 'sentry-cli'
16+
17+
18+
WHEELS = (
19+
Wheel(
20+
src='sentry-cli-Darwin-arm64',
21+
plat='macosx_11_0_arm64',
22+
),
23+
Wheel(
24+
src='sentry-cli-Darwin-universal',
25+
plat='macosx_11_0_universal2',
26+
),
27+
Wheel(
28+
src='sentry-cli-Darwin-x86_64',
29+
plat='macosx_10_15_x86_64',
30+
),
31+
Wheel(
32+
src='sentry-cli-Linux-aarch64',
33+
plat='manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_2_aarch64',
34+
),
35+
Wheel(
36+
src='sentry-cli-Linux-armv7',
37+
plat='manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_2_armv7l',
38+
),
39+
Wheel(
40+
src='sentry-cli-Linux-i686',
41+
plat='manylinux_2_17_i686.manylinux2014_i686.musllinux_1_2_i686',
42+
),
43+
Wheel(
44+
src='sentry-cli-Linux-x86_64',
45+
plat='manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_2_x86_64',
46+
),
47+
Wheel(
48+
src='sentry-cli-Windows-i686.exe',
49+
plat='win32',
50+
exe='sentry-cli.exe',
51+
),
52+
Wheel(
53+
src='sentry-cli-Windows-x86_64.exe',
54+
plat='win_amd64',
55+
exe='sentry-cli.exe',
56+
),
57+
Wheel(
58+
src='sentry-cli-Windows-aarch64.exe',
59+
plat='win_arm64',
60+
exe='sentry-cli.exe',
61+
),
62+
)
63+
64+
65+
def main() -> int:
66+
parser = argparse.ArgumentParser()
67+
parser.add_argument('--binaries', required=True)
68+
parser.add_argument('--base', required=True)
69+
parser.add_argument('--dest', required=True)
70+
args = parser.parse_args()
71+
72+
expected = {wheel.src for wheel in WHEELS}
73+
received = set(os.listdir(args.binaries))
74+
if expected < received:
75+
raise SystemExit(
76+
f'Unexpected binaries:\n\n'
77+
f'- extra: {", ".join(sorted(received - expected))}\n'
78+
f'- missing: {", ".join(sorted(expected - received))}'
79+
)
80+
81+
sdist_path = wheel_path = None
82+
for fname in os.listdir(args.base):
83+
if fname.endswith('.tar.gz'):
84+
sdist_path = os.path.join(args.base, fname)
85+
elif fname.endswith('.whl'):
86+
wheel_path = os.path.join(args.base, fname)
87+
else:
88+
raise SystemExit(f'unexpected file in `--base`: {fname}')
89+
90+
if sdist_path is None or wheel_path is None:
91+
raise SystemExit('expected wheel and sdist in `--base`')
92+
93+
os.makedirs(args.dest, exist_ok=True)
94+
shutil.copy(sdist_path, args.dest)
95+
96+
for wheel in WHEELS:
97+
binary_src = os.path.join(args.binaries, wheel.src)
98+
binary_size = os.stat(binary_src).st_size
99+
with open(binary_src, 'rb') as bf:
100+
digest = hashlib.sha256(bf.read()).digest()
101+
digest_b64 = base64.urlsafe_b64encode(digest).rstrip(b'=').decode()
102+
103+
basename = os.path.basename(wheel_path)
104+
wheelname, _ = os.path.splitext(basename)
105+
name, version, py, abi, plat = wheelname.split('-')
106+
107+
with tempfile.TemporaryDirectory() as tmp:
108+
with zipfile.ZipFile(wheel_path) as zipf:
109+
zipf.extractall(tmp)
110+
111+
distinfo = os.path.join(tmp, f'{name}-{version}.dist-info')
112+
scripts = os.path.join(tmp, f'{name}-{version}.data', 'scripts')
113+
114+
# replace the script binary with our copy
115+
os.remove(os.path.join(scripts, 'sentry-cli'))
116+
shutil.copy(binary_src, os.path.join(scripts, wheel.exe))
117+
118+
# rewrite RECORD to include the new file
119+
record_fname = os.path.join(distinfo, 'RECORD')
120+
with open(record_fname) as f:
121+
record_lines = list(f)
122+
123+
record = f'{name}-{version}.data/scripts/sentry-cli,'
124+
for i, line in enumerate(record_lines):
125+
if line.startswith(record):
126+
record_lines[i] = (
127+
f'{name}-{version}.data/scripts/{wheel.exe},'
128+
f'sha256={digest_b64},'
129+
f'{binary_size}\n'
130+
)
131+
break
132+
else:
133+
raise SystemExit(f'could not find {record!r} in RECORD')
134+
135+
with open(record_fname, 'w') as f:
136+
f.writelines(record_lines)
137+
138+
# rewrite WHEEL to have the new tags
139+
wheel_fname = os.path.join(distinfo, 'WHEEL')
140+
with open(wheel_fname) as f:
141+
wheel_lines = list(f)
142+
143+
for i, line in enumerate(wheel_lines):
144+
if line.startswith('Tag: '):
145+
wheel_lines[i:i + 1] = [
146+
f'Tag: {py}-{abi}-{plat}\n'
147+
for plat in wheel.plat.split('.')
148+
]
149+
break
150+
else:
151+
raise SystemExit("could not find 'Tag: ' in WHEEL")
152+
153+
with open(wheel_fname, 'w') as f:
154+
f.writelines(wheel_lines)
155+
156+
# write out the final zip
157+
new_basename = f'{name}-{version}-{py}-{abi}-{wheel.plat}.whl'
158+
tmp_new_wheel = os.path.join(tmp, new_basename)
159+
fnames = sorted(
160+
os.path.join(root, fname)
161+
for root, _, fnames in os.walk(tmp)
162+
for fname in fnames
163+
)
164+
with zipfile.ZipFile(tmp_new_wheel, 'w') as zipf:
165+
for fname in fnames:
166+
zinfo = zipfile.ZipInfo(os.path.relpath(fname, tmp))
167+
if '/scripts/' in zinfo.filename:
168+
zinfo.external_attr = 0o100755 << 16
169+
with open(fname, 'rb') as fb:
170+
zipf.writestr(zinfo, fb.read())
171+
172+
# move into dest
173+
shutil.move(tmp_new_wheel, args.dest)
174+
175+
return 0
176+
177+
178+
if __name__ == '__main__':
179+
raise SystemExit(main())

setup.cfg

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[metadata]
2+
name = sentry_cli
3+
description = A command line utility to work with Sentry.
4+
long_description = file: README.md
5+
long_description_content_type = text/markdown
6+
url = https://github.com/getsentry/sentry-cli
7+
author = Sentry
8+
author_email = oss@sentry.io
9+
license = BSD-3-Clause
10+
license_file = LICENSE
11+
classifiers =
12+
License :: OSI Approved :: BSD License
13+
Programming Language :: Python :: 3
14+
Programming Language :: Python :: 3 :: Only
15+
Programming Language :: Python :: Implementation :: CPython
16+
Programming Language :: Python :: Implementation :: PyPy
17+
18+
[options]
19+
packages =
20+
py_modules =
21+
python_requires = >=3.7

setup.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from setuptools import setup
2+
from setuptools_rust import RustBin
3+
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
4+
5+
with open('Cargo.toml') as f:
6+
for line in f:
7+
if line.startswith('version = "'):
8+
_, VERSION, _ = line.split('"')
9+
break
10+
11+
12+
class bdist_wheel(_bdist_wheel):
13+
def finalize_options(self):
14+
super().finalize_options()
15+
self.root_is_pure = False
16+
17+
def get_tag(self):
18+
_, _, plat = super().get_tag()
19+
return 'py3', 'none', plat
20+
21+
22+
setup(
23+
version=VERSION,
24+
rust_extensions=[RustBin("sentry-cli")],
25+
cmdclass={'bdist_wheel': bdist_wheel},
26+
)

0 commit comments

Comments
 (0)