mkit-cli 0.3.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.
- mkit_cli-0.3.1/.gitattributes +19 -0
- mkit_cli-0.3.1/.github/ISSUE_TEMPLATE/bug_report.yml +58 -0
- mkit_cli-0.3.1/.github/ISSUE_TEMPLATE/config.yml +11 -0
- mkit_cli-0.3.1/.github/workflows/publish.yml +48 -0
- mkit_cli-0.3.1/.github/workflows/tests.yml +37 -0
- mkit_cli-0.3.1/.gitignore +7 -0
- mkit_cli-0.3.1/AGENTS.md +89 -0
- mkit_cli-0.3.1/CHANGELOG.md +57 -0
- mkit_cli-0.3.1/CONTRIBUTING.md +71 -0
- mkit_cli-0.3.1/LICENSE +21 -0
- mkit_cli-0.3.1/PKG-INFO +179 -0
- mkit_cli-0.3.1/README.md +147 -0
- mkit_cli-0.3.1/SECURITY.md +39 -0
- mkit_cli-0.3.1/docs/commands.md +1057 -0
- mkit_cli-0.3.1/docs/config.md +309 -0
- mkit_cli-0.3.1/docs/in-app-update.md +467 -0
- mkit_cli-0.3.1/docs/news-topics.md +65 -0
- mkit_cli-0.3.1/docs/store-art.md +245 -0
- mkit_cli-0.3.1/docs/store.md +139 -0
- mkit_cli-0.3.1/pyproject.toml +55 -0
- mkit_cli-0.3.1/scripts/gen_docs.py +14 -0
- mkit_cli-0.3.1/scripts/release.py +69 -0
- mkit_cli-0.3.1/src/mkit/__init__.py +5 -0
- mkit_cli-0.3.1/src/mkit/art.py +1220 -0
- mkit_cli-0.3.1/src/mkit/aso.py +359 -0
- mkit_cli-0.3.1/src/mkit/cli.py +176 -0
- mkit_cli-0.3.1/src/mkit/cloud/__init__.py +1 -0
- mkit_cli-0.3.1/src/mkit/cloud/auth.py +130 -0
- mkit_cli-0.3.1/src/mkit/cloud/fbproject.py +180 -0
- mkit_cli-0.3.1/src/mkit/cloud/firebase.py +164 -0
- mkit_cli-0.3.1/src/mkit/cloud/insight.py +286 -0
- mkit_cli-0.3.1/src/mkit/cloud/money.py +676 -0
- mkit_cli-0.3.1/src/mkit/cloud/play.py +497 -0
- mkit_cli-0.3.1/src/mkit/cloud/store.py +390 -0
- mkit_cli-0.3.1/src/mkit/commands/__init__.py +2 -0
- mkit_cli-0.3.1/src/mkit/commands/art.py +116 -0
- mkit_cli-0.3.1/src/mkit/commands/aso.py +130 -0
- mkit_cli-0.3.1/src/mkit/commands/dev.py +256 -0
- mkit_cli-0.3.1/src/mkit/commands/doctor.py +191 -0
- mkit_cli-0.3.1/src/mkit/commands/firebase_cmds.py +194 -0
- mkit_cli-0.3.1/src/mkit/commands/init.py +213 -0
- mkit_cli-0.3.1/src/mkit/commands/insight.py +110 -0
- mkit_cli-0.3.1/src/mkit/commands/meta.py +84 -0
- mkit_cli-0.3.1/src/mkit/commands/money.py +152 -0
- mkit_cli-0.3.1/src/mkit/commands/release.py +430 -0
- mkit_cli-0.3.1/src/mkit/commands/selfcmd.py +167 -0
- mkit_cli-0.3.1/src/mkit/commands/store.py +263 -0
- mkit_cli-0.3.1/src/mkit/config.py +146 -0
- mkit_cli-0.3.1/src/mkit/data/art/art.toml +119 -0
- mkit_cli-0.3.1/src/mkit/data/art/en.json +38 -0
- mkit_cli-0.3.1/src/mkit/data/datasafety-questions.csv +783 -0
- mkit_cli-0.3.1/src/mkit/datasafety.py +302 -0
- mkit_cli-0.3.1/src/mkit/device.py +246 -0
- mkit_cli-0.3.1/src/mkit/docgen.py +100 -0
- mkit_cli-0.3.1/src/mkit/errors.py +78 -0
- mkit_cli-0.3.1/src/mkit/git.py +95 -0
- mkit_cli-0.3.1/src/mkit/hooks.py +32 -0
- mkit_cli-0.3.1/src/mkit/kinds.py +350 -0
- mkit_cli-0.3.1/src/mkit/notify.py +49 -0
- mkit_cli-0.3.1/src/mkit/output.py +377 -0
- mkit_cli-0.3.1/src/mkit/proc.py +154 -0
- mkit_cli-0.3.1/src/mkit/registry.py +99 -0
- mkit_cli-0.3.1/src/mkit/safety.py +60 -0
- mkit_cli-0.3.1/src/mkit/secrets.py +148 -0
- mkit_cli-0.3.1/src/mkit/toolchain.py +210 -0
- mkit_cli-0.3.1/tests/conftest.py +26 -0
- mkit_cli-0.3.1/tests/fakeplay.py +290 -0
- mkit_cli-0.3.1/tests/test_art.py +435 -0
- mkit_cli-0.3.1/tests/test_aso.py +88 -0
- mkit_cli-0.3.1/tests/test_core.py +276 -0
- mkit_cli-0.3.1/tests/test_datasafety.py +253 -0
- mkit_cli-0.3.1/tests/test_device_logs.py +157 -0
- mkit_cli-0.3.1/tests/test_docs.py +28 -0
- mkit_cli-0.3.1/tests/test_firebase_apps.py +80 -0
- mkit_cli-0.3.1/tests/test_network_errors.py +82 -0
- mkit_cli-0.3.1/tests/test_products.py +359 -0
- mkit_cli-0.3.1/tests/test_release.py +413 -0
- mkit_cli-0.3.1/tests/test_store.py +247 -0
- mkit_cli-0.3.1/tests/test_studio.py +110 -0
- mkit_cli-0.3.1/uv.lock +701 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Everything text lands in the working tree as LF, on every platform.
|
|
2
|
+
#
|
|
3
|
+
# Not a preference. mkit generates docs/commands.md from docstrings in the
|
|
4
|
+
# source, so a checkout that rewrote those files to CRLF made the generator
|
|
5
|
+
# produce a different reference than the one in the repo — the suite went red
|
|
6
|
+
# on Windows for a file nobody had touched. Pinning the endings removes the
|
|
7
|
+
# whole class of it.
|
|
8
|
+
* text=auto eol=lf
|
|
9
|
+
|
|
10
|
+
# Shell scripts must stay LF wherever they run.
|
|
11
|
+
*.sh text eol=lf
|
|
12
|
+
|
|
13
|
+
# Binary, never touched.
|
|
14
|
+
*.png binary
|
|
15
|
+
*.jpg binary
|
|
16
|
+
*.webp binary
|
|
17
|
+
*.ttf binary
|
|
18
|
+
*.otf binary
|
|
19
|
+
*.woff2 binary
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: A command did the wrong thing, or stopped doing anything
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Please do not paste a service account key or a `.env`.
|
|
9
|
+
`mkit <command> --json` is safe to share: it names missing credentials
|
|
10
|
+
and prints none of them.
|
|
11
|
+
|
|
12
|
+
- type: input
|
|
13
|
+
id: command
|
|
14
|
+
attributes:
|
|
15
|
+
label: The command
|
|
16
|
+
placeholder: mkit deploy --dry-run
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: output
|
|
22
|
+
attributes:
|
|
23
|
+
label: What it printed
|
|
24
|
+
description: The JSON envelope if you have it — `mkit <command> --json`.
|
|
25
|
+
render: shell
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: expected
|
|
31
|
+
attributes:
|
|
32
|
+
label: What you expected instead
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
|
|
36
|
+
- type: dropdown
|
|
37
|
+
id: kind
|
|
38
|
+
attributes:
|
|
39
|
+
label: App kind
|
|
40
|
+
options: [flutter, android, android-wear, not sure]
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
43
|
+
|
|
44
|
+
- type: input
|
|
45
|
+
id: versions
|
|
46
|
+
attributes:
|
|
47
|
+
label: mkit and OS
|
|
48
|
+
description: "`mkit --version`, and which OS."
|
|
49
|
+
placeholder: "0.3.1 on Windows 11"
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
52
|
+
|
|
53
|
+
- type: textarea
|
|
54
|
+
id: doctor
|
|
55
|
+
attributes:
|
|
56
|
+
label: mkit doctor --json
|
|
57
|
+
description: Optional, and safe to paste — it never prints a secret.
|
|
58
|
+
render: json
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Something only Play Console can do
|
|
4
|
+
url: https://github.com/almasumdev/mkit-cli/blob/main/docs/commands.md
|
|
5
|
+
about: >-
|
|
6
|
+
Creating an app, content rating, target audience, tester email lists,
|
|
7
|
+
production access and App access credentials have no API. `mkit manual`
|
|
8
|
+
lists them — those are not bugs in mkit.
|
|
9
|
+
- name: Security issue
|
|
10
|
+
url: https://github.com/almasumdev/mkit-cli/security/advisories/new
|
|
11
|
+
about: Anything exposing a credential or publishing without confirmation. Please report privately.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a version tag is pushed. No token lives here: PyPI's
|
|
4
|
+
# trusted publishing verifies the workflow's own identity, so there is nothing
|
|
5
|
+
# to leak and nothing to rotate.
|
|
6
|
+
#
|
|
7
|
+
# One-time setup, on https://pypi.org/manage/account/publishing/ :
|
|
8
|
+
# PyPI project name mkit-cli
|
|
9
|
+
# Owner almasumdev
|
|
10
|
+
# Repository mkit-cli
|
|
11
|
+
# Workflow publish.yml
|
|
12
|
+
# Environment pypi
|
|
13
|
+
# Then make a release: scripts/release.py minor go && git push --follow-tags
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
tags: ["v*"]
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: astral-sh/setup-uv@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
# The tag is not a release until the suite says so.
|
|
29
|
+
- run: uv sync --all-extras --dev
|
|
30
|
+
- run: uv run pytest -q
|
|
31
|
+
- run: uv build
|
|
32
|
+
- uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: dist
|
|
35
|
+
path: dist/
|
|
36
|
+
|
|
37
|
+
publish:
|
|
38
|
+
needs: build
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
environment: pypi
|
|
41
|
+
permissions:
|
|
42
|
+
id-token: write # what trusted publishing signs with
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/download-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
pytest:
|
|
11
|
+
# Three platforms because mkit shells out to git, gradle, adb and a JDK, and
|
|
12
|
+
# finds each of them differently per OS. Everything here runs against the
|
|
13
|
+
# fake Play service in tests/ — no job touches a real account.
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
18
|
+
python: ["3.11", "3.13"]
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python }}
|
|
27
|
+
|
|
28
|
+
- name: Install
|
|
29
|
+
run: uv sync --all-extras --dev
|
|
30
|
+
|
|
31
|
+
- name: Tests
|
|
32
|
+
run: uv run pytest -q
|
|
33
|
+
|
|
34
|
+
- name: Generated docs are current
|
|
35
|
+
# docs/commands.md is generated from the command registry; a stale one
|
|
36
|
+
# means a flag was changed without the reference following it.
|
|
37
|
+
run: uv run python scripts/gen_docs.py && git diff --exit-code docs/commands.md
|
mkit_cli-0.3.1/AGENTS.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# mkit for AI agents
|
|
2
|
+
|
|
3
|
+
Read this before running mkit in any app.
|
|
4
|
+
|
|
5
|
+
## The release rule
|
|
6
|
+
|
|
7
|
+
**Never run a release or publish command unless the user asked for that
|
|
8
|
+
exact action in this conversation.** Not to test, not to verify a change,
|
|
9
|
+
not as a "safe" dry run.
|
|
10
|
+
|
|
11
|
+
Release and publish commands:
|
|
12
|
+
|
|
13
|
+
| Command | Changes |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `deploy` (including `deploy --dry-run`) | builds, bumps and commits the version, uploads to Play |
|
|
16
|
+
| `promote`, `rollout` | what users on a track get |
|
|
17
|
+
| `listing apply`, `datasafety apply`, `testers set` | the store listing and testing setup |
|
|
18
|
+
| `products apply` | in-app products and prices |
|
|
19
|
+
| `rules`, `config set`, `remoteconfig apply`, `remoteconfig rollback` | the live Firebase project |
|
|
20
|
+
| `reviews reply` | a public reply |
|
|
21
|
+
| `bump`, `share` | the app's version commit; a build handed to testers |
|
|
22
|
+
|
|
23
|
+
`deploy --dry-run` is on the list because it bumps and builds, uploads a
|
|
24
|
+
full bundle to Play and takes minutes; it is still release work.
|
|
25
|
+
|
|
26
|
+
When the user does ask:
|
|
27
|
+
|
|
28
|
+
1. Say exactly what will happen (app, version, track, what changes).
|
|
29
|
+
2. Run the plan form first where there is one (`listing plan`,
|
|
30
|
+
`products plan`, `remoteconfig plan`) and show the result.
|
|
31
|
+
3. Run it with `--yes --confirm <package>`. The engine refuses without both
|
|
32
|
+
when it is not at a terminal (exit 6). `safety.no_prompt` does not change
|
|
33
|
+
this: it only spares a person at a terminal the typed confirmation. Approval covers that one action;
|
|
34
|
+
the next publish needs a new one.
|
|
35
|
+
|
|
36
|
+
## Free to run
|
|
37
|
+
|
|
38
|
+
Everything else, when it helps the task: `doctor`, `status`, `version`,
|
|
39
|
+
`commands`, `schema`, `manual`, `self status`, `devices`, `listing plan`,
|
|
40
|
+
`products plan`, `remoteconfig plan`, `whatsnew check`, `datasafety check`,
|
|
41
|
+
`stats`, `vitals`, `crashes`, `reviews list`, `aso rank`, `aso score`,
|
|
42
|
+
`config show`, `testers show`, `products list`, `prices convert`,
|
|
43
|
+
`firebase sha`, `remoteconfig versions`.
|
|
44
|
+
|
|
45
|
+
`run` builds and installs on a device: only when the user wants the app on a
|
|
46
|
+
device, and only on the device they mean.
|
|
47
|
+
|
|
48
|
+
`studio` opens a window on the user's screen: only when they ask for it.
|
|
49
|
+
|
|
50
|
+
## Discover, don't guess
|
|
51
|
+
|
|
52
|
+
- `mkit commands --json`: every command with its risk class, needed
|
|
53
|
+
features, and a JSON Schema of its input.
|
|
54
|
+
- `mkit schema <command> --json`: one command in detail.
|
|
55
|
+
- `mkit doctor --json`: which features this app uses and what is broken.
|
|
56
|
+
- `mkit manual`: what only Play Console can do. Tell the user; don't look for
|
|
57
|
+
a workaround.
|
|
58
|
+
- Reference: `docs/commands.md`, `docs/config.md`.
|
|
59
|
+
|
|
60
|
+
## Output contract
|
|
61
|
+
|
|
62
|
+
Off a terminal mkit prints JSON on its own. stdout is exactly one envelope:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{"ok": true, "command": "...", "exit": 0, "result": {}, "warnings": [], "skipped": []}
|
|
66
|
+
{"ok": false, "command": "...", "exit": 3, "error": {"code": "...", "message": "...", "hint": "...", "retryable": false}}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
stderr has one JSON event per line (`step`, `done`, `detail`, `warn`,
|
|
70
|
+
`skipped`, `upload`, `log`). Branch on `exit`; follow `error.hint`.
|
|
71
|
+
|
|
72
|
+
| exit | meaning | what to do |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| 0 | ok | |
|
|
75
|
+
| 1 | failed | read `error`, report it |
|
|
76
|
+
| 2 | usage | fix the arguments |
|
|
77
|
+
| 3 | credential missing | tell the user which key `hint` names; never ask for the secret itself |
|
|
78
|
+
| 4 | not found | |
|
|
79
|
+
| 5 | conflict: remote changed, edit expired, already in review | re-run the plan, then ask again |
|
|
80
|
+
| 6 | needs confirmation | stop and ask the user |
|
|
81
|
+
| 7 | done, with skipped steps | report what `skipped` lists |
|
|
82
|
+
| 10 | plan found differences | show the diff |
|
|
83
|
+
|
|
84
|
+
## Changing mkit itself
|
|
85
|
+
|
|
86
|
+
Changes go in the engine, never in an app's copy; follow
|
|
87
|
+
CONTRIBUTING.md (tests, regenerated docs, changelog, version).
|
|
88
|
+
|
|
89
|
+
Never read, print or copy `.env` files or credentials. Never commit them.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Every change is described here before it is released. Versions follow semantic
|
|
4
|
+
versioning (see CONTRIBUTING.md). An app states the oldest engine it works with
|
|
5
|
+
in `mkit.toml` (`requires = ">=0.3"`), and an older engine refuses to run for
|
|
6
|
+
it rather than doing the wrong thing.
|
|
7
|
+
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
## 0.3.1 — first public release
|
|
11
|
+
|
|
12
|
+
mkit shipped a small studio's Android apps for a year before this; this is that
|
|
13
|
+
tool, with the studio's own house style and private services taken out. What is
|
|
14
|
+
here is the engine.
|
|
15
|
+
|
|
16
|
+
**Release.** `mkit deploy` in one command: preflight, a commit for whatever was
|
|
17
|
+
already uncommitted, the version bump in its own commit, Firestore rules, the
|
|
18
|
+
release build, the upload with mapping and release notes, the in-app update
|
|
19
|
+
document, a Telegram message, and a push. A failure before Play accepts the
|
|
20
|
+
build undoes the bump commit — and only if it is still at HEAD, so it can never
|
|
21
|
+
drop someone else's work. `promote`, `rollout` and `share` move a build on from
|
|
22
|
+
there.
|
|
23
|
+
|
|
24
|
+
**Store.** The listing, what's new, screenshots, the feature graphic, data
|
|
25
|
+
safety and in-app products all live in the repo, in every language, with `plan`
|
|
26
|
+
showing the difference against Play before `apply` sends it. `mkit art build`
|
|
27
|
+
draws the screenshots from real device captures.
|
|
28
|
+
|
|
29
|
+
**Insight.** `stats`, `vitals`, `crashes`, `reviews`, and `aso rank` /
|
|
30
|
+
`aso score` for where an app sits in Play search.
|
|
31
|
+
|
|
32
|
+
**Firebase.** Firestore rules, Remote Config (`plan`, `apply`, `pull`,
|
|
33
|
+
`rollback`), and an in-app update document the app reads at startup.
|
|
34
|
+
|
|
35
|
+
**Devices.** `run` builds and installs on a phone or emulator, `logs` follows
|
|
36
|
+
just that app, `studio` opens the project in Android Studio.
|
|
37
|
+
|
|
38
|
+
**Getting started.** `mkit init` writes `mkit.toml` and a commented `.env`
|
|
39
|
+
naming every credential, where it comes from and how to encode it; an existing
|
|
40
|
+
`.env` is never replaced, not even with `--force`. `mkit doctor` says what is
|
|
41
|
+
configured, what is broken, and which store commands an app cannot run because
|
|
42
|
+
it has no file for them. `mkit manual` lists the Play Console steps that have no
|
|
43
|
+
API — including production access for a new personal account and App access
|
|
44
|
+
credentials for an app behind a sign-in.
|
|
45
|
+
|
|
46
|
+
**Staying current.** `mkit self status` says whether a newer release is on PyPI,
|
|
47
|
+
and `mkit self update` names the upgrade command for whichever of uv, pipx or
|
|
48
|
+
pip installed it.
|
|
49
|
+
|
|
50
|
+
**For agents.** JSON output off a terminal, one envelope per run, an exit code
|
|
51
|
+
per outcome, a risk class per command, and a confirmation that publish-class
|
|
52
|
+
commands will not run without.
|
|
53
|
+
|
|
54
|
+
**Built and tested** on Linux, macOS and Windows against Python 3.11 and 3.13,
|
|
55
|
+
with a check that the generated command reference matches the code on every
|
|
56
|
+
platform. Releases publish to PyPI from a version tag through trusted
|
|
57
|
+
publishing, with no token stored anywhere.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Issues and pull requests are welcome. mkit drives real releases to the Play
|
|
4
|
+
Store, so the bar is less about style than about never surprising someone on
|
|
5
|
+
release day.
|
|
6
|
+
|
|
7
|
+
## Getting set up
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/almasumdev/mkit-cli
|
|
11
|
+
cd mkit-cli
|
|
12
|
+
uv sync # or: pip install -e ".[dev]"
|
|
13
|
+
uv run pytest # the whole suite, against a fake Play service
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Nothing in the tests touches a real Google account. Play is faked by
|
|
17
|
+
`tests/fakeplay.py`, and it stays that way: a test that could publish is not a
|
|
18
|
+
test.
|
|
19
|
+
|
|
20
|
+
## The checklist for a change
|
|
21
|
+
|
|
22
|
+
1. Make the change. Keep anything app-specific out of the code.
|
|
23
|
+
2. Add or update tests in `tests/`.
|
|
24
|
+
3. `uv run python scripts/gen_docs.py` if a command, flag or summary changed —
|
|
25
|
+
`docs/commands.md` is generated from the command registry, and
|
|
26
|
+
`tests/test_docs.py` fails while it is stale.
|
|
27
|
+
4. `uv run pytest` — everything passes.
|
|
28
|
+
5. Describe the change under `## Unreleased` in `CHANGELOG.md`, in words
|
|
29
|
+
somebody using the command would understand.
|
|
30
|
+
|
|
31
|
+
## Rules that must hold
|
|
32
|
+
|
|
33
|
+
- **A command that changes what users, testers or Play review see is
|
|
34
|
+
`risk='publish'`** and calls `safety.confirm` before changing anything.
|
|
35
|
+
`tests/test_docs.py` pins the list, so adding one is a deliberate act.
|
|
36
|
+
- **Nothing publishes in a test.** Use `tests/fakeplay.py` or `--dry-run`.
|
|
37
|
+
- **Secrets never reach output.** Read them through `secrets.Secrets`, which
|
|
38
|
+
registers each one for masking.
|
|
39
|
+
- **JSON output and exit codes are a contract.** Agents and scripts branch on
|
|
40
|
+
them; changing a shape or a code is a major version.
|
|
41
|
+
- **A per-app difference becomes an `mkit.toml` key**, documented in
|
|
42
|
+
`docs/config.md` — never a branch in the code on an app's name.
|
|
43
|
+
|
|
44
|
+
## Versioning
|
|
45
|
+
|
|
46
|
+
Semantic versioning, in `src/mkit/__init__.py` only (`pyproject.toml` reads it
|
|
47
|
+
from there).
|
|
48
|
+
|
|
49
|
+
| Bump | When |
|
|
50
|
+
|---|---|
|
|
51
|
+
| patch | fixes; commands, flags, `mkit.toml` keys and JSON output unchanged |
|
|
52
|
+
| minor | new commands, flags, config keys or output fields; nothing existing breaks |
|
|
53
|
+
| major | anything an existing `mkit.toml`, script or agent would break on |
|
|
54
|
+
|
|
55
|
+
Releasing:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv run python scripts/release.py minor # shows the version and changelog entry
|
|
59
|
+
uv run python scripts/release.py minor go # tests, bumps, dates the changelog, tags
|
|
60
|
+
git push --follow-tags
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The script refuses with uncommitted changes, failing tests, or an empty
|
|
64
|
+
`## Unreleased` section, so every tag is a tested, described state.
|
|
65
|
+
|
|
66
|
+
## Reporting a bug
|
|
67
|
+
|
|
68
|
+
Say which app kind (Flutter, native, Wear), the command you ran, and the JSON
|
|
69
|
+
output — `mkit <command> --json`. Never paste a service account key, and note
|
|
70
|
+
that `mkit doctor --json` is safe to share: it names which credentials are
|
|
71
|
+
missing without printing any of them.
|
mkit_cli-0.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nurullah Al-Masum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mkit_cli-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mkit-cli
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Release Android apps to Google Play from the command line: build, upload, listing, screenshots, data safety, in-app products, vitals and Firebase, in one tool built for humans and AI agents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/almasumdev/mkit-cli
|
|
6
|
+
Project-URL: Documentation, https://github.com/almasumdev/mkit-cli/blob/main/docs/commands.md
|
|
7
|
+
Project-URL: Repository, https://github.com/almasumdev/mkit-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/almasumdev/mkit-cli/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/almasumdev/mkit-cli/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Nurullah Al-Masum
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: android,aso,firebase,flutter,google-play,release
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
25
|
+
Classifier: Topic :: System :: Software Distribution
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: google-api-python-client>=2.150
|
|
28
|
+
Requires-Dist: google-auth>=2.35
|
|
29
|
+
Requires-Dist: pillow>=11
|
|
30
|
+
Requires-Dist: requests>=2.32
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# mkit
|
|
34
|
+
|
|
35
|
+
[](https://github.com/almasumdev/mkit-cli/actions/workflows/tests.yml)
|
|
36
|
+
[](https://github.com/almasumdev/mkit-cli/blob/main/LICENSE)
|
|
37
|
+
|
|
38
|
+
One command-line tool for everything around an Android app that is not writing
|
|
39
|
+
it: build and install on a device, release to Google Play, keep the store
|
|
40
|
+
listing, screenshots, data safety and in-app products in your repo, read
|
|
41
|
+
installs, vitals, crashes and reviews, check search rank, and drive the
|
|
42
|
+
Firebase side (Firestore rules, Remote Config, an in-app update document).
|
|
43
|
+
|
|
44
|
+
Flutter and native Kotlin apps, including apps with a Wear OS module.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
mkit deploy # bump, build, upload to Play, publish, notify, push
|
|
48
|
+
mkit run -p # build and install on the phone
|
|
49
|
+
mkit status # what every track holds right now
|
|
50
|
+
mkit crashes # what is breaking in production
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A release is one command. `mkit deploy` bumps the version, commits it, builds
|
|
54
|
+
the bundle, uploads it with its mapping file and release notes, stages it on a
|
|
55
|
+
track, writes the update document, sends a message, and pushes — and if
|
|
56
|
+
anything fails before Play accepts the build, the version bump undoes itself so
|
|
57
|
+
the repo never claims a release that did not happen.
|
|
58
|
+
|
|
59
|
+
## Why it exists
|
|
60
|
+
|
|
61
|
+
Shipping an Android app means a dozen small jobs that live in different places:
|
|
62
|
+
a Gradle command, the Play Console, the Firebase console, a screenshot folder
|
|
63
|
+
somebody renamed, a changelog nobody updated. Each is easy; together they are a
|
|
64
|
+
release day. mkit puts them behind one tool, with the app's settings in one
|
|
65
|
+
file, so the same release happens the same way every time — and so an AI agent
|
|
66
|
+
can run the safe parts without being handed your Play Console password.
|
|
67
|
+
|
|
68
|
+
It was built to ship a small studio's apps and has been doing that for a while.
|
|
69
|
+
It is opinionated where opinions save time and configurable where apps really
|
|
70
|
+
differ.
|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
Requires Python 3.11 or newer. [uv](https://docs.astral.sh/uv/) is the easiest
|
|
75
|
+
way in, and installs mkit as a command of its own rather than into a project:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv tool install mkit-cli
|
|
79
|
+
mkit --version
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
With pipx: `pipx install mkit-cli`. With pip: `pip install mkit-cli`.
|
|
83
|
+
|
|
84
|
+
The latest from `main`, between releases:
|
|
85
|
+
`uv tool install git+https://github.com/almasumdev/mkit-cli`
|
|
86
|
+
|
|
87
|
+
`mkit self status` says whether a newer release is out, and `mkit self update`
|
|
88
|
+
gives the upgrade command for whichever of these installed it.
|
|
89
|
+
|
|
90
|
+
## Getting started
|
|
91
|
+
|
|
92
|
+
In an app's folder:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
mkit init # writes mkit.toml, asking what it cannot work out
|
|
96
|
+
mkit doctor # what is configured, what is missing, and what to add
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`mkit.toml` is the whole of an app's configuration:
|
|
100
|
+
|
|
101
|
+
```toml
|
|
102
|
+
[app]
|
|
103
|
+
name = "My App"
|
|
104
|
+
kind = "flutter" # flutter | android | android-wear
|
|
105
|
+
package = "com.example.app"
|
|
106
|
+
|
|
107
|
+
[play] # switches Play features on
|
|
108
|
+
|
|
109
|
+
[store] # store listing, art and data safety in the repo
|
|
110
|
+
listing_dir = "store/listing"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Credentials never live in that file. A Google Play service account goes in
|
|
114
|
+
`.env` (per app) or `~/.mkit/.env` (shared); `mkit doctor` names the exact key
|
|
115
|
+
when one is missing, and never prints a secret. Every setting is documented in
|
|
116
|
+
[docs/config.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/config.md).
|
|
117
|
+
|
|
118
|
+
## What it does
|
|
119
|
+
|
|
120
|
+
| | |
|
|
121
|
+
|---|---|
|
|
122
|
+
| **Develop** | `run`, `devices`, `logs`, `emu`, `studio`, `gradle`, `version`, `bump` |
|
|
123
|
+
| **Release** | `deploy`, `status`, `promote`, `rollout`, `share` |
|
|
124
|
+
| **Store** | `listing`, `whatsnew`, `datasafety`, `testers`, `art` |
|
|
125
|
+
| **Money** | `products`, `prices` |
|
|
126
|
+
| **Insight** | `stats`, `vitals`, `crashes`, `reviews`, `aso` |
|
|
127
|
+
| **Firebase** | `rules`, `config`, `remoteconfig`, `firebase` |
|
|
128
|
+
|
|
129
|
+
Every command, flag and example: [docs/commands.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/commands.md),
|
|
130
|
+
generated from the code so it cannot describe a flag that does not exist.
|
|
131
|
+
|
|
132
|
+
Commands are classed by what they can change — `read`, `plan`, `write`,
|
|
133
|
+
`publish` — and anything in the `publish` class refuses to run without an
|
|
134
|
+
explicit confirmation naming the package.
|
|
135
|
+
|
|
136
|
+
Some things have no API and must be done in the Play Console. `mkit manual`
|
|
137
|
+
lists them, so you know what is left rather than discovering it at release
|
|
138
|
+
time.
|
|
139
|
+
|
|
140
|
+
## Working with AI agents
|
|
141
|
+
|
|
142
|
+
mkit answers in JSON whenever it is not attached to a terminal, with one
|
|
143
|
+
envelope on stdout and a documented exit code per outcome, so an agent can
|
|
144
|
+
branch on a result instead of reading prose. [AGENTS.md](https://github.com/almasumdev/mkit-cli/blob/main/AGENTS.md) is the
|
|
145
|
+
contract: which commands are safe to run unasked, which need a human to say so,
|
|
146
|
+
and what an agent must never do.
|
|
147
|
+
|
|
148
|
+
## Documentation
|
|
149
|
+
|
|
150
|
+
| | |
|
|
151
|
+
|---|---|
|
|
152
|
+
| [docs/commands.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/commands.md) | every command and flag |
|
|
153
|
+
| [docs/config.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/config.md) | `mkit.toml`, the store and keyword files, credentials |
|
|
154
|
+
| [docs/store.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/store.md) | the `store/` folder: what lives where, in every language |
|
|
155
|
+
| [docs/store-art.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/store-art.md) | screenshots and the feature graphic, built from real captures |
|
|
156
|
+
| [docs/in-app-update.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/in-app-update.md) | how an app should check for updates: Play first, your policy second |
|
|
157
|
+
| [docs/news-topics.md](https://github.com/almasumdev/mkit-cli/blob/main/docs/news-topics.md) | news and offer notifications over FCM topics |
|
|
158
|
+
| [AGENTS.md](https://github.com/almasumdev/mkit-cli/blob/main/AGENTS.md) | the agent contract |
|
|
159
|
+
| [CONTRIBUTING.md](https://github.com/almasumdev/mkit-cli/blob/main/CONTRIBUTING.md) | changing mkit, tests, versioning |
|
|
160
|
+
| [SECURITY.md](https://github.com/almasumdev/mkit-cli/blob/main/SECURITY.md) | what counts as a security bug here, and how to report it |
|
|
161
|
+
|
|
162
|
+
## Status and scope
|
|
163
|
+
|
|
164
|
+
Developed on Windows against real apps on Google Play; the code paths for
|
|
165
|
+
macOS and Linux exist but are less travelled, and there is no CI yet. The test
|
|
166
|
+
suite runs against a fake Play service — nothing in the tests touches a real
|
|
167
|
+
account.
|
|
168
|
+
|
|
169
|
+
It does not: create an app in the Play Console, answer content rating or target
|
|
170
|
+
audience questionnaires, manage tester email lists (the API only takes Google
|
|
171
|
+
Groups), or publish for you when managed publishing is on. `mkit manual` is the
|
|
172
|
+
full list.
|
|
173
|
+
|
|
174
|
+
Issues and pull requests are welcome. If you use it for your own apps, I would
|
|
175
|
+
like to hear what broke.
|
|
176
|
+
|
|
177
|
+
## Licence
|
|
178
|
+
|
|
179
|
+
MIT. See [LICENSE](https://github.com/almasumdev/mkit-cli/blob/main/LICENSE).
|