anodizer_core/context/mode.rs
1use super::*;
2
3impl Context {
4 pub fn is_dry_run(&self) -> bool {
5 self.options.dry_run
6 }
7
8 pub fn is_snapshot(&self) -> bool {
9 self.options.snapshot
10 }
11
12 /// Whether this run builds only a subset of the configured targets — either
13 /// a `--split` / `--targets` determinism shard (`partial_target`) or a
14 /// host-only `--single-target` build.
15 ///
16 /// A publisher whose eligible artifact is legitimately absent on a
17 /// restricted build (e.g. a Windows-only publisher on a Linux single-target
18 /// snapshot) must self-skip its schema validation rather than error: the
19 /// artifact reaches another target, not a misconfiguration. On a FULL build
20 /// the same absence IS a misconfiguration and must surface. `--single-target`
21 /// (`single_target`) is clap-exclusive with `--targets` / `--host-targets`
22 /// (which populate `partial_target`), but NOT with `--split` (a split shard
23 /// resolves its own `partial_target` from `partial.by` yet may still be
24 /// scoped to the host target), so both signals can be set at once; this OR
25 /// is the single "restricted build" predicate the per-publisher validators
26 /// gate their no-artifact skip on, correct whether one or both are set.
27 pub fn is_target_restricted_build(&self) -> bool {
28 self.options.partial_target.is_some() || self.options.single_target.is_some()
29 }
30
31 /// Whether this run is `anodizer release --publish-only` (publishing a
32 /// preserved dist rather than building from source).
33 ///
34 /// The preserved dist holds the release assets, not the raw cargo output
35 /// they were built from, so a stage that reads a build-time path must
36 /// tolerate its absence here rather than assume the file is on disk.
37 pub fn is_publish_only(&self) -> bool {
38 self.options.publish_only
39 }
40
41 pub fn is_strict(&self) -> bool {
42 self.options.strict
43 }
44
45 /// Effective preflight strictness: the global `--strict` or the
46 /// config-level `preflight.strict` — either one turns it on. Under
47 /// strict preflight, indeterminate probe outcomes (Unknown publisher
48 /// state, 5xx / rate-limit / network failure / undeterminable
49 /// permissions) become hard blockers instead of warnings. Definitive
50 /// failures keep their required→blocker / optional→warning severity
51 /// either way.
52 pub fn preflight_is_strict(&self) -> bool {
53 self.options.strict || self.config.preflight.strict
54 }
55
56 /// Toggle the runtime strict-render flag (see the `render_strict` field).
57 ///
58 /// The pre-publish guard calls this with `true` before its render pass and
59 /// restores the prior value after, so render-error swallowing is suppressed
60 /// only for that in-memory validation — production publish renders stay
61 /// lenient unless the user passed the global `--strict`. Returns the prior
62 /// value so the caller can restore it.
63 pub fn set_render_strict(&self, on: bool) -> bool {
64 self.render_strict.replace(on)
65 }
66
67 /// Whether template renders should propagate errors (strict) rather than
68 /// warn-and-fall-back-to-raw (lenient).
69 ///
70 /// True when EITHER the guard's transient `render_strict` flag is set OR the
71 /// user passed the global `--strict`, so a malformed publisher/announce
72 /// template fails loud under the guard and under `--strict` everywhere.
73 pub fn render_is_strict(&self) -> bool {
74 self.render_strict.get() || self.is_strict()
75 }
76
77 /// In strict mode, return an error. In normal mode, log a warning and continue.
78 /// Use this for any situation where a configured feature silently skips.
79 pub fn strict_guard(&self, log: &crate::log::StageLogger, msg: &str) -> anyhow::Result<()> {
80 if self.options.strict {
81 anyhow::bail!("{} (strict mode)", msg);
82 }
83 log.warn(msg);
84 Ok(())
85 }
86
87 /// Defense-in-depth helper for upload-style stages.
88 ///
89 /// Returns `true` (after logging the skip) when the context is in snapshot
90 /// mode. Stages that perform external uploads (registries, package indexes,
91 /// object storage, snap store, …) call this at entry so they no-op even
92 /// when invoked directly without the orchestration layer's auto-skip.
93 /// Centralising the check keeps every publish stage consistent and avoids
94 /// per-stage copy-paste.
95 pub fn skip_in_snapshot(&self, log: &crate::log::StageLogger, stage: &str) -> bool {
96 if self.is_snapshot() {
97 // The stage name stays in the line: this guard fires on direct
98 // stage invocation, where no pipeline section header has named
99 // the stage yet.
100 log.status(&format!("skipped {stage} — snapshot mode"));
101 true
102 } else {
103 false
104 }
105 }
106
107 pub fn is_nightly(&self) -> bool {
108 self.options.nightly
109 }
110
111 /// Set the `ReleaseURL` template variable.
112 ///
113 /// Should be called after a GitHub release is created, with the URL of
114 /// the created release (e.g. `https://github.com/owner/repo/releases/tag/v1.0.0`).
115 pub fn set_release_url(&mut self, url: &str) {
116 self.template_vars.set("ReleaseURL", url);
117 }
118}