Skip to repository content374 lines · 13.0 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T06:47:42.976Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
deploy_docs.rs
1use gh_workflow::{
2 Event, Expression, Input, Job, Level, Permissions, Push, Run, Step, Use, UsesJob, Workflow,
3 WorkflowCall, WorkflowCallSecret, WorkflowDispatch,
4};
5
6use crate::tasks::workflows::{
7 runners,
8 steps::{
9 self, CommonJobConditions, CommonPermissionSets, FluentBuilder as _, NamedJob,
10 UploadArtifactStep, named, release_job,
11 },
12 vars::{self, StepOutput, WorkflowInput},
13};
14
15const BUILD_OUTPUT_DIR: &str = "target/deploy";
16
17pub(crate) enum DocsChannel {
18 Nightly,
19 Preview,
20 Stable,
21}
22
23impl DocsChannel {
24 pub(crate) fn site_url(&self) -> &'static str {
25 match self {
26 Self::Nightly => "/docs/nightly/",
27 Self::Preview => "/docs/preview/",
28 Self::Stable => "/docs/",
29 }
30 }
31
32 pub(crate) fn project_name(&self) -> &'static str {
33 match self {
34 Self::Nightly => "docs-nightly",
35 Self::Preview => "docs-preview",
36 Self::Stable => "docs",
37 }
38 }
39
40 pub(crate) fn channel_name(&self) -> &'static str {
41 match self {
42 Self::Nightly => "nightly",
43 Self::Preview => "preview",
44 Self::Stable => "stable",
45 }
46 }
47}
48
49pub(crate) fn lychee_link_check(dir: &str) -> Step<Use> {
50 named::uses(
51 "lycheeverse",
52 "lychee-action",
53 "82202e5e9c2f4ef1a55a3d02563e1cb6041e5332",
54 ) // v2.4.1
55 .add_with(("args", format!("--no-progress --exclude '^http' '{dir}'")))
56 .add_with(("fail", true))
57 .add_with(("jobSummary", false))
58}
59
60pub(crate) fn install_mdbook() -> Step<Use> {
61 named::uses(
62 "peaceiris",
63 "actions-mdbook",
64 "ee69d230fe19748b7abf22df32acaa93833fad08", // v2
65 )
66 .with(("mdbook-version", "0.4.37"))
67}
68
69pub(crate) fn build_docs_book(docs_channel: String, site_url: String) -> Step<Run> {
70 named::bash(indoc::formatdoc! {r#"
71 mkdir -p {BUILD_OUTPUT_DIR}
72 mdbook build ./docs --dest-dir=../{BUILD_OUTPUT_DIR}/docs/
73 "#})
74 .add_env(("DOCS_CHANNEL", docs_channel))
75 .add_env(("MDBOOK_BOOK__SITE_URL", site_url))
76}
77
78fn docs_build_steps(
79 job: Job,
80 checkout_ref: Option<String>,
81 docs_channel: impl Into<String>,
82 site_url: impl Into<String>,
83) -> Job {
84 let docs_channel = docs_channel.into();
85 let site_url = site_url.into();
86
87 steps::use_clang(
88 job.add_env(("DOCS_AMPLITUDE_API_KEY", vars::DOCS_AMPLITUDE_API_KEY))
89 .add_env(("DOCS_CONSENT_IO_INSTANCE", vars::DOCS_CONSENT_IO_INSTANCE))
90 .add_step(
91 steps::checkout_repo().when_some(checkout_ref, |step, checkout_ref| {
92 step.with_ref(checkout_ref)
93 }),
94 )
95 .runs_on(runners::LINUX_XL)
96 .add_step(steps::setup_cargo_config(runners::Platform::Linux))
97 .add_step(steps::cache_rust_dependencies_namespace())
98 .map(steps::install_linux_dependencies)
99 .add_step(steps::script("./script/generate-action-metadata"))
100 .add_step(lychee_link_check("./docs/src/**/*"))
101 .add_step(install_mdbook())
102 .add_step(build_docs_book(docs_channel, site_url))
103 .add_step(lychee_link_check(&format!("{BUILD_OUTPUT_DIR}/docs"))),
104 )
105}
106
107fn docs_deploy_steps(job: Job, project_name: &StepOutput) -> Job {
108 fn deploy_to_cf_pages(project_name: &StepOutput) -> Step<Use> {
109 named::uses(
110 "cloudflare",
111 "wrangler-action",
112 "da0e0dfe58b7a431659754fdf3f186c529afbe65",
113 ) // v3
114 .add_with(("apiToken", vars::CLOUDFLARE_API_TOKEN))
115 .add_with(("accountId", vars::CLOUDFLARE_ACCOUNT_ID))
116 .add_with((
117 "command",
118 format!(
119 "pages deploy {BUILD_OUTPUT_DIR} --project-name=${{{{ {} }}}} --branch main",
120 project_name.expr()
121 ),
122 ))
123 }
124
125 fn upload_install_script() -> Step<Use> {
126 named::uses(
127 "cloudflare",
128 "wrangler-action",
129 "da0e0dfe58b7a431659754fdf3f186c529afbe65",
130 ) // v3
131 .add_with(("apiToken", vars::CLOUDFLARE_API_TOKEN))
132 .add_with(("accountId", vars::CLOUDFLARE_ACCOUNT_ID))
133 .add_with((
134 "command",
135 "r2 object put -f script/install.sh zed-open-source-website-assets/install.sh",
136 ))
137 }
138
139 fn deploy_docs_worker() -> Step<Use> {
140 named::uses(
141 "cloudflare",
142 "wrangler-action",
143 "da0e0dfe58b7a431659754fdf3f186c529afbe65",
144 ) // v3
145 .add_with(("apiToken", vars::CLOUDFLARE_API_TOKEN))
146 .add_with(("accountId", vars::CLOUDFLARE_ACCOUNT_ID))
147 .add_with(("command", "deploy .cloudflare/docs-proxy/src/worker.js"))
148 }
149
150 fn upload_wrangler_logs() -> UploadArtifactStep {
151 steps::upload_artifact("wrangler_logs", "/home/runner/.config/.wrangler/logs/")
152 .if_condition(Expression::new("always()"))
153 }
154
155 job.add_step(deploy_to_cf_pages(project_name))
156 .add_step(upload_install_script())
157 .add_step(deploy_docs_worker())
158 .add_step(upload_wrangler_logs())
159}
160
161pub(crate) fn check_docs() -> NamedJob {
162 NamedJob {
163 name: "check_docs".to_owned(),
164 job: docs_build_steps(
165 release_job(&[]).add_step(steps::harden_runner()),
166 None,
167 DocsChannel::Stable.channel_name(),
168 DocsChannel::Stable.site_url(),
169 ),
170 }
171}
172
173fn resolve_channel_step(
174 channel_expr: impl Into<String>,
175) -> (Step<Run>, StepOutput, StepOutput, StepOutput) {
176 let step = Step::new("deploy_docs::resolve_channel_step").run(format!(
177 indoc::indoc! {r#"
178 if [ -z "$CHANNEL" ]; then
179 if [ "$GITHUB_REF" = "refs/heads/main" ]; then
180 CHANNEL="nightly"
181 else
182 echo "::error::channel input is required when ref is not main."
183 exit 1
184 fi
185 fi
186
187 case "$CHANNEL" in
188 "nightly")
189 SITE_URL="{nightly_site_url}"
190 PROJECT_NAME="{nightly_project_name}"
191 ;;
192 "preview")
193 SITE_URL="{preview_site_url}"
194 PROJECT_NAME="{preview_project_name}"
195 ;;
196 "stable")
197 SITE_URL="{stable_site_url}"
198 PROJECT_NAME="{stable_project_name}"
199 ;;
200 *)
201 echo "::error::Invalid docs channel '$CHANNEL'. Expected one of: nightly, preview, stable."
202 exit 1
203 ;;
204 esac
205
206 {{
207 echo "channel=$CHANNEL"
208 echo "site_url=$SITE_URL"
209 echo "project_name=$PROJECT_NAME"
210 }} >> "$GITHUB_OUTPUT"
211 "#},
212 nightly_site_url = DocsChannel::Nightly.site_url(),
213 preview_site_url = DocsChannel::Preview.site_url(),
214 stable_site_url = DocsChannel::Stable.site_url(),
215 nightly_project_name = DocsChannel::Nightly.project_name(),
216 preview_project_name = DocsChannel::Preview.project_name(),
217 stable_project_name = DocsChannel::Stable.project_name(),
218 ))
219 .id("resolve-channel")
220 .add_env(("CHANNEL", channel_expr.into()));
221
222 let channel = StepOutput::new(&step, "channel");
223 let site_url = StepOutput::new(&step, "site_url");
224 let project_name = StepOutput::new(&step, "project_name");
225 (step, channel, site_url, project_name)
226}
227
228fn docs_job(channel_expr: impl Into<String>, checkout_ref: Option<String>) -> NamedJob {
229 let (resolve_step, channel, site_url, project_name) = resolve_channel_step(channel_expr);
230
231 NamedJob {
232 name: "deploy_docs".to_owned(),
233 job: docs_deploy_steps(
234 docs_build_steps(
235 release_job(&[])
236 .cond(Expression::new(
237 "github.repository_owner == 'zed-industries'",
238 ))
239 .name("Build and Deploy Docs")
240 .add_step(resolve_step),
241 checkout_ref,
242 channel.to_string(),
243 site_url.to_string(),
244 ),
245 &project_name,
246 ),
247 }
248}
249
250pub(crate) fn deploy_docs_workflow_call(
251 channel: impl Into<String>,
252 checkout_ref: impl Into<String>,
253) -> NamedJob<UsesJob> {
254 let job = Job::default()
255 .with_repository_owner_guard()
256 .permissions(Permissions::default().contents(Level::Read))
257 .uses(
258 "zed-industries",
259 "zed",
260 ".github/workflows/deploy_docs.yml",
261 // Pinned to a commit rather than the mutable `main` ref (supply-chain hardening).
262 // Same-repo reusable workflow; bump via Dependabot or alongside deploy_docs.yml changes.
263 "3f16f7b9082f8828e4d6ae207d2349b1ef932517",
264 )
265 .with(
266 Input::default()
267 .add("channel", channel.into())
268 .add("checkout_ref", checkout_ref.into()),
269 )
270 .secrets(indexmap::IndexMap::from([
271 (
272 "DOCS_AMPLITUDE_API_KEY".to_owned(),
273 vars::DOCS_AMPLITUDE_API_KEY.to_owned(),
274 ),
275 (
276 "DOCS_CONSENT_IO_INSTANCE".to_owned(),
277 vars::DOCS_CONSENT_IO_INSTANCE.to_owned(),
278 ),
279 (
280 "CLOUDFLARE_API_TOKEN".to_owned(),
281 vars::CLOUDFLARE_API_TOKEN.to_owned(),
282 ),
283 (
284 "CLOUDFLARE_ACCOUNT_ID".to_owned(),
285 vars::CLOUDFLARE_ACCOUNT_ID.to_owned(),
286 ),
287 ]));
288
289 NamedJob {
290 name: "deploy_docs".to_owned(),
291 job,
292 }
293}
294
295pub(crate) fn deploy_docs_job(
296 channel_input: &WorkflowInput,
297 checkout_ref_input: &WorkflowInput,
298) -> NamedJob {
299 docs_job(
300 channel_input.to_string(),
301 Some(format!(
302 "${{{{ {} != '' && {} || github.sha }}}}",
303 checkout_ref_input.expr(),
304 checkout_ref_input.expr()
305 )),
306 )
307}
308
309pub(crate) fn deploy_docs() -> Workflow {
310 let channel = WorkflowInput::string("channel", Some(String::new()))
311 .description("Docs channel to deploy: nightly, preview, or stable");
312 let checkout_ref = WorkflowInput::string("checkout_ref", Some(String::new()))
313 .description("Git ref to checkout and deploy. Defaults to event SHA when omitted.");
314 let deploy_docs = deploy_docs_job(&channel, &checkout_ref);
315
316 named::workflow()
317 .with_minimal_permissions()
318 .add_event(
319 Event::default().workflow_dispatch(
320 WorkflowDispatch::default()
321 .add_input(channel.name, channel.input())
322 .add_input(checkout_ref.name, checkout_ref.input()),
323 ),
324 )
325 .add_event(
326 Event::default().workflow_call(
327 WorkflowCall::default()
328 .add_input(channel.name, channel.call_input())
329 .add_input(checkout_ref.name, checkout_ref.call_input())
330 .secrets([
331 (
332 "DOCS_AMPLITUDE_API_KEY".to_owned(),
333 WorkflowCallSecret {
334 description: "DOCS_AMPLITUDE_API_KEY".to_owned(),
335 required: true,
336 },
337 ),
338 (
339 "DOCS_CONSENT_IO_INSTANCE".to_owned(),
340 WorkflowCallSecret {
341 description: "DOCS_CONSENT_IO_INSTANCE".to_owned(),
342 required: true,
343 },
344 ),
345 (
346 "CLOUDFLARE_API_TOKEN".to_owned(),
347 WorkflowCallSecret {
348 description: "CLOUDFLARE_API_TOKEN".to_owned(),
349 required: true,
350 },
351 ),
352 (
353 "CLOUDFLARE_ACCOUNT_ID".to_owned(),
354 WorkflowCallSecret {
355 description: "CLOUDFLARE_ACCOUNT_ID".to_owned(),
356 required: true,
357 },
358 ),
359 ]),
360 ),
361 )
362 .add_job(deploy_docs.name, deploy_docs.job)
363}
364
365pub(crate) fn deploy_nightly_docs() -> Workflow {
366 let deploy_docs = deploy_docs_workflow_call("nightly", "${{ github.sha }}");
367
368 named::workflow()
369 .name("deploy_nightly_docs")
370 .permissions(Permissions::default())
371 .add_event(Event::default().push(Push::default().add_branch("main")))
372 .add_job(deploy_docs.name, deploy_docs.job)
373}
374