mozbridge-cli 0.2.0__tar.gz → 0.3.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.
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/PKG-INFO +1 -1
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/docs/commands.md +190 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/pyproject.toml +1 -1
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/scripts/release.sh +17 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/api.py +552 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_auth.py +152 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_deploy.py +307 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_env.py +115 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_projects.py +92 -0
- mozbridge_cli-0.2.0/src/mozbridge_cli/main.py → mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_publish.py +8 -331
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_registry.py +97 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_secrets.py +165 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/cmd_shared.py +31 -0
- mozbridge_cli-0.3.0/src/mozbridge_cli/main.py +49 -0
- mozbridge_cli-0.3.0/tests/test_deploy.py +268 -0
- mozbridge_cli-0.3.0/tests/test_env.py +242 -0
- mozbridge_cli-0.3.0/tests/test_logs.py +252 -0
- mozbridge_cli-0.3.0/tests/test_registry.py +196 -0
- mozbridge_cli-0.3.0/tests/test_secrets.py +294 -0
- mozbridge_cli-0.2.0/src/mozbridge_cli/api.py +0 -274
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/.gitignore +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/README.md +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/__init__.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/__main__.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/auth.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/build.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/compose.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/config.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/link.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/local_build.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/runtime_secrets.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/src/mozbridge_cli/session.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/conftest.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_build.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_ci_token_auth.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_compose.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_diff.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_link.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_local_build.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_login.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_login_cli.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_logout.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_publish.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_publish_local.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_publish_multi_component.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_refresh.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_rollback.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_runtime_secrets.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_session_permissions.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_status.py +0 -0
- {mozbridge_cli-0.2.0 → mozbridge_cli-0.3.0}/tests/test_whoami.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mozbridge-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Command-line client for the Mozbridge deployment platform: SSO login, build, publish, status, and rollback for any project hosted on Mozbridge.
|
|
5
5
|
Project-URL: Homepage, https://mozbridge.com
|
|
6
6
|
Project-URL: Documentation, https://github.com/jessin01/mozbridge/blob/main/cli/docs/commands.md
|
|
@@ -547,6 +547,196 @@ Rollback triggered (task_id=777).
|
|
|
547
547
|
|
|
548
548
|
---
|
|
549
549
|
|
|
550
|
+
## `mozbridge deploy`
|
|
551
|
+
|
|
552
|
+
Deploys an already-built image tag to the linked Mozbridge project. A real,
|
|
553
|
+
consequential production action — same category as `mozbridge rollback`: it
|
|
554
|
+
mutates production the moment it's called, **not a dry-run**. Prompts for
|
|
555
|
+
confirmation unless `--yes` is given.
|
|
556
|
+
|
|
557
|
+
**Flags**:
|
|
558
|
+
| Flag | Meaning |
|
|
559
|
+
|---|---|
|
|
560
|
+
| `--frontend TAG` | Frontend image tag to deploy. |
|
|
561
|
+
| `--backend TAG` | Backend image tag to deploy. |
|
|
562
|
+
| `--env NAME` | Environment to deploy to. Default `prod`. |
|
|
563
|
+
| `--force` | Override a blocking preflight check. Never set automatically — a separate, explicit decision each time. |
|
|
564
|
+
| `--yes` | Skip the interactive confirmation prompt. |
|
|
565
|
+
|
|
566
|
+
**Requires**: link + login, same as `publish`/`status`/`rollback`. At least
|
|
567
|
+
one of `--frontend`/`--backend` must be given — deploying neither makes no
|
|
568
|
+
sense.
|
|
569
|
+
|
|
570
|
+
**What it does**: prints what it's about to do (project, which service(s),
|
|
571
|
+
which tag(s), which environment), then either aborts on a declined prompt or
|
|
572
|
+
calls `POST /api/v1/projects/{project_id}/deploy` with
|
|
573
|
+
`{frontend_version, backend_version, services, environment, force}`.
|
|
574
|
+
**`services` is built from which of `--frontend`/`--backend` you actually
|
|
575
|
+
gave a tag** — not the API's own default of deploying both — so the CLI only
|
|
576
|
+
ever asks the platform to deploy what you specified.
|
|
577
|
+
|
|
578
|
+
The backend runs a preflight check before enqueuing the deploy. A 409
|
|
579
|
+
response means it found a real, known-to-fail condition and refused —
|
|
580
|
+
each blocking check is printed with its title, detail, and suggested
|
|
581
|
+
action, followed by a hint to re-run with `--force` if you want to override
|
|
582
|
+
it. **The CLI never retries with `--force` automatically** — that is always
|
|
583
|
+
a separate, explicit re-invocation.
|
|
584
|
+
|
|
585
|
+
**Example (`--yes`, single service)**:
|
|
586
|
+
```
|
|
587
|
+
$ mozbridge deploy --backend v1.9.319 --yes
|
|
588
|
+
This will deploy acme/web-app (prod):
|
|
589
|
+
backend -> v1.9.319
|
|
590
|
+
Deploy triggered (task_id=888).
|
|
591
|
+
Run `mozbridge logs` to watch it.
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
**Example (preflight blocked)**:
|
|
595
|
+
```
|
|
596
|
+
$ mozbridge deploy --backend v1.9.319 --yes
|
|
597
|
+
This will deploy acme/web-app (prod):
|
|
598
|
+
backend -> v1.9.319
|
|
599
|
+
Preflight failed — this deploy is known to fail.
|
|
600
|
+
- No registry credential: GHCR_TOKEN is not configured for this project.
|
|
601
|
+
action: Set a registry credential in Project Settings.
|
|
602
|
+
Pass force=true to deploy anyway.
|
|
603
|
+
Re-run with --force to override — this is not done automatically.
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
**Failure modes**:
|
|
607
|
+
- Neither `--frontend` nor `--backend` given: clear error, exit 1, no API
|
|
608
|
+
call is made.
|
|
609
|
+
- Not linked / not logged in: identical messages to `publish` above, exit 1.
|
|
610
|
+
- Confirmation prompt declined (`--yes` not passed, answer is not `y`):
|
|
611
|
+
Typer's own `Abort` handling — the command exits non-zero without calling
|
|
612
|
+
the API.
|
|
613
|
+
- Preflight-blocked (409, structured body): every blocking check printed
|
|
614
|
+
clearly plus a `--force` hint, exit 1 — no automatic retry.
|
|
615
|
+
- Any other API error: the raw `ApiError` message, exit 1.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## `mozbridge logs`
|
|
620
|
+
|
|
621
|
+
Shows **BUILD/DEPLOY OPERATION logs** for the linked project — the log
|
|
622
|
+
output of a Mozbridge build or deploy task (what `publish`, `deploy`, and
|
|
623
|
+
`rollback` trigger). **This is not your running application's
|
|
624
|
+
runtime/request logs** — the platform does not expose those via any API
|
|
625
|
+
today, and this command is not `docker logs` for your live app.
|
|
626
|
+
|
|
627
|
+
**Flags**:
|
|
628
|
+
| Flag | Meaning |
|
|
629
|
+
|---|---|
|
|
630
|
+
| `TASK_ID` (argument, optional) | Task id of a build/deploy operation. Omit to use the most recent one for this project. |
|
|
631
|
+
| `--follow` / `-f` | Stream new log output as it arrives; exits when the run finishes. |
|
|
632
|
+
|
|
633
|
+
**Requires**: link + login, same as `status`/`diff`/`rollback`.
|
|
634
|
+
|
|
635
|
+
**What it does**:
|
|
636
|
+
- If `TASK_ID` is omitted: `GET /api/v1/projects/{project_id}/operations?limit=1`
|
|
637
|
+
(newest-first, same ordering `status`/`diff` already rely on for
|
|
638
|
+
deployments) to resolve the most recent operation's `task_id`.
|
|
639
|
+
- Without `--follow`: one `GET /api/v1/projects/operations/{task_id}` call,
|
|
640
|
+
printing whatever is in `result.logs` right now — a single snapshot, no
|
|
641
|
+
long-lived connection.
|
|
642
|
+
- With `--follow`: opens `GET /api/v1/projects/operations/{task_id}/stream`
|
|
643
|
+
(SSE) and prints each `log` event's content as it's parsed. The server
|
|
644
|
+
closes the stream itself once the operation reaches a terminal state
|
|
645
|
+
(success/failed/error) — the CLI exits cleanly at that point. A dropped
|
|
646
|
+
connection surfaces a clear error instead of hanging.
|
|
647
|
+
|
|
648
|
+
**Example (snapshot)**:
|
|
649
|
+
```
|
|
650
|
+
$ mozbridge logs task-123
|
|
651
|
+
Step 1/5 : FROM python:3.12
|
|
652
|
+
Step 2/5 : COPY . /app
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**Example (follow)**:
|
|
656
|
+
```
|
|
657
|
+
$ mozbridge logs task-123 --follow
|
|
658
|
+
Step 1/5 : FROM python:3.12
|
|
659
|
+
Step 2/5 : COPY . /app
|
|
660
|
+
Successfully built abc123
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
**Failure modes**:
|
|
664
|
+
- Not linked / not logged in: identical messages to `publish` above, exit 1.
|
|
665
|
+
- No `TASK_ID` given and the project has no operations yet: `No operations
|
|
666
|
+
found for this project yet.`, exit 1.
|
|
667
|
+
- The operation lookup or stream request fails: the raw `ApiError` message
|
|
668
|
+
(snapshot mode) or `Log stream connection dropped: <error>` (`--follow`),
|
|
669
|
+
exit 1.
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## `mozbridge env list` / `mozbridge env set` / `mozbridge env rm`
|
|
674
|
+
|
|
675
|
+
Manages the linked project's environment variables
|
|
676
|
+
(`GET`/`POST`/`DELETE /api/v1/projects/{project_id}/env-vars[...]`).
|
|
677
|
+
`EnvVar` is a plain `{key, value}` pair — distinct from the project's
|
|
678
|
+
separate Vault-backed secrets blocks — and nothing in the platform's own
|
|
679
|
+
dashboard UI masks these values, so `env list` prints them in plain text.
|
|
680
|
+
|
|
681
|
+
**Requires**: link + login, same as `status`/`diff`/`rollback`.
|
|
682
|
+
|
|
683
|
+
### `mozbridge env list`
|
|
684
|
+
|
|
685
|
+
**Flags**: none.
|
|
686
|
+
|
|
687
|
+
**What it does**: `GET /api/v1/projects/{project_id}/env-vars`, prints every
|
|
688
|
+
key/value pair sorted by key. Prints `No environment variables set.` if
|
|
689
|
+
there are none.
|
|
690
|
+
|
|
691
|
+
```
|
|
692
|
+
$ mozbridge env list
|
|
693
|
+
DATABASE_URL postgres://user:pass@host/db
|
|
694
|
+
DEBUG false
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### `mozbridge env set KEY VALUE`
|
|
698
|
+
|
|
699
|
+
**What it does**: `POST /api/v1/projects/{project_id}/env-vars` with body
|
|
700
|
+
`{"key": KEY, "value": VALUE}`. **This is an upsert, not create-only** —
|
|
701
|
+
read directly off `backend/app/security.py:store_project_env_var`: the
|
|
702
|
+
handler loads the existing key->value dict out of Vault, does
|
|
703
|
+
`existing[key] = value`, and writes the whole dict back. Setting an
|
|
704
|
+
already-existing `KEY` silently overwrites it; there is no 409/400 and no
|
|
705
|
+
separate create-vs-update codepath.
|
|
706
|
+
|
|
707
|
+
The confirmation deliberately prints only the key, never the value, so a
|
|
708
|
+
secret-shaped `VALUE` isn't echoed a second time into your terminal beyond
|
|
709
|
+
the command invocation itself:
|
|
710
|
+
|
|
711
|
+
```
|
|
712
|
+
$ mozbridge env set DATABASE_URL postgres://user:pass@host/db
|
|
713
|
+
Set DATABASE_URL.
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### `mozbridge env rm KEY`
|
|
717
|
+
|
|
718
|
+
**What it does**: `DELETE /api/v1/projects/{project_id}/env-vars/{KEY}`.
|
|
719
|
+
**This is idempotent, not a strict "must exist" delete** — read directly
|
|
720
|
+
off `backend/app/security.py:delete_project_env_var`: it deletes `KEY`
|
|
721
|
+
`if key in existing`, and otherwise falls straight through to `return
|
|
722
|
+
True` — either way the route responds 200. Removing a `KEY` that was never
|
|
723
|
+
set still reports success; there is no 404 for a missing key, and this
|
|
724
|
+
command does not invent one.
|
|
725
|
+
|
|
726
|
+
```
|
|
727
|
+
$ mozbridge env rm DATABASE_URL
|
|
728
|
+
Removed DATABASE_URL.
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**Failure modes (all three)**:
|
|
732
|
+
- Not linked / not logged in: identical messages to `publish` above, exit 1.
|
|
733
|
+
- Any other API error (e.g. a 500 from a Vault write/delete failure): the
|
|
734
|
+
raw `ApiError` message (`Could not list env vars: <detail>` / `Could not
|
|
735
|
+
set the env var: <detail>` / `Could not remove the env var: <detail>`),
|
|
736
|
+
exit 1.
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
550
740
|
## A note on authorization for `publish` / `rollback`
|
|
551
741
|
|
|
552
742
|
Both commands work today because a plain human Logto session token passes
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mozbridge-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Command-line client for the Mozbridge deployment platform: SSO login, build, publish, status, and rollback for any project hosted on Mozbridge."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -10,8 +10,25 @@
|
|
|
10
10
|
set -euo pipefail
|
|
11
11
|
|
|
12
12
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
13
|
+
REPO_ROOT="$(cd "$ROOT/.." && pwd)"
|
|
13
14
|
PYPROJECT="$ROOT/pyproject.toml"
|
|
14
15
|
|
|
16
|
+
# Hard first check: `git fetch` updates the remote-tracking ref, not the
|
|
17
|
+
# working tree — only merge/rebase/pull do that. mozbridge-cli 0.2.0 was
|
|
18
|
+
# published missing 3 commands because this build ran between a `git
|
|
19
|
+
# fetch` and the merge that would have actually updated the checkout.
|
|
20
|
+
# Refuse to build from a checkout that's behind origin/main.
|
|
21
|
+
if command -v git >/dev/null 2>&1 && git -C "$REPO_ROOT" rev-parse --git-dir >/dev/null 2>&1; then
|
|
22
|
+
git -C "$REPO_ROOT" fetch origin main --quiet 2>/dev/null || true
|
|
23
|
+
BEHIND="$(git -C "$REPO_ROOT" rev-list --count HEAD..origin/main 2>/dev/null || echo 0)"
|
|
24
|
+
if [ "${BEHIND:-0}" != "0" ]; then
|
|
25
|
+
echo "✗ Local main is ${BEHIND} commit(s) behind origin/main." >&2
|
|
26
|
+
echo " Run: git -C \"$REPO_ROOT\" merge --ff-only origin/main" >&2
|
|
27
|
+
echo " then re-run this script. Refusing to build a stale release." >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
15
32
|
usage() {
|
|
16
33
|
echo "Usage: $0 [--patch|--minor|--major] [--dry-run]" >&2
|
|
17
34
|
echo " Default bump: patch" >&2
|