minitest-cli 0.4.4__tar.gz → 0.5.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.
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/.github/workflows/ci.yml +33 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/PKG-INFO +49 -33
- minitest_cli-0.5.0/README.md +141 -0
- minitest_cli-0.5.0/install.ps1 +116 -0
- minitest_cli-0.5.0/install.sh +144 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/pyproject.toml +1 -1
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/auth.py +52 -1
- minitest_cli-0.5.0/src/minitest_cli/commands/maintenance_check.py +52 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/oauth.py +27 -28
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/token_exchange.py +38 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/main.py +2 -1
- minitest_cli-0.5.0/src/minitest_cli/models/maintenance_check.py +12 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/uv.lock +1 -1
- minitest_cli-0.4.4/README.md +0 -125
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/.env.example +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/.github/workflows/release.yml +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/.gitignore +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/.opencode/skill/release/SKILL.md +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/AGENTS.md +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/RELEASE.md +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/pyrightconfig.json +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/api/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/api/client.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/assets/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/assets/callback.html +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/apps.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/build.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/build_helpers.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/flow.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/flow_helpers.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/flow_modify.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/run.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/run_display.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/run_helpers.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/commands/skill.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/app_context.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/auth.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/config.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/core/credentials.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/app.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/base.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/build.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/flow_run.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/models/flow_template.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/utils/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/utils/output.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/src/minitest_cli/utils/update_check.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/__init__.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_apps_commands.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_auth.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_auth_commands.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_build_commands.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_code_quality.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_flow_commands.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_run_commands.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_skill_command.py +0 -0
- {minitest_cli-0.4.4 → minitest_cli-0.5.0}/tests/test_version.py +0 -0
|
@@ -63,3 +63,36 @@ jobs:
|
|
|
63
63
|
|
|
64
64
|
- name: Run tests
|
|
65
65
|
run: uv run pytest
|
|
66
|
+
|
|
67
|
+
install-script:
|
|
68
|
+
strategy:
|
|
69
|
+
matrix:
|
|
70
|
+
os: [ubuntu-latest, macos-latest]
|
|
71
|
+
runs-on: ${{ matrix.os }}
|
|
72
|
+
steps:
|
|
73
|
+
- name: Clone the repository
|
|
74
|
+
uses: actions/checkout@v5
|
|
75
|
+
|
|
76
|
+
- name: Run install.sh
|
|
77
|
+
run: |
|
|
78
|
+
bash install.sh
|
|
79
|
+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
80
|
+
|
|
81
|
+
- name: Verify minitest is usable
|
|
82
|
+
run: minitest --help
|
|
83
|
+
|
|
84
|
+
install-script-windows:
|
|
85
|
+
runs-on: windows-latest
|
|
86
|
+
steps:
|
|
87
|
+
- name: Clone the repository
|
|
88
|
+
uses: actions/checkout@v5
|
|
89
|
+
|
|
90
|
+
- name: Run install.ps1
|
|
91
|
+
shell: pwsh
|
|
92
|
+
run: |
|
|
93
|
+
.\install.ps1
|
|
94
|
+
"$env:USERPROFILE\.local\bin" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
|
|
95
|
+
|
|
96
|
+
- name: Verify minitest is usable
|
|
97
|
+
shell: pwsh
|
|
98
|
+
run: minitest --help
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: minitest-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Minitest CLI – command-line interface for the Minitest testing platform
|
|
5
5
|
Project-URL: Homepage, https://minitap.ai/
|
|
6
6
|
Project-URL: Source, https://github.com/minitap-ai/minitest-cli
|
|
@@ -37,27 +37,43 @@ Command-line interface for the Minitest testing platform.
|
|
|
37
37
|
|
|
38
38
|
## Installation
|
|
39
39
|
|
|
40
|
-
###
|
|
40
|
+
### One-liner (recommended)
|
|
41
|
+
|
|
42
|
+
**macOS / Linux:**
|
|
41
43
|
|
|
42
44
|
```bash
|
|
43
|
-
|
|
45
|
+
curl -fsSL https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.sh | bash
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Windows (PowerShell):**
|
|
49
|
+
|
|
50
|
+
```powershell
|
|
51
|
+
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.ps1 | iex"
|
|
44
52
|
```
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
Both scripts use `uv` if available, or install it automatically.
|
|
55
|
+
|
|
56
|
+
### Other methods
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
**uv** (all platforms):
|
|
49
59
|
|
|
50
60
|
```bash
|
|
51
|
-
|
|
61
|
+
uv tool install minitest-cli
|
|
52
62
|
```
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
**Homebrew** (macOS):
|
|
55
65
|
|
|
56
66
|
```bash
|
|
57
67
|
brew install minitap-ai/tap/minitest-cli
|
|
58
68
|
```
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
**uvx** (zero-install, all platforms):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uvx --from minitest-cli minitest --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**From source:**
|
|
61
77
|
|
|
62
78
|
```bash
|
|
63
79
|
git clone https://github.com/minitap-ai/minitest-cli.git
|
|
@@ -81,40 +97,40 @@ minitest run --app <app-id>
|
|
|
81
97
|
|
|
82
98
|
## Configuration
|
|
83
99
|
|
|
84
|
-
| Environment Variable | Description
|
|
85
|
-
|
|
86
|
-
| `MINITEST_TOKEN`
|
|
87
|
-
| `MINITEST_APP_ID`
|
|
88
|
-
| `MINITEST_API_URL`
|
|
100
|
+
| Environment Variable | Description | Required |
|
|
101
|
+
| -------------------- | ------------------------ | ---------------------------------- |
|
|
102
|
+
| `MINITEST_TOKEN` | API authentication token | Yes (or use `minitest auth login`) |
|
|
103
|
+
| `MINITEST_APP_ID` | Default app ID | No (can use `--app` flag) |
|
|
104
|
+
| `MINITEST_API_URL` | API base URL | No (defaults to production) |
|
|
89
105
|
|
|
90
106
|
## Global Flags
|
|
91
107
|
|
|
92
|
-
| Flag
|
|
93
|
-
|
|
94
|
-
| `--json`
|
|
95
|
-
| `--app <id-or-name>` | Target app for commands that require one
|
|
96
|
-
| `--version`
|
|
97
|
-
| `--help`
|
|
108
|
+
| Flag | Description |
|
|
109
|
+
| -------------------- | ------------------------------------------------ |
|
|
110
|
+
| `--json` | Output JSON to stdout (diagnostics go to stderr) |
|
|
111
|
+
| `--app <id-or-name>` | Target app for commands that require one |
|
|
112
|
+
| `--version` | Show CLI version |
|
|
113
|
+
| `--help` | Show help |
|
|
98
114
|
|
|
99
115
|
## Commands
|
|
100
116
|
|
|
101
|
-
| Command
|
|
102
|
-
|
|
103
|
-
| `minitest auth`
|
|
104
|
-
| `minitest apps`
|
|
105
|
-
| `minitest flow`
|
|
106
|
-
| `minitest build` | Build management
|
|
107
|
-
| `minitest run`
|
|
117
|
+
| Command | Description |
|
|
118
|
+
| ---------------- | ------------------------- |
|
|
119
|
+
| `minitest auth` | Authentication management |
|
|
120
|
+
| `minitest apps` | App management |
|
|
121
|
+
| `minitest flow` | Testing flow operations |
|
|
122
|
+
| `minitest build` | Build management |
|
|
123
|
+
| `minitest run` | Test execution |
|
|
108
124
|
|
|
109
125
|
## Exit Codes
|
|
110
126
|
|
|
111
|
-
| Code | Meaning
|
|
112
|
-
|
|
113
|
-
| 0
|
|
114
|
-
| 1
|
|
115
|
-
| 2
|
|
116
|
-
| 3
|
|
117
|
-
| 4
|
|
127
|
+
| Code | Meaning |
|
|
128
|
+
| ---- | -------------------- |
|
|
129
|
+
| 0 | Success |
|
|
130
|
+
| 1 | General error |
|
|
131
|
+
| 2 | Authentication error |
|
|
132
|
+
| 3 | Network / API error |
|
|
133
|
+
| 4 | Resource not found |
|
|
118
134
|
|
|
119
135
|
## Using the Dev Environment
|
|
120
136
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# minitest-cli
|
|
2
|
+
|
|
3
|
+
Command-line interface for the Minitest testing platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### One-liner (recommended)
|
|
8
|
+
|
|
9
|
+
**macOS / Linux:**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.sh | bash
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Windows (PowerShell):**
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.ps1 | iex"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Both scripts use `uv` if available, or install it automatically.
|
|
22
|
+
|
|
23
|
+
### Other methods
|
|
24
|
+
|
|
25
|
+
**uv** (all platforms):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv tool install minitest-cli
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Homebrew** (macOS):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
brew install minitap-ai/tap/minitest-cli
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**uvx** (zero-install, all platforms):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uvx --from minitest-cli minitest --help
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**From source:**
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/minitap-ai/minitest-cli.git
|
|
47
|
+
cd minitest-cli
|
|
48
|
+
uv sync
|
|
49
|
+
uv run minitest --help
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Authenticate
|
|
56
|
+
minitest auth login
|
|
57
|
+
|
|
58
|
+
# List your apps
|
|
59
|
+
minitest apps list
|
|
60
|
+
|
|
61
|
+
# Run tests
|
|
62
|
+
minitest run --app <app-id>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
| Environment Variable | Description | Required |
|
|
68
|
+
| -------------------- | ------------------------ | ---------------------------------- |
|
|
69
|
+
| `MINITEST_TOKEN` | API authentication token | Yes (or use `minitest auth login`) |
|
|
70
|
+
| `MINITEST_APP_ID` | Default app ID | No (can use `--app` flag) |
|
|
71
|
+
| `MINITEST_API_URL` | API base URL | No (defaults to production) |
|
|
72
|
+
|
|
73
|
+
## Global Flags
|
|
74
|
+
|
|
75
|
+
| Flag | Description |
|
|
76
|
+
| -------------------- | ------------------------------------------------ |
|
|
77
|
+
| `--json` | Output JSON to stdout (diagnostics go to stderr) |
|
|
78
|
+
| `--app <id-or-name>` | Target app for commands that require one |
|
|
79
|
+
| `--version` | Show CLI version |
|
|
80
|
+
| `--help` | Show help |
|
|
81
|
+
|
|
82
|
+
## Commands
|
|
83
|
+
|
|
84
|
+
| Command | Description |
|
|
85
|
+
| ---------------- | ------------------------- |
|
|
86
|
+
| `minitest auth` | Authentication management |
|
|
87
|
+
| `minitest apps` | App management |
|
|
88
|
+
| `minitest flow` | Testing flow operations |
|
|
89
|
+
| `minitest build` | Build management |
|
|
90
|
+
| `minitest run` | Test execution |
|
|
91
|
+
|
|
92
|
+
## Exit Codes
|
|
93
|
+
|
|
94
|
+
| Code | Meaning |
|
|
95
|
+
| ---- | -------------------- |
|
|
96
|
+
| 0 | Success |
|
|
97
|
+
| 1 | General error |
|
|
98
|
+
| 2 | Authentication error |
|
|
99
|
+
| 3 | Network / API error |
|
|
100
|
+
| 4 | Resource not found |
|
|
101
|
+
|
|
102
|
+
## Using the Dev Environment
|
|
103
|
+
|
|
104
|
+
To point the CLI at the **dev** environment instead of production, set these environment variables when running `minitest`:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
MINITEST_SUPABASE_URL=https://qrezuucghnmfvaxghqsv.supabase.co \
|
|
108
|
+
MINITEST_SUPABASE_PUBLISHABLE_KEY=sb_publishable_4JRhoCm8pa5PbII0dhS09A_jhpkQhmy \
|
|
109
|
+
MINITEST_API_URL=https://testing-service.dev.minitap.ai \
|
|
110
|
+
minitest auth login
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This authenticates against the dev environment and stores a dev-specific auth token. After logging in, keep the same variables set for all subsequent commands:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
MINITEST_SUPABASE_URL=https://qrezuucghnmfvaxghqsv.supabase.co \
|
|
117
|
+
MINITEST_SUPABASE_PUBLISHABLE_KEY=sb_publishable_4JRhoCm8pa5PbII0dhS09A_jhpkQhmy \
|
|
118
|
+
MINITEST_API_URL=https://testing-service.dev.minitap.ai \
|
|
119
|
+
minitest apps list
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
> **Tip:** You can `export` these variables in your shell session (or add them to a `.envrc` / `.env` file) to avoid repeating them on every invocation.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Install dependencies
|
|
128
|
+
uv sync --dev
|
|
129
|
+
|
|
130
|
+
# Run linter
|
|
131
|
+
uv run ruff check .
|
|
132
|
+
|
|
133
|
+
# Run formatter
|
|
134
|
+
uv run ruff format .
|
|
135
|
+
|
|
136
|
+
# Run type checker
|
|
137
|
+
uv run pyright
|
|
138
|
+
|
|
139
|
+
# Run tests
|
|
140
|
+
uv run pytest
|
|
141
|
+
```
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# install.ps1 - Install minitest-cli via uv (installs uv if not installed)
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.ps1 | iex"
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
$Package = "minitest-cli"
|
|
9
|
+
$InstalledVia = ""
|
|
10
|
+
|
|
11
|
+
function Write-Info { param([string]$Message) Write-Host "==> $Message" -ForegroundColor Blue }
|
|
12
|
+
function Write-Ok { param([string]$Message) Write-Host "==> $Message" -ForegroundColor Green }
|
|
13
|
+
function Write-Warn { param([string]$Message) Write-Host "Warning: $Message" -ForegroundColor Yellow }
|
|
14
|
+
function Write-Err { param([string]$Message) Write-Host "Error: $Message" -ForegroundColor Red }
|
|
15
|
+
|
|
16
|
+
function Get-UvToolBinDir {
|
|
17
|
+
$dir = & uv tool dir --bin 2>$null
|
|
18
|
+
if ($dir) { return $dir }
|
|
19
|
+
return "$env:USERPROFILE\.local\bin"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function Add-PathEntryIfMissing {
|
|
23
|
+
param([string]$Entry)
|
|
24
|
+
$normalizedEntry = $Entry.TrimEnd('\')
|
|
25
|
+
$pathEntries = ($env:PATH -split ';' | Where-Object { $_ }) | ForEach-Object { $_.TrimEnd('\') }
|
|
26
|
+
if (-not ($pathEntries | Where-Object { $_ -ieq $normalizedEntry })) {
|
|
27
|
+
$env:PATH = "$Entry;$env:PATH"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Install-WithUv {
|
|
32
|
+
Write-Info "Installing $Package with uv..."
|
|
33
|
+
try {
|
|
34
|
+
& uv tool install $Package --force 2>&1 | Write-Host
|
|
35
|
+
if ($LASTEXITCODE -eq 0) {
|
|
36
|
+
$script:InstalledVia = "uv"
|
|
37
|
+
return $true
|
|
38
|
+
}
|
|
39
|
+
Write-Warn "uv tool install failed with exit code $LASTEXITCODE."
|
|
40
|
+
return $false
|
|
41
|
+
} catch {
|
|
42
|
+
Write-Warn "uv tool install failed."
|
|
43
|
+
return $false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Install-Uv {
|
|
48
|
+
Write-Info "Installing uv package manager..."
|
|
49
|
+
try {
|
|
50
|
+
& ([scriptblock]::Create((Invoke-RestMethod "https://astral.sh/uv/install.ps1")))
|
|
51
|
+
# Refresh PATH so uv is available in this session
|
|
52
|
+
$uvPath = "$env:USERPROFILE\.local\bin"
|
|
53
|
+
Add-PathEntryIfMissing -Entry $uvPath
|
|
54
|
+
# Also check cargo bin (uv may install there on some setups)
|
|
55
|
+
$cargoPath = "$env:USERPROFILE\.cargo\bin"
|
|
56
|
+
Add-PathEntryIfMissing -Entry $cargoPath
|
|
57
|
+
return $true
|
|
58
|
+
} catch {
|
|
59
|
+
Write-Warn "Failed to install uv."
|
|
60
|
+
return $false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# -------------------------------------------------------------------
|
|
65
|
+
# Main: use uv if available, otherwise bootstrap it
|
|
66
|
+
# -------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
# 1. uv already installed? Use it
|
|
69
|
+
if (Get-Command uv -ErrorAction SilentlyContinue) {
|
|
70
|
+
Install-WithUv | Out-Null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# 2. No uv - bootstrap it
|
|
74
|
+
if (-not $InstalledVia) {
|
|
75
|
+
if (Install-Uv) {
|
|
76
|
+
Install-WithUv | Out-Null
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (-not $InstalledVia) {
|
|
81
|
+
Write-Err "Installation failed."
|
|
82
|
+
Write-Err "Please install manually:"
|
|
83
|
+
Write-Err " powershell -ExecutionPolicy ByPass -c `"irm https://astral.sh/uv/install.ps1 | iex`""
|
|
84
|
+
Write-Err " uv tool install $Package"
|
|
85
|
+
exit 1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# -------------------------------------------------------------------
|
|
89
|
+
# Verify installation
|
|
90
|
+
# -------------------------------------------------------------------
|
|
91
|
+
if (Get-Command minitest -ErrorAction SilentlyContinue) {
|
|
92
|
+
Write-Ok "minitest-cli installed successfully!"
|
|
93
|
+
minitest --version
|
|
94
|
+
Write-Host ""
|
|
95
|
+
Write-Info "Next steps:"
|
|
96
|
+
Write-Host " minitest auth login # authenticate"
|
|
97
|
+
Write-Host " minitest apps list # list your apps"
|
|
98
|
+
Write-Host " minitest --help # see all commands"
|
|
99
|
+
} else {
|
|
100
|
+
# Check uv tool bin directory
|
|
101
|
+
$toolBinDir = Get-UvToolBinDir
|
|
102
|
+
$uvBin = Join-Path $toolBinDir "minitest.exe"
|
|
103
|
+
if (Test-Path $uvBin) {
|
|
104
|
+
Write-Ok "minitest-cli installed successfully!"
|
|
105
|
+
& $uvBin --version
|
|
106
|
+
Write-Host ""
|
|
107
|
+
Write-Warn "minitest is not on your PATH in this session."
|
|
108
|
+
Write-Warn "Close and reopen your terminal, then run:"
|
|
109
|
+
Write-Host " minitest --help"
|
|
110
|
+
} else {
|
|
111
|
+
Write-Err "Installation reported success, but 'minitest' binary was not found."
|
|
112
|
+
Write-Err "Please try reinstalling:"
|
|
113
|
+
Write-Err " uv tool install $Package"
|
|
114
|
+
exit 1
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# install.sh — Install minitest-cli via uv (installs uv if not installed)
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# curl -fsSL https://raw.githubusercontent.com/minitap-ai/minitest-cli/main/install.sh | bash
|
|
6
|
+
#
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
PACKAGE="minitest-cli"
|
|
10
|
+
INSTALLED_VIA=""
|
|
11
|
+
|
|
12
|
+
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
|
13
|
+
ok() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
|
14
|
+
warn() { printf '\033[1;33mWarning:\033[0m %s\n' "$*"; }
|
|
15
|
+
error() { printf '\033[1;31mError:\033[0m %s\n' "$*" >&2; }
|
|
16
|
+
|
|
17
|
+
# Resolve the directory where uv installs tool executables.
|
|
18
|
+
# Respects UV_TOOL_BIN_DIR / XDG_BIN_HOME; falls back to ~/.local/bin.
|
|
19
|
+
get_uv_bin_dir() {
|
|
20
|
+
uv tool dir --bin 2>/dev/null || printf '%s\n' "${UV_TOOL_BIN_DIR:-${XDG_BIN_HOME:-${HOME}/.local/bin}}"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Resolve the target shell rc file based on $SHELL.
|
|
24
|
+
get_shell_rc() {
|
|
25
|
+
case "${SHELL:-}" in
|
|
26
|
+
*/zsh) printf '%s\n' "${HOME}/.zshrc" ;;
|
|
27
|
+
*/bash) printf '%s\n' "${HOME}/.bashrc" ;;
|
|
28
|
+
*) printf '%s\n' "${HOME}/.profile" ;;
|
|
29
|
+
esac
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# -------------------------------------------------------------------
|
|
33
|
+
# ensure_on_path — make sure a directory is on PATH now + in shell rc
|
|
34
|
+
# -------------------------------------------------------------------
|
|
35
|
+
ensure_on_path() {
|
|
36
|
+
local dir="$1"
|
|
37
|
+
case ":${PATH}:" in
|
|
38
|
+
*":${dir}:"*) return 0 ;; # already on PATH
|
|
39
|
+
esac
|
|
40
|
+
export PATH="${dir}:${PATH}"
|
|
41
|
+
|
|
42
|
+
# Patch the user's shell rc file so new terminals pick it up
|
|
43
|
+
local rc
|
|
44
|
+
rc="$(get_shell_rc)"
|
|
45
|
+
|
|
46
|
+
local line="export PATH=\"${dir}:\$PATH\""
|
|
47
|
+
local dir_relative="${dir/#${HOME}/\$HOME}"
|
|
48
|
+
if grep -qF "${dir}" "${rc}" 2>/dev/null \
|
|
49
|
+
|| grep -qF "${dir_relative}" "${rc}" 2>/dev/null \
|
|
50
|
+
|| grep -q "local/bin/env" "${rc}" 2>/dev/null; then
|
|
51
|
+
: # already has a PATH entry for this dir
|
|
52
|
+
else
|
|
53
|
+
info "Adding ${dir} to PATH in ${rc}"
|
|
54
|
+
printf '\n# Added by minitest-cli installer\n%s\n' "${line}" >> "${rc}"
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# -------------------------------------------------------------------
|
|
59
|
+
# install_with_uv — use uv tool install
|
|
60
|
+
# -------------------------------------------------------------------
|
|
61
|
+
install_with_uv() {
|
|
62
|
+
info "Installing ${PACKAGE} with uv…"
|
|
63
|
+
if uv tool install "${PACKAGE}" --force 2>&1; then
|
|
64
|
+
INSTALLED_VIA="uv"
|
|
65
|
+
local bin_dir
|
|
66
|
+
bin_dir="$(get_uv_bin_dir)"
|
|
67
|
+
ensure_on_path "${bin_dir}"
|
|
68
|
+
return 0
|
|
69
|
+
fi
|
|
70
|
+
warn "uv tool install failed."
|
|
71
|
+
return 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# -------------------------------------------------------------------
|
|
75
|
+
# bootstrap_uv — install uv itself, then use it to install minitest
|
|
76
|
+
# -------------------------------------------------------------------
|
|
77
|
+
bootstrap_uv() {
|
|
78
|
+
info "Installing uv package manager…"
|
|
79
|
+
if curl -LsSf https://astral.sh/uv/install.sh | sh 2>&1; then
|
|
80
|
+
# uv installer defaults to ~/.local/bin; add it so uv is available
|
|
81
|
+
ensure_on_path "${HOME}/.local/bin"
|
|
82
|
+
install_with_uv
|
|
83
|
+
return $?
|
|
84
|
+
fi
|
|
85
|
+
warn "Failed to install uv."
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# -------------------------------------------------------------------
|
|
90
|
+
# Main: use uv if available, otherwise bootstrap it
|
|
91
|
+
# -------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
# 1. uv already installed? Use it
|
|
94
|
+
if command -v uv &>/dev/null; then
|
|
95
|
+
install_with_uv || true
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# 2. No uv — bootstrap it
|
|
99
|
+
if [[ -z "${INSTALLED_VIA}" ]]; then
|
|
100
|
+
bootstrap_uv || true
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
if [[ -z "${INSTALLED_VIA}" ]]; then
|
|
104
|
+
error "Installation failed."
|
|
105
|
+
error "Please install manually:"
|
|
106
|
+
error " curl -LsSf https://astral.sh/uv/install.sh | sh"
|
|
107
|
+
error " uv tool install ${PACKAGE}"
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# -------------------------------------------------------------------
|
|
112
|
+
# Verify installation
|
|
113
|
+
# -------------------------------------------------------------------
|
|
114
|
+
if command -v minitest &>/dev/null; then
|
|
115
|
+
ok "minitest-cli installed successfully!"
|
|
116
|
+
minitest --version
|
|
117
|
+
echo ""
|
|
118
|
+
info "Next steps:"
|
|
119
|
+
echo " minitest auth login # authenticate"
|
|
120
|
+
echo " minitest apps list # list your apps"
|
|
121
|
+
echo " minitest --help # see all commands"
|
|
122
|
+
else
|
|
123
|
+
# minitest binary exists but shell doesn't see it yet (current session)
|
|
124
|
+
uv_bin_dir="$(get_uv_bin_dir)"
|
|
125
|
+
if [[ -x "${uv_bin_dir}/minitest" ]]; then
|
|
126
|
+
ok "minitest-cli installed successfully!"
|
|
127
|
+
"${uv_bin_dir}/minitest" --version
|
|
128
|
+
echo ""
|
|
129
|
+
warn "Run this to use minitest in your current terminal:"
|
|
130
|
+
echo " export PATH=\"${uv_bin_dir}:\$PATH\""
|
|
131
|
+
echo ""
|
|
132
|
+
info "It will work automatically in new terminals."
|
|
133
|
+
echo ""
|
|
134
|
+
info "Next steps:"
|
|
135
|
+
echo " minitest auth login # authenticate"
|
|
136
|
+
echo " minitest apps list # list your apps"
|
|
137
|
+
echo " minitest --help # see all commands"
|
|
138
|
+
else
|
|
139
|
+
error "Installation reported success, but 'minitest' binary was not found."
|
|
140
|
+
error "Please try reinstalling:"
|
|
141
|
+
error " uv tool install ${PACKAGE}"
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
fi
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Authentication commands: login, logout, status."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
3
5
|
from datetime import UTC, datetime
|
|
4
6
|
|
|
5
7
|
import typer
|
|
@@ -13,10 +15,37 @@ from minitest_cli.core.auth import (
|
|
|
13
15
|
oauth_pkce_login,
|
|
14
16
|
)
|
|
15
17
|
from minitest_cli.core.config import Settings
|
|
16
|
-
from minitest_cli.utils.output import output, print_error, print_success
|
|
18
|
+
from minitest_cli.utils.output import output, print_error, print_info, print_success
|
|
17
19
|
|
|
18
20
|
app = typer.Typer(name="auth", help="Authentication management.")
|
|
19
21
|
|
|
22
|
+
SKILL_NAME = "minitest-cli"
|
|
23
|
+
SKILL_INSTALL_CMD = "npx skills add minitap-ai/agent-skills --skill minitest-cli"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _is_skill_installed() -> bool:
|
|
27
|
+
"""Check if the minitest-cli skill is installed via ``npx skills ls``.
|
|
28
|
+
|
|
29
|
+
Queries both project-level and global scopes so the detection stays in
|
|
30
|
+
sync with whatever directories the ``skills`` CLI manages.
|
|
31
|
+
"""
|
|
32
|
+
for flags in (["--json"], ["--json", "-g"]):
|
|
33
|
+
try:
|
|
34
|
+
result = subprocess.run(
|
|
35
|
+
["npx", "skills", "ls", *flags],
|
|
36
|
+
capture_output=True,
|
|
37
|
+
text=True,
|
|
38
|
+
timeout=30,
|
|
39
|
+
)
|
|
40
|
+
if result.returncode == 0:
|
|
41
|
+
skills = json.loads(result.stdout)
|
|
42
|
+
if any(s.get("name") == SKILL_NAME for s in skills):
|
|
43
|
+
return True
|
|
44
|
+
except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError, OSError):
|
|
45
|
+
# npx not available or unexpected output – fall through
|
|
46
|
+
pass
|
|
47
|
+
return False
|
|
48
|
+
|
|
20
49
|
|
|
21
50
|
def _get_settings() -> Settings:
|
|
22
51
|
"""Retrieve settings stored by the main callback."""
|
|
@@ -40,6 +69,28 @@ def login() -> None:
|
|
|
40
69
|
creds = oauth_pkce_login(settings)
|
|
41
70
|
print_success(f"Authenticated as {creds.email}")
|
|
42
71
|
|
|
72
|
+
# Check if the minitest-cli agent skill is installed
|
|
73
|
+
if not _is_skill_installed():
|
|
74
|
+
print_info("")
|
|
75
|
+
print_info("💡 The minitest-cli agent skill is not installed in this project.")
|
|
76
|
+
print_info(" Your AI agent needs it to know how to use minitest.")
|
|
77
|
+
print_info("")
|
|
78
|
+
try:
|
|
79
|
+
answer = input(" Install it now? [Y/n] ").strip().lower()
|
|
80
|
+
except (EOFError, KeyboardInterrupt):
|
|
81
|
+
answer = "n"
|
|
82
|
+
print() # newline after ^C / ^D
|
|
83
|
+
if answer in ("", "y", "yes"):
|
|
84
|
+
print_info("")
|
|
85
|
+
print_info(f" Running: {SKILL_INSTALL_CMD}")
|
|
86
|
+
print_info("")
|
|
87
|
+
subprocess.run(SKILL_INSTALL_CMD.split(), check=False)
|
|
88
|
+
else:
|
|
89
|
+
print_info("")
|
|
90
|
+
print_info(" You can install it later with:")
|
|
91
|
+
print_info(f" {SKILL_INSTALL_CMD}")
|
|
92
|
+
print_info("")
|
|
93
|
+
|
|
43
94
|
|
|
44
95
|
@app.command()
|
|
45
96
|
def logout() -> None:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Maintenance check command - acknowledge test freshness for a commit."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from minitest_cli.api.client import ApiClient
|
|
8
|
+
from minitest_cli.commands.run_helpers import (
|
|
9
|
+
handle_response_error,
|
|
10
|
+
resolve_app,
|
|
11
|
+
run_api_call,
|
|
12
|
+
)
|
|
13
|
+
from minitest_cli.models.maintenance_check import MaintenanceCheckResponse
|
|
14
|
+
from minitest_cli.utils.output import print_json, print_success
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(name="maintenance-check", help="Test maintenance acknowledgment.")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.callback(invoke_without_command=True)
|
|
20
|
+
def maintenance_check(
|
|
21
|
+
ctx: typer.Context,
|
|
22
|
+
commit_sha: Annotated[str, typer.Argument(help="Git commit SHA to acknowledge.")],
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Acknowledge that tests have been reviewed for a commit."""
|
|
25
|
+
if ctx.invoked_subcommand is not None:
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
settings, app_id, json_mode = resolve_app()
|
|
29
|
+
|
|
30
|
+
async def _acknowledge() -> MaintenanceCheckResponse:
|
|
31
|
+
async with ApiClient(settings) as client:
|
|
32
|
+
body = {"commitSha": commit_sha}
|
|
33
|
+
resp = await client.post(
|
|
34
|
+
f"/api/v1/apps/{app_id}/maintenance-check",
|
|
35
|
+
json=body,
|
|
36
|
+
)
|
|
37
|
+
handle_response_error(resp, resource="Maintenance check")
|
|
38
|
+
return MaintenanceCheckResponse.model_validate(resp.json())
|
|
39
|
+
|
|
40
|
+
result = run_api_call(_acknowledge())
|
|
41
|
+
|
|
42
|
+
if json_mode:
|
|
43
|
+
print_json(
|
|
44
|
+
{
|
|
45
|
+
"id": result.id,
|
|
46
|
+
"app_id": result.app_id,
|
|
47
|
+
"commit_sha": result.commit_sha,
|
|
48
|
+
"created_at": result.created_at,
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
else:
|
|
52
|
+
print_success(f"Tests acknowledged for commit {commit_sha[:8]}")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""OAuth PKCE login flow and token refresh."""
|
|
1
|
+
"""OAuth PKCE login flow via Supabase OAuth2 server, and token refresh."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -20,9 +20,8 @@ from minitest_cli.core.config import Settings
|
|
|
20
20
|
from minitest_cli.core.credentials import Credentials
|
|
21
21
|
from minitest_cli.core.token_exchange import (
|
|
22
22
|
auth_error,
|
|
23
|
-
get_apikey_header,
|
|
24
23
|
parse_and_save_token_response,
|
|
25
|
-
|
|
24
|
+
register_oauth_client,
|
|
26
25
|
)
|
|
27
26
|
|
|
28
27
|
_ASSETS = importlib.resources.files("minitest_cli.assets")
|
|
@@ -59,31 +58,24 @@ def refresh_token(settings: Settings, creds: Credentials) -> Credentials | None:
|
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
def oauth_pkce_login(settings: Settings) -> Credentials:
|
|
62
|
-
"""Run the full OAuth PKCE login flow.
|
|
61
|
+
"""Run the full OAuth PKCE login flow via Supabase's OAuth2 server.
|
|
63
62
|
|
|
64
63
|
Steps:
|
|
65
|
-
1.
|
|
66
|
-
2.
|
|
67
|
-
3.
|
|
68
|
-
4.
|
|
69
|
-
5.
|
|
70
|
-
6.
|
|
64
|
+
1. Start local callback server
|
|
65
|
+
2. Dynamically register an OAuth2 client with Supabase
|
|
66
|
+
3. Generate PKCE code verifier + challenge
|
|
67
|
+
4. Open browser to Supabase authorize endpoint (shows hosted sign-in page)
|
|
68
|
+
5. Wait for callback with authorization code
|
|
69
|
+
6. Exchange code + verifier for tokens at Supabase token endpoint
|
|
70
|
+
7. Save and return credentials
|
|
71
71
|
"""
|
|
72
|
-
supabase_url =
|
|
72
|
+
supabase_url = settings.supabase_url.rstrip("/")
|
|
73
73
|
|
|
74
74
|
# PKCE challenge: base64url(sha256(verifier)) without padding
|
|
75
75
|
code_verifier = secrets.token_urlsafe(64)
|
|
76
76
|
digest = hashlib.sha256(code_verifier.encode()).digest()
|
|
77
77
|
code_challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode()
|
|
78
78
|
|
|
79
|
-
# CSRF protection: We do NOT generate our own state parameter.
|
|
80
|
-
# Supabase internally uses 'state' as a FlowState UUID (database key) to track
|
|
81
|
-
# the OAuth flow context (redirect_to, PKCE params, etc.). If we override it,
|
|
82
|
-
# Supabase can't find the FlowState record and falls back to Site URL.
|
|
83
|
-
# We still have CSRF protection via:
|
|
84
|
-
# 1. Supabase's FlowState UUID (validated on callback)
|
|
85
|
-
# 2. PKCE (code_challenge + code_verifier) per OAuth 2.1
|
|
86
|
-
|
|
87
79
|
# Start callback server
|
|
88
80
|
auth_code_holder: dict[str, str | None] = {"code": None, "error": None}
|
|
89
81
|
ready_event = Event()
|
|
@@ -122,17 +114,21 @@ def oauth_pkce_login(settings: Settings) -> Credentials:
|
|
|
122
114
|
port = server.server_address[1]
|
|
123
115
|
redirect_uri = f"http://127.0.0.1:{port}/callback"
|
|
124
116
|
|
|
125
|
-
#
|
|
117
|
+
# Register OAuth client with Supabase (dynamic client registration)
|
|
118
|
+
client_id = register_oauth_client(supabase_url, redirect_uri)
|
|
119
|
+
|
|
120
|
+
# Build authorize URL — Supabase's OAuth2 server shows its hosted sign-in page
|
|
126
121
|
authorize_params = urllib.parse.urlencode(
|
|
127
122
|
{
|
|
128
|
-
"
|
|
123
|
+
"client_id": client_id,
|
|
124
|
+
"redirect_uri": redirect_uri,
|
|
129
125
|
"response_type": "code",
|
|
130
126
|
"code_challenge": code_challenge,
|
|
131
127
|
"code_challenge_method": "S256",
|
|
132
|
-
"
|
|
128
|
+
"scope": "openid email profile",
|
|
133
129
|
}
|
|
134
130
|
)
|
|
135
|
-
authorize_url = f"{supabase_url}/auth/v1/authorize?{authorize_params}"
|
|
131
|
+
authorize_url = f"{supabase_url}/auth/v1/oauth/authorize?{authorize_params}"
|
|
136
132
|
|
|
137
133
|
print("Opening browser for authentication...", file=sys.stderr) # noqa: T201
|
|
138
134
|
print(f"If the browser doesn't open, visit:\n{authorize_url}", file=sys.stderr) # noqa: T201
|
|
@@ -156,16 +152,19 @@ def oauth_pkce_login(settings: Settings) -> Credentials:
|
|
|
156
152
|
if not auth_code:
|
|
157
153
|
auth_error("No authorization code received.")
|
|
158
154
|
|
|
159
|
-
# Exchange code for tokens
|
|
155
|
+
# Exchange code for tokens at Supabase's OAuth2 token endpoint
|
|
160
156
|
assert auth_code is not None # for type narrowing
|
|
161
157
|
try:
|
|
162
158
|
token_response = httpx.post(
|
|
163
|
-
f"{supabase_url}/auth/v1/token
|
|
164
|
-
|
|
165
|
-
"
|
|
159
|
+
f"{supabase_url}/auth/v1/oauth/token",
|
|
160
|
+
data={
|
|
161
|
+
"grant_type": "authorization_code",
|
|
162
|
+
"code": auth_code,
|
|
163
|
+
"redirect_uri": redirect_uri,
|
|
164
|
+
"client_id": client_id,
|
|
166
165
|
"code_verifier": code_verifier,
|
|
167
166
|
},
|
|
168
|
-
headers={"Content-Type": "application/
|
|
167
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
169
168
|
timeout=15.0,
|
|
170
169
|
)
|
|
171
170
|
except httpx.HTTPError as exc:
|
|
@@ -6,6 +6,8 @@ import sys
|
|
|
6
6
|
import time
|
|
7
7
|
from typing import Any, NoReturn
|
|
8
8
|
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
9
11
|
from minitest_cli.core.config import Settings
|
|
10
12
|
from minitest_cli.core.credentials import Credentials, save_credentials
|
|
11
13
|
|
|
@@ -51,6 +53,42 @@ def parse_and_save_token_response(settings: Settings, data: dict[str, Any]) -> C
|
|
|
51
53
|
return None
|
|
52
54
|
|
|
53
55
|
|
|
56
|
+
def register_oauth_client(supabase_url: str, redirect_uri: str) -> str:
|
|
57
|
+
"""Dynamically register an OAuth2 client with Supabase and return the client_id."""
|
|
58
|
+
register_url = f"{supabase_url}/auth/v1/oauth/clients/register"
|
|
59
|
+
try:
|
|
60
|
+
resp = httpx.post(
|
|
61
|
+
register_url,
|
|
62
|
+
json={
|
|
63
|
+
"client_name": "minitest-cli",
|
|
64
|
+
"redirect_uris": [redirect_uri],
|
|
65
|
+
"grant_types": ["authorization_code", "refresh_token"],
|
|
66
|
+
"response_types": ["code"],
|
|
67
|
+
"token_endpoint_auth_method": "none",
|
|
68
|
+
},
|
|
69
|
+
headers={"Content-Type": "application/json"},
|
|
70
|
+
timeout=15.0,
|
|
71
|
+
)
|
|
72
|
+
except httpx.HTTPError as exc:
|
|
73
|
+
auth_error(f"Failed to register OAuth client: {exc}")
|
|
74
|
+
|
|
75
|
+
if resp.status_code not in (200, 201):
|
|
76
|
+
auth_error(f"OAuth client registration failed: {resp.text}")
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
data = resp.json()
|
|
80
|
+
except ValueError:
|
|
81
|
+
auth_error(
|
|
82
|
+
f"OAuth client registration returned invalid response "
|
|
83
|
+
f"(HTTP {resp.status_code}): {resp.text}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
client_id: str | None = data.get("client_id")
|
|
87
|
+
if not client_id:
|
|
88
|
+
auth_error("OAuth client registration returned no client_id.")
|
|
89
|
+
return client_id # type: ignore[return-value]
|
|
90
|
+
|
|
91
|
+
|
|
54
92
|
def auth_error(message: str) -> NoReturn:
|
|
55
93
|
"""Print auth error to stderr and exit with code 2."""
|
|
56
94
|
print(f"Error: {message}", file=sys.stderr) # noqa: T201
|
|
@@ -5,7 +5,7 @@ from typing import Annotated
|
|
|
5
5
|
import typer
|
|
6
6
|
|
|
7
7
|
from minitest_cli import __version__
|
|
8
|
-
from minitest_cli.commands import apps, auth, build, flow, run, skill
|
|
8
|
+
from minitest_cli.commands import apps, auth, build, flow, maintenance_check, run, skill
|
|
9
9
|
from minitest_cli.core.config import get_settings
|
|
10
10
|
from minitest_cli.utils.update_check import check_for_updates
|
|
11
11
|
|
|
@@ -21,6 +21,7 @@ app.add_typer(auth.app)
|
|
|
21
21
|
app.add_typer(apps.app)
|
|
22
22
|
app.add_typer(flow.app)
|
|
23
23
|
app.add_typer(build.app)
|
|
24
|
+
app.add_typer(maintenance_check.app)
|
|
24
25
|
app.add_typer(run.app)
|
|
25
26
|
app.add_typer(skill.app)
|
|
26
27
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Models for maintenance check responses."""
|
|
2
|
+
|
|
3
|
+
from minitest_cli.models.base import CamelModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MaintenanceCheckResponse(CamelModel):
|
|
7
|
+
"""Response from creating a maintenance check acknowledgment."""
|
|
8
|
+
|
|
9
|
+
id: str
|
|
10
|
+
app_id: str
|
|
11
|
+
commit_sha: str
|
|
12
|
+
created_at: str
|
minitest_cli-0.4.4/README.md
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# minitest-cli
|
|
2
|
-
|
|
3
|
-
Command-line interface for the Minitest testing platform.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
### pip (recommended)
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pip install minitest-cli
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### uvx (zero-install)
|
|
14
|
-
|
|
15
|
-
Run without installing:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
uvx --from minitest-cli minitest --help
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### Homebrew
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
brew install minitap-ai/tap/minitest-cli
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### From source
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
git clone https://github.com/minitap-ai/minitest-cli.git
|
|
31
|
-
cd minitest-cli
|
|
32
|
-
uv sync
|
|
33
|
-
uv run minitest --help
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Quick Start
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
# Authenticate
|
|
40
|
-
minitest auth login
|
|
41
|
-
|
|
42
|
-
# List your apps
|
|
43
|
-
minitest apps list
|
|
44
|
-
|
|
45
|
-
# Run tests
|
|
46
|
-
minitest run --app <app-id>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Configuration
|
|
50
|
-
|
|
51
|
-
| Environment Variable | Description | Required |
|
|
52
|
-
|---------------------|-------------|----------|
|
|
53
|
-
| `MINITEST_TOKEN` | API authentication token | Yes (or use `minitest auth login`) |
|
|
54
|
-
| `MINITEST_APP_ID` | Default app ID | No (can use `--app` flag) |
|
|
55
|
-
| `MINITEST_API_URL` | API base URL | No (defaults to production) |
|
|
56
|
-
|
|
57
|
-
## Global Flags
|
|
58
|
-
|
|
59
|
-
| Flag | Description |
|
|
60
|
-
|------|-------------|
|
|
61
|
-
| `--json` | Output JSON to stdout (diagnostics go to stderr) |
|
|
62
|
-
| `--app <id-or-name>` | Target app for commands that require one |
|
|
63
|
-
| `--version` | Show CLI version |
|
|
64
|
-
| `--help` | Show help |
|
|
65
|
-
|
|
66
|
-
## Commands
|
|
67
|
-
|
|
68
|
-
| Command | Description |
|
|
69
|
-
|---------|-------------|
|
|
70
|
-
| `minitest auth` | Authentication management |
|
|
71
|
-
| `minitest apps` | App management |
|
|
72
|
-
| `minitest flow` | Testing flow operations |
|
|
73
|
-
| `minitest build` | Build management |
|
|
74
|
-
| `minitest run` | Test execution |
|
|
75
|
-
|
|
76
|
-
## Exit Codes
|
|
77
|
-
|
|
78
|
-
| Code | Meaning |
|
|
79
|
-
|------|---------|
|
|
80
|
-
| 0 | Success |
|
|
81
|
-
| 1 | General error |
|
|
82
|
-
| 2 | Authentication error |
|
|
83
|
-
| 3 | Network / API error |
|
|
84
|
-
| 4 | Resource not found |
|
|
85
|
-
|
|
86
|
-
## Using the Dev Environment
|
|
87
|
-
|
|
88
|
-
To point the CLI at the **dev** environment instead of production, set these environment variables when running `minitest`:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
MINITEST_SUPABASE_URL=https://qrezuucghnmfvaxghqsv.supabase.co \
|
|
92
|
-
MINITEST_SUPABASE_PUBLISHABLE_KEY=sb_publishable_4JRhoCm8pa5PbII0dhS09A_jhpkQhmy \
|
|
93
|
-
MINITEST_API_URL=https://testing-service.dev.minitap.ai \
|
|
94
|
-
minitest auth login
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This authenticates against the dev environment and stores a dev-specific auth token. After logging in, keep the same variables set for all subsequent commands:
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
MINITEST_SUPABASE_URL=https://qrezuucghnmfvaxghqsv.supabase.co \
|
|
101
|
-
MINITEST_SUPABASE_PUBLISHABLE_KEY=sb_publishable_4JRhoCm8pa5PbII0dhS09A_jhpkQhmy \
|
|
102
|
-
MINITEST_API_URL=https://testing-service.dev.minitap.ai \
|
|
103
|
-
minitest apps list
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
> **Tip:** You can `export` these variables in your shell session (or add them to a `.envrc` / `.env` file) to avoid repeating them on every invocation.
|
|
107
|
-
|
|
108
|
-
## Development
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
# Install dependencies
|
|
112
|
-
uv sync --dev
|
|
113
|
-
|
|
114
|
-
# Run linter
|
|
115
|
-
uv run ruff check .
|
|
116
|
-
|
|
117
|
-
# Run formatter
|
|
118
|
-
uv run ruff format .
|
|
119
|
-
|
|
120
|
-
# Run type checker
|
|
121
|
-
uv run pyright
|
|
122
|
-
|
|
123
|
-
# Run tests
|
|
124
|
-
uv run pytest
|
|
125
|
-
```
|
|
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
|
|
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
|