anodizer_core/config/publishers/winget.rs
1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use super::super::{
5 Amd64Variant, PostPublishPollConfig, StringOrBool, deserialize_string_or_bool_opt,
6};
7use super::{CommitAuthorConfig, RepositoryConfig};
8
9// ---------------------------------------------------------------------------
10// WingetConfig
11// ---------------------------------------------------------------------------
12
13#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
14#[serde(default, deny_unknown_fields)]
15pub struct WingetConfig {
16 /// Override the package name (default: crate name).
17 pub name: Option<String>,
18 /// Package name as displayed (default: same as name).
19 pub package_name: Option<String>,
20 /// WinGet package identifier (e.g. "Publisher.AppName"). Auto-generated if empty.
21 pub package_identifier: Option<String>,
22 /// Publisher name (required).
23 pub publisher: Option<String>,
24 /// Publisher homepage URL shown in the WinGet manifest.
25 pub publisher_url: Option<String>,
26 /// Publisher support URL.
27 pub publisher_support_url: Option<String>,
28 /// Privacy policy URL.
29 pub privacy_url: Option<String>,
30 /// Author name.
31 pub author: Option<String>,
32 /// Copyright notice.
33 pub copyright: Option<String>,
34 /// Copyright URL.
35 pub copyright_url: Option<String>,
36 /// License identifier (required, e.g. "MIT").
37 pub license: Option<String>,
38 /// License URL.
39 pub license_url: Option<String>,
40 /// Short description (required, max 256 chars).
41 pub short_description: Option<String>,
42 /// Locale stamped into the WinGet manifests: the version manifest's
43 /// `DefaultLocale`, the installer manifest's `InstallerLocale`, the
44 /// locale manifest's `PackageLocale`, and the locale manifest's
45 /// `.locale.<locale>.yaml` file name. Supports templates.
46 /// Default: `en-US`.
47 ///
48 /// ```yaml
49 /// winget:
50 /// default_locale: "pt-BR"
51 /// ```
52 pub default_locale: Option<String>,
53 /// Full package description displayed in the WinGet gallery.
54 pub description: Option<String>,
55 /// Project homepage URL.
56 pub homepage: Option<String>,
57 /// Custom URL template for download URLs (overrides release URL).
58 pub url_template: Option<String>,
59 /// Build IDs filter: only include artifacts whose `id` is in this list.
60 pub ids: Option<Vec<String>>,
61 /// Skip publishing. `"true"` always skips; `"auto"` skips for prereleases.
62 /// Accepts bool or template string.
63 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
64 pub skip_upload: Option<StringOrBool>,
65 /// Custom commit message template.
66 pub commit_msg_template: Option<String>,
67 /// Manifest file path (auto-generated if empty from publisher/name/version).
68 pub path: Option<String>,
69 /// Release notes for this version.
70 pub release_notes: Option<String>,
71 /// URL to full release notes.
72 pub release_notes_url: Option<String>,
73 /// Post-install notes shown to the user.
74 pub installation_notes: Option<String>,
75 /// Tags for package discovery (lowercased, spaces→hyphens).
76 pub tags: Option<Vec<String>>,
77 /// Package dependencies.
78 pub dependencies: Option<Vec<WingetDependency>>,
79 /// Unified repository config with branch, token, PR, git SSH support.
80 /// (Replaces the legacy `manifests_repo: WingetManifestsRepoConfig`.)
81 pub repository: Option<RepositoryConfig>,
82 /// Commit author with optional signing.
83 pub commit_author: Option<CommitAuthorConfig>,
84 /// Product code for the installer (used in Add/Remove Programs).
85 pub product_code: Option<String>,
86 /// Short invoke alias shown as the package `Moniker` (e.g. `rg` for
87 /// ripgrep, `fd` for fd). This is the command users type, NOT the
88 /// package/crate name. When unset, anodizer derives it from the single
89 /// published binary name; with multiple binaries and no override the
90 /// Moniker is omitted (winget treats it as optional).
91 ///
92 /// Example: `moniker: "rg"`.
93 pub moniker: Option<String>,
94 /// Documentation links rendered as the `Documentations[]` block on the
95 /// locale manifest. Each entry is a `{ label, url }` pair surfaced in the
96 /// winget gallery (real ripgrep emits a `FAQ` and a `User Guide` entry).
97 /// Omitted entirely when empty.
98 ///
99 /// Example:
100 /// ```yaml
101 /// documentations:
102 /// - label: "User Guide"
103 /// url: "https://github.com/owner/repo/blob/master/GUIDE.md"
104 /// ```
105 pub documentations: Option<Vec<WingetDocumentation>>,
106 /// Installer `UpgradeBehavior` for every installer entry. winget accepts
107 /// `install`, `uninstallPrevious`, and `deny`. Defaults to `install` —
108 /// the correct behavior for portable-zip CLI tools (`uninstallPrevious`
109 /// forces a clobbering reinstall).
110 ///
111 /// Example: `upgrade_behavior: "uninstallPrevious"`.
112 pub upgrade_behavior: Option<String>,
113 /// Silent-install switch string emitted as `InstallerSwitches.Silent` for
114 /// actual installers (`wix`/`msi`/`exe`/`nsis`). When unset, anodizer
115 /// derives the switch from the installer type (`/quiet` for msi, `/S` for
116 /// exe/nsis). Never emitted for `zip`/`portable` artifacts.
117 ///
118 /// Example: `silent_switch: "/qn"`.
119 pub silent_switch: Option<String>,
120 /// Artifact selection: "archive" (default), "msi", or "nsis".
121 #[serde(rename = "use")]
122 pub use_artifact: Option<String>,
123 /// amd64 microarchitecture variant filter (`v1` / `v2` / `v3` / `v4`).
124 /// Only artifacts matching this variant are included. Default: `v1`.
125 /// Typed as [`Amd64Variant`], so any value outside `v1`..`v4` is
126 /// rejected when the config is parsed.
127 pub amd64_variant: Option<Amd64Variant>,
128 /// Post-publish PR-validation polling settings. Polling is
129 /// disabled by default — winget-pkgs PR validation routinely
130 /// takes hours to days, and blocking a CI workflow on that wait
131 /// is wrong. Opt in per-publisher with
132 /// `post_publish_poll: { enabled: true }` when running locally and
133 /// willing to wait, or disable globally via `--no-post-publish-poll`.
134 pub post_publish_poll: Option<PostPublishPollConfig>,
135 /// When true, force-push the updated manifest to the existing PR branch
136 /// when a PR for the same head branch already exists. The PR content is
137 /// updated in place rather than creating a duplicate. When false (default),
138 /// the push is skipped and a warning is emitted so the operator sees that
139 /// the publisher did not update the PR.
140 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
141 pub update_existing_pr: Option<StringOrBool>,
142 /// Override whether this publisher failing should fail the overall release.
143 ///
144 /// Default: `false` — a failure here is logged but does not abort the release.
145 /// Set to `true` to fail the release on any error.
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub required: Option<bool>,
148 /// Template-conditional gate: when the rendered result is falsy
149 /// (`"false"` / `"0"` / `"no"` / empty), the WinGet publisher is
150 /// skipped. Render failure hard-errors. Config key: `winget[].if:`.
151 #[serde(rename = "if")]
152 pub if_condition: Option<String>,
153 /// When `true`, a triggered rollback leaves this publisher's work in
154 /// place rather than attempting to undo it. Default `false`.
155 pub retain_on_rollback: Option<bool>,
156}
157
158/// The WinGet architecture vocabulary an installer manifest may carry, and the
159/// only values a `WingetDependency.architectures` scope may name. Mirrors the
160/// output domain of the publisher's raw-arch → WinGet-arch mapping (`amd64`→
161/// `x64`, `386`/`i686`→`x86`, `arm64`→`arm64`). A scope value outside this set
162/// matches no installer, so the dependency would silently vanish from the
163/// manifest — config validation rejects it up front.
164pub const WINGET_ARCHITECTURES: [&str; 3] = ["x64", "arm64", "x86"];
165
166/// A single documentation link rendered into the winget locale manifest's
167/// `Documentations[]` block as `{ DocumentLabel, DocumentUrl }`.
168#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
169#[serde(default, deny_unknown_fields)]
170pub struct WingetDocumentation {
171 /// Display label for the link (e.g. `FAQ`, `User Guide`).
172 pub label: String,
173 /// Target URL for the documentation entry.
174 pub url: String,
175}
176
177/// WinGet package dependency.
178#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
179#[serde(default, deny_unknown_fields)]
180pub struct WingetDependency {
181 /// WinGet package identifier of the dependency (e.g., "Publisher.App").
182 pub package_identifier: String,
183 /// Minimum required version of the dependency.
184 pub minimum_version: Option<String>,
185 /// Architecture scope: attach this dependency only to installers whose
186 /// architecture matches one of these WinGet architecture names (`x64`,
187 /// `arm64`, `x86`). When unset or empty the dependency applies to every
188 /// installer (the default — preserves the manifest-wide behavior).
189 ///
190 /// Use this when a runtime dependency is architecture-specific: e.g. an
191 /// `x64` build needs the x64 VC++ runtime while the native `arm64` build
192 /// needs the arm64 one, so each must be scoped to its own installer rather
193 /// than attached to all of them.
194 ///
195 /// Example:
196 /// ```yaml
197 /// dependencies:
198 /// - package_identifier: "Microsoft.VCRedist.2015+.x64"
199 /// architectures: ["x64"]
200 /// - package_identifier: "Microsoft.VCRedist.2015+.arm64"
201 /// architectures: ["arm64"]
202 /// # unscoped — applies to every installer:
203 /// - package_identifier: "Acme.CommonRuntime"
204 /// ```
205 pub architectures: Option<Vec<String>>,
206}