1use tatara_rust_ast::CrateScaffold;
12
13#[derive(Clone, Debug, Default)]
15pub struct CaixaConfig {
16 pub description: Option<String>,
19 pub attach_auto_release: bool,
21}
22
23pub fn attach_caixa_biblioteca(scaffold: &mut CrateScaffold, config: &CaixaConfig) {
26 if !scaffold.files.iter().any(|f| f.path == "caixa.lisp") {
27 scaffold.add_file(
28 "caixa.lisp",
29 render_caixa_biblioteca(
30 &scaffold.name,
31 &scaffold.version,
32 config.description.as_deref(),
33 ),
34 );
35 }
36 if config.attach_auto_release
37 && !scaffold
38 .files
39 .iter()
40 .any(|f| f.path == ".github/workflows/auto-release.yml")
41 {
42 scaffold.add_file(
43 ".github/workflows/auto-release.yml",
44 render_auto_release_workflow(),
45 );
46 }
47}
48
49#[must_use]
65pub fn render_caixa_biblioteca(name: &str, version: &str, description: Option<&str>) -> String {
66 let desc = description.unwrap_or("Generated by tatara-rust-ast.");
67 let repo = format!("https://github.com/pleme-io/{name}");
68 format!(
69 r#";; caixa.lisp — generated by tatara-rust-caixa (tatara-rust-ast).
70;;
71;; Consumed by `pleme-doc-gen` for the SDLC pipeline (Cargo.toml +
72;; .pleme-io-release.toml + CI shims + nix module trio + flake.nix).
73;; Re-emit with `pleme-doc-gen caixa --source caixa.lisp --out .`.
74
75(defcaixa {name}
76 :kind "Biblioteca"
77 :ecosystem "rust-single-crate"
78
79 :package {{ :name "{name}"
80 :version "{version}"
81 :license "MIT"
82 :description "{desc}"
83 :repository "{repo}"
84 :homepage "{repo}"
85 :categories [ "development-tools::procedural-macro-helpers" ]
86 :keywords [ "tatara" "macro" "derive" "generated" ] }}
87
88 :ci-config {{ :bump {{ :default-type "patch" }}
89 :publish {{ :no-verify false }} }}
90
91 :workflows [ :auto-release ]
92 :stacks [ ]
93 :depends-on [ ]
94 :exposes [ :rust-crate ]
95 :publish-to-git true)
96"#
97 )
98}
99
100#[must_use]
108pub fn render_auto_release_workflow() -> String {
109 r#"# Auto-emitted by tatara-rust-caixa.
110# The reusable substrate workflow does auto-bump → tag → publish to crates.io.
111on:
112 push:
113 branches: [main]
114 workflow_dispatch:
115 inputs:
116 bump-type:
117 description: "patch | minor | major"
118 required: false
119 default: patch
120
121jobs:
122 release:
123 uses: pleme-io/substrate/.github/workflows/cargo-auto-release.yml@main
124 with:
125 bump-type: ${{ inputs.bump-type || 'patch' }}
126 regenerate-cargo-nix: "false"
127 secrets: inherit
128"#
129 .to_string()
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn attaches_caixa_lisp() {
138 let mut s = CrateScaffold::new("my-derive", "0.1.0");
139 attach_caixa_biblioteca(
140 &mut s,
141 &CaixaConfig {
142 description: Some("Test crate".into()),
143 attach_auto_release: false,
144 },
145 );
146 let files = s.to_files();
147 assert!(files.contains_key("caixa.lisp"));
148 let lisp = files.get("caixa.lisp").unwrap();
149 assert!(lisp.contains("(defcaixa my-derive"));
151 assert!(lisp.contains(r#":kind "Biblioteca""#));
152 assert!(lisp.contains(r#":ecosystem "rust-single-crate""#));
153 assert!(lisp.contains(r#":name "my-derive""#));
154 assert!(lisp.contains(r#":version "0.1.0""#));
155 assert!(lisp.contains("Test crate"));
156 }
157
158 #[test]
164 fn emits_every_keyword_pleme_doc_gen_parser_consumes() {
165 let lisp = render_caixa_biblioteca("foo-derive", "1.2.3", Some("Foo macro."));
166
167 assert!(lisp.starts_with(";;") || lisp.contains("(defcaixa foo-derive"));
169
170 for kw in [":kind", ":ecosystem", ":package", ":ci-config", ":workflows"] {
172 assert!(
173 lisp.contains(kw),
174 "caixa.lisp missing required keyword `{kw}` for pleme-doc-gen parser"
175 );
176 }
177
178 for pkg_key in [":name", ":version", ":license", ":description", ":repository"] {
181 assert!(
182 lisp.contains(pkg_key),
183 "caixa.lisp :package missing `{pkg_key}`"
184 );
185 }
186
187 assert!(lisp.contains(r#":ecosystem "rust-single-crate""#));
190 }
191
192 #[test]
193 fn attaches_workflow_when_enabled() {
194 let mut s = CrateScaffold::new("x", "0.1.0");
195 attach_caixa_biblioteca(
196 &mut s,
197 &CaixaConfig {
198 attach_auto_release: true,
199 ..Default::default()
200 },
201 );
202 assert!(
203 s.to_files()
204 .contains_key(".github/workflows/auto-release.yml")
205 );
206 }
207
208 #[test]
209 fn idempotent() {
210 let mut s = CrateScaffold::new("x", "0.1.0");
211 s.add_file("caixa.lisp", "custom");
212 attach_caixa_biblioteca(&mut s, &CaixaConfig::default());
213 assert_eq!(s.to_files()["caixa.lisp"], "custom");
214 }
215
216 #[test]
217 fn workflow_references_substrate_reusable() {
218 let w = render_auto_release_workflow();
219 assert!(w.contains("uses: pleme-io/substrate/.github/workflows/cargo-auto-release.yml"));
222 assert!(w.contains(r#"regenerate-cargo-nix: "false""#));
223 assert!(w.contains("secrets: inherit"));
224 }
225}