Skip to main content

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