Repository: axodotdev/cargo-dist (rust)

Issue:
Homebrew taps update with prerelease versions
Currently, we push every tagged release to a Homebrew tap. For example: https://github.com/axodotdev/homebrew-tap/commit/8f5ef81fc87944d7c1eb83b037b3d40e71646450

While this is consistent with how we always push to releases, we're able to mark an entire GitHub release as a prerelease in a way we don't do to the Homebrew formula. We should likely either stop pushing prereleases to the tap, or add a configuration flag as to whether to push prereleases to package managers.

Pull request description:
feat(ci): allow disabling publishing prereleases
We currently unconditionally publish prereleases to package managers. We should instead disable that by default while optionally enabling it.

I've left it out of `init` because I see this as more of a power user feature; I've documented it but don't think we should prompt most users about it.

Fixes #398.

Patch:
diff --git a/book/src/config.md b/book/src/config.md
index a299c67c..a6cbf7a0 100644
--- a/book/src/config.md
+++ b/book/src/config.md
@@ -27,6 +27,10 @@ The version of your package is used pervasively, and cargo-dist will generally e
 
 If you set `publish = false` in your Cargo.toml we will treat this as a hint that cargo-dist should ignore all the affected packages completely. You can override this with dist's own `dist = true` config.
 
+### publish-prereleases
+
+If you set `publish-prereleases = true`, cargo-dist will publish prerelease versions to package managers such as Homebrew. By default, cargo-dist will only publish stable versions.
+
 ### repository
 
 cargo-dist has an internal notion of an "artifact download URL" that is required for things like [installers][] that detect the current platform and fetch binaries. If your CI backend is "github" then we will base the "[artifact download URL][artifact-url]" on the "repository" key. To be safe, we will only do this if your workspace agrees on this value. It's fine if only some packages bother setting "repository", as long as the ones that do use the exact same string. If they don't we will fail to compute an "artifact download URL", emit a warning, and ignore your request for installers that require it. (This might want to be a hard error in the future.)
diff --git a/cargo-dist-schema/src/lib.rs b/cargo-dist-schema/src/lib.rs
index efa73194..864c678a 100644
--- a/cargo-dist-schema/src/lib.rs
+++ b/cargo-dist-schema/src/lib.rs
@@ -65,6 +65,9 @@ pub struct DistManifest {
     #[serde(default)]
     #[serde(skip_serializing_if = "BTreeMap::is_empty")]
     pub artifacts: BTreeMap<ArtifactId, Artifact>,
+    /// Whether to publish prereleases to package managers
+    #[serde(default)]
+    pub publish_prereleases: bool,
     /// ci backend info
     #[serde(default)]
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -348,6 +351,7 @@ impl DistManifest {
             system_info: None,
             releases,
             artifacts,
+            publish_prereleases: false,
             ci: None,
         }
     }
diff --git a/cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap b/cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap
index 8c8f2f23..d50f4a8f 100644
--- a/cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap
+++ b/cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap
@@ -66,6 +66,11 @@ expression: json_schema
         "null"
       ]
     },
+    "publish_prereleases": {
+      "description": "Whether to publish prereleases to package managers",
+      "default": false,
+      "type": "boolean"
+    },
     "releases": {
       "description": "App releases we're distributing",
       "type": "array",
diff --git a/cargo-dist/src/config.rs b/cargo-dist/src/config.rs
index 10dfcfa6..5fbfbbe3 100644
--- a/cargo-dist/src/config.rs
+++ b/cargo-dist/src/config.rs
@@ -243,6 +243,13 @@ pub struct DistMetadata {
     #[serde(rename = "publish-jobs")]
     pub publish_jobs: Option<Vec<PublishStyle>>,
 
+    /// Whether to publish prereleases to package managers
+    ///
+    /// (defaults to false)
+    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "publish-prereleases")]
+    pub publish_prereleases: Option<bool>,
+
     /// Whether we should create the Github Release for you when you push a tag.
     ///
     /// If true (default), cargo-dist will create a new Github Release and generate
