sdk-release-kit 0.2.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.
- sdk_release_kit-0.2.0/.claude-plugin/marketplace.json +20 -0
- sdk_release_kit-0.2.0/.gitignore +41 -0
- sdk_release_kit-0.2.0/AGENTS.md +68 -0
- sdk_release_kit-0.2.0/CLAUDE.md +1 -0
- sdk_release_kit-0.2.0/CONTRIBUTING.md +13 -0
- sdk_release_kit-0.2.0/LICENSE +21 -0
- sdk_release_kit-0.2.0/PKG-INFO +307 -0
- sdk_release_kit-0.2.0/README.md +277 -0
- sdk_release_kit-0.2.0/context7.json +16 -0
- sdk_release_kit-0.2.0/examples/custom.example.yaml +18 -0
- sdk_release_kit-0.2.0/examples/keys.example.yaml +18 -0
- sdk_release_kit-0.2.0/examples/outputs.example.yaml +19 -0
- sdk_release_kit-0.2.0/examples/repos.example.yaml +33 -0
- sdk_release_kit-0.2.0/llms.txt +24 -0
- sdk_release_kit-0.2.0/plugins/sdk-release-kit/.claude-plugin/icon.png +0 -0
- sdk_release_kit-0.2.0/plugins/sdk-release-kit/.claude-plugin/plugin.json +13 -0
- sdk_release_kit-0.2.0/plugins/sdk-release-kit/.mcp.json +8 -0
- sdk_release_kit-0.2.0/plugins/sdk-release-kit/skills/release-sdks/SKILL.md +25 -0
- sdk_release_kit-0.2.0/pyproject.toml +55 -0
- sdk_release_kit-0.2.0/recipes/sdks.yaml +222 -0
- sdk_release_kit-0.2.0/server.json +29 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/__init__.py +3 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/__init__.py +24 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/android.py +86 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/base.py +217 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/flutter.py +16 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/generic.py +56 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/ios.py +204 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/builders/reactnative.py +32 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/cli.py +198 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/mcp_server.py +240 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/models.py +306 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/paths.py +85 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/pipeline.py +446 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/recipes.py +110 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/runlog.py +62 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/server.py +331 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/__init__.py +29 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/_yaml.py +46 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/custom.py +34 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/keys.py +111 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/outputs.py +15 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/store/repos.py +15 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/uploaders/__init__.py +20 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/uploaders/onedrive.py +129 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/uploaders/play.py +108 -0
- sdk_release_kit-0.2.0/src/sdk_release_kit/uploaders/testflight.py +105 -0
- sdk_release_kit-0.2.0/web/app.js +305 -0
- sdk_release_kit-0.2.0/web/index.html +142 -0
- sdk_release_kit-0.2.0/web/styles.css +93 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sdk-release-kit",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Yahya",
|
|
5
|
+
"url": "https://github.com/yehyatt"
|
|
6
|
+
},
|
|
7
|
+
"metadata": {
|
|
8
|
+
"description": "Build and ship mobile SDK demo apps and packages from Claude Code."
|
|
9
|
+
},
|
|
10
|
+
"plugins": [
|
|
11
|
+
{
|
|
12
|
+
"name": "sdk-release-kit",
|
|
13
|
+
"source": "./plugins/sdk-release-kit",
|
|
14
|
+
"description": "MCP server and skill to build Android, iOS, Flutter and React Native SDK demos and packages and publish them to a shared folder, Google Play internal testing and TestFlight.",
|
|
15
|
+
"version": "0.2.0",
|
|
16
|
+
"category": "development",
|
|
17
|
+
"keywords": ["mobile", "sdk", "release", "android", "ios", "flutter", "react-native", "testflight", "google-play"]
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
|
|
12
|
+
# Local settings never belong in git (they live in ~/.config/sdk-release-kit/)
|
|
13
|
+
repos.yaml
|
|
14
|
+
outputs.yaml
|
|
15
|
+
keys.yaml
|
|
16
|
+
custom.yaml
|
|
17
|
+
recipes.d/
|
|
18
|
+
!examples/*.example.yaml
|
|
19
|
+
|
|
20
|
+
# Build output
|
|
21
|
+
staging/
|
|
22
|
+
runs/
|
|
23
|
+
|
|
24
|
+
# Secrets and key material
|
|
25
|
+
.env
|
|
26
|
+
.env.*
|
|
27
|
+
*.keystore
|
|
28
|
+
*.jks
|
|
29
|
+
*.p8
|
|
30
|
+
*.p12
|
|
31
|
+
*.pem
|
|
32
|
+
*.mobileprovision
|
|
33
|
+
key.properties
|
|
34
|
+
*service-account*.json
|
|
35
|
+
*adminsdk*.json
|
|
36
|
+
client_secret*.json
|
|
37
|
+
|
|
38
|
+
# OS / editors
|
|
39
|
+
.DS_Store
|
|
40
|
+
.idea/
|
|
41
|
+
.vscode/
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents (and humans) changing this repository.
|
|
4
|
+
|
|
5
|
+
## Hard rules
|
|
6
|
+
|
|
7
|
+
1. **No absolute machine paths** in `recipes/`, `examples/` or Python defaults. Recipes use
|
|
8
|
+
paths relative to the SDK checkout. Absolute paths live only in user settings
|
|
9
|
+
(`~/.config/sdk-release-kit/`). Defaults may use `~`, which is portable.
|
|
10
|
+
2. **No secrets in git.** Never commit keystores, `.p8` files, Play service account JSON,
|
|
11
|
+
tokens, passwords or card numbers, and never write them into examples or tests. Keys are
|
|
12
|
+
configured through the Settings UI or the user data directory, and passwords are referenced
|
|
13
|
+
(`SecretRef`: keychain or env), never stored.
|
|
14
|
+
3. **Never log a secret.** Anything resolved from a `SecretRef` must be registered with
|
|
15
|
+
`RunLog.add_secret()` before it can reach a log line. Prefer environment variables over
|
|
16
|
+
command-line arguments for secret values.
|
|
17
|
+
4. **Keep settings backward compatible.** Settings models use `extra="allow"`; add fields with
|
|
18
|
+
defaults, never rename or remove without a migration and a `schema_version` bump.
|
|
19
|
+
5. **Destinations soft-skip.** Missing Play or TestFlight credentials must produce a "skipped"
|
|
20
|
+
result with a reason, not a failed run.
|
|
21
|
+
|
|
22
|
+
## Where things are
|
|
23
|
+
|
|
24
|
+
| Path | Purpose |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `recipes/sdks.yaml` | Portable recipes and shared-folder target ids |
|
|
27
|
+
| `examples/*.example.yaml` | Templates copied by `sdk-release-kit init` |
|
|
28
|
+
| `src/sdk_release_kit/models.py` | Pydantic schemas for recipes and settings |
|
|
29
|
+
| `src/sdk_release_kit/paths.py` | User data dir, env overrides, `safe_join` |
|
|
30
|
+
| `src/sdk_release_kit/store/` | One module per settings layer (repos, outputs, keys, custom) |
|
|
31
|
+
| `src/sdk_release_kit/recipes.py` | Recipe loading, overlays, `${...}` substitution |
|
|
32
|
+
| `src/sdk_release_kit/builders/` | Step handlers per platform; `base.py` runs and collects |
|
|
33
|
+
| `src/sdk_release_kit/uploaders/` | Shared folder, Google Play, TestFlight |
|
|
34
|
+
| `src/sdk_release_kit/pipeline.py` | Select, build, publish, report |
|
|
35
|
+
| `src/sdk_release_kit/server.py` | Settings UI API (FastAPI) |
|
|
36
|
+
| `src/sdk_release_kit/cli.py` | Typer CLI |
|
|
37
|
+
| `src/sdk_release_kit/mcp_server.py` | MCP server for agents (`sdk-release-kit mcp`); never return secret values |
|
|
38
|
+
| `plugins/sdk-release-kit/` | Claude Code plugin (MCP config + `release-sdks` skill); `.claude-plugin/marketplace.json` lists it |
|
|
39
|
+
| `server.json`, `context7.json`, `llms.txt` | MCP Registry, Context7 and LLM discovery metadata; keep versions in sync with `pyproject.toml` |
|
|
40
|
+
| `web/` | Static Settings UI (plain HTML, CSS, JS; no build step) |
|
|
41
|
+
|
|
42
|
+
## Common changes
|
|
43
|
+
|
|
44
|
+
**Add an SDK.** Add a recipe in `recipes/sdks.yaml` using existing step types, plus any new
|
|
45
|
+
`onedrive_targets`. No code change needed. Run `sdk-release-kit recipes` and
|
|
46
|
+
`sdk-release-kit build --dry-run --sdks <id>` to check it.
|
|
47
|
+
|
|
48
|
+
**Add a step type or platform.**
|
|
49
|
+
1. Add a model class to `models.py` (subclass `_StepBase`, `type: Literal["name"]`) and add it
|
|
50
|
+
to the `Step` union.
|
|
51
|
+
2. Write a handler in `builders/<platform>.py` decorated with `@handler("name")` that returns a
|
|
52
|
+
`StepPlan` (commands, optional `prepare`/`finish`, extra collect roots).
|
|
53
|
+
3. Import the module in `builders/__init__.py`.
|
|
54
|
+
4. Document it in the step table in `README.md`.
|
|
55
|
+
|
|
56
|
+
**Add a destination.** Add an uploader module with `readiness()` and an upload function, add the
|
|
57
|
+
name to `Destination`/`DESTINATIONS` in `models.py`, add an Outputs model section, and wire it
|
|
58
|
+
into `Pipeline.destination_status` and `Pipeline._upload`.
|
|
59
|
+
|
|
60
|
+
**Read a new custom value.** Reference it from a recipe as `${custom.your.key:-default}`. Do not
|
|
61
|
+
hardcode team ids, bundle ids or package names in Python.
|
|
62
|
+
|
|
63
|
+
## Working style
|
|
64
|
+
|
|
65
|
+
* Small, focused diffs. Keep the UI dependency free.
|
|
66
|
+
* Verify changes with `sdk-release-kit build --dry-run`, then a real build of one recipe into
|
|
67
|
+
a scratch staging directory (`SDK_RELEASE_KIT_HOME=/tmp/srk sdk-release-kit init`).
|
|
68
|
+
* Run `ruff check src` before committing.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping. Issues and pull requests are welcome.
|
|
4
|
+
|
|
5
|
+
1. Read [AGENTS.md](AGENTS.md); its hard rules apply to everyone, human or AI.
|
|
6
|
+
2. Set up: `python3 -m venv .venv && source .venv/bin/activate && pip install -e '.[dev]'`.
|
|
7
|
+
3. Use a scratch settings directory while developing:
|
|
8
|
+
`export SDK_RELEASE_KIT_HOME=/tmp/srk && sdk-release-kit init`.
|
|
9
|
+
4. Before opening a pull request: `ruff check src` and `sdk-release-kit build --dry-run`.
|
|
10
|
+
5. Never include real credentials, client names, real bundle ids or card numbers in code,
|
|
11
|
+
examples, screenshots or issues. Use `com.example.*` identifiers.
|
|
12
|
+
|
|
13
|
+
Keep pull requests small and describe how you verified the change.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yahya (github.com/yehyatt)
|
|
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.
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sdk-release-kit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Build mobile SDK demo apps and packages, then publish them to a shared folder, Google Play internal testing and TestFlight.
|
|
5
|
+
Project-URL: Homepage, https://github.com/yehyatt/sdk-release-kit
|
|
6
|
+
Project-URL: Repository, https://github.com/yehyatt/sdk-release-kit
|
|
7
|
+
Project-URL: Issues, https://github.com/yehyatt/sdk-release-kit/issues
|
|
8
|
+
Author: Yahya
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-agents,android,flutter,google-play,ios,mcp,mcp-server,react-native,release,sdk,testflight
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: fastapi>=0.110
|
|
17
|
+
Requires-Dist: keyring>=24
|
|
18
|
+
Requires-Dist: mcp<3,>=2.3
|
|
19
|
+
Requires-Dist: pydantic>=2.6
|
|
20
|
+
Requires-Dist: pyyaml>=6.0
|
|
21
|
+
Requires-Dist: typer>=0.12
|
|
22
|
+
Requires-Dist: uvicorn>=0.29
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
26
|
+
Provides-Extra: play
|
|
27
|
+
Requires-Dist: google-api-python-client>=2.100; extra == 'play'
|
|
28
|
+
Requires-Dist: google-auth>=2.25; extra == 'play'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# SDK Release Kit
|
|
32
|
+
|
|
33
|
+
Build mobile SDK demo apps and SDK packages from one or more local checkouts, then publish
|
|
34
|
+
them to a shared folder (OneDrive or any synced folder), Google Play internal testing and
|
|
35
|
+
TestFlight. Configure it once per machine through a local Settings UI; the same repository
|
|
36
|
+
works on every developer's Mac without editing scripts.
|
|
37
|
+
|
|
38
|
+
Supports Android (Gradle), iOS (Xcode), Flutter and React Native SDKs out of the box. New
|
|
39
|
+
SDKs are added in a YAML recipe file, usually without code changes.
|
|
40
|
+
|
|
41
|
+
AI agents can drive it too: it ships an [MCP server](#use-with-ai-agents) and a Claude Code
|
|
42
|
+
plugin.
|
|
43
|
+
|
|
44
|
+
<!-- mcp-name: io.github.yehyatt/sdk-release-kit -->
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
Python 3.11 or newer.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install sdk-release-kit # or run without installing: uvx sdk-release-kit --help
|
|
52
|
+
sdk-release-kit init
|
|
53
|
+
sdk-release-kit serve
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
From source:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/yehyatt/sdk-release-kit.git
|
|
60
|
+
cd sdk-release-kit
|
|
61
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
62
|
+
pip install -e . # add '.[play]' for direct Google Play API uploads
|
|
63
|
+
sdk-release-kit init # creates your settings from examples/
|
|
64
|
+
sdk-release-kit serve # opens the Settings UI on http://127.0.0.1:8765
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Fill in **Repositories**, **Outputs** and **Keys** in the UI, then:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
sdk-release-kit build --sdks flutter,android-current --artifacts both --dest onedrive
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Use with AI agents
|
|
74
|
+
|
|
75
|
+
`sdk-release-kit mcp` runs an MCP server on stdio. Its tools:
|
|
76
|
+
|
|
77
|
+
| Tool | Does |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `get_status` | Checkouts, key status (configured or missing, never values), destination readiness, tools on PATH |
|
|
80
|
+
| `list_recipes` | Recipe ids, steps, store flags and checkout per recipe |
|
|
81
|
+
| `plan_build` | Dry run: exact commands, collected files, ready or skipped destinations |
|
|
82
|
+
| `run_build` | Build and publish; returns the run report and the end of the log |
|
|
83
|
+
| `list_runs`, `get_run_report` | Previous runs and their reports |
|
|
84
|
+
| `set_repo_path` | Point a recipe at a local checkout |
|
|
85
|
+
|
|
86
|
+
**Claude Code plugin** (MCP server plus a `release-sdks` skill):
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
/plugin install sdk-release-kit --marketplace yehyatt/sdk-release-kit
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
On older Claude Code versions: `/plugin marketplace add yehyatt/sdk-release-kit`, then
|
|
93
|
+
`/plugin install sdk-release-kit@sdk-release-kit`.
|
|
94
|
+
|
|
95
|
+
**Claude Code, MCP only:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
claude mcp add sdk-release-kit -- uvx sdk-release-kit mcp
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Claude Desktop, Cursor, Windsurf, VS Code and other MCP clients:**
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"sdk-release-kit": { "command": "uvx", "args": ["sdk-release-kit", "mcp"] }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The server never returns secret values, and keys are still entered through the Settings UI.
|
|
112
|
+
Agents are told to plan before building and to confirm before uploading to Play or TestFlight.
|
|
113
|
+
Listed in the [MCP Registry](https://registry.modelcontextprotocol.io) as
|
|
114
|
+
`io.github.yehyatt/sdk-release-kit`. A summary for language models is in
|
|
115
|
+
[llms.txt](https://github.com/yehyatt/sdk-release-kit/blob/main/llms.txt).
|
|
116
|
+
|
|
117
|
+
## Commands
|
|
118
|
+
|
|
119
|
+
| Command | What it does |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `sdk-release-kit init [--force]` | Copy `examples/*.example.yaml` into your settings directory |
|
|
122
|
+
| `sdk-release-kit serve` | Settings UI (Repositories, Outputs, Keys, Custom data, Run) |
|
|
123
|
+
| `sdk-release-kit build ...` | Build and publish (see options below) |
|
|
124
|
+
| `sdk-release-kit build --dry-run` | Print the plan: commands, collected files, destinations |
|
|
125
|
+
| `sdk-release-kit recipes` | List recipe ids and where they were loaded from |
|
|
126
|
+
| `sdk-release-kit status` | Settings files, key status (never values), installed tools |
|
|
127
|
+
| `sdk-release-kit keys set <name>` | Store a secret in the OS keychain (prompted, not echoed) |
|
|
128
|
+
| `sdk-release-kit mcp` | MCP server on stdio for AI agents |
|
|
129
|
+
|
|
130
|
+
`build` options:
|
|
131
|
+
|
|
132
|
+
* `--sdks android-current,flutter`: recipe ids. Default: every enabled repository.
|
|
133
|
+
* `--artifacts demos|packages|both`
|
|
134
|
+
* `--dest onedrive,play,testflight`: default is every destination enabled in Outputs.
|
|
135
|
+
* `--dry-run`: plan only. `--skip-upload`: build only. `--json`: print the report.
|
|
136
|
+
|
|
137
|
+
## How configuration is split
|
|
138
|
+
|
|
139
|
+
| Layer | Where | In git? | Holds |
|
|
140
|
+
| --- | --- | --- | --- |
|
|
141
|
+
| Recipes | `recipes/sdks.yaml` | Yes | Relative paths inside a repo, Gradle tasks, Xcode schemes, shared-folder target ids, store flags |
|
|
142
|
+
| Repos | `<settings>/repos.yaml` | No | Recipe id to absolute checkout path; JDK, Android SDK, Flutter, Xcode locations |
|
|
143
|
+
| Outputs | `<settings>/outputs.yaml` | No | Staging directory, shared folder root, Play and TestFlight options |
|
|
144
|
+
| Keys | `<settings>/keys.yaml` | No | Paths to key files and *references* to passwords (keychain or env) |
|
|
145
|
+
| Custom | `<settings>/custom.yaml` | No | Free-form YAML read by recipes as `${custom.key}` |
|
|
146
|
+
|
|
147
|
+
`<settings>` is `~/.config/sdk-release-kit/` (or `$XDG_CONFIG_HOME/sdk-release-kit`, or
|
|
148
|
+
`%APPDATA%\sdk-release-kit` on Windows). Overrides:
|
|
149
|
+
|
|
150
|
+
* `SDK_RELEASE_KIT_HOME`: use another settings directory
|
|
151
|
+
* `SDK_RELEASE_KIT_REPOS`, `SDK_RELEASE_KIT_OUTPUTS`, `SDK_RELEASE_KIT_KEYS`, `SDK_RELEASE_KIT_CUSTOM`: point one layer at a specific file
|
|
152
|
+
* `SDK_RELEASE_KIT_RECIPES`: an extra recipe file merged over the shipped one
|
|
153
|
+
|
|
154
|
+
Machine-specific recipe tweaks go in `<settings>/recipes.d/*.yaml`. They are deep-merged over
|
|
155
|
+
`recipes/sdks.yaml`, so you can change one scheme name without forking the file.
|
|
156
|
+
|
|
157
|
+
## Adapting it to your SDKs
|
|
158
|
+
|
|
159
|
+
The shipped recipes use placeholder names. Do these three things before your first release.
|
|
160
|
+
|
|
161
|
+
1. **Match the recipes to your repositories.** Open `recipes/sdks.yaml` and check, for every
|
|
162
|
+
recipe you use, the `workdir`, Xcode `workspace` and `scheme`, Gradle tasks, `framework_name`
|
|
163
|
+
and `collect` globs. Placeholders include `DemoApp`, `PaymentSDK`, `SimpleIntegration`,
|
|
164
|
+
`:app` and `example/`. If the change applies to everyone using the repo, edit the file and
|
|
165
|
+
commit it. If it only applies to your machine, put just the changed keys in
|
|
166
|
+
`<settings>/recipes.d/local.yaml`; it is deep-merged over the shipped file:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
recipes:
|
|
170
|
+
ios-current:
|
|
171
|
+
demos:
|
|
172
|
+
- type: xcode-simulator
|
|
173
|
+
workspace: Example/Example.xcworkspace
|
|
174
|
+
scheme: Example
|
|
175
|
+
target: ios-native-current
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Lists such as `demos` are replaced as a whole, so repeat every step of a list you override.
|
|
179
|
+
Then run `sdk-release-kit build --dry-run --sdks <id>` and read the commands it prints.
|
|
180
|
+
|
|
181
|
+
2. **Put your real identifiers in Custom data, not in git.** The recipes read store ids and the
|
|
182
|
+
Apple team from `custom.yaml` (Custom data page), falling back to `com.example.*`:
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
ios_team_id: "ABCDE12345"
|
|
186
|
+
app_ids:
|
|
187
|
+
android_native: com.yourcompany.sdk.demo
|
|
188
|
+
ios_native: com.yourcompany.sdk.demoapp
|
|
189
|
+
flutter_android: com.yourcompany.sdk.flutter.demoapp
|
|
190
|
+
flutter_ios: com.yourcompany.sdk.flutter.demoapp
|
|
191
|
+
rn_android: com.yourcompany.sdk.reactnative.demoapp
|
|
192
|
+
rn_ios: com.yourcompany.sdk.reactnative.demoapp
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
A recipe with an empty `android_package` is skipped for Play. A `com.example.*` id is not
|
|
196
|
+
skipped: the upload fails, because Play only accepts apps that exist in your Play Console.
|
|
197
|
+
|
|
198
|
+
3. **Prove each destination once.** Start with the shared folder only:
|
|
199
|
+
`sdk-release-kit build --sdks <id> --artifacts demos --dest onedrive`, and open the copied
|
|
200
|
+
APK or `.app`. Then fill in the Keys page (the Keys chips must all show "configured") and
|
|
201
|
+
run one upload per store with a single recipe:
|
|
202
|
+
`--dest play` with an Android recipe, `--dest testflight` with an iOS one. Check the build
|
|
203
|
+
appears on the internal track or in TestFlight before relying on combined runs. Each run's
|
|
204
|
+
`report.json` lists what was uploaded, skipped or failed and why.
|
|
205
|
+
|
|
206
|
+
## Multi-device setup
|
|
207
|
+
|
|
208
|
+
1. Clone the repository and `pip install -e .` on the new machine.
|
|
209
|
+
2. `sdk-release-kit init`, or copy your `<settings>` directory from another machine and fix
|
|
210
|
+
the absolute paths.
|
|
211
|
+
3. Open `sdk-release-kit serve` and check that every repository shows a green check and every
|
|
212
|
+
key shows "configured".
|
|
213
|
+
4. Run `sdk-release-kit build --dry-run` before the first real build.
|
|
214
|
+
|
|
215
|
+
## Destinations
|
|
216
|
+
|
|
217
|
+
| Artifact | Shared folder | Google Play | TestFlight |
|
|
218
|
+
| --- | --- | --- | --- |
|
|
219
|
+
| Demo apps (APK, AAB, IPA, simulator `.app`) | Yes | AAB, when the recipe sets `store.play` | IPA, when the recipe sets `store.testflight` |
|
|
220
|
+
| SDK packages (AAR zip, XCFramework zip, `npm pack` tarball, Flutter source zip) | Yes | No | No |
|
|
221
|
+
|
|
222
|
+
* **Shared folder.** Treated as a locally synced directory: files are copied in (written to a
|
|
223
|
+
temporary name, then renamed). Demos land at `<root>/<demos folder>/<target name>`, for
|
|
224
|
+
example `android/native-current.apk`. Packages land at
|
|
225
|
+
`<root>/packages/<recipe-id>/<version>/` with `<recipe-id>/LATEST.txt` describing the newest.
|
|
226
|
+
* **Google Play.** Uploads the AAB to the configured track (default `internal`) with the
|
|
227
|
+
Google Play Developer API (`pip install -e '.[play]'`) or `fastlane supply`.
|
|
228
|
+
* **TestFlight.** Uploads the IPA with an App Store Connect API key, through `xcrun altool`
|
|
229
|
+
(default) or `fastlane pilot`.
|
|
230
|
+
|
|
231
|
+
When Play or TestFlight credentials are missing, those uploads are **skipped with a message**
|
|
232
|
+
and the build and shared-folder copy still run.
|
|
233
|
+
|
|
234
|
+
**Store collision rule.** Current and legacy demos often share an applicationId or bundle id.
|
|
235
|
+
Only recipes with `store.play: true` or `store.testflight: true` are uploaded, and within one
|
|
236
|
+
run each id is uploaded once. The shipped recipes enable stores for `*-current` and `flutter`
|
|
237
|
+
and disable them for `*-legacy`.
|
|
238
|
+
|
|
239
|
+
## Recipes
|
|
240
|
+
|
|
241
|
+
A recipe has `demos` and `packages`, each a list of steps:
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
recipes:
|
|
245
|
+
android-current:
|
|
246
|
+
platform: android
|
|
247
|
+
version: {file: gradle.properties, regex: '^\s*VERSION_NAME\s*=\s*(\S+)'}
|
|
248
|
+
store: {play: true, android_package: "${custom.app_ids.android_native:-com.example.demo}"}
|
|
249
|
+
demos:
|
|
250
|
+
- type: gradle
|
|
251
|
+
tasks: [":app:assembleRelease", ":app:bundleRelease"]
|
|
252
|
+
collect:
|
|
253
|
+
- {glob: "app/build/outputs/apk/release/*.apk", kind: apk, target: android-native-current}
|
|
254
|
+
- {glob: "app/build/outputs/bundle/release/*.aab", kind: aab}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Step type | Runs |
|
|
258
|
+
| --- | --- |
|
|
259
|
+
| `run` | Any command (`cmd` as a list or a string, no shell) |
|
|
260
|
+
| `gradle` | `./gradlew <tasks>` with JAVA_HOME, Android SDK and optional release signing |
|
|
261
|
+
| `flutter` | `flutter <args>` |
|
|
262
|
+
| `xcode-simulator` | `xcodebuild` for the iOS Simulator; collects the `.app` |
|
|
263
|
+
| `xcode-ipa` | Archive and export an IPA (App Store Connect key used for automatic signing when set) |
|
|
264
|
+
| `xcframework` | Device and simulator archives combined into a zipped XCFramework |
|
|
265
|
+
| `npm-pack` | `npm pack` |
|
|
266
|
+
| `source-zip` | `git archive` of the committed sources (or a filtered file walk) |
|
|
267
|
+
|
|
268
|
+
Every step accepts `workdir` (relative to the checkout), `env`, `when: [play|testflight|onedrive]`
|
|
269
|
+
(run only when that destination is active, for example IPA archives only for TestFlight),
|
|
270
|
+
`host: macos` and `collect`.
|
|
271
|
+
|
|
272
|
+
Strings may use `${custom.dotted.key}`, `${env.NAME}`, `${version}` and `${recipe}`, with an
|
|
273
|
+
optional default: `${custom.ios_team_id:-}`.
|
|
274
|
+
|
|
275
|
+
The version comes from the recipe's `version` (a file plus regex, or a command), then
|
|
276
|
+
`git describe`, then a timestamp.
|
|
277
|
+
|
|
278
|
+
## Security model
|
|
279
|
+
|
|
280
|
+
* Secrets are never stored in the repository or in plain YAML. `keys.yaml` holds file paths
|
|
281
|
+
and references such as `{source: keychain, name: android.store_password}` or
|
|
282
|
+
`{source: env, name: ASC_KEY_ID}`. Values are read at run time.
|
|
283
|
+
* Settings files are written with mode `600` and the settings directory with mode `700`. Key
|
|
284
|
+
files uploaded through the UI are stored in `<settings>/keys/` with mode `600`.
|
|
285
|
+
* Android signing is passed to Gradle through `ORG_GRADLE_PROJECT_*` environment variables, not
|
|
286
|
+
the command line, so passwords do not show up in process listings.
|
|
287
|
+
* Every log line passes through a redactor that masks known secret values. The Keys page and
|
|
288
|
+
`status` command only report "configured" or "missing".
|
|
289
|
+
* The Settings UI binds to `127.0.0.1`, accepts only loopback `Host` headers, and requires a
|
|
290
|
+
per-process token on every API call, so other websites in your browser cannot drive it.
|
|
291
|
+
* `.gitignore` excludes settings files, staging output and key material.
|
|
292
|
+
|
|
293
|
+
## Output
|
|
294
|
+
|
|
295
|
+
Each real run writes `<staging>/runs/<timestamp>/` with the collected artifacts per recipe,
|
|
296
|
+
`log.txt` and `report.json` (selections, versions, commits, artifacts, upload results).
|
|
297
|
+
Intermediate build products (derived data, archives) are kept in `<staging>/work/` between
|
|
298
|
+
runs to speed up rebuilds.
|
|
299
|
+
|
|
300
|
+
## Contributing
|
|
301
|
+
|
|
302
|
+
See [CONTRIBUTING.md](https://github.com/yehyatt/sdk-release-kit/blob/main/CONTRIBUTING.md). AI coding agents should read [AGENTS.md](https://github.com/yehyatt/sdk-release-kit/blob/main/AGENTS.md)
|
|
303
|
+
first.
|
|
304
|
+
|
|
305
|
+
## License
|
|
306
|
+
|
|
307
|
+
MIT. See [LICENSE](https://github.com/yehyatt/sdk-release-kit/blob/main/LICENSE).
|