Skip to main content

newgit_core/
templates.rs

1/// Starter resource templates. `companions` are additional resource
2/// definitions the template depends on, and `companion_trackers` are lanes
3/// it deposits into; both are created alongside it when absent (e.g. the
4/// user-owned `pnpm-store` that `deps` depends on, or the `db-snapshots`
5/// lane a Postgres dump lands in).
6#[derive(Debug, Clone, Copy)]
7pub struct ResourceTemplate {
8    pub name: &'static str,
9    pub description: &'static str,
10    pub contents: &'static str,
11    pub companions: &'static [CompanionFile],
12    pub companion_trackers: &'static [CompanionTracker],
13}
14
15#[derive(Debug, Clone, Copy)]
16pub struct CompanionFile {
17    pub name: &'static str,
18    pub contents: &'static str,
19}
20
21/// A tracker a template's checkpoint deposits into. Created through the same
22/// CLI path as `newgit tracker create`, so trackers stay CLI-managed and
23/// templates never hand-write tracker TOML.
24#[derive(Debug, Clone, Copy)]
25pub struct CompanionTracker {
26    pub name: &'static str,
27    pub audience: &'static str,
28    pub merge_with_source: bool,
29}
30
31pub const RESOURCE_TEMPLATES: &[ResourceTemplate] = &[
32    ResourceTemplate {
33        name: "process",
34        description: "a branch-local long-running process with its own port",
35        companions: &[],
36        companion_trackers: &[],
37        contents: r#"kind = "process"
38ownership = "branch"
39# Trackers or resources that must be ready first, e.g. ["deps", "runtime-env"].
40depends_on = []
41
42[ports]
43app = { start = 3100, env = "PORT" }
44
45[actions.start]
46# Edit to your dev command, e.g. "pnpm dev" or "bin/rails server".
47command = "npm run dev"
48long_running = true
49
50[actions.stop]
51signal = "term"
52
53[exports]
54APP_URL = "http://127.0.0.1:{{ports.app}}"
55"#,
56    },
57    ResourceTemplate {
58        name: "pnpm",
59        description: "dependency install via pnpm; recomputed, never copied",
60        // The shared package store is user-owned: newgit must never delete
61        // or rewrite it. Created alongside so `depends_on` resolves.
62        companions: &[CompanionFile {
63            name: "pnpm-store",
64            contents: r#"kind = "external-store"
65ownership = "user"
66
67[checkpoint]
68mode = "hash"
69paths = ["pnpm-lock.yaml"]
70
71[restore]
72mode = "none"
73"#,
74        }],
75        companion_trackers: &[],
76        contents: r#"kind = "command"
77ownership = "workspace"
78depends_on = ["pnpm-store"]
79
80[identity]
81paths = ["package.json", "pnpm-lock.yaml"]
82
83[actions.prepare]
84command = "pnpm install --frozen-lockfile"
85
86[checkpoint]
87mode = "hash"
88paths = ["package.json", "pnpm-lock.yaml"]
89
90[restore]
91mode = "recompute"
92action = "prepare"
93"#,
94    },
95    ResourceTemplate {
96        name: "command-snapshot",
97        description: "a daemon-owned database captured through the daemon into a tracker",
98        companions: &[],
99        // The dump has to land somewhere versioned; this is the one seam
100        // between the two primitives, so the lane ships with the template.
101        companion_trackers: &[CompanionTracker {
102            name: "db-snapshots",
103            audience: "project-devs",
104            merge_with_source: false,
105        }],
106        contents: r#"kind = "command-snapshot"
107ownership = "branch"
108
109# A branch-local database, named after the instance so instances never share
110# one. Edit the commands for your database; the shape is what matters:
111# checkpoint emits a dump into the lane, restore reads it back.
112
113[actions.prepare]
114command = "createdb {{branch.slug}} || true"
115
116[actions.migrate]
117# Edit to your migration command.
118command = "npm run db:migrate"
119
120[checkpoint]
121mode = "command"
122command = "pg_dump {{branch.slug}} > {{snapshot.path}}/db.sql && echo {{snapshot.path}}/db.sql"
123into_tracker = "db-snapshots"
124
125[restore]
126mode = "command"
127command = "dropdb {{branch.slug}} --if-exists && createdb {{branch.slug}} && psql --quiet {{branch.slug}} < {{state_ref}}"
128
129[cleanup]
130command = "dropdb {{branch.slug}} --if-exists"
131
132[exports]
133DATABASE_URL = "postgres://localhost/{{branch.slug}}"
134"#,
135    },
136    ResourceTemplate {
137        name: "external",
138        description: "a resource another system owns; newgit holds only a handle",
139        companions: &[],
140        companion_trackers: &[],
141        contents: r#"kind = "external"
142ownership = "external"
143
144# newgit does not own this resource, so it never assumes deletion semantics
145# it did not author: `ownership = "external"` means cleanup runs exactly the
146# command below and nothing else.
147#
148# `captures` reads names out of the prepare command's stdout — either a flat
149# JSON object or KEY=VALUE lines — and publishes them as this resource's
150# exports, so `newgit run` and the hooks below can use them.
151
152[actions.prepare]
153# Edit to your provisioning command.
154command = "cloudctl preview create --branch {{branch.name}} --json"
155captures = ["PREVIEW_ID", "PREVIEW_URL"]
156
157[checkpoint]
158mode = "external"
159state_ref = "{{exports.PREVIEW_ID}}"
160
161[restore]
162# The handle is recorded, not re-created: an undo does not rewind another
163# system. Change to `mode = "command"` if yours can be rewound.
164mode = "external"
165
166[cleanup]
167command = "cloudctl preview delete {{state_ref}}"
168"#,
169    },
170];
171
172pub fn resource_template(name: &str) -> Option<&'static ResourceTemplate> {
173    RESOURCE_TEMPLATES
174        .iter()
175        .find(|template| template.name == name)
176}