sweatstack-cli 0.12.0__tar.gz → 0.12.1__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.
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/CHANGELOG.md +12 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/DEVELOPMENT.md +8 -6
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/PKG-INFO +38 -9
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/README.md +37 -8
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/pyproject.toml +1 -1
- sweatstack_cli-0.12.1/src/sweatstack_cli/__init__.py +10 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/commands/app.py +13 -12
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/test_app.py +22 -4
- sweatstack_cli-0.12.1/tests/test_version.py +17 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/uv.lock +1 -1
- sweatstack_cli-0.12.0/src/sweatstack_cli/__init__.py +0 -3
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/settings.local.json +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/SKILL.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/api.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/auth.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/cli.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/pyscript.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.claude/skills/sweatstack/webapp.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.gitignore +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/.python-version +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/CREATE_PRIVATE_APP.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/Makefile +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/PLAN.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/plans/001-page-init-command.md +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/api/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/api/client.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/auth/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/auth/callback_server.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/auth/jwt.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/auth/pkce.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/auth/tokens.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/commands/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/commands/auth.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/commands/page.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/config.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/console.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/exceptions.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/main.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/project.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/py.typed +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/services/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/services/applications.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/templates/page/index.html +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/version_check.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/sweatstack.toml +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/conftest.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_api/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_api/test_client.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_auth/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_auth/test_callback_server.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_auth/test_jwt.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_auth/test_pkce.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_auth/test_tokens.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/test_auth.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/test_cli.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/test_page_deploy.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_commands/test_page_init.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_project.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_services/__init__.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_services/test_applications.py +0 -0
- {sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/tests/test_version_check.py +0 -0
|
@@ -4,6 +4,18 @@ All notable changes to this project are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.12.1] - 2026-10-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- 0.12.0 reported itself as 0.11.0: in `--version`, in `status` (which then
|
|
12
|
+
always offered an "update" to 0.12.0) and in the `User-Agent` header. The
|
|
13
|
+
version is now read from the installed package, so `pyproject.toml` is the
|
|
14
|
+
only place to bump it.
|
|
15
|
+
- `app create` checks for an existing `sweatstack.toml` before creating the
|
|
16
|
+
application, not after. Non-interactively, or when declining to overwrite, it
|
|
17
|
+
used to create the app and then stop, leaving an application nothing pointed to.
|
|
18
|
+
|
|
7
19
|
## [0.12.0] - 2026-10-13
|
|
8
20
|
|
|
9
21
|
### Fixed
|
|
@@ -25,7 +25,7 @@ pytest
|
|
|
25
25
|
|
|
26
26
|
```
|
|
27
27
|
src/sweatstack_cli/
|
|
28
|
-
├── __init__.py # Package version
|
|
28
|
+
├── __init__.py # Package version (read from metadata)
|
|
29
29
|
├── main.py # CLI entry point (Typer app)
|
|
30
30
|
├── config.py # Environment-based configuration
|
|
31
31
|
├── console.py # Rich console singleton
|
|
@@ -338,11 +338,13 @@ def my_command():
|
|
|
338
338
|
|
|
339
339
|
## Release Process
|
|
340
340
|
|
|
341
|
-
1.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
341
|
+
1. Bump `version` in `pyproject.toml`, then run `uv lock` to update `uv.lock`.
|
|
342
|
+
This is the only place the version lives: `__version__` reads it from the
|
|
343
|
+
installed package.
|
|
344
|
+
2. Rename `## [Unreleased]` in `CHANGELOG.md` to `## [X.Y.Z] - YYYY-MM-DD`.
|
|
345
|
+
3. Run all checks: `make check`
|
|
346
|
+
4. Commit as `Release X.Y.Z`
|
|
347
|
+
5. Build and publish: `make publish`
|
|
346
348
|
|
|
347
349
|
## Debugging
|
|
348
350
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sweatstack-cli
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.1
|
|
4
4
|
Summary: Command-line interface for SweatStack — the sports data platform for developers
|
|
5
5
|
Project-URL: Homepage, https://sweatstack.no
|
|
6
6
|
Project-URL: Documentation, https://docs.sweatstack.no
|
|
@@ -67,8 +67,11 @@ uv tool install --reinstall sweatstack-cli
|
|
|
67
67
|
# Authenticate with SweatStack
|
|
68
68
|
sweatstack login
|
|
69
69
|
|
|
70
|
-
# Create an app and
|
|
71
|
-
sweatstack
|
|
70
|
+
# Create an app with a page, and scaffold public/index.html
|
|
71
|
+
sweatstack page init "My App"
|
|
72
|
+
|
|
73
|
+
# Preview locally, then publish to https://my-app.pages.sweatstack.dev
|
|
74
|
+
sweatstack page serve
|
|
72
75
|
sweatstack page deploy
|
|
73
76
|
```
|
|
74
77
|
|
|
@@ -110,7 +113,7 @@ sweatstack page deploy
|
|
|
110
113
|
|
|
111
114
|
### Project Configuration
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
`app create`, `app link` and `page init` generate a `sweatstack.toml` in the current directory. Other commands read defaults from this file.
|
|
114
117
|
|
|
115
118
|
```toml
|
|
116
119
|
[app]
|
|
@@ -122,9 +125,33 @@ slug = "my-page"
|
|
|
122
125
|
directory = "dist"
|
|
123
126
|
```
|
|
124
127
|
|
|
125
|
-
###
|
|
128
|
+
### Pages
|
|
129
|
+
|
|
130
|
+
Static sites hosted at `https://<slug>.pages.sweatstack.dev`. Each application has at most one page.
|
|
131
|
+
|
|
132
|
+
| Command | Description |
|
|
133
|
+
|---------|-------------|
|
|
134
|
+
| `sweatstack page init [NAME]` | Create an app and its page, and scaffold `public/index.html` |
|
|
135
|
+
| `sweatstack page serve` | Preview the site locally |
|
|
136
|
+
| `sweatstack page deploy [SLUG]` | Publish the site, creating the page if needed |
|
|
137
|
+
|
|
138
|
+
#### `page init`
|
|
139
|
+
|
|
140
|
+
Creates a private application and its page, records both in `sweatstack.toml`, and writes a starter app to `public/index.html` that signs in with SweatStack and plots your latest activity. The slug is derived from the name. With an app already linked in `sweatstack.toml`, it reuses that app instead of creating one.
|
|
126
141
|
|
|
127
|
-
|
|
142
|
+
| Option | Description |
|
|
143
|
+
|--------|-------------|
|
|
144
|
+
| `--slug TEXT` | Page slug (default: derived from the name) |
|
|
145
|
+
| `--dir PATH` | Directory to scaffold (default: `public`) |
|
|
146
|
+
| `--title TEXT` | Title shown on the page (default: the name) |
|
|
147
|
+
| `--client-id TEXT` | Reuse an existing application |
|
|
148
|
+
| `--force, -f` | Overwrite an existing `index.html` |
|
|
149
|
+
|
|
150
|
+
#### `page serve`
|
|
151
|
+
|
|
152
|
+
Serves the `[page] directory` from `sweatstack.toml` on the first free port from 8000. Extra arguments are passed to `python -m http.server`. Apps created by the CLI accept sign-in redirects to localhost on any port.
|
|
153
|
+
|
|
154
|
+
#### `page deploy`
|
|
128
155
|
|
|
129
156
|
```bash
|
|
130
157
|
# Deploy using sweatstack.toml defaults (recommended)
|
|
@@ -134,9 +161,11 @@ sweatstack page deploy
|
|
|
134
161
|
sweatstack page deploy my-page --dir ./dist
|
|
135
162
|
```
|
|
136
163
|
|
|
137
|
-
If the page doesn't exist yet, `deploy` creates it. With an app linked in
|
|
138
|
-
|
|
139
|
-
|
|
164
|
+
Every deploy replaces all files on the page. If the page doesn't exist yet, `deploy` creates it. With an app linked in `sweatstack.toml`, it creates that app's page. Without one, it asks to create a new app with the page, and fails instead when not run interactively (e.g. in CI).
|
|
165
|
+
|
|
166
|
+
New apps are private: only you can sign in. After deploying, `deploy` prints a link to make the app public.
|
|
167
|
+
|
|
168
|
+
**Limits:** 10 MB per file; 100 MB and about 1,000 files per deploy.
|
|
140
169
|
|
|
141
170
|
## License
|
|
142
171
|
|
|
@@ -37,8 +37,11 @@ uv tool install --reinstall sweatstack-cli
|
|
|
37
37
|
# Authenticate with SweatStack
|
|
38
38
|
sweatstack login
|
|
39
39
|
|
|
40
|
-
# Create an app and
|
|
41
|
-
sweatstack
|
|
40
|
+
# Create an app with a page, and scaffold public/index.html
|
|
41
|
+
sweatstack page init "My App"
|
|
42
|
+
|
|
43
|
+
# Preview locally, then publish to https://my-app.pages.sweatstack.dev
|
|
44
|
+
sweatstack page serve
|
|
42
45
|
sweatstack page deploy
|
|
43
46
|
```
|
|
44
47
|
|
|
@@ -80,7 +83,7 @@ sweatstack page deploy
|
|
|
80
83
|
|
|
81
84
|
### Project Configuration
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
`app create`, `app link` and `page init` generate a `sweatstack.toml` in the current directory. Other commands read defaults from this file.
|
|
84
87
|
|
|
85
88
|
```toml
|
|
86
89
|
[app]
|
|
@@ -92,9 +95,33 @@ slug = "my-page"
|
|
|
92
95
|
directory = "dist"
|
|
93
96
|
```
|
|
94
97
|
|
|
95
|
-
###
|
|
98
|
+
### Pages
|
|
99
|
+
|
|
100
|
+
Static sites hosted at `https://<slug>.pages.sweatstack.dev`. Each application has at most one page.
|
|
101
|
+
|
|
102
|
+
| Command | Description |
|
|
103
|
+
|---------|-------------|
|
|
104
|
+
| `sweatstack page init [NAME]` | Create an app and its page, and scaffold `public/index.html` |
|
|
105
|
+
| `sweatstack page serve` | Preview the site locally |
|
|
106
|
+
| `sweatstack page deploy [SLUG]` | Publish the site, creating the page if needed |
|
|
107
|
+
|
|
108
|
+
#### `page init`
|
|
109
|
+
|
|
110
|
+
Creates a private application and its page, records both in `sweatstack.toml`, and writes a starter app to `public/index.html` that signs in with SweatStack and plots your latest activity. The slug is derived from the name. With an app already linked in `sweatstack.toml`, it reuses that app instead of creating one.
|
|
96
111
|
|
|
97
|
-
|
|
112
|
+
| Option | Description |
|
|
113
|
+
|--------|-------------|
|
|
114
|
+
| `--slug TEXT` | Page slug (default: derived from the name) |
|
|
115
|
+
| `--dir PATH` | Directory to scaffold (default: `public`) |
|
|
116
|
+
| `--title TEXT` | Title shown on the page (default: the name) |
|
|
117
|
+
| `--client-id TEXT` | Reuse an existing application |
|
|
118
|
+
| `--force, -f` | Overwrite an existing `index.html` |
|
|
119
|
+
|
|
120
|
+
#### `page serve`
|
|
121
|
+
|
|
122
|
+
Serves the `[page] directory` from `sweatstack.toml` on the first free port from 8000. Extra arguments are passed to `python -m http.server`. Apps created by the CLI accept sign-in redirects to localhost on any port.
|
|
123
|
+
|
|
124
|
+
#### `page deploy`
|
|
98
125
|
|
|
99
126
|
```bash
|
|
100
127
|
# Deploy using sweatstack.toml defaults (recommended)
|
|
@@ -104,9 +131,11 @@ sweatstack page deploy
|
|
|
104
131
|
sweatstack page deploy my-page --dir ./dist
|
|
105
132
|
```
|
|
106
133
|
|
|
107
|
-
If the page doesn't exist yet, `deploy` creates it. With an app linked in
|
|
108
|
-
|
|
109
|
-
|
|
134
|
+
Every deploy replaces all files on the page. If the page doesn't exist yet, `deploy` creates it. With an app linked in `sweatstack.toml`, it creates that app's page. Without one, it asks to create a new app with the page, and fails instead when not run interactively (e.g. in CI).
|
|
135
|
+
|
|
136
|
+
New apps are private: only you can sign in. After deploying, `deploy` prints a link to make the app public.
|
|
137
|
+
|
|
138
|
+
**Limits:** 10 MB per file; 100 MB and about 1,000 files per deploy.
|
|
110
139
|
|
|
111
140
|
## License
|
|
112
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sweatstack-cli"
|
|
3
|
-
version = "0.12.
|
|
3
|
+
version = "0.12.1"
|
|
4
4
|
description = "Command-line interface for SweatStack — the sports data platform for developers"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Aart Goossens", email = "aart@sweatstack.no" }]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""SweatStack CLI — Command-line interface for the SweatStack platform."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
# Single source of truth: the version in pyproject.toml, read from the installed
|
|
6
|
+
# package's metadata. A hardcoded copy here drifted once (0.12.0 shipped as 0.11.0).
|
|
7
|
+
try:
|
|
8
|
+
__version__ = version("sweatstack-cli")
|
|
9
|
+
except PackageNotFoundError: # Imported from a source tree that isn't installed.
|
|
10
|
+
__version__ = "unknown"
|
|
@@ -74,6 +74,18 @@ def create(
|
|
|
74
74
|
raise typer.Exit(1)
|
|
75
75
|
name = typer.prompt("App name")
|
|
76
76
|
|
|
77
|
+
# Protect an existing sweatstack.toml before creating anything, so declining
|
|
78
|
+
# (or a non-interactive refusal) never leaves an orphaned application behind.
|
|
79
|
+
if Path(CONFIG_FILENAME).exists():
|
|
80
|
+
if not interactive:
|
|
81
|
+
console.print(
|
|
82
|
+
f"[red]Error:[/red] {CONFIG_FILENAME} already exists. "
|
|
83
|
+
"Remove it first or run interactively."
|
|
84
|
+
)
|
|
85
|
+
raise typer.Exit(1)
|
|
86
|
+
console.print(f"[yellow]Warning:[/yellow] {CONFIG_FILENAME} already exists.")
|
|
87
|
+
typer.confirm("Overwrite?", abort=True)
|
|
88
|
+
|
|
77
89
|
# Prompt for optional fields in interactive mode
|
|
78
90
|
if interactive:
|
|
79
91
|
if description is None:
|
|
@@ -110,18 +122,7 @@ def create(
|
|
|
110
122
|
if env_path:
|
|
111
123
|
_write_env_file(env_path, result)
|
|
112
124
|
|
|
113
|
-
# Write sweatstack.toml (
|
|
114
|
-
config_path = Path(CONFIG_FILENAME)
|
|
115
|
-
if config_path.exists():
|
|
116
|
-
if not interactive:
|
|
117
|
-
console.print(
|
|
118
|
-
f"[red]Error:[/red] {CONFIG_FILENAME} already exists. "
|
|
119
|
-
"Remove it first or run interactively."
|
|
120
|
-
)
|
|
121
|
-
raise typer.Exit(1)
|
|
122
|
-
console.print(f"[yellow]Warning:[/yellow] {CONFIG_FILENAME} already exists.")
|
|
123
|
-
typer.confirm("Overwrite?", abort=True)
|
|
124
|
-
|
|
125
|
+
# Write sweatstack.toml (checked for overwrite before the app was created)
|
|
125
126
|
# Default the deploy directory to public/ so the project is deploy-ready and
|
|
126
127
|
# consistent with `page init` / `page serve` / `page deploy`.
|
|
127
128
|
config_path = write_config(
|
|
@@ -189,9 +189,12 @@ class TestAppCreate:
|
|
|
189
189
|
assert result.exit_code == 1
|
|
190
190
|
assert "mutually exclusive" in result.stdout
|
|
191
191
|
|
|
192
|
-
def test_create_not_authenticated(self) -> None:
|
|
192
|
+
def test_create_not_authenticated(self, tmp_path: Path) -> None:
|
|
193
193
|
"""Should error when not authenticated."""
|
|
194
|
-
with
|
|
194
|
+
with (
|
|
195
|
+
patch("sweatstack_cli.commands.app.APIClient") as mock_client,
|
|
196
|
+
runner.isolated_filesystem(temp_dir=tmp_path),
|
|
197
|
+
):
|
|
195
198
|
mock_client.side_effect = AuthenticationError("Not authenticated")
|
|
196
199
|
|
|
197
200
|
result = runner.invoke(app, ["app", "create", "Test App"])
|
|
@@ -200,15 +203,30 @@ class TestAppCreate:
|
|
|
200
203
|
assert "Not authenticated" in result.stdout
|
|
201
204
|
assert "sweatstack login" in result.stdout
|
|
202
205
|
|
|
203
|
-
def test_create_api_error(self, mock_api: MagicMock) -> None:
|
|
206
|
+
def test_create_api_error(self, mock_api: MagicMock, tmp_path: Path) -> None:
|
|
204
207
|
"""Should handle API errors."""
|
|
205
208
|
mock_api.post.side_effect = APIError("App name already exists")
|
|
206
209
|
|
|
207
|
-
|
|
210
|
+
with runner.isolated_filesystem(temp_dir=tmp_path):
|
|
211
|
+
result = runner.invoke(app, ["app", "create", "Test App"])
|
|
208
212
|
|
|
209
213
|
assert result.exit_code == 3
|
|
210
214
|
assert "App name already exists" in result.stdout
|
|
211
215
|
|
|
216
|
+
def test_create_existing_config_creates_nothing(
|
|
217
|
+
self, mock_api: MagicMock, tmp_path: Path
|
|
218
|
+
) -> None:
|
|
219
|
+
"""Should refuse before creating the app, never leaving an orphan behind."""
|
|
220
|
+
with runner.isolated_filesystem(temp_dir=tmp_path):
|
|
221
|
+
Path("sweatstack.toml").write_text('[app]\nclient_id = "existing"\n')
|
|
222
|
+
|
|
223
|
+
result = runner.invoke(app, ["app", "create", "Test App"])
|
|
224
|
+
|
|
225
|
+
assert result.exit_code == 1
|
|
226
|
+
assert "already exists" in result.stdout
|
|
227
|
+
mock_api.post.assert_not_called()
|
|
228
|
+
assert Path("sweatstack.toml").read_text() == '[app]\nclient_id = "existing"\n'
|
|
229
|
+
|
|
212
230
|
def test_create_env_with_secret_no_warning_without_env(
|
|
213
231
|
self, mock_api: MagicMock, tmp_path: Path
|
|
214
232
|
) -> None:
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""The reported version is the one in pyproject.toml."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import tomllib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from sweatstack_cli import __version__
|
|
9
|
+
|
|
10
|
+
PYPROJECT = Path(__file__).parent.parent / "pyproject.toml"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_version_matches_pyproject() -> None:
|
|
14
|
+
with PYPROJECT.open("rb") as f:
|
|
15
|
+
expected = tomllib.load(f)["project"]["version"]
|
|
16
|
+
|
|
17
|
+
assert __version__ == expected
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sweatstack_cli-0.12.0 → sweatstack_cli-0.12.1}/src/sweatstack_cli/templates/page/index.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|