@@ -282,6 +289,7 @@ impl DistMetadata {
             default_features: _,
             all_features: _,
             publish_jobs: _,
+            publish_prereleases: _,
             create_release: _,
             pr_run_mode: _,
             allow_dirty: _,
@@ -322,6 +330,7 @@ impl DistMetadata {
             default_features,
             all_features,
             publish_jobs,
+            publish_prereleases,
             create_release,
             pr_run_mode: _,
             allow_dirty,
@@ -354,6 +363,9 @@ impl DistMetadata {
         if allow_dirty.is_some() {
             warn!("package.metadata.dist.allow-dirty is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path);
         }
+        if publish_prereleases.is_some() {
+            warn!("package.metadata.dist.publish-prereleases is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path);
+        }
 
         // Merge non-global settings
         if installers.is_none() {
diff --git a/cargo-dist/src/init.rs b/cargo-dist/src/init.rs
index 58b2f48e..c8eb8ddb 100644
--- a/cargo-dist/src/init.rs
+++ b/cargo-dist/src/init.rs
@@ -208,6 +208,7 @@ fn get_new_dist_metadata(
             default_features: None,
             all_features: None,
             publish_jobs: None,
+            publish_prereleases: None,
             create_release: None,
             pr_run_mode: None,
             allow_dirty: None,
@@ -677,6 +678,7 @@ fn update_toml_metadata(
         all_features,
         default_features,
         publish_jobs,
+        publish_prereleases,
         create_release,
         pr_run_mode,
         allow_dirty,
@@ -836,6 +838,13 @@ fn update_toml_metadata(
         publish_jobs.as_ref(),
     );
 
+    apply_optional_value(
+        table,
+        "publish-prereleases",
+        "# Whether to publish prereleases to package managers\n",
+        *publish_prereleases,
+    );
+
     apply_optional_value(
         table,
         "pr-run-mode",
diff --git a/cargo-dist/src/lib.rs b/cargo-dist/src/lib.rs
index 6bbe1a30..539afc7e 100644
--- a/cargo-dist/src/lib.rs
+++ b/cargo-dist/src/lib.rs
@@ -139,6 +139,8 @@ fn build_manifest(cfg: &Config, dist: &DistGraph) -> DistManifest {
         manifest.ci = Some(cargo_dist_schema::CiInfo { github });
     }
 
+    manifest.publish_prereleases = dist.publish_prereleases;
+
     manifest
 }
 
diff --git a/cargo-dist/src/tasks.rs b/cargo-dist/src/tasks.rs
index a4b567d1..f23701ad 100644
--- a/cargo-dist/src/tasks.rs
+++ b/cargo-dist/src/tasks.rs
@@ -199,6 +199,8 @@ pub struct DistGraph {
     pub ci: CiInfo,
     /// List of publish jobs to run
     pub publish_jobs: Vec<PublishStyle>,
+    /// Whether to publish prerelease builds to package managers
+    pub publish_prereleases: bool,
     /// A GitHub repo to publish the Homebrew formula to
     pub tap: Option<String>,
 }
@@ -643,6 +645,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
             install_path: _,
             // Only the final value merged into a package_config matters
             publish_jobs: _,
+            publish_prereleases,
             features,
             default_features: no_default_features,
             all_features,
@@ -696,6 +699,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
 
         let templates = Templates::new()?;
         let publish_jobs = workspace_metadata.publish_jobs.clone().unwrap_or(vec![]);
+        let publish_prereleases = publish_prereleases.unwrap_or(false);
 
         let allow_dirty = if allow_all_dirty {
             DirtyMode::AllowAll
@@ -733,6 +737,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
                 pr_run_mode: workspace_metadata.pr_run_mode.unwrap_or_default(),
                 tap: workspace_metadata.tap.clone(),
                 publish_jobs,
+                publish_prereleases,
                 allow_dirty,
             },
             package_metadata,
diff --git a/cargo-dist/templates/ci/github_ci.yml.j2 b/cargo-dist/templates/ci/github_ci.yml.j2
index 711c8434..fc73ccb6 100644
--- a/cargo-dist/templates/ci/github_ci.yml.j2
+++ b/cargo-dist/templates/ci/github_ci.yml.j2
@@ -201,6 +201,7 @@ jobs:
       PLAN: ${{ needs.plan.outputs.val }}
       GITHUB_USER: "axo bot"
       GITHUB_EMAIL: "admin+bot@axo.dev"
+    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
     steps:
       - uses: actions/checkout@v3
         with:


Test patch:
diff --git a/cargo-dist/tests/snapshots/akaikatana_basic.snap b/cargo-dist/tests/snapshots/akaikatana_basic.snap
index 113555be..9475ef04 100644
--- a/cargo-dist/tests/snapshots/akaikatana_basic.snap
+++ b/cargo-dist/tests/snapshots/akaikatana_basic.snap
@@ -1236,6 +1236,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
@@ -1449,6 +1450,7 @@ jobs:
       PLAN: ${{ needs.plan.outputs.val }}
       GITHUB_USER: "axo bot"
       GITHUB_EMAIL: "admin+bot@axo.dev"
+    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
     steps:
       - uses: actions/checkout@v3
         with:
diff --git a/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap b/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap
index 113555be..9475ef04 100644
--- a/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap
+++ b/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap
@@ -1236,6 +1236,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
@@ -1449,6 +1450,7 @@ jobs:
       PLAN: ${{ needs.plan.outputs.val }}
       GITHUB_USER: "axo bot"
       GITHUB_EMAIL: "admin+bot@axo.dev"
+    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
     steps:
       - uses: actions/checkout@v3
         with:
diff --git a/cargo-dist/tests/snapshots/axolotlsay_basic.snap b/cargo-dist/tests/snapshots/axolotlsay_basic.snap
index eb9c28d4..1da8d988 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_basic.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_basic.snap
@@ -2109,6 +2109,7 @@ maybeInstall(true).then(run);
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
@@ -2316,6 +2317,7 @@ jobs:
       PLAN: ${{ needs.plan.outputs.val }}
       GITHUB_USER: "axo bot"
       GITHUB_EMAIL: "admin+bot@axo.dev"
+    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
     steps:
       - uses: actions/checkout@v3
         with:
diff --git a/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap b/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
index 1136fb14..a0f3af56 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
@@ -2109,6 +2109,7 @@ maybeInstall(true).then(run);
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
@@ -2316,6 +2317,7 @@ jobs:
       PLAN: ${{ needs.plan.outputs.val }}
       GITHUB_USER: "axo bot"
       GITHUB_EMAIL: "admin+bot@axo.dev"
+    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
     steps:
       - uses: actions/checkout@v3
         with:
diff --git a/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
index 3cf70b5c..d86d4008 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
@@ -2109,6 +2109,7 @@ maybeInstall(true).then(run);
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_cargo_home.snap b/cargo-dist/tests/snapshots/install_path_cargo_home.snap
index 25d0f1b9..e1186d93 100644
--- a/cargo-dist/tests/snapshots/install_path_cargo_home.snap
+++ b/cargo-dist/tests/snapshots/install_path_cargo_home.snap
@@ -1238,6 +1238,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_env_no_subdir.snap b/cargo-dist/tests/snapshots/install_path_env_no_subdir.snap
index a6e35a45..f1d4fdff 100644
--- a/cargo-dist/tests/snapshots/install_path_env_no_subdir.snap
+++ b/cargo-dist/tests/snapshots/install_path_env_no_subdir.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_env_subdir.snap b/cargo-dist/tests/snapshots/install_path_env_subdir.snap
index bb82ca75..df09ecfa 100644
--- a/cargo-dist/tests/snapshots/install_path_env_subdir.snap
+++ b/cargo-dist/tests/snapshots/install_path_env_subdir.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_env_subdir_space.snap b/cargo-dist/tests/snapshots/install_path_env_subdir_space.snap
index 352fba6b..ba98aa3c 100644
--- a/cargo-dist/tests/snapshots/install_path_env_subdir_space.snap
+++ b/cargo-dist/tests/snapshots/install_path_env_subdir_space.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_env_subdir_space_deeper.snap b/cargo-dist/tests/snapshots/install_path_env_subdir_space_deeper.snap
index a97b5754..fb812149 100644
--- a/cargo-dist/tests/snapshots/install_path_env_subdir_space_deeper.snap
+++ b/cargo-dist/tests/snapshots/install_path_env_subdir_space_deeper.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_home_subdir_deeper.snap b/cargo-dist/tests/snapshots/install_path_home_subdir_deeper.snap
index be7b9132..c6ceea75 100644
--- a/cargo-dist/tests/snapshots/install_path_home_subdir_deeper.snap
+++ b/cargo-dist/tests/snapshots/install_path_home_subdir_deeper.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_home_subdir_min.snap b/cargo-dist/tests/snapshots/install_path_home_subdir_min.snap
index 6bcb2771..03b9716d 100644
--- a/cargo-dist/tests/snapshots/install_path_home_subdir_min.snap
+++ b/cargo-dist/tests/snapshots/install_path_home_subdir_min.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_home_subdir_space.snap b/cargo-dist/tests/snapshots/install_path_home_subdir_space.snap
index 83ad76fd..bbcd88e7 100644
--- a/cargo-dist/tests/snapshots/install_path_home_subdir_space.snap
+++ b/cargo-dist/tests/snapshots/install_path_home_subdir_space.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/install_path_home_subdir_space_deeper.snap b/cargo-dist/tests/snapshots/install_path_home_subdir_space_deeper.snap
index 65f28395..075084c1 100644
--- a/cargo-dist/tests/snapshots/install_path_home_subdir_space_deeper.snap
+++ b/cargo-dist/tests/snapshots/install_path_home_subdir_space_deeper.snap
@@ -1218,6 +1218,7 @@ Install-Binary "$Args"
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {
diff --git a/cargo-dist/tests/snapshots/lib_manifest.snap b/cargo-dist/tests/snapshots/lib_manifest.snap
index 0d466447..171046fe 100644
--- a/cargo-dist/tests/snapshots/lib_manifest.snap
+++ b/cargo-dist/tests/snapshots/lib_manifest.snap
@@ -13,6 +13,7 @@ stdout:
   "system_info": {
     "cargo_version_line": "CENSORED"
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {},
diff --git a/cargo-dist/tests/snapshots/lib_manifest_slash.snap b/cargo-dist/tests/snapshots/lib_manifest_slash.snap
index 8ada0ac1..01d51a22 100644
--- a/cargo-dist/tests/snapshots/lib_manifest_slash.snap
+++ b/cargo-dist/tests/snapshots/lib_manifest_slash.snap
@@ -13,6 +13,7 @@ stdout:
   "system_info": {
     "cargo_version_line": "CENSORED"
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {},
diff --git a/cargo-dist/tests/snapshots/manifest.snap b/cargo-dist/tests/snapshots/manifest.snap
index 0b87d671..792bd1aa 100644
--- a/cargo-dist/tests/snapshots/manifest.snap
+++ b/cargo-dist/tests/snapshots/manifest.snap
@@ -232,6 +232,7 @@ stdout:
       "description": "Install prebuilt binaries via Homebrew"
     }
   },
+  "publish_prereleases": false,
   "ci": {
     "github": {
       "artifacts_matrix": {