Skip to content

Commit f7f8968

Browse files
authored
Merge pull request #16 from jtpio/finalize
Prep for PyPI Release
2 parents 5ed3cfa + 55dcf82 commit f7f8968

File tree

5 files changed

+67
-34
lines changed

5 files changed

+67
-34
lines changed

.github/workflows/publish-release.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ on:
55
release_url:
66
description: "The URL of the draft GitHub release"
77
required: true
8+
pypi_registry:
9+
description: "The PYPI registry"
10+
default: https://pypi.org/simple/
11+
npm_registry:
12+
description: "The npm registry"
13+
default: https://registry.npmjs.org/
814
jobs:
915
publish_release:
1016
runs-on: ubuntu-latest
@@ -30,8 +36,11 @@ jobs:
3036
- name: Publish Release
3137
id: publish-release
3238
env:
33-
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }} # use final when ready to publish
34-
TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/
39+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
40+
TWINE_USERNAME: __token__
41+
TWINE_REGISTRY: $${{ github.event.inputs.pypi_registry }}
42+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
43+
NPM_REGISTRY: $${{ github.event.inputs.npm_registry }}
3544
uses: jupyter-server/jupyter_releaser/.github/actions/publish-release@v1
3645
with:
3746
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}

README.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ See [checklist](#Checklist-for-Adoption) below for details:
2626
- Markdown changelog
2727
- Bump version configuration (if using Python), for example [tbump](https://github.com/dmerejkowsky/tbump)
2828
- [Access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with access to target GitHub repo to run GitHub Actions.
29-
- Access token for the test [PyPI registry](https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github)
29+
- Access token for the [PyPI registry](https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github)
3030
- If needed, access token for [npm](https://docs.npmjs.com/creating-and-viewing-access-tokens).
3131

3232
## Typical Workflow
@@ -191,7 +191,9 @@ A. Prep the `jupyter_releaser` fork:
191191
- [ ] Clone this repository onto your GitHub user account.
192192
- [ ] Add a [GitHub Access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with access to target GitHub repo to run GitHub Actions, saved as
193193
`ADMIN_GITHUB_TOKEN` in the [repository secrets](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository).
194-
- [ ] Add access tokens for the test [PyPI registry](https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github) stored as `TEST_PYPI_TOKEN`
194+
- [ ] Add access token for the [PyPI registry](https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github) stored as `PYPI_TOKEN`.
195+
_Note_ For security reasons, it is recommended that you scope the access
196+
to a single repository, and update the value of `PYPI_TOKEN` for each repository that you are releasing.
195197
- [ ] If needed, add access token for [npm](https://docs.npmjs.com/creating-and-viewing-access-tokens), saved as `NPM_TOKEN`.
196198

197199
B. Prep target repository:
@@ -204,14 +206,21 @@ B. Prep target repository:
204206
- [ ] Add [tbump](https://github.com/tankerhq/tbump) support if using Python - see example metadata in [pyproject.toml](./pyproject.toml)
205207
- We recommend putting `setuptools` metadata in `setup.cfg` and using `version attr: <package_name>.__version__`, see example [`setup.cfg`](./setup.cfg)
206208
- See documentation on `setup.cfg` [metadata](https://setuptools.readthedocs.io/en/latest/userguide/declarative_config.html)
207-
- If previously providing `version_info`, use `get_version_info` from `jupyter_packaging`, since `tbump` requires the intact version string, e.g.
209+
- If previously providing `version_info`, use a snippet like the one below, since `tbump` requires the intact version string, e.g.
208210

209211
```python
210-
from jupyter_packaging import get_version_info
212+
import re
211213

212214
# Version string must appear intact for tbump versioning
213215
__version__ = '1.4.0.dev0'
214-
version_info = get_version_info(__version__)
216+
217+
# Build up version_info tuple for backwards compatibility
218+
pattern = r'(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)'
219+
match = re.match(pattern, __version__)
220+
parts = [int(match[part]) for part in ['major', 'minor', 'patch']]
221+
if match['rest']:
222+
parts.append(match['rest'])
223+
version_info = tuple(parts)
215224
```
216225

217226
- [ ] Add a GitHub Actions CI step to run the `check_release` action. For example:
@@ -238,6 +247,7 @@ _Note_ The check release action needs `contents: write` [permission](https://doc
238247
- [ ] Optionally add [configuration](#Configuration) to the target repository if non-standard options or hooks are needed.
239248
- [ ] If desired, add `check_release` job, changelog, and `tbump` support to other active release branches
240249
- [ ] Try out the `Draft Changelog` and `Draft Release` process against a fork of the target repo first so you don't accidentally push tags and GitHub releases to the source repository.
250+
- [ ] Try the `Publish Release` process using a prerelease version before publishing a final version.
241251

242252
## Backport Branches
243253

@@ -303,18 +313,22 @@ Detailed workflows are available to draft a changelog, draft a release, publish
303313
### Check Release Workflow
304314

305315
- Runs on CI in the target repository to verify compatibility and release-ability.
306-
- Runs the `Draft Changelog`, `Draft Release`, and `Publish Release` actions in dry run mode
307-
- Publishes to the Test PyPI server
308-
- Deletes the Release
316+
- Runs the `Draft Changelog` and `Draft Release` actions in dry run mode
317+
- Publishes to the local PyPI server and/or dry-run `npm publish`.
309318
- Does not make PRs or push git changes
310319

311-
## Troubleshooting
320+
## FAQs
312321

313-
### Changelog gets out of sync
322+
### My changelog is out of sync
314323

315324
Create a new manual PR to fix the PR and re-orient the changelog entry markers.
316325

317326
### PR is merged to the target branch in the middle of a "Draft Release"
318327

319328
The release will fail to push commits because it will not be up to date. Delete the pushed tags and re-start with "Draft Changelog" to
320329
pick up the new PR.
330+
331+
## How to keep fork of Jupyter Releaser up to date
332+
333+
The manual workflow files target the `@v1` actions in the source repository, which means that as long as
334+
the workflow files themselves are up to date, you will always be running the most up to date actions.

jupyter_releaser/lib.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
3-
import atexit
43
import os
54
import os.path as osp
65
import re
@@ -11,8 +10,6 @@
1110
from datetime import datetime
1211
from glob import glob
1312
from pathlib import Path
14-
from subprocess import PIPE
15-
from subprocess import Popen
1613
from tempfile import TemporaryDirectory
1714

1815
import requests
@@ -350,26 +347,17 @@ def publish_assets(dist_dir, npm_token, npm_cmd, twine_cmd, dry_run, use_checkou
350347
if dry_run:
351348
# Start local pypi server with no auth, allowing overwrites,
352349
# in a temporary directory
353-
temp_dir = TemporaryDirectory()
354-
cmd = f"pypi-server -p 8081 -P . -a . -o -v {temp_dir.name}"
355-
proc = Popen(shlex.split(cmd), stderr=PIPE)
356-
# Wait for the server to start
357-
while True:
358-
line = proc.stderr.readline().decode("utf-8").strip()
359-
util.log(line)
360-
if "Listening on" in line:
361-
break
362-
atexit.register(proc.kill)
363-
atexit.register(temp_dir.cleanup)
364-
twine_cmd = "twine upload --repository-url=http://localhost:8081"
365-
os.environ["TWINE_USERNAME"] = "foo"
366-
os.environ["TWINE_PASSWORD"] = "bar"
350+
if len(glob(f"{dist_dir}/*.whl")):
351+
python.start_local_pypi()
352+
twine_cmd = "twine upload --repository-url=http://localhost:8081"
353+
os.environ["TWINE_USERNAME"] = "foo"
354+
os.environ["TWINE_PASSWORD"] = "bar"
367355
npm_cmd = "npm publish --dry-run"
368356
else:
369357
os.environ.setdefault("TWINE_USERNAME", "__token__")
370358

371-
if npm_token:
372-
npm.handle_auth_token(npm_token)
359+
if len(glob(f"{dist_dir}/*.tgz")):
360+
npm.handle_npm_config(npm_token)
373361

374362
found = False
375363
for path in glob(f"{dist_dir}/*.*"):

jupyter_releaser/npm.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,13 @@ def extract_package(path):
131131
return data
132132

133133

134-
def handle_auth_token(npm_token):
135-
"""Handle token auth for npm registry"""
134+
def handle_npm_config(npm_token):
135+
"""Handle npm_config"""
136136
npmrc = Path(".npmrc")
137-
text = "//registry.npmjs.org/:_authToken={npm_token}"
137+
registry = os.environ.get("NPM_REGISTRY", "registry.npmjs.org")
138+
text = f"registry={registry}"
139+
if npm_token:
140+
text += f"\n///{registry}:_authToken={npm_token}"
138141
if npmrc.exists():
139142
text = npmrc.read_text(encoding="utf-8") + text
140143
npmrc.write_text(text, encoding="utf-8")

jupyter_releaser/python.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
3+
import atexit
34
import os
45
import os.path as osp
56
import re
7+
import shlex
68
from glob import glob
79
from pathlib import Path
10+
from subprocess import PIPE
11+
from subprocess import Popen
812
from tempfile import TemporaryDirectory
913

1014
from jupyter_releaser import util
@@ -54,3 +58,18 @@ def check_dist(dist_file, test_cmd=""):
5458
util.run(f"{bin_path}/python -m pip install -U pip")
5559
util.run(f"{bin_path}/pip install -q {dist_file}")
5660
util.run(f"{bin_path}/{test_cmd}")
61+
62+
63+
def start_local_pypi():
64+
"""Start a local PyPI server"""
65+
temp_dir = TemporaryDirectory()
66+
cmd = f"pypi-server -p 8081 -P . -a . -o -v {temp_dir.name}"
67+
proc = Popen(shlex.split(cmd), stderr=PIPE)
68+
# Wait for the server to start
69+
while True:
70+
line = proc.stderr.readline().decode("utf-8").strip()
71+
util.log(line)
72+
if "Listening on" in line:
73+
break
74+
atexit.register(proc.kill)
75+
atexit.register(temp_dir.cleanup)

0 commit comments

Comments
 (0)