woltapi 0.0.1__tar.gz → 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {woltapi-0.0.1 → woltapi-0.1.0}/MANIFEST.in +1 -1
- {woltapi-0.0.1/src/woltapi.egg-info → woltapi-0.1.0}/PKG-INFO +98 -9
- {woltapi-0.0.1 → woltapi-0.1.0}/README.md +97 -8
- woltapi-0.1.0/RELEASING.md +91 -0
- woltapi-0.1.0/examples/order.py +395 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/pyproject.toml +1 -1
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/__init__.py +2 -0
- woltapi-0.1.0/src/woltapi/auth.py +201 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/client.py +5 -4
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/selection.py +35 -8
- {woltapi-0.0.1 → woltapi-0.1.0/src/woltapi.egg-info}/PKG-INFO +98 -9
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi.egg-info/SOURCES.txt +5 -1
- woltapi-0.1.0/tests/test_auth.py +553 -0
- woltapi-0.1.0/tests/test_order_example.py +301 -0
- woltapi-0.0.1/WOLT_API.md +0 -1040
- {woltapi-0.0.1 → woltapi-0.1.0}/LICENSE +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/examples/browse.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/examples/check_session.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/setup.cfg +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/credentials.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/errors.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/models.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/purchase.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/services.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi/transport.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi.egg-info/dependency_links.txt +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi.egg-info/requires.txt +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/src/woltapi.egg-info/top_level.txt +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/__init__.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/test_browse.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/test_check_session.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/test_client.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/test_purchase.py +0 -0
- {woltapi-0.0.1 → woltapi-0.1.0}/tests/test_selection.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: woltapi
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: A small synchronous client for observed Wolt ordering flows.
|
|
5
5
|
License-Expression: AGPL-3.0-only
|
|
6
6
|
Project-URL: Repository, https://github.com/skorokithakis/woltapi
|
|
@@ -26,9 +26,23 @@ part is unfinished and has not been tested with a real purchase.
|
|
|
26
26
|
|
|
27
27
|
## Install
|
|
28
28
|
|
|
29
|
-
You need Python 3.10 or newer.
|
|
29
|
+
You need Python 3.10 or newer. Install the library from PyPI:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
+
pip install woltapi
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can then use `from woltapi import WoltClient, SessionCredentials` in your
|
|
36
|
+
Python code. See [Use it in Python](#use-it-in-python) below.
|
|
37
|
+
|
|
38
|
+
### Install from source
|
|
39
|
+
|
|
40
|
+
To run the example scripts or work on the library, clone this repository and
|
|
41
|
+
install an editable copy:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/skorokithakis/woltapi.git
|
|
45
|
+
cd woltapi
|
|
32
46
|
python3 -m venv .venv
|
|
33
47
|
source .venv/bin/activate
|
|
34
48
|
python -m pip install -e .
|
|
@@ -39,6 +53,9 @@ it. On Windows, activate it with `.venv\Scripts\activate` instead of `source`.
|
|
|
39
53
|
|
|
40
54
|
## Try it
|
|
41
55
|
|
|
56
|
+
Run these commands from the project folder after installing from source above.
|
|
57
|
+
The `examples/` scripts are not installed by `pip install woltapi`.
|
|
58
|
+
|
|
42
59
|
The browsing example shows your recent orders, searches for a restaurant, and
|
|
43
60
|
lists some of its menu items. **It will not order anything or change your basket.**
|
|
44
61
|
|
|
@@ -94,9 +111,10 @@ The browsing script can also read the token from an environment variable named
|
|
|
94
111
|
when it starts. If that variable is set, the script uses it instead of asking
|
|
95
112
|
you to paste a token. No credential file is needed.
|
|
96
113
|
|
|
97
|
-
|
|
98
|
-
**HTTP 401**,
|
|
99
|
-
|
|
114
|
+
Access tokens expire. With manually supplied headers, get a current access token
|
|
115
|
+
if you receive **HTTP 401**, and update `WOLT_ACCESS_TOKEN` if you use it. For
|
|
116
|
+
automatic renewal in Python, use a consumer refresh token as described below.
|
|
117
|
+
The library cannot sign you in.
|
|
100
118
|
|
|
101
119
|
## Use it in Python
|
|
102
120
|
|
|
@@ -148,6 +166,60 @@ only to its matching server.
|
|
|
148
166
|
`SessionCredentials`. Reading an environment variable or asking for a token is
|
|
149
167
|
the job of your script, not the library.
|
|
150
168
|
|
|
169
|
+
### Automatic token refresh
|
|
170
|
+
|
|
171
|
+
Only a **consumer refresh token** is needed to start: no access token, password,
|
|
172
|
+
client secret, or browser cookies need to accompany the request. In your logged-in
|
|
173
|
+
Wolt browser, find `__wrtoken` under **Developer Tools > Application > Cookies**.
|
|
174
|
+
Use its value, without surrounding quotes. This is not the access token from an
|
|
175
|
+
Authorization header or the refresh token used by the Converse support widget.
|
|
176
|
+
Treat it like a password and do not put it in Git or logs.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from getpass import getpass
|
|
180
|
+
|
|
181
|
+
from woltapi import RefreshTokenCredentials, WoltClient
|
|
182
|
+
|
|
183
|
+
credentials = RefreshTokenCredentials(
|
|
184
|
+
getpass("Wolt consumer refresh token: ").strip(),
|
|
185
|
+
)
|
|
186
|
+
client = WoltClient(credentials)
|
|
187
|
+
history = client.get_orders_page()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The first API call exchanges the refresh token at
|
|
191
|
+
`https://authentication.wolt.com/v1/wauth2/access_token`. Subsequent calls reuse
|
|
192
|
+
the access token until shortly before its server-reported expiry (30 minutes in
|
|
193
|
+
the verified response). The access token is supplied to the restaurant, consumer,
|
|
194
|
+
and payment hosts; the refresh token is sent only to the authentication host.
|
|
195
|
+
You can also call `credentials.refresh()` to exchange it explicitly.
|
|
196
|
+
|
|
197
|
+
Wolt may return a replacement refresh token. `credentials.refresh_token` always
|
|
198
|
+
holds the latest successfully validated value. For applications that run across
|
|
199
|
+
restarts, pass `on_refresh=save_refresh_token`, where your function accepts that
|
|
200
|
+
string and saves it to your secret store after each exchange. The library does
|
|
201
|
+
not read or write credential files. Without persistence, a rotated token may be
|
|
202
|
+
lost when your process exits. Do not share one refresh token across independent
|
|
203
|
+
processes that might refresh it concurrently.
|
|
204
|
+
|
|
205
|
+
The callback runs before the API request proceeds and must not call back into
|
|
206
|
+
`credentials.refresh()` or `credentials.headers_for()`. If it raises, the
|
|
207
|
+
exception propagates but the new tokens remain in memory. Later calls retry the
|
|
208
|
+
callback before any further authentication or API request; they remain blocked
|
|
209
|
+
until persistence succeeds. Make your callback safe to repeat with the same token.
|
|
210
|
+
|
|
211
|
+
Optional `restaurant_headers`, `consumer_headers`, and `payment_headers` still
|
|
212
|
+
scope extra headers to their respective hosts. `Authorization` is managed by
|
|
213
|
+
`RefreshTokenCredentials`. Its `timeout` controls authentication requests
|
|
214
|
+
separately from `WoltClient`'s API timeout (both default to 10 seconds).
|
|
215
|
+
|
|
216
|
+
Refresh requests are not retried or redirected, and API requests are never
|
|
217
|
+
automatically replayed after a 401, including purchases. An expired or revoked
|
|
218
|
+
refresh token requires a new browser session credential. Authentication failures
|
|
219
|
+
use the existing exceptions, such as `HTTPStatusError` with
|
|
220
|
+
`service == "authentication"`. The example scripts still accept access tokens;
|
|
221
|
+
automatic renewal is opt-in through this Python API.
|
|
222
|
+
|
|
151
223
|
### Useful methods
|
|
152
224
|
|
|
153
225
|
| Call | What you get |
|
|
@@ -178,6 +250,21 @@ sending them to shared logs. The browsing example prints only selected fields.
|
|
|
178
250
|
|
|
179
251
|
Not as a simple, ready-to-use feature yet. There is no `order("pizza")` method.
|
|
180
252
|
|
|
253
|
+
To try **checkout without buying anything**, use the new checkout-only example
|
|
254
|
+
from an editable source installation:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
python examples/order.py --latitude 60.17 --longitude 24.94 --query pizza
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Use your own coordinates. It prompts for your token (or uses `WOLT_ACCESS_TOKEN`),
|
|
261
|
+
guides you through selecting an item and a saved delivery target/card, then asks
|
|
262
|
+
before requesting a price. It never submits a purchase. Basket saving is off by
|
|
263
|
+
default and needs a separate confirmation if enabled.
|
|
264
|
+
|
|
265
|
+
This is still a test tool: it may stop if the catalog lacks required checkout
|
|
266
|
+
fields. Run `python examples/order.py --help` for available options.
|
|
267
|
+
|
|
181
268
|
The library has methods to choose items, save a basket, ask Wolt for a price,
|
|
182
269
|
and submit a purchase. But some required inputs still need to come from your
|
|
183
270
|
own code, including browser/device information and detailed item data.
|
|
@@ -191,12 +278,9 @@ Do not call it unless you intend to buy the exact order you have reviewed. If it
|
|
|
191
278
|
times out or raises `OrderOutcomeUnknown`, **do not send it again**: Wolt may
|
|
192
279
|
already have received it. Check the order in Wolt instead.
|
|
193
280
|
|
|
194
|
-
Login,
|
|
281
|
+
Login, adding cards, payment verification screens, scheduled
|
|
195
282
|
orders, cancellation, and refunds are not supported.
|
|
196
283
|
|
|
197
|
-
For the technical details behind the ordering code, see [WOLT_API.md](WOLT_API.md).
|
|
198
|
-
You do not need to read that file to use the browsing example.
|
|
199
|
-
|
|
200
284
|
## Run the tests
|
|
201
285
|
|
|
202
286
|
With your Python environment active:
|
|
@@ -209,6 +293,11 @@ python -m pytest
|
|
|
209
293
|
The tests use made-up responses. They do not contact Wolt, need your token, or
|
|
210
294
|
place orders.
|
|
211
295
|
|
|
296
|
+
## Releases
|
|
297
|
+
|
|
298
|
+
Maintainers: see [RELEASING.md](RELEASING.md) for tests, release PRs, and automatic
|
|
299
|
+
PyPI publishing.
|
|
300
|
+
|
|
212
301
|
## License
|
|
213
302
|
|
|
214
303
|
Licensed under the GNU Affero General Public License, version 3
|
|
@@ -8,9 +8,23 @@ part is unfinished and has not been tested with a real purchase.
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
You need Python 3.10 or newer.
|
|
11
|
+
You need Python 3.10 or newer. Install the library from PyPI:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
+
pip install woltapi
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
You can then use `from woltapi import WoltClient, SessionCredentials` in your
|
|
18
|
+
Python code. See [Use it in Python](#use-it-in-python) below.
|
|
19
|
+
|
|
20
|
+
### Install from source
|
|
21
|
+
|
|
22
|
+
To run the example scripts or work on the library, clone this repository and
|
|
23
|
+
install an editable copy:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/skorokithakis/woltapi.git
|
|
27
|
+
cd woltapi
|
|
14
28
|
python3 -m venv .venv
|
|
15
29
|
source .venv/bin/activate
|
|
16
30
|
python -m pip install -e .
|
|
@@ -21,6 +35,9 @@ it. On Windows, activate it with `.venv\Scripts\activate` instead of `source`.
|
|
|
21
35
|
|
|
22
36
|
## Try it
|
|
23
37
|
|
|
38
|
+
Run these commands from the project folder after installing from source above.
|
|
39
|
+
The `examples/` scripts are not installed by `pip install woltapi`.
|
|
40
|
+
|
|
24
41
|
The browsing example shows your recent orders, searches for a restaurant, and
|
|
25
42
|
lists some of its menu items. **It will not order anything or change your basket.**
|
|
26
43
|
|
|
@@ -76,9 +93,10 @@ The browsing script can also read the token from an environment variable named
|
|
|
76
93
|
when it starts. If that variable is set, the script uses it instead of asking
|
|
77
94
|
you to paste a token. No credential file is needed.
|
|
78
95
|
|
|
79
|
-
|
|
80
|
-
**HTTP 401**,
|
|
81
|
-
|
|
96
|
+
Access tokens expire. With manually supplied headers, get a current access token
|
|
97
|
+
if you receive **HTTP 401**, and update `WOLT_ACCESS_TOKEN` if you use it. For
|
|
98
|
+
automatic renewal in Python, use a consumer refresh token as described below.
|
|
99
|
+
The library cannot sign you in.
|
|
82
100
|
|
|
83
101
|
## Use it in Python
|
|
84
102
|
|
|
@@ -130,6 +148,60 @@ only to its matching server.
|
|
|
130
148
|
`SessionCredentials`. Reading an environment variable or asking for a token is
|
|
131
149
|
the job of your script, not the library.
|
|
132
150
|
|
|
151
|
+
### Automatic token refresh
|
|
152
|
+
|
|
153
|
+
Only a **consumer refresh token** is needed to start: no access token, password,
|
|
154
|
+
client secret, or browser cookies need to accompany the request. In your logged-in
|
|
155
|
+
Wolt browser, find `__wrtoken` under **Developer Tools > Application > Cookies**.
|
|
156
|
+
Use its value, without surrounding quotes. This is not the access token from an
|
|
157
|
+
Authorization header or the refresh token used by the Converse support widget.
|
|
158
|
+
Treat it like a password and do not put it in Git or logs.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from getpass import getpass
|
|
162
|
+
|
|
163
|
+
from woltapi import RefreshTokenCredentials, WoltClient
|
|
164
|
+
|
|
165
|
+
credentials = RefreshTokenCredentials(
|
|
166
|
+
getpass("Wolt consumer refresh token: ").strip(),
|
|
167
|
+
)
|
|
168
|
+
client = WoltClient(credentials)
|
|
169
|
+
history = client.get_orders_page()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The first API call exchanges the refresh token at
|
|
173
|
+
`https://authentication.wolt.com/v1/wauth2/access_token`. Subsequent calls reuse
|
|
174
|
+
the access token until shortly before its server-reported expiry (30 minutes in
|
|
175
|
+
the verified response). The access token is supplied to the restaurant, consumer,
|
|
176
|
+
and payment hosts; the refresh token is sent only to the authentication host.
|
|
177
|
+
You can also call `credentials.refresh()` to exchange it explicitly.
|
|
178
|
+
|
|
179
|
+
Wolt may return a replacement refresh token. `credentials.refresh_token` always
|
|
180
|
+
holds the latest successfully validated value. For applications that run across
|
|
181
|
+
restarts, pass `on_refresh=save_refresh_token`, where your function accepts that
|
|
182
|
+
string and saves it to your secret store after each exchange. The library does
|
|
183
|
+
not read or write credential files. Without persistence, a rotated token may be
|
|
184
|
+
lost when your process exits. Do not share one refresh token across independent
|
|
185
|
+
processes that might refresh it concurrently.
|
|
186
|
+
|
|
187
|
+
The callback runs before the API request proceeds and must not call back into
|
|
188
|
+
`credentials.refresh()` or `credentials.headers_for()`. If it raises, the
|
|
189
|
+
exception propagates but the new tokens remain in memory. Later calls retry the
|
|
190
|
+
callback before any further authentication or API request; they remain blocked
|
|
191
|
+
until persistence succeeds. Make your callback safe to repeat with the same token.
|
|
192
|
+
|
|
193
|
+
Optional `restaurant_headers`, `consumer_headers`, and `payment_headers` still
|
|
194
|
+
scope extra headers to their respective hosts. `Authorization` is managed by
|
|
195
|
+
`RefreshTokenCredentials`. Its `timeout` controls authentication requests
|
|
196
|
+
separately from `WoltClient`'s API timeout (both default to 10 seconds).
|
|
197
|
+
|
|
198
|
+
Refresh requests are not retried or redirected, and API requests are never
|
|
199
|
+
automatically replayed after a 401, including purchases. An expired or revoked
|
|
200
|
+
refresh token requires a new browser session credential. Authentication failures
|
|
201
|
+
use the existing exceptions, such as `HTTPStatusError` with
|
|
202
|
+
`service == "authentication"`. The example scripts still accept access tokens;
|
|
203
|
+
automatic renewal is opt-in through this Python API.
|
|
204
|
+
|
|
133
205
|
### Useful methods
|
|
134
206
|
|
|
135
207
|
| Call | What you get |
|
|
@@ -160,6 +232,21 @@ sending them to shared logs. The browsing example prints only selected fields.
|
|
|
160
232
|
|
|
161
233
|
Not as a simple, ready-to-use feature yet. There is no `order("pizza")` method.
|
|
162
234
|
|
|
235
|
+
To try **checkout without buying anything**, use the new checkout-only example
|
|
236
|
+
from an editable source installation:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
python examples/order.py --latitude 60.17 --longitude 24.94 --query pizza
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Use your own coordinates. It prompts for your token (or uses `WOLT_ACCESS_TOKEN`),
|
|
243
|
+
guides you through selecting an item and a saved delivery target/card, then asks
|
|
244
|
+
before requesting a price. It never submits a purchase. Basket saving is off by
|
|
245
|
+
default and needs a separate confirmation if enabled.
|
|
246
|
+
|
|
247
|
+
This is still a test tool: it may stop if the catalog lacks required checkout
|
|
248
|
+
fields. Run `python examples/order.py --help` for available options.
|
|
249
|
+
|
|
163
250
|
The library has methods to choose items, save a basket, ask Wolt for a price,
|
|
164
251
|
and submit a purchase. But some required inputs still need to come from your
|
|
165
252
|
own code, including browser/device information and detailed item data.
|
|
@@ -173,12 +260,9 @@ Do not call it unless you intend to buy the exact order you have reviewed. If it
|
|
|
173
260
|
times out or raises `OrderOutcomeUnknown`, **do not send it again**: Wolt may
|
|
174
261
|
already have received it. Check the order in Wolt instead.
|
|
175
262
|
|
|
176
|
-
Login,
|
|
263
|
+
Login, adding cards, payment verification screens, scheduled
|
|
177
264
|
orders, cancellation, and refunds are not supported.
|
|
178
265
|
|
|
179
|
-
For the technical details behind the ordering code, see [WOLT_API.md](WOLT_API.md).
|
|
180
|
-
You do not need to read that file to use the browsing example.
|
|
181
|
-
|
|
182
266
|
## Run the tests
|
|
183
267
|
|
|
184
268
|
With your Python environment active:
|
|
@@ -191,6 +275,11 @@ python -m pytest
|
|
|
191
275
|
The tests use made-up responses. They do not contact Wolt, need your token, or
|
|
192
276
|
place orders.
|
|
193
277
|
|
|
278
|
+
## Releases
|
|
279
|
+
|
|
280
|
+
Maintainers: see [RELEASING.md](RELEASING.md) for tests, release PRs, and automatic
|
|
281
|
+
PyPI publishing.
|
|
282
|
+
|
|
194
283
|
## License
|
|
195
284
|
|
|
196
285
|
Licensed under the GNU Affero General Public License, version 3
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Releasing woltapi
|
|
2
|
+
|
|
3
|
+
This follows the release setup in `skorokithakis/catt`, using `main` instead of
|
|
4
|
+
`master` and setuptools instead of Poetry.
|
|
5
|
+
|
|
6
|
+
## How it works
|
|
7
|
+
|
|
8
|
+
1. A push or pull request runs tests on Python 3.10 through 3.14. It also checks
|
|
9
|
+
formatting and builds the package. Tests use fake responses, not Wolt accounts.
|
|
10
|
+
2. On `main`, Release Please opens or updates a release pull request. It changes
|
|
11
|
+
the version in `pyproject.toml` and writes the changelog for you.
|
|
12
|
+
3. Review the release PR and wait for its checks to pass, then merge it.
|
|
13
|
+
4. Release Please creates the tag and GitHub release, then starts **Publish to
|
|
14
|
+
PyPI** with that tag.
|
|
15
|
+
5. The publishing workflow tests and builds the tagged code. Only after those
|
|
16
|
+
checks pass does a separate job upload it to PyPI.
|
|
17
|
+
|
|
18
|
+
Use commit messages such as `fix: correct menu prices` and `feat: add search
|
|
19
|
+
filters`. Release Please uses these messages to choose the next version.
|
|
20
|
+
Like catt, breaking changes before version 1.0 bump the minor version rather
|
|
21
|
+
than jumping to 1.0. The starting release is `v0.0.1`.
|
|
22
|
+
|
|
23
|
+
## One-time GitHub setup
|
|
24
|
+
|
|
25
|
+
Add a repository Actions secret named **`RELEASE_PLEASE_TOKEN`**. You can use the
|
|
26
|
+
same personal access token as catt if it also has access to this repository.
|
|
27
|
+
GitHub cannot reveal an existing secret's value, so it cannot be copied from
|
|
28
|
+
catt automatically.
|
|
29
|
+
|
|
30
|
+
For a fine-grained token, allow access to `skorokithakis/woltapi` with read/write
|
|
31
|
+
permissions for **Contents** (code) and **Pull requests**, matching catt's token.
|
|
32
|
+
GitHub adds read access to Metadata automatically. No separate Issues or Actions
|
|
33
|
+
permission is needed on this personal token. Do not commit the token.
|
|
34
|
+
|
|
35
|
+
You can add it through GitHub's **Settings > Secrets and variables > Actions**,
|
|
36
|
+
or run:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
gh secret set RELEASE_PLEASE_TOKEN --repo skorokithakis/woltapi
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This token matters: release PRs made with the built-in `GITHUB_TOKEN` would not
|
|
43
|
+
automatically trigger the test workflow. A personal access token allows those
|
|
44
|
+
checks to run, as in catt.
|
|
45
|
+
|
|
46
|
+
Starting the publishing workflow uses the separate, built-in `GITHUB_TOKEN`,
|
|
47
|
+
with `actions: write` granted in the workflow file. Explicit `workflow_dispatch`
|
|
48
|
+
events can trigger another workflow with this token. Its permissions do not
|
|
49
|
+
change the permissions of your personal access token.
|
|
50
|
+
|
|
51
|
+
## One-time PyPI setup
|
|
52
|
+
|
|
53
|
+
No PyPI API token is needed. PyPI must be told to trust this GitHub workflow.
|
|
54
|
+
|
|
55
|
+
In your PyPI account, add a **trusted publisher** for `woltapi`. If you have not
|
|
56
|
+
created the project yet, use **Publishing > Add a new pending publisher**.
|
|
57
|
+
If it already exists, use the project's **Publishing** page. You must own the
|
|
58
|
+
project, or choose an available package name before publishing.
|
|
59
|
+
|
|
60
|
+
Enter these exact values:
|
|
61
|
+
|
|
62
|
+
| Field | Value |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| PyPI project name | `woltapi` |
|
|
65
|
+
| GitHub owner | `skorokithakis` |
|
|
66
|
+
| Repository | `woltapi` |
|
|
67
|
+
| Workflow filename | `publish-pypi.yml` |
|
|
68
|
+
| Environment | Leave blank, matching catt |
|
|
69
|
+
|
|
70
|
+
The job asks PyPI for a short-lived publishing credential using GitHub's
|
|
71
|
+
identity. Building and testing run in a different job without that permission.
|
|
72
|
+
|
|
73
|
+
## Publish the existing 0.0.1 release
|
|
74
|
+
|
|
75
|
+
After these workflow files are on `main` and PyPI trusts the publisher, run:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
gh workflow run publish-pypi.yml \
|
|
79
|
+
--repo skorokithakis/woltapi \
|
|
80
|
+
--ref main \
|
|
81
|
+
-f tag=v0.0.1
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This also lets you retry a failed upload for a later release. Do not change or
|
|
85
|
+
move a tag after publishing: PyPI will not let you replace an uploaded version.
|
|
86
|
+
The workflow deliberately fails on duplicate files instead of silently skipping
|
|
87
|
+
them. Check PyPI before retrying an upload that may have partly succeeded.
|
|
88
|
+
|
|
89
|
+
Automatic publication is not ready until both the GitHub secret and PyPI
|
|
90
|
+
publisher are configured. These workflows do not add login or refresh support
|
|
91
|
+
to the Wolt client.
|