Skip to content

Commit a63399c

Browse files
authored
manifest and scripts to sync template repos (#232)
1 parent e8058c1 commit a63399c

File tree

5 files changed

+98
-4
lines changed

5 files changed

+98
-4
lines changed

_scripts/check-templates.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
//! ```cargo
44
//! [dependencies]
55
//! shuttle-common = "*" # always use latest version
6-
//! toml = "0.8"
6+
//! # for local use
7+
//! # shuttle-common = { path = "../../common" }
8+
//! toml = "0.9"
79
//! ignore = "0.4"
810
//! ```
911
@@ -13,6 +15,8 @@ fn main() {
1315
let s = std::fs::read_to_string("templates.toml").expect("to find file");
1416
let schema: TemplatesSchema = toml::from_str(&s).expect("to parse toml file");
1517

18+
let print_template_repos = std::env::args().any(|a| a == "--list-template-repos");
19+
1620
let (tx, rx) = std::sync::mpsc::channel::<String>();
1721

1822
let thread =
@@ -70,7 +74,7 @@ fn main() {
7074
std::process::exit(1);
7175
}
7276

73-
let path = t.path.unwrap_or_default();
77+
let path = t.path.expect("template to have a path field");
7478

7579
if !set.insert(path.clone()) {
7680
eprintln!("Path '{}' referenced in two places", path);
@@ -84,6 +88,10 @@ fn main() {
8488
);
8589
std::process::exit(1);
8690
}
91+
92+
if print_template_repos && t.has_template_repo.is_some_and(|t| t) {
93+
println!("{}|{}", name, path);
94+
}
8795
}
8896

8997
if !manifests.is_empty() {
@@ -94,5 +102,5 @@ fn main() {
94102
std::process::exit(1);
95103
}
96104

97-
println!("Template definitions verified ✅")
105+
eprintln!("Template definitions verified ✅")
98106
}

_scripts/ci.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ DIRS=$(find . -name Cargo.toml -exec dirname {} \; | sort | awk -v from="$FROM"
1010

1111
# Loop through each directory and run cargo fmt and cargo clippy, exit on failure
1212
for dir in $DIRS; do
13+
# skip workspace roots
1314
grep "\[workspace\]" "$dir/Cargo.toml" > /dev/null && continue
14-
15+
1516
echo "Checking $dir"
1617
cargo fmt --all --manifest-path "$dir/Cargo.toml" -- --check
1718
cargo clippy --no-deps --manifest-path "$dir/Cargo.toml" -- -D warnings
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
# Run with:
3+
# bash _scripts/sync-all-template-repos.sh
4+
# Dependencies:
5+
# - rust-script
6+
# - + all dependencies of _scripts/sync-template-repo.sh
7+
8+
set -euo pipefail
9+
10+
for line in $(rust-script _scripts/check-templates.rs -- --list-template-repos); do
11+
name="$(echo "$line" | cut -d'|' -f1)"
12+
path="$(echo "$line" | cut -d'|' -f2)"
13+
echo "Synching $name $path"
14+
bash _scripts/sync-template-repo.sh "$name" "$path"
15+
done

_scripts/sync-template-repo.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env bash
2+
# Run with:
3+
# bash _scripts/sync-template-repo.sh [template name] [path]
4+
# where [template name] is the hashmap key in templates.toml
5+
# and [path] is the path attribute of the template
6+
# Dependencies:
7+
# - shuttle CLI (no auth)
8+
# - gh CLI (authenticated with sufficient permissions for the org)
9+
# - git (will create commits with your default name+email)
10+
11+
set -euo pipefail
12+
13+
OWNER="shuttle-hq"
14+
NAME="$1"
15+
TEMPLATE_PATH="$2"
16+
17+
export GH_PAGER=""
18+
19+
set +e
20+
repo=$(gh repo create "$OWNER/$NAME" --public)
21+
if echo "$repo" | grep "Name already exists" -q; then
22+
# GraphQL: Name already exists on this account (createRepository)
23+
echo "already exists"
24+
fi
25+
set -e
26+
27+
# add admin permission for core and devrel teams
28+
gh api -X PUT -H "Accept: application/vnd.github+json" "/orgs/$OWNER/teams/core/repos/$OWNER/$NAME" -f permission=admin
29+
gh api -X PUT -H "Accept: application/vnd.github+json" "/orgs/$OWNER/teams/devrel/repos/$OWNER/$NAME" -f permission=admin
30+
31+
# set repo to be a template
32+
gh api -X PATCH -H "Accept: application/vnd.github+json" "/repos/$OWNER/$NAME" -f is_template=true
33+
34+
tmp=$(mktemp -d)
35+
36+
shuttle init --from "./$TEMPLATE_PATH" --name "$NAME" $tmp
37+
pushd $tmp
38+
39+
# get a fresh Cargo.lock
40+
cargo update
41+
42+
# add template info to end of README
43+
echo "
44+
45+
## Shuttle template: $NAME
46+
47+
This template ([repo](https://github.com/$OWNER/$NAME)) is a synced replica from [shuttle-examples](https://github.com/shuttle-hq/shuttle-examples/tree/main/$TEMPLATE_PATH).
48+
49+
[Deploy on Shuttle with just a few clicks!](https://console.shuttle.dev/templates/$NAME)
50+
51+
" >> README.md
52+
53+
git add .
54+
git commit -am "Sync $NAME with shuttle-hq/shuttle-examples repo"
55+
56+
git remote add origin git@github.com:$OWNER/$NAME.git
57+
git branch -M main
58+
git push -u origin main --force
59+
60+
popd

templates.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ path = "actix-web/hello-world"
3636
use_cases = ["Web app"]
3737
tags = ["actix-web"]
3838
template = "actix-web"
39+
has_template_repo = true
3940

4041
[starters.axum-hello-world]
4142
title = "Axum"
@@ -44,13 +45,15 @@ path = "axum/hello-world"
4445
use_cases = ["Web app"]
4546
tags = ["axum"]
4647
template = "axum"
48+
has_template_repo = true
4749

4850
[starters.bevy-hello-world]
4951
title = "Bevy"
5052
description = "Data driven game engine that compiles to WASM"
5153
path = "bevy/hello-world"
5254
use_cases = ["Web app", "Game"]
5355
tags = ["bevy", "axum"]
56+
has_template_repo = true
5457

5558
[starters.loco-hello-world]
5659
title = "Loco"
@@ -59,6 +62,7 @@ path = "loco/hello-world"
5962
use_cases = ["Web app"]
6063
tags = ["loco"]
6164
template = "loco"
65+
has_template_repo = true
6266

6367
[starters.poem-hello-world]
6468
title = "Poem"
@@ -91,6 +95,7 @@ path = "rocket/hello-world"
9195
use_cases = ["Web app"]
9296
tags = ["rocket"]
9397
template = "rocket"
98+
has_template_repo = true
9499

95100
[starters.salvo-hello-world]
96101
title = "Salvo"
@@ -232,6 +237,7 @@ description = "CRUD API, Postgres database, and static file server combined into
232237
path = "axum/todo-list"
233238
use_cases = ["Web app", "Storage"]
234239
tags = ["axum", "postgres", "database"]
240+
has_template_repo = true
235241

236242
[templates.axum-todo-app]
237243
title = "Todo app"
@@ -267,13 +273,15 @@ description = "Health monitoring service using websockets"
267273
path = "axum/websocket"
268274
use_cases = ["Web app", "Monitoring"]
269275
tags = ["axum", "websocket"]
276+
has_template_repo = true
270277

271278
[templates.axum-next-fullstack-saas]
272279
title = "Fullstack SaaS"
273280
description = "Opinionated fullstack web app with pre-made routes and assets"
274281
path = "fullstack-templates/saas"
275282
use_cases = ["Web app", "Authentication", "Storage", "Monetization"]
276283
tags = ["nextjs", "axum", "database", "postgres", "typescript", "tailwind"]
284+
has_template_repo = true
277285

278286
[templates.rama-hello-world-tcp]
279287
title = "Rama TCP"
@@ -337,6 +345,7 @@ description = "Use the image library to rescale the Shuttle logo"
337345
path = "salvo/image-rescaler"
338346
use_cases = ["Web app", "Image processing"]
339347
tags = ["salvo", "image"]
348+
has_template_repo = true
340349

341350
[templates.serenity-postgres]
342351
title = "Postgres"
@@ -372,6 +381,7 @@ description = "Model Context Protocol server with Server-Sent Events transport"
372381
path = "mcp/mcp-sse"
373382
use_cases = ["Web app", "MCP"]
374383
tags = ["axum", "mcp", "sse"]
384+
has_template_repo = true
375385

376386
[templates.mcp-sse-oauth]
377387
title = "SSE MCP Server with OAuth"

0 commit comments

Comments
 (0)