anodizer_core/config/publishers/krew.rs
1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use super::super::{Amd64Variant, StringOrBool, deserialize_string_or_bool_opt};
5use super::{CommitAuthorConfig, RepositoryConfig};
6
7// ---------------------------------------------------------------------------
8// KrewConfig
9// ---------------------------------------------------------------------------
10
11#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
12#[serde(default, deny_unknown_fields)]
13pub struct KrewConfig {
14 /// Override the plugin name (default: crate name).
15 pub name: Option<String>,
16 /// Build IDs filter: only include artifacts whose `id` is in this list.
17 pub ids: Option<Vec<String>>,
18 /// Unified repository config with branch, token, PR, git SSH support.
19 /// (Replaces the legacy `manifests_repo:` / `upstream_repo:` form.) The
20 /// upstream PR target is derived from `repository.pull_request.base`
21 /// when set, falling back to the canonical kubernetes-sigs/krew-index.
22 pub repository: Option<RepositoryConfig>,
23 /// Commit author with optional signing.
24 pub commit_author: Option<CommitAuthorConfig>,
25 /// Custom commit message template.
26 pub commit_msg_template: Option<String>,
27 /// Full description of the kubectl plugin.
28 pub description: Option<String>,
29 /// One-line summary of the kubectl plugin (max 255 chars).
30 pub short_description: Option<String>,
31 /// Project homepage URL for the plugin.
32 pub homepage: Option<String>,
33 /// Custom URL template for download URLs (overrides release URL).
34 pub url_template: Option<String>,
35 /// Post-install message shown to the user.
36 pub caveats: Option<String>,
37 /// Skip publishing. `"true"` always skips; `"auto"` skips for prereleases.
38 /// Accepts bool or template string.
39 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
40 pub skip_upload: Option<StringOrBool>,
41 /// Skip this Krew config. Accepts bool or template string
42 /// (e.g. `"{{ if .IsSnapshot }}true{{ endif }}"` for conditional skip).
43 /// Distinct from `skip_upload` so users can opt out of generating the
44 /// manifest entirely (common when a project is not a kubectl plugin and
45 /// has no krew channel).
46 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
47 pub skip: Option<StringOrBool>,
48 /// amd64 microarchitecture variant filter (`v1` / `v2` / `v3` / `v4`).
49 /// Only artifacts matching this variant are included. Default: `v1`.
50 /// Typed as [`Amd64Variant`], so any value outside `v1`..`v4` is
51 /// rejected when the config is parsed.
52 pub amd64_variant: Option<Amd64Variant>,
53 /// ARM version filter (e.g. "6", "7"). Only artifacts matching this
54 /// variant are included.
55 pub arm_variant: Option<String>,
56 /// When true, force-push the updated plugin manifest to the existing PR
57 /// branch when a PR for the same head branch already exists. The PR content
58 /// is updated in place rather than creating a duplicate. When false
59 /// (default), the push is skipped and a warning is emitted so the operator
60 /// sees that the publisher did not update the PR.
61 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
62 pub update_existing_pr: Option<StringOrBool>,
63 /// Override whether this publisher failing should fail the overall release.
64 ///
65 /// Default: `false` — a failure here is logged but does not abort the release.
66 /// Set to `true` to fail the release on any error.
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub required: Option<bool>,
69 /// Template-conditional gate: when the rendered result is falsy
70 /// (`"false"` / `"0"` / `"no"` / empty), the Krew publisher is
71 /// skipped. Render failure hard-errors. Config key: `krews[].if:`.
72 #[serde(rename = "if")]
73 pub if_condition: Option<String>,
74 /// Which krew-index submission path to take.
75 ///
76 /// - `auto` (default): probe whether the plugin already exists in
77 /// `kubernetes-sigs/krew-index`. Already present → `bot` (the
78 /// hosted krew-release-bot opens the version-bump PR server-side);
79 /// definitively absent → `pr-direct` (anodizer opens the initial
80 /// fork PR). A probe that can't reach a definitive answer
81 /// (rate-limit, network error) hard-errors rather than guessing,
82 /// so a transient blip never routes an existing plugin into a
83 /// maintainer-hostile fork PR.
84 /// - `bot`: always POST to the krew-release-bot webhook. Use when
85 /// the plugin is known to be in krew-index and you want to skip
86 /// the membership probe entirely.
87 /// - `pr-direct`: always open a fork PR against krew-index. Use for
88 /// the initial submission, or a self-hosted krew-index mirror the
89 /// hosted bot can't reach.
90 #[serde(default, skip_serializing_if = "Option::is_none")]
91 pub mode: Option<KrewMode>,
92 /// When `true`, a triggered rollback leaves this publisher's work in
93 /// place rather than attempting to undo it. Default `false`.
94 pub retain_on_rollback: Option<bool>,
95}
96
97/// Which krew-index submission path the krew publisher takes.
98///
99/// Selects between the self-contained krew-release-bot webhook and the
100/// fork-PR flow. Defaults to [`KrewMode::Auto`], which probes krew-index
101/// membership to decide.
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
103#[serde(rename_all = "kebab-case")]
104pub enum KrewMode {
105 /// Probe krew-index membership and pick `bot` (present) or
106 /// `pr-direct` (absent). An indeterminate probe hard-errors.
107 #[default]
108 Auto,
109 /// Always submit via the krew-release-bot webhook.
110 Bot,
111 /// Always open a fork PR against krew-index.
112 PrDirect,
113}