diff --git a/README.md b/README.md
index 29c3ab61a..a2b7b5a43 100644
--- a/README.md
+++ b/README.md
@@ -8,18 +8,69 @@
[![docs](https://docs.rs/cargo-dist/badge.svg)](https://docs.rs/cargo-dist)
[![Rust CI](https://github.com/axodotdev/cargo-dist/workflows/Rust%20CI/badge.svg?branch=main)](https://github.com/axodotdev/cargo-dist/actions/workflows/ci.yml)
-`cargo build` but For Building Final Distributable Artifacts and uploading them to an archive.
+*cargo-dist distributes your binaries*
-The Big Idea of cargo-dist is that we want to streamline all the steps of providing prebuilt binaries
-for a rust project. This includes:
+The TL;DR is that with cargo-dist setup, just doing this:
-1. Generating your "Cut A Release" Github CI for you
-2. Picking good build flags for a "production" release
-3. Making zips and installers for the resulting binaries
-4. Generating a machine-readable manifest so other tools can understand the results
-5. Uploading all the resulting artifacts to a Github Release™️
+```sh
+git commit -am "release: 0.2.0"
+git tag "v0.2.0"
+git push
+git push --tags
+```
+
+Will make [this Github Release](https://github.com/axodotdev/axolotlsay/releases/tag/v0.2.0):
+
+Or if you're using [oranda](https://opensource.axo.dev/oranda/), you'll get [this website](https://opensource.axo.dev/axolotlsay/).
+
+
+## Plan, Build, Host, Publish, Announce
+
+Cutting releases of your apps and distributing binaries for them has a lot of steps, and cargo-dist is quickly growing to try to cover them all!
+
+To accomplish this, cargo-dist functionality can be broken up into two parts:
+
+* building (**planning** the release; **building** binaries and installers)
+* distributing (**hosting** artifacts; **publishing** packages; **announcing** releases)
+
+The build functionality can be used on its own if you just want some tarballs and installers, but everything really comes together when you use the distribution functionality too.
+
+
+## Building
+
+As a build tool, cargo-dist can do the following:
+
+* Pick good build flags for "shippable binaries"
+* Make [tarballs][] and [installers][] for the resulting binaries
+* Generate [machine-readable manifests][manifest] so other tools can understand the results
+
+That's a short list because "we make [installers][]" is doing a lot of heavy lifting. Each installer could be (and sometimes is!) an entire standalone tool with its own documentation and ecosystem.
+
+
+## Distributing
+
+As a distribution tool, cargo-dist gets to flex its biggest superpower: **it generates [its own CI scripts][ci-providers]**. For instance, enabling [GitHub CI][github-ci] with `cargo dist init` will generate release.yml, which implements the full pipeline of plan, build, host, publish, announce:
+
+* Plan
+ * Waits for you to push a git tag for a new version (v1.0.0, my-app-v1.0.0, my-app/1.0.0, ...)
+ * Selects what apps in your workspace to announce new releases for based on that tag
+ * Generates [a machine-readable manifest][manifest] with changelogs and build plans
+* Build
+ * Spins up machines for each platform you support
+ * Builds your [binaries and tarballs][tarballs]
+ * Builds [installers][] for your binaries
+* Publish:
+ * Uploads to package managers
+* Host + Announce:
+ * Creates (or edits) a GitHub Release
+ * Uploads build artifacts to the Release
+ * Adds relevant release notes from your RELEASES/CHANGELOG
-Even though cargo-dist is primarily a tool for building and packaging applications (steps 2-4), we put a fair amount of effort into Generating Your CI Scripts For You because we want to be able to run things locally and know what the CI *should* do without actually running it. It also helps avoid needless vendor lock-in -- while the extra conveniences currently only support GitHub Actions, in the future migrating from Github to Gitlab or your own personal infra will be just one invocation of cargo-dist away!
+[tarballs]: https://opensource.axo.dev/cargo-dist/book/artifacts/archives.html
+[installers]: https://opensource.axo.dev/cargo-dist/book/installers/index.html
+[manifest]: https://opensource.axo.dev/cargo-dist/book/reference/schema.html
+[github-ci]: https://opensource.axo.dev/cargo-dist/book/ci/github.html
+[ci-providers]: https://opensource.axo.dev/cargo-dist/book/ci/index.html
# Read The Book!
@@ -28,8 +79,8 @@ We've got all the docs you need over at the [cargo-dist book](https://axodotdev.
* [Introduction](https://axodotdev.github.io/cargo-dist/book/introduction.html)
* [Install](https://axodotdev.github.io/cargo-dist/book/install.html)
* [Way-Too-Quickstart](https://axodotdev.github.io/cargo-dist/book/way-too-quickstart.html)
-* [Guide](https://axodotdev.github.io/cargo-dist/book/guide.html)
-* [Reference](https://axodotdev.github.io/cargo-dist/book/reference.html)
+* [Workspaces Guide](https://axodotdev.github.io/cargo-dist/book/workspaces-guide.html)
+* [Reference](https://axodotdev.github.io/cargo-dist/book/reference/index.html)
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index b12d52569..cb6a277fe 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -3,15 +3,25 @@
- [Introduction](./introduction.md)
- [Install](./install.md)
- [Way Too Quick Start](./way-too-quickstart.md)
-- [Guide](./guide.md)
- - [A Simple Application](./simple-guide.md)
- - [More Complex Workspaces](./workspace-guide.md)
- - [Using cargo-release](./cargo-release-guide.md)
-- [Customizing CI](./customizing-ci.md)
-- [Reference](./reference.md)
- - [Concepts](./concepts.md)
- - [Config](./config.md)
- - [Artifacts](./artifacts.md)
- - [Installers](./installers.md)
- - [CLI Manual](./cli.md)
- - [dist-manifest.json](./schema.md)
+- [Installers](./installers/index.md)
+ - [shell](./installers/shell.md)
+ - [powershell](./installers/powershell.md)
+ - [npm](./installers/npm.md)
+ - [homebrew](./installers/homebrew.md)
+ - [msi](./installers/msi.md)
+- [Artifacts](./artifacts/index.md)
+ - [archives](./artifacts/archives.md)
+ - [checksums](./artifacts/checksums.md)
+ - [symbols](./artifacts/symbols.md)
+- [CI](./ci/index.md)
+ - [github](./ci/github.md)
+- [Workspaces](./workspaces/index.md)
+ - [A Simple Application](./workspaces/simple-guide.md)
+ - [More Complex Workspaces](./workspaces/workspace-guide.md)
+ - [Using cargo-release](./workspaces/cargo-release-guide.md)
+- [Reference](./reference/index.md)
+ - [Concepts](./reference/concepts.md)
+ - [Artifact URLs](./reference/artifact-url.md)
+ - [Config](./reference/config.md)
+ - [CLI Manual](./reference/cli.md)
+ - [dist-manifest.json](./reference/schema.md)
diff --git a/book/src/artifacts.md b/book/src/artifacts.md
deleted file mode 100644
index bd450f967..000000000
--- a/book/src/artifacts.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Artifacts
-
-
-
-cargo-dist's primary role is to produce "Artifacts", either to use locally or to upload as part of a release announcement. Here's a listing of the supported kinds!
-
-
-## executable-zip
-
-executable-zips are the primary output of cargo-dist: a zip (or tarball) containing prebuilt executables/binaries for an app, along with additional static files like READMEs, LICENSES, and CHANGELOGs.
-
-When you [tell us to build an App for a platform][apps] we will make an executable-zip for it. Global [installers][] will fetch and unpack executable zips from wherever you uploaded them (currently Github Releases).
-
-You can modify what files get included with the [include][config-include] and [auto-includes][config-auto-includes] configs.
-
-Currently we always make .zip on windows and .tar.xz elsewhere. [This will be made configurable][extension-issue].
-
-Some notes on how we build your executables:
-
-* We currently always build `--workspace` [to keep things consistent][workspace-hacks]
-* We currently [always build with `--profile=dist`][dist-profile]
-* We currently [always build with default features][features-issue]
-* When targeting windows-msvc we will unconditionally [append "-Ctarget-feature=+crt-static"][crt-static-rfc] to your RUSTFLAGS, which should just be the default for rustc but isn't for legacy reasons
-* We don't yet [support cross-compilation][cross-issue]. We'll faithfully attempt the compile by passing `--target` to cargo as instructed but it will probably just fail.
- * [linux-musl is slated for a future version][musl-issue]
-
-## symbols
-
-This feature is currently disabled [pending a rework][rework-symbols], but basically we want to save your debuginfo in the form of pdbs, dSYMs, etc. This should automatically happen as a side-effect of requiring executable-zips with the appropriate build settings to generate them.
-
-
-## installers
-
-Most other kinds of artifact are referred to as "installers", because they generally exist as ways of downloading and installing the binaries that were made for the executable-zips.
-
-[See the full docs on installers for details][installers].
-
-
-
-[apps]: ./concepts.md#defining-your-apps
-[rework-symbols]: https://github.com/axodotdev/cargo-dist/issues/136
-[config-targets]: ./config.md#targets
-[installers]: ./installers.md
-[config-include]: ./config.md#include
-[config-auto-includes]: ./config.md#auto-includes
-
-[arm64-apple-issue]: https://github.com/axodotdev/cargo-dist/issues/133
-[musl-issue]: https://github.com/axodotdev/cargo-dist/issues/75
-[extension-issue]: https://github.com/axodotdev/cargo-dist/issues/17
-[cross-issue]: https://github.com/axodotdev/cargo-dist/issues/74
-[features-issue]: https://github.com/axodotdev/cargo-dist/issues/22
-[crt-static-rfc]: https://rust-lang.github.io/rfcs/1721-crt-static.html
-[dist-profile]: ./simple-guide.md#the-dist-profile
-[workspace-hacks]: https://docs.rs/cargo-hakari/latest/cargo_hakari/about/index.html#what-are-workspace-hack-crates
diff --git a/book/src/artifacts/archives.md b/book/src/artifacts/archives.md
new file mode 100644
index 000000000..16aaa81b1
--- /dev/null
+++ b/book/src/artifacts/archives.md
@@ -0,0 +1,93 @@
+# Archives
+
+Archives are the primary output of cargo-dist: a single file (zip or tarball) containing prebuilt executables/binaries for an app, along with additional static files like READMEs, LICENSEs, and CHANGELOGs. The docs previously referred to these as "executable-zips", so if you ever see that term floating around, this is what's being talked about.
+
+When you [tell us to build an app][apps] for [a platform][config-targets] we will always make an archive for it.
+
+[Fetching installers][fetching-installers] will fetch and unpack archives from wherever you [uploaded them][artifact-url]. [Bundling installers][bundling-installers] will use an exact copy of the binary stored in the archive, but may differ on other included files.
+
+
+
+## Auto-Detected Files
+
+We will always auto-detect READMEs, LICENSES, and CHANGELOGs with the following logic (described more below):
+
+* README: [package.readme][config-package-readme], or find `README*`
+* LICENSE: [package.license-file][config-package-license-file], or find `LICENSE*`/`UNLICENSE*`
+* CHANGELOG: find `CHANGELOG*`/`RELEASES*`
+
+"Find `XYZ*`" means we will look for a file whose name starts with "XYZ" in the same directory as the Cargo.toml for a package that defines the app. If no such file is found, we will also search for it in the same directory as the workspace's Cargo.toml (so packages "inherit" these files from the workspace).
+
+It is generally assumed that a directory only contains one of each kind of file. If multiple possible matches are in the same directory we will arbitrarily pick the first one we saw, so don't rely on that.
+
+Auto-detected files are first and foremost [auto-included into the archive](#archive-contents), however they can also be used for other things. For instance, the autodetected CHANGELOG is fed into our CHANGELOG features.
+
+
+
+## Archive Contents
+
+The "root" of an archive is either the actual root directory of the archive (zips); or a directory with the same name as the archive, but without the extension (tarballs). This difference is for compatibility/legacy reasons, and can be smoothed away by unpacking tarballs with tar's `--strip-components=1`.
+
+An app's archive always includes its binaries at the root.
+
+By default [auto-detected files](#auto-detected-files) for a package are auto-included into its archives at the root of the package. The [auto-includes][config-auto-includes] config controls this behaviour.
+
+The [include][config-include] can be used to manually add specific files/directories to the root of the archive.
+
+
+
+## Archive Formats
+
+Archives can be zips or tarballs (gz, xz, or zstd).
+
+By default we make .zip on windows and .tar.xz elsewhere, but this can be configured with [windows-archive][config-windows-archive] and [unix-archive][config-unix-archive] features.
+
+
+
+
+## Build Flags
+
+We currently [always build with `--profile=dist`][dist-profile]
+
+By default we build with `--workspace` [to keep things consistent][workspace-hacks], but this can be configured with the [precise-builds config][config-precise-builds] (see those docs for details on when precise-builds will be force-enabled).
+
+By default we build your packages with default features, but this can be configured with the [features][config-features], [default-features][config-default-features], and [all-features][config-all-features] configs.
+
+When targeting windows-msvc we will unconditionally [append "-Ctarget-feature=+crt-static"][crt-static] to your RUSTFLAGS, which should just be the default for rustc but isn't for legacy reasons.
+
+We don't really [support cross-compilation][issue-cross], but we'll faithfully attempt the compile by telling rustup to install the toolchain and passing `--target` to cargo as instructed -- it will probably just fail. On macOS cross-compiles between Intel and Apple Silicon will work. [linux-musl is slated for a future version][issue-musl].
+
+
+
+## Code Signing
+
+"Code Signing" is a very overloaded term, with wildly varying implementations that accomplish different goals. For instance, Linux users are currently very big on [sigstore][issue-sigstore] as a fairly turn-key code signing solution, but [neither Windows nor macOS][issue-native-sign] acknowledge its existence (and likely never will, as the benefits of sigstore completely defeat the stated purpose of code signing requirements on those platforms).
+
+Roughly speaking, codesigning can be broken up into "Is this app made by the developer?" and "Can I trust apps made by this developer?". Tools like sigstore are focused on the former, while Windows/macOS only care about the latter. They want you to pay some money and jump through administrative hoops. They also expect you to pay completely different groups and go through completely different hoops, so each platform requires a completely different solution.
+
+
+[config-package-readme]: ../reference/config.md#readme
+[config-package-license-file]: ../reference/config.md#license-file
+[config-windows-archive]: ../reference/config.md#windows-archive
+[config-unix-archive]: ../reference/config.md#unix-archive
+[config-precise-builds]: ../reference/config.md#precise-builds
+[config-default-features]: ../reference/config.md#default-features
+[config-all-features]: ../reference/config.md#all-features
+[config-features]: ../reference/config.md#features
+[config-include]: ../reference/config.md#include
+[config-auto-includes]: ../reference/config.md#auto-includes
+[config-targets]: ../reference/config.md#targets
+
+[issue-musl]: https://github.com/axodotdev/cargo-dist/issues/75
+[issue-cross]: https://github.com/axodotdev/cargo-dist/issues/74
+[issue-sigstore]: https://github.com/axodotdev/cargo-dist/issues/120
+[issue-native-sign]: https://github.com/axodotdev/cargo-dist/issues/21
+
+[apps]: ../reference/concepts.md#defining-your-apps
+[fetching-installers]: ../installers/index.md#fetching-installers
+[bundling-installers]: ../installers/index.md#bundling-installers
+[artifact-url]: ../reference/artifact-url.md
+[dist-profile]: ../workspaces/simple-guide.md#the-dist-profile
+
+[crt-static]: https://rust-lang.github.io/rfcs/1721-crt-static.html
+[workspace-hacks]: https://docs.rs/cargo-hakari/latest/cargo_hakari/about/index.html#what-are-workspace-hack-crates
diff --git a/book/src/artifacts/checksums.md b/book/src/artifacts/checksums.md
new file mode 100644
index 000000000..7b4075f63
--- /dev/null
+++ b/book/src/artifacts/checksums.md
@@ -0,0 +1,18 @@
+# Checksums
+
+By default cargo-dist will generate a matching checksum file for each [archive][] it generates. The default checksum is sha256, so for instance `my-app-x86_64-pc-windows-msvc.zip` will also come with `my-app-x86_64-pc-windows-msvc.zip.sha256` that tools like `sha256sum` can use. This can be configured with [the checksum config][config-checksum].
+
+[Fetching installers][fetching-installers] can also use these checksums (or ones baked into them) to validate the integrity of the files they download. With https and unsigned checksums the security benefit is minimal, but it can catch more boring problems like data corruption.
+
+The homebrew installer actually ignores your checksum setting and always uses sha256 hashes that are baked into it, as required by homebrew itself.
+
+Updating the other fetching installers to use these checksums is [still a work in progress][issue-checksum-backlog].
+
+
+
+[issue-checksum-backlog]: https://github.com/axodotdev/cargo-dist/issues/439
+
+[config-checksum]: ../reference/config.md#checksum
+
+[archive]: ../artifacts/archives.md
+[fetching-installers]: ../installers/index.md#fetching-installers
\ No newline at end of file
diff --git a/book/src/artifacts/index.md b/book/src/artifacts/index.md
new file mode 100644
index 000000000..a7967b4f0
--- /dev/null
+++ b/book/src/artifacts/index.md
@@ -0,0 +1,11 @@
+# Artifacts
+
+cargo-dist exists to help you distribute your binaries, which involves generating a lot of different files which we call *Artifacts*. Archives are the baseline artifacts that contain your binaries, and installers are the fancy artifacts that make it easy to install or run the binaries.
+
+* [Archives](./archives.md): tarballs/zips containing your binaries
+* [Installers](../installers/index.md): things that help fetch/install archives
+* [Checksums](./checksums.md): hashes of other artifacts
+* [Symbols](./symbols.md): debuginfo/symbols/sourcemaps of your binaries
+
+
+
diff --git a/book/src/artifacts/symbols.md b/book/src/artifacts/symbols.md
new file mode 100644
index 000000000..44124f00f
--- /dev/null
+++ b/book/src/artifacts/symbols.md
@@ -0,0 +1,6 @@
+# Symbols
+
+This feature is currently disabled [pending a rework][rework-symbols], but basically we want to save your debuginfo/symbols/sourcemaps in the form of pdbs, dSYMs, etc. This will automatically happen as a side-effect of building [archives][].
+
+[rework-symbols]: https://github.com/axodotdev/cargo-dist/issues/136
+[archives]: ./archives.md
\ No newline at end of file
diff --git a/book/src/ci/customizing-ci.md b/book/src/ci/customizing-ci.md
new file mode 100644
index 000000000..c0eb3a39f
--- /dev/null
+++ b/book/src/ci/customizing-ci.md
@@ -0,0 +1 @@
+# CI
diff --git a/book/src/ci/github.md b/book/src/ci/github.md
new file mode 100644
index 000000000..96308e252
--- /dev/null
+++ b/book/src/ci/github.md
@@ -0,0 +1,154 @@
+# GitHub CI
+
+> since 0.0.3
+
+
+
+The GitHub CI backend provides a "Release" Workflow that is triggered by pushing a tagged commit to your repository. It uses the tag to determine which packages you're trying to publish, and builds and uploads them to a GitHub Release.
+
+
+## Setup
+
+cargo-dist is currently very eager to setup the GitHub CI backend, so it's pretty easy to do! Most likely it was automatically setup the first time you ran `cargo dist init`. If you followed [the way-too-quickstart][quickstart], then you should also have it setup.
+
+
+### Setup Step 1: set "repository" in your Cargo.toml
+
+You probably already have it set, but if you don't, now's the time to do it. We need to know [the URL of your GitHub repository][artifact-url] for several features, and the next step will fail without it.
+
+
+### Setup Step 2: run init and enable GitHub CI
+
+Run `cargo dist init` on your project.
+
+If you did the previous step, you should get prompted to "enable Github CI and Releases?", with the default answer being "yes". Choose yes.
+
+You will also get prompted to "check your release process in pull requests?", with the default answer being "plan - run 'cargo dist plan' on PRs (recommended)". Choose that option.
+
+Once init completes, some changes will be made to your project, **check all of them in**:
+
+* `ci = ["github"]` should be added to `[workspace.metadata.dist]`
+* `./github/workflows/release.yml` should be created, this is your Release Workflow
+
+
+### Setup Step 3: you're done! (time to test)
+
+See [the quickstart's testing guide][testing] for the various testing options.
+
+The easiest testing option for this is to open a pull-request for everything you checked in -- it should run the `plan` step of your release CI as part of the PR.
+
+
+
+## Advanced Usage
+
+Here are some more advanced things you can do with GitHub CI.
+
+
+### Build and upload artifacts on every pull request
+
+> since 0.3.0
+
+By default, cargo-dist will run the plan step on every pull request but won't perform a full release build. If these builds are turned on, the resulting pull request artifacts won't be uploaded to a release but will be available as a download from within the CI job. To enable this, select the "upload" option from the "check your release process in pull requests" question in `cargo-dist-init` or set [the `pr-run-mode` key][config-pr-run-mode] to `"upload"` in `Cargo.toml`'s cargo-dist config. For example:
+
+```toml
+pr-run-mode = "upload"
+```
+
+
+### Bring your own release
+
+> since 0.2.0
+
+By default, cargo-dist will want to create its own GitHub Release and set the title/body with things like your CHANGELOG/RELEASES and some info about how to install the release. However if you have your own process for generating the contents of GitHub Release, we support that.
+
+If you set `create-release = false` in your cargo-dist config, cargo-dist will assume a draft Github Release for the current git tag already exists with the title/body you want, and just upload artifacts to it. At the end of a successful publish it will undraft the GitHub Release for you.
+
+
+
+### Custom jobs
+
+> since 0.3.0
+
+cargo-dist's CI can be configured to call additional jobs on top of the ones it has builtin. Currently, we support adding extra jobs to the publish step; in the future, we'll allow extending all of the lifecycle steps of the CI workflow. To add one, you need to follow two steps:
+
+1. Define the new job as a reusable workflow using the standard method defined by your CI system. For GitHub actions, see the documentation on [reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow).
+2. Add the name of your new workflow file to the `publish-jobs` array in your `Cargo.toml`'s cargo-dist config, prefixed with a `./`. For example, if your job name is `.github/workflows/my-publish.yml`, you would write it like this:
+
+```toml
+publish-jobs = ["./my-publish"]
+```
+
+Here's an example reusable workflow written using GitHub Actions. It won't do any real publishing, just echo text to the CI output. First, create a file named `.github/workflows/publish-greeter.yml` with these contents:
+
+```yaml
+name: Greeter
+
+on:
+ # Defining workflow_call means that this workflow can be called from
+ # your main workflow job
+ workflow_call:
+ # cargo-dist exposes the plan from the plan step, as a JSON string,
+ # to your job if it needs it
+ inputs:
+ plan:
+ required: true
+ type: string
+
+jobs:
+ greeter:
+ runs-on: ubuntu-latest
+ # This is optional; it exposes the plan to your job as an environment variable
+ env:
+ PLAN: ${{ inputs.plan }}
+ steps:
+ - name: Step 1
+ run: |
+ echo "Hello!"
+ echo "Plan is: ${PLAN}"
+```
+
+Then, add the following to your `publish-jobs` array:
+
+```toml
+publish-jobs = ["./publish-greeter"]
+```
+
+Running `cargo-dist init` for your tool will update your GitHub Actions configuration to make use of the new reusable workflow during the publish step.
+
+
+
+### Hand-editing release.yml
+
+> since 0.3.0
+
+The happy-path of cargo-dist has us completely managing release.yml, and since 0.3.0 we will actually consider it an error for there to be any edits or out of date information in release.yml.
+
+If there's something that cargo-dist can't do that makes you want to hand-edit the file, we'd love to hear about it so that you can stay on the happy-path!
+
+However we know you sometimes really need to do those hand-edits, so there is a way to opt into it. If you [set `allow-dirty = ["ci"]` in your cargo-dist config][config-allow-dirty], cargo-dist will stop trying to update the file and stop checking if it's out of date.
+
+Although you're not "using cargo-dist wrong" if you do this, **be aware that you are losing access to a lot of the convenience and UX benefits of cargo-dist**. Every piece of documentation that says "just run cargo dist init" may not work correctly, as a new feature may require the CI template to be updated. Even things as simple as "updating cargo-dist" will stop working.
+
+We have put a lot of effort into minimizing those situations, with `plan` increasingly being responsible for dynamically computing what the CI should do, but that's not perfect, and there's no guarantees that future versions of cargo-dist won't completely change the way CI is structured.
+
+
+### Fiddly build task settings
+
+> since 0.0.1
+
+Here's a grab-bag of more random settings you probably don't want to use, but exist in case you need them.
+
+By default cargo-dist lets all the build tasks keep running even if one of them fails, to try to get you as much as possible when things go wrong. [`fail-fast = true` can be set to disable this][config-fail-fast].
+
+By default cargo-dist breaks build tasks onto more machines than strictly necessary to create the maximum opportunities for concurrency and to increase fault-tolerance. For instance if you want to build for both arm64 macOS and x64 macOS, that *could* be done on the same machine, but we put it on two machines so they can be in parallel and succeed/fail independently. [`merge-tasks = true` can be set to disable this][config-merge-tasks].
+
+
+
+[config-fail-fast]: ../reference/config.md#fail-fast
+[config-merge-tasks]: ../reference/config.md#merge-tasks
+[config-allow-dirty]: ../reference/config.md#allow-dirty
+[config-pr-run-mode]: ../reference/config.md#pr-run-mode
+
+[artifact-url]: ../reference/artifact-url.md#github
+[quickstart]: ../way-too-quickstart.md
+[testing]: ../way-too-quickstart.md#test-it-out
\ No newline at end of file
diff --git a/book/src/ci/index.md b/book/src/ci/index.md
new file mode 100644
index 000000000..b1a9a644b
--- /dev/null
+++ b/book/src/ci/index.md
@@ -0,0 +1,32 @@
+# CI
+
+All of the [distribute functionality][distribute] of cargo-dist depends on some kind of CI integration to provide things like [file hosting][artifact-url], secret keys, and the ability to spin up multiple machines.
+
+A CI backend can be enabled with [the ci config][config-ci]
+
+
+
+## Supported CI Providers
+
+* [github][]: use GitHub Actions and uploads to GitHub Releases
+
+
+
+
+## Future CI Providers
+
+The following CI providers have been requested, and we're open to supporting them, but we have no specific timeline for when they will be implemented. Providing additional info/feedback on them helps us prioritize the work:
+
+* [gitlab](https://github.com/axodotdev/cargo-dist/issues/48)
+* [travis](https://github.com/axodotdev/cargo-dist/issues/273)
+
+
+
+
+
+[config-ci]: ../reference/config.md#ci
+
+[github]: ./github.md
+
+[artifact-url]: ../reference/artifact-url.md
+[distribute]: ../introduction.md#distributing
\ No newline at end of file
diff --git a/book/src/customizing-ci.md b/book/src/customizing-ci.md
deleted file mode 100644
index e9a22baa9..000000000
--- a/book/src/customizing-ci.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Customizing CI
-
-Out of the box, cargo-dist's CI configuration is designed to cover the majority of usecases. We provide some tools to customize how it works for your project.
-
-## Build and upload artifacts on every pull request
-
-> since 0.3.0
-
-By default, cargo-dist will run the plan step on every pull request but won't perform a full release build. If these builds are turned on, the resulting pull request artifacts won't be uploaded to a release but will be available as a download from within the CI job. To enable this, select the "upload" option from the "check your release process in pull requests" question in `cargo-dist-init` or set the `pr-run-mode` key to `"upload"` in `Cargo.toml`'s cargo-dist config. For example:
-
-```toml
-pr-run-mode = "upload"
-```
-
-## Custom jobs
-
-> since 0.3.0
-
-cargo-dist's CI can be configured to call additional jobs on top of the ones it has builtin. Currently, we support adding extra jobs to the publish step; in the future, we'll allow extending all of the lifecycle steps of the CI workflow. To add one, you need to follow two steps:
-
-1. Define the new job as a reusable workflow using the standard method defined by your CI system. For GitHub actions, see the documentation on [reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow).
-2. Add the name of your new workflow file to the `publish-jobs` array in your `Cargo.toml`'s cargo-dist config, prefixed with a `./`. For example, if your job name is `.github/workflows/my-publish.yml`, you would write it like this:
-
-```toml
-publish-jobs = ["./my-publish"]
-```
-
-Here's an example reusable workflow written using GitHub Actions. It won't do any real publishing, just echo text to the CI output. First, create a file named `.github/workflows/publish-greeter.yml` with these contents:
-
-```yaml
-name: Greeter
-
-on:
- # Defining workflow_call means that this workflow can be called from
- # your main workflow job
- workflow_call:
- # cargo-dist exposes the plan from the plan step, as a JSON string,
- # to your job if it needs it
- inputs:
- plan:
- required: true
- type: string
-
-jobs:
- greeter:
- runs-on: ubuntu-latest
- # This is optional; it exposes the plan to your job as an environment variable
- env:
- PLAN: ${{ inputs.plan }}
- steps:
- - name: Step 1
- run: |
- echo "Hello!"
- echo "Plan is: ${PLAN}"
-```
-
-Then, add the following to your `publish-jobs` array:
-
-```toml
-publish-jobs = ["./publish-greeter"]
-```
-
-Running `cargo-dist init` for your tool will update your GitHub Actions configuration to make use of the new reusable workflow during the publish step.
diff --git a/book/src/img/simple-github-release.png b/book/src/img/simple-github-release.png
index d6273d085..fb0ad8c59 100644
Binary files a/book/src/img/simple-github-release.png and b/book/src/img/simple-github-release.png differ
diff --git a/book/src/img/simple-oranda.png b/book/src/img/simple-oranda.png
new file mode 100644
index 000000000..dd6106c69
Binary files /dev/null and b/book/src/img/simple-oranda.png differ
diff --git a/book/src/img/workflow-artifacts.png b/book/src/img/workflow-artifacts.png
new file mode 100644
index 000000000..31237eb8a
Binary files /dev/null and b/book/src/img/workflow-artifacts.png differ
diff --git a/book/src/installers.md b/book/src/installers.md
deleted file mode 100644
index f6dd9b8dc..000000000
--- a/book/src/installers.md
+++ /dev/null
@@ -1,311 +0,0 @@
-# Installers
-
-
-
-The core functionality of cargo-dist is to build your binaries and produce tarballs/zips containing them. Basically every other kind of file it produces is considered an "installer" that helps download/install those binaries.
-
-> Currently all supported installers are "global"/"universal" installers that detect the current platform and download and unpack the appropriate tarball/zip. This currently requires CI support to be enabled so we can ensure the files are hosted somewhere and know where to fetch them from.
->
-> In the future we will allow you to specify the download URL manually, and will enable more self-contained "vendored" installers like [Windows .msi][msi-installer-issue] and [macOS .dmg/.app][dmg-installer-issue], as well as [various][linux-pm-issue] [package-managers][windows-pm-issue].
-
-
-## Supported Installers
-
-Currently supported installers include:
-
-* "shell": a shell script that fetches and installs executables
-* "powershell": a powershell script that fetches and installs executables
-* "npm": an npm project that fetches and runs executables (e.g. via npx)
-* "homebrew": a Homebrew formula that fetches and installs executables
-
-These keys can be specified via [`installer` in your cargo-dist config][installer-config]. The [`cargo dist init` command][init] provides an interactive UI for enabling/disabling them.
-
-
-
-
-### shell
-
-> since 0.0.3
-
-This provides a shell script (installer.sh) which detects the current platform, fetches the best possible [executable-zip][] from your [artifact download URL][artifact-download-url], copies the binary into your [install-path][], and attempts to add that path to the user's PATH (see the next section for details).
-
-This kind of installer is ideal for bootstrapping setup on a fairly bare-bones system.
-
-An "installer hint" will be provided that shows how to install via `curl | sh`, like so:
-
-```sh
-curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.sh | sh
-```
-
-Limitations/Caveats:
-
-* Requires a well-defined [artifact download URL][artifact-download-url]
-* Currently only really designed for "linux" and "macOS", and won't detect other platforms properly (and certainly won't play nice with things like nixOS).
-* [Cannot detect situations where musl-based builds are appropriate][musl] (static or dynamic)
-* [Relies on the user's installation of `tar` and `unzip` to unpack the files][unpacking]
-* Relies on the the user's installation of `curl` or `wget` to fetch the files
-* [Will throw out all files except for the binary, so the binary can't rely on assets included in the archive][issue-unpack-all]
-* Cannot run any kind of custom install logic
-
-In an ideal world all of these caveats improve (except for maybe relying on tar/unzip/curl/wget, that's kinda fundamental).
-
-
-#### shell: adding things to PATH
-
-Here is a more fleshed out description of how the shell installer attempts to add the [install-path][] to the user's PATH, and the limitations of that process.
-
-The most fundamental limitation is that installers fundamentally cannot edit the PATH of the currently running shell (it's a parent process). Only an explicit `source some_file` (or the more portable `. some_file`) can do that. As such, it benefits an installer to try to install to a directory that will already be on PATH (such as [CARGO_HOME][cargo home]). Otherwise all we can do is prompt the user to run `source` themselves after the installer has run (or restart their shell to freshly source rcfiles).
-
-The process we use to add [install-path][] to the user's PATH is roughly the same process that rustup uses (hopefully making us harmonious with running rustup before/after one of our installer scripts). In the following description we will use `$install-path` as a placeholder for the path computed at install-time where the binaries get installed. Its actual value will likely look something like `$HOME/.myapp` or `$HOME/.cargo/bin`.
-
-* we generate a shell script and write it to `$install-path/env` (let's call this `$env-path`)
- * the script checks if `$install-path` is in PATH already, and prepends it if not
- * prepending is used to ideally override system-installed binaries, as that is assumed to be desired when explicitly installing with not-your-system-package-manager
- * the `env` script will only be added if it doesn't already exist
- * if `install-path = "CARGO_HOME"`, then `$env-path` will actually be in the parent directory, mirroring the behaviour of rustup
-* we add `. $env-path` to `$HOME/.profile`
- * this is just a more portable version of `source $install-path/env`
- * this line will only be added if it doesn't exist (we also check for the `source` equivalent)
- * the file is created if it doesn't exist
- * [rustup shotgun blasts this line into many more files like .bashrc and .zshenv](https://github.com/rust-lang/rustup/blob/bcfac6278c7c2f16a41294f7533aeee2f7f88d07/src/cli/self_update/shell.rs#L70-L76), while still [lacking proper support for fish](https://github.com/rust-lang/rustup/issues/478) and other more obscure shells -- we opted to start conservative with just .profile
-* if `$HOME/.profile` was edited, we prompt the user to `source "$env-path"` or restart their shell
- * although this is less portable than `. "$env-path"`, it's very easy to misread/miscopy the portable version (not as much of a concern for an rcfile, but an issue for humans)
- * hopefully folks on platforms where this matters are aware of this issue (or they can restart their shell)
-
-
-
-### powershell
-
-> since 0.0.3
-
-This provides a powershell script (installer.ps1) which detects the current platform, fetches the best possible [executable-zip][] from your [artifact download URL][artifact-download-url], copies the binary into your [install-path][], and attempts to add that path to the user's PATH (see the next section for details).
-
-This kind of installer is ideal for bootstrapping setup on a fairly bare-bones system.
-
-An "installer hint" will be provided that shows how to install via `irm | iex` (the windows equivalent of `curl | sh`), like so:
-
-```sh
-irm https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.ps1 | iex
-```
-
-Limitations/Caveats:
-
-* Requires a well-defined [artifact download URL][artifact-download-url]
-* Currently only really designed for "native windows", and won't detect other platforms properly
-* [Cannot detect situations where musl-based builds are appropriate][musl] (static or dynamic)
-* [Relies on the user's installation of `tar` and `Expand-Archive` to unpack the files][unpacking]
-* Relies on the the user's installation of `Net.Webclient` to fetch the files
-* [Won't work if run in cmd instead of powershell][issue-irm-iex]
-* [Will throw out all files except for the binary, so the binary can't rely on assets included in the archive][issue-unpack-all]
-* Cannot run any kind of custom install logic
-
-On the scale of Windows (where many people are still running Windows 7) commands like "Expand-Archive" and "tar" are in fact relatively new innovations. Any system that predates 2016 (PowerShell 5.0) certainly has no hope of working. I believe that someone running Windows 10 is basically guaranteed to work, and anything before that gets sketchier.
-
-In an ideal world most of these caveats improve (except for maybe the requirement of PowerShell >= 5.0 which is not pleasant to push past).
-
-
-#### powershell: adding things to PATH
-
-Here is a more fleshed out description of how the powershell installer attempts to add the [install-path][] to the user's PATH, and the limitations of that process.
-
-The most fundamental limitation is that installers fundamentally cannot edit the PATH of the currently running shell (it's a parent process). Powershell does not have an equivalent of `source`, so to the best of our knowledge restarting the shell is the only option (which if using Windows Terminal seems to mean opening a whole new window, tabs aren't good enough). As such, it benefits an installer to try to install to a directory that will already be on PATH (such as [CARGO_HOME][cargo home]). ([rustup also sends a broadcast WM_SETTINGCHANGE message](https://github.com/rust-lang/rustup/blob/bcfac6278c7c2f16a41294f7533aeee2f7f88d07/src/cli/self_update/windows.rs#L397-L409), but we couldn't find any evidence that this does anything useful.)
-
-The process we use to add [install-path][] to the user's PATH is roughly the same process that rustup uses (hopefully making us harmonious with running rustup before/after one of our installer scripts). In the following description we will use `$install-path` as a placeholder for the path computed at install-time where the binaries get installed. Its actual value will likely look something like `C:\Users\axo\.myapp` or `C:\Users\.cargo\bin`.
-
-* we load from the registry `HKCU:\Environment`'s "Path" Item
-* we check if `$install-path` is contained within it already
-* if not, we prepend it and write the value back
- * prepending is used to ideally override system-installed binaries, as that is assumed to be desired when explicitly installing with not-your-system-package-manager
-* if we edited the registry, we prompt the user to restart their shell
-
-
-
-
-
-### npm
-
-> since 0.0.6
-
-This provides a tarball containing an npm package (npm-package.tar.gz) which when installed into an npm project: detects the current platform, fetches the best possible [executable-zip][] from your [artifact download URL][artifact-download-url], and copies the binary into your node_modules. This can be used to install the binaries like any other npm package, or to run them with `npx`.
-
-This kind of installer is ideal for making a native Rust tool available to JS devs.
-
-An "installer hint" will be provided that shows how to install via `npm` like so:
-
-```sh
-npm install @axodotdev/cargodisttest@0.2.0
-```
-
-**cargo-dist does not publish the package for you, you need to do that manually once the tarball is built.** Conveniently, npm supports publishing from a url-to-a-tarball directly, and since 0.0.7 we make our tarballs look like "proper" npm package tarballs, so you can just do this:
-
-```sh
-npm publish URL_TO_TARBALL
-```
-
-You can find the URL to the tarball at the bottom of the Github Release, inside the collapsible "assets" dropdown (*-npm-package.tar.gz). The format of the url is:
-
-```text
-
/releases/download//-npm-package.tar.gz
-```
-
-Example:
-
-https://github.com/axodotdev/oranda/releases/download/v0.0.3/oranda-npm-package.tar.gz
-
-If you're cutting a stable release (not-prerelease), you can use the "latest" URL format:
-
-https://github.com/axodotdev/oranda/releases/latest/download/oranda-npm-package.tar.gz
-
-In the future we may [introduce more streamlined CI-based publishing workflows][issue-npm-ci].
-
-[You can set the @scope the package is published under with the npm-scope cargo-dist config][npm-scope].
-
-We will otherwise do our best to faithfully translate [any standard Cargo.toml values you set][cargo-manifest] to an equivalent in the npm package.json format (name, version, authors, description, homepage, repository, keywords, categories...).
-
-The package will also include an npm-shrinkwrap.json file for the npm packages the installer uses, this is the same as package-lock.json but "really for reals I want this to be respected even if it's installed into another project". Note that [cargo install similarly disrespects Cargo.lock unless you pass --locked][install-locked].
-
-
-
-
-Limitations/Caveats:
-
-* Requires a well-defined [artifact download URL][artifact-download-url]
-* [Cannot detect situations where musl-based builds are appropriate][musl] (static or dynamic)
-* [Relies on nodejs's builtin gzip support to unpack the files, which only works with .tar.gz][unpacking]
-* Cannot run any kind of custom install logic
-
-As a result of the `.tar.gz` limitation, `cargo dist init` will prompt you to change [windows-archive][] and [unix-archive][] to ".tar.gz" if you enable the npm installer, erroring if you decline.
-
-
-
-### Homebrew
-
-> since 0.2.0
-
-This provides a [Homebrew](https://brew.sh) formula which allows users to `brew install` your package. Since it installs to a location on the user's `PATH`, it provides a simple and convenient installation method for users who already have Homebrew available. When published to a [tap](https://docs.brew.sh/Taps) (package repository), this gives your users an easy way to both install your package and to keep it up to date using `brew update` and `brew upgrade`. It fetches the same prebuilt macOS binaries as the shell installer.
-
-cargo-dist can, optionally, publish your formula to a tap repository for you on every release. To enable this, add a `tap` field to your `Cargo.toml` pointing to a GitHub repository that you control and add `homebrew` to the `publish-jobs` field. The repository name must start with `homebrew-`. For example:
-
-```toml
-tap = "axodotdev/homebrew-formulae"
-publish-jobs = ["homebrew"]
-```
-
-In order to write to a tap GitHub repository, cargo-dist needs a [personal access token](https://github.com/settings/tokens/new?scopes=repo) with the `repo` scope exposed as `HOMEBREW_TAP_TOKEN`. For more information on GitHub Actions secrets, [consult this documentation](https://docs.github.com/en/actions/security-guides/encrypted-secrets).
-
-Limitations/Caveats:
-
-* Does not support creating a formula which builds from source
-* Does not support Linuxbrew (Homebrew on Linux)
-* Does not support [Cask][cask-issue] for more convenient GUI app installation
-
-
-
-## Artifact Download URL
-
-All installers which rely on detecting the current platform and fetching "your" [executable-zips][] (archives) to install prebuilt binaries need to know where to fetch from. They do this by combining a base URL with the precomputed name of the archive. That base URL is the *Artifact Download URL*.
-
-The Artifact Download URL effectively mandates that all archives for a Release must be stored in the same directory (or pretend to be with redirects), and must have the exact name that cargo-dist selected for them.
-
-The Artifact Download URL is currently on defined if:
-
-* [You have enabled Github CI][github-ci]
-* [All crates in your workspace agree on the Cargo "repository" key][repository-url]
-
-"Agree" here means that:
-
-* At least one crate defines the key
-* Every other crate that bothers to set the key has the same value (modulo trailing "/")
-
-If this is the case, then it will be:
-
-```text
-{{repository}}/releases/download/{{tag}}
-```
-
-For instance the Artifact Download URL for cargo-dist 0.0.5 is:
-
-```text
-https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/
-```
-
-In the future this will be made more configurable.
-
-
-
-
-## Unpacking Files
-
-cargo-dist theoretically allows you to build [executable-zips][] with any of the following formats:
-
-* .tar.gz
-* .tar.xz
-* .tar.zstd
-* .zip
-
-(See [windows-archive][] and [unix-archive][] for details and defaults)
-
-But that doesn't necessarily mean a random user can unpack those formats, and that *especially* doesn't mean an installer that's trying to bootstrap the installation by fetching one of those archives can. This section serves to document some known limitations of various systems' builtin unpacking utilities.
-
-* On unix-y platforms `tar` tends to be available with .tar.gz and .tar.xz well-supported, but not .tar.zstd. `unzip` is also pretty standard for handling .zip files.
-
-* Modern Windows (~Windows 10) has a copy of bsd `tar`, but it *only* supports .tar.gz out of the box (and zip I think, but we use the similarly-new Expand-Archive command for that). The windows file explorer also seemingly has no idea how to open a .tar.gz, unlike a .zip which just pops open with a double click, so worse UX for anyone manually falling back to the raw archives. Both of these are relatively new commands that older Windows systems might lack (introduced in ~2016/2017).
-
-* The npm `binary-install` and `tar` packages only support .tar.gz (because nodejs provides a builtin gzip decoder and they just rely on that). There are seemingly packages for other formats but we have yet to cobble together a comprehensive implementation that combines them all.
-
-* The Rust ecosystem similarly requires individual packages for all these formats, but they all have pretty simple/uniform APIs so we were able to cobble together basic support without too much effort.
-
-
-
-
-
-## Other Installation Methods
-
-cargo-dist projects can also theoretically be installed with the following, through no active effort of our own:
-
-* [cargo-install][] (just [cargo publish][] like normal)
-* [cargo-binstall][] (the URL schema we use for Github Releases is auto-detected)
-
-In the future we might [support displaying these kinds of install methods][issue-info-install].
-
-Note that cargo-install is just building from the uploaded source with the --release profile, and so if you're relying on cargo-dist or unpublished files for some key behaviours, this may cause problems. [It also disrespects your lockfile unless you pass --locked][install-locked]. You can more closely approximate cargo-dist's build with:
-
-```sh
-cargo install --profile=dist --locked
-```
-
-Although that's still missing things like [Windows crt-static workarounds][crt-static].
-
-
-
-
-[issue-info-install]: https://github.com/axodotdev/cargo-dist/issues/72
-[issue-npm-ci]: https://github.com/axodotdev/cargo-dist/issues/245
-[linux-pm-issue]: https://github.com/axodotdev/cargo-dist/issues/76
-[windows-pm-issue]: https://github.com/axodotdev/cargo-dist/issues/87
-[msi-installer-issue]: https://github.com/axodotdev/cargo-dist/issues/23
-[dmg-installer-issue]: https://github.com/axodotdev/cargo-dist/issues/24
-[issue-unpack-all]: https://github.com/axodotdev/cargo-dist/issues/307
-[issue-irm-iex]: https://github.com/axodotdev/oranda/issues/393
-[installer-config]: ./config.md#installers
-[executable-zip]: ./artifacts.md#executable-zip
-[executable-zips]: ./artifacts.md#executable-zip
-[init]: ./cli.md#cargo-dist-init
-[artifact-download-url]: #artifact-download-url
-[cargo home]: https://doc.rust-lang.org/cargo/guide/cargo-home.html
-[cargo-binstall]: https://github.com/cargo-bins/cargo-binstall
-[cargo-install]: https://doc.rust-lang.org/cargo/commands/cargo-install.html
-[cargo publish]: https://doc.rust-lang.org/cargo/commands/cargo-publish.html
-[unpacking]: #unpacking-files
-[npm-targz]: https://github.com/axodotdev/cargo-dist/issues/226
-[musl]: https://github.com/axodotdev/cargo-dist/issues/75
-[npm-scope]: ./config.md#npm-scope
-[unix-archive]: ./config.md#unix-archive
-[windows-archive]: ./config.md#windows-archive
-[github-ci]: ./config.md#ci
-[repository-url]: ./config.md#repository
-[install-path]: ./config.md#install-path
-[cargo-manifest]: https://doc.rust-lang.org/cargo/reference/manifest.html
-[install-locked]: https://doc.rust-lang.org/cargo/commands/cargo-install.html#dealing-with-the-lockfile
-[crt-static]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md
-[cask-issue]: https://github.com/axodotdev/cargo-dist/issues/309
diff --git a/book/src/installers/homebrew.md b/book/src/installers/homebrew.md
new file mode 100644
index 000000000..99a4cbcb7
--- /dev/null
+++ b/book/src/installers/homebrew.md
@@ -0,0 +1,24 @@
+# Homebrew Installer
+
+> since 0.2.0
+
+This provides a [Homebrew](https://brew.sh) formula which allows users to `brew install` your package. Since it installs to a location on the user's `PATH`, it provides a simple and convenient installation method for users who already have Homebrew available. When published to a [tap](https://docs.brew.sh/Taps) (package repository), this gives your users an easy way to both install your package and to keep it up to date using `brew update` and `brew upgrade`. It fetches the same prebuilt macOS binaries as the shell installer.
+
+cargo-dist can, optionally, publish your formula to a tap repository for you on every release. To enable this, add a `tap` field to your `Cargo.toml` pointing to a GitHub repository that you control and add `homebrew` to the `publish-jobs` field. The repository name must start with `homebrew-`. For example:
+
+```toml
+tap = "axodotdev/homebrew-formulae"
+publish-jobs = ["homebrew"]
+```
+
+In order to write to a tap GitHub repository, cargo-dist needs a [personal access token](https://github.com/settings/tokens/new?scopes=repo) with the `repo` scope exposed as `HOMEBREW_TAP_TOKEN`. For more information on GitHub Actions secrets, [consult this documentation](https://docs.github.com/en/actions/security-guides/encrypted-secrets).
+
+Limitations/Caveats:
+
+* Does not support creating a formula which builds from source
+* Does not support Linuxbrew (Homebrew on Linux)
+* Does not support [Cask][issue-cask] for more convenient GUI app installation
+
+
+
+[issue-cask]: https://github.com/axodotdev/cargo-dist/issues/309
diff --git a/book/src/installers/index.md b/book/src/installers/index.md
new file mode 100644
index 000000000..8ed48fd55
--- /dev/null
+++ b/book/src/installers/index.md
@@ -0,0 +1,84 @@
+# Installers
+
+The core functionality of cargo-dist is to build your binaries and produce [tarballs / zips][archives] containing them. Basically every other kind of output it produces is considered an "installer" that helps download/install/run those binaries.
+
+Note that we use the term "installer" very loosely -- if it's fancier than a tarball, it's an installer to us!
+
+
+## Supported Installers
+
+Currently supported installers include:
+
+* [shell][]: a shell script that fetches and installs executables (for `curl | sh`)
+* [powershell][]: a powershell script that fetches and installs executables (for `irm | iex`)
+* [npm][]: an npm project that fetches and runs executables (for `npx`)
+* [homebrew][]: a Homebrew formula that fetches and installs executables
+* [msi][]: a Windows msi that bundles and installs executables
+
+These keys can be specified via [`installer` in your cargo-dist config][config-installers]. The [`cargo dist init` command][init] provides an interactive UI for enabling/disabling them.
+
+The above installers can have one of two strategies: *fetching* and *bundling* (defined below). Currently each installer is hardcoded to one particular strategy, but in the future [we may make it configurable][issue-unlock-installers].
+
+
+## Future Installers
+
+The following installers have been requested, and we're open to supporting them, but we have no specific timeline for when they will be implemented. Providing additional info/feedback on them helps us prioritize the work:
+
+* [linux docker image containing binaries](https://github.com/axodotdev/cargo-dist/issues/365)
+* [linux flatpak](https://github.com/axodotdev/cargo-dist/issues/25)
+* [macOS cask](https://github.com/axodotdev/cargo-dist/issues/309)
+* [macOS dmg / app](https://github.com/axodotdev/cargo-dist/issues/24)
+* [pypi package](https://github.com/axodotdev/cargo-dist/issues/86)
+* [windows winget package](https://github.com/axodotdev/cargo-dist/issues/87)
+
+
+
+## Fetching Installers
+
+Fetching installers are thin wrappers which detect the user's current platform and download and unpack the appropriate [archive][archives] from a server.
+
+In exchange for requiring [a well-defined Artifact URL][artifact-url] and an internet connection at install-time, this strategy gives you a simple and efficient way to host prebuilt binaries and make sure that all users get the same binaries regardless of how the installed your application.
+
+Fetching installers are also easy to make "universal" (cross-platform), so your installing users don't need to care about the OS or CPU they're using -- the installer will handle that for them.
+
+Installers which support fetching:
+
+* [shell][]: a shell script that fetches and installs executables (for `curl | sh`)
+* [powershell][]: a powershell script that fetches and installs executables (for `irm | iex`)
+* [npm][]: an npm project that fetches and runs executables (for `npx`)
+* [homebrew][]: a Homebrew formula that fetches and installs executables
+
+
+## Bundling Installers
+
+Bundling installers contain the actual binaries they will install on the user's system.
+
+These installers can work without any internet connection, which some users will demand or appreciate.
+
+Bundling requires a fundamental compromise when it comes to "universal" (cross-platform) installers, as any installer that wants to support e.g. [Intel macOS and Apple Silicon macOS][issue-macos-universal] will need to include both binaries, even if only one will ever be used.
+
+For this reason all bundling installers are currently single-platform, requiring the installing user to know what platform they're on.
+
+Installers which support bundling:
+
+* [msi][]: a Windows msi that bundles and installs executables
+
+
+
+
+[config-installers]: ../reference/config.md#installers
+
+[issue-unlock-installers]: https://github.com/axodotdev/cargo-dist/issues/450
+[issue-info-install]: https://github.com/axodotdev/cargo-dist/issues/72
+[issue-macos-universal]: https://github.com/axodotdev/cargo-dist/issues/77
+
+[shell]: ./shell.md
+[powershell]: ./powershell.md
+[msi]: ./msi.md
+[npm]: ./npm.md
+[homebrew]: ./homebrew.md
+
+[archives]: ../artifacts/archives.md
+[artifact-url]: ../reference/artifact-url.md
+[init]: ../reference/cli.md#cargo-dist-init
+
diff --git a/book/src/installers/msi.md b/book/src/installers/msi.md
new file mode 100644
index 000000000..c537d4526
--- /dev/null
+++ b/book/src/installers/msi.md
@@ -0,0 +1,92 @@
+# msi Installer
+
+> Since 0.3.0
+
+
+
+This guide will walk you through setting up a [bundling][] Windows msi installer. It assumes you've already done initial setup of cargo-dist, as described in [the way-too-quickstart][quickstart], and now want to add an msi to your release process.
+
+(Just a bit of a warning, this stuff works but there's a few rough edges, please let us know if you run into any issues!)
+
+
+## Setup
+
+We'll start with the bare-minimum and then explain what we did and how to modify it afterwards.
+
+
+### Setup Step 1: set "authors" in your Cargo.toml
+
+msi requires you to specify a "manufacturer" for you application, which is by default sourced from the "authors" field in you Cargo.toml. **If you don’t have that field set, the next step will error out.** If you have an authors entry like `My Cool Company ` then the manufacturer will be "My Cool Company".
+
+
+### Setup Step 2: run init and enable "msi"
+
+Rerun `cargo dist init` and when it prompts you to choose installers, enable "msi".
+
+Once init completes, some changes will be made to your project, **check all of them in**:
+
+1. `installers = ["msi"]` will be added to `[workspace.metadata.dist]`
+2. `[package.metadata.wix]` will be added to your packages with distable binaries. This is your msi-specific config. For now don't worry about it.
+3. `wix/main.wxs` will be created for each of your packages with distable binaries. This is a template for your msi. For now assume this file is completely managed by cargo-dist, and can't be hand-edited.
+
+
+### Setup Step 3: you're done! (time to test)
+
+See [the quickstart's testing guide][testing] for the various testing options.
+
+If the above steps worked, `cargo dist plan` should now include an msi for each Windows platform you support.
+
+`cargo dist build` is a bit trickier. Not only do you have to be on Windows to get an msi built, you also need to have the [WiX v3 toolchain][wix3] installed (WiX v4 isn't yet supported). If you don't the build will just error out. In GitHub CI the WiX v3 toolchain is pre-installed, so using PR testing is recommended.
+
+The resulting msi should include the following functionality:
+
+* (optional) EULA dialog
+* A menu that lets you choose where to install and whether to add it to PATH
+ * Default install location is `%ProgramFiles%\{app_name}\` (e.g. `C:\Program Files\axolotlsay\`)
+ * Default is to add the install location to PATH
+ * Currently the only files that will be included are the app's binaries in a `bin` subdir
+* If rerun, you will get an uninstall/reinstall menu
+* If a newer version is run, it will automatically uninstall the old version
+* If an older version is run, it will report that a newer version is installed and exit
+* The application will appear in the Windows "Add or remove programs" menu and can be uninstalled from there
+
+Certain licenses in your Cargo.toml like "Apache" or "MIT" (but *not* dual MIT/Apache) will get an auto-generated EULA that's just agreeing to the software license -- we know, that's not how software licenses work, but people seem to like to do it. See the section on advanced usage for how to set a more useful EULA.
+
+
+
+## How It Works
+
+As you may suspect from the setup, we rely on the industry standard [WiX v3 toolchain][wix3] to generate your msi installers (WiX v4 isn't yet supported). The `main.wxs` format is its xml-based templating system. Some of the information about your app is baked into this template (binaries, descriptions, licenses...), while other information is sourced at build time (mostly the version).
+
+If the template ever desyncs from the values it was generated from, commands like `cargo dist plan` (and therefore your pull request CI) will error out and ask you to rerun `cargo dist init` to regenerate it.
+
+The values we added to `[package.metadata.wix]` are special GUIDs that Windows uses to determine that two msi's with different versions refer to the same application and install location, which is required for it to properly handle things like upgrades. They are persisted in your Cargo.toml to keep them stable across regenerations of `main.wxs`.
+
+**All of the logic for generating this file is part of [cargo-wix][], which cargo-dist includes as a library.** It's a great project we happily contribute to, although some TLC is still needed to make the integration perfect (some of its warnings/errors may mention its own CLI's flags, and those sure won't work if you pass them to cargo-dist). The `[package.metadata.wix]` config is purely cargo-wix's, see [their docs for all the knobs it exposes][cargo-wix].
+
+
+
+## Advanced Usage
+
+There are two paths for advanced usage: managed and unmanaged. We recommend the managed approach, but the unmanaged approach is there for true power users.
+
+### Managed Advanced Usage
+
+If you want cargo-dist to be able to keep your `main.wxs` consistent with the definitions in your Cargo.tomls, then all you have available is the knobs exposed in `[package.metadata.wix]` -- see [cargo-wix's docs for details][cargo-wix].
+
+### Unmanaged Advanced Usage
+
+If you're not worried about keeping `main.wxs` consistent, then you can choose to dive deep into the full power of [WiX v3][wix3] by adding `allow-dirty = ["msi"]` to your cargo-dist config. Once you do this cargo-dist will stop trying to update it, and won't check if it's out of date.
+
+At that point you can make whatever hand-edits you want to main.wxs, as long as you still use the variables that cargo-wix injects into the template at build-time for things like versions and binary paths.
+
+See [WiX v3's docs][wix3] for all the things their format supports.
+
+
+
+[quickstart]: ../way-too-quickstart.md
+[testing]: ../way-too-quickstart.md#test-it-out
+[bundling]: ./index.md#bundling-installers
+
+[cargo-wix]: https://volks73.github.io/cargo-wix/cargo_wix/
+[wix3]: https://wixtoolset.org/docs/wix3/
\ No newline at end of file
diff --git a/book/src/installers/npm.md b/book/src/installers/npm.md
new file mode 100644
index 000000000..3a18ceba0
--- /dev/null
+++ b/book/src/installers/npm.md
@@ -0,0 +1,70 @@
+# npm Installer
+
+> since 0.0.6
+
+This provides a tarball containing an npm package (npm-package.tar.gz) which when installed into an npm project: detects the current platform, fetches the best possible [archive][] from your [artifact URL][artifact-url], and copies the binary into your node_modules. This can be used to install the binaries like any other npm package, or to run them with `npx`.
+
+This kind of installer is ideal for making a native Rust tool available to JS devs.
+
+An "installer hint" will be provided that shows how to install via `npm` like so:
+
+```sh
+npm install @axodotdev/cargodisttest@0.2.0
+```
+
+**cargo-dist does not publish the package for you, you need to do that manually once the tarball is built.** Conveniently, npm supports publishing from a url-to-a-tarball directly, and since 0.0.7 we make our tarballs look like "proper" npm package tarballs, so you can just do this:
+
+```sh
+npm publish URL_TO_TARBALL
+```
+
+You can find the URL to the tarball at the bottom of the Github Release, inside the collapsible "assets" dropdown (*-npm-package.tar.gz). The format of the url is:
+
+```text
+/releases/download//-npm-package.tar.gz
+```
+
+Example:
+
+https://github.com/axodotdev/oranda/releases/download/v0.0.3/oranda-npm-package.tar.gz
+
+If you're cutting a stable release (not-prerelease), you can use the "latest" URL format:
+
+https://github.com/axodotdev/oranda/releases/latest/download/oranda-npm-package.tar.gz
+
+In the future we may [introduce more streamlined CI-based publishing workflows][issue-npm-ci].
+
+[You can set the @scope the package is published under with the npm-scope cargo-dist config][config-npm-scope].
+
+We will otherwise do our best to faithfully translate [any standard Cargo.toml values you set][cargo-manifest] to an equivalent in the npm package.json format (name, version, authors, description, homepage, repository, keywords, categories...).
+
+The package will also include an npm-shrinkwrap.json file for the npm packages the installer uses, this is the same as package-lock.json but "really for reals I want this to be respected even if it's installed into another project". Note that [cargo install similarly disrespects Cargo.lock unless you pass --locked][install-locked].
+
+
+
+
+## Limitations and Caveats
+
+* Requires a well-defined [artifact URL][artifact-url]
+* [Cannot detect situations where musl-based builds are appropriate][issue-musl] (static or dynamic)
+* [Relies on nodejs's builtin gzip support to unpack the files, which only works with .tar.gz][issue-unpacking]
+* Cannot run any kind of custom install logic
+
+As a result of the `.tar.gz` limitation, `cargo dist init` will prompt you to change [windows-archive][config-windows-archive] and [unix-archive][config-unix-archive] to ".tar.gz" if you enable the npm installer, erroring if you decline.
+
+
+
+
+[issue-npm-ci]: https://github.com/axodotdev/cargo-dist/issues/245
+[issue-musl]: https://github.com/axodotdev/cargo-dist/issues/75
+[issue-unpacking]: https://github.com/axodotdev/cargo-dist/issues/226
+
+[config-windows-archive]: ../reference/config.md#windows-archive
+[config-unix-archive]: ../reference/config.md#unix-archive
+[config-npm-scope]: ../reference/config.md#npm-scope
+
+[archive]: ../artifacts/archives.md
+[artifact-url]: ../reference/artifact-url.md
+
+[cargo-manifest]: https://doc.rust-lang.org/cargo/reference/manifest.html
+[install-locked]: https://doc.rust-lang.org/cargo/commands/
diff --git a/book/src/installers/other.md b/book/src/installers/other.md
new file mode 100644
index 000000000..91e649c4a
--- /dev/null
+++ b/book/src/installers/other.md
@@ -0,0 +1,18 @@
+# Other Installation Methods
+
+cargo-dist projects can also theoretically be installed with the following, through no active effort of our own:
+
+* [cargo-install][] (just [cargo publish][] like normal)
+* [cargo-binstall][] (the URL schema we use for Github Releases is auto-detected)
+
+In the future we might [support displaying these kinds of install methods][issue-info-install].
+
+Note that cargo-install is just building from the uploaded source with the --release profile, and so if you're relying on cargo-dist or unpublished files for some key behaviours, this may cause problems. [It also disrespects your lockfile unless you pass --locked][install-locked]. You can more closely approximate cargo-dist's build with:
+
+```sh
+cargo install --locked
+```
+
+Although that's still missing things like [Windows crt-static workarounds][crt-static] and the "dist" profile.
+
+
diff --git a/book/src/installers/powershell.md b/book/src/installers/powershell.md
new file mode 100644
index 000000000..3d42e0c08
--- /dev/null
+++ b/book/src/installers/powershell.md
@@ -0,0 +1,57 @@
+# PowerShell Script Installer
+
+> since 0.0.3
+
+This provides a powershell script (my-app-installer.ps1) which detects the current platform, fetches the best possible [archive][] from your [Artifact URL][artifact-url], copies the binary into your [install-path][config-install-path], and attempts to add that path to the user's PATH (see the next section for details).
+
+This kind of installer is ideal for bootstrapping setup on a fairly bare-bones system.
+
+An "installer hint" will be provided that shows how to install via `irm | iex` (the windows equivalent of `curl | sh`), like so:
+
+```sh
+irm https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.ps1 | iex
+```
+
+Limitations/Caveats:
+
+* Requires a well-defined [Artifact URL][artifact-url]
+* Currently only really designed for "native windows", and won't detect other platforms properly
+* [Cannot detect situations where musl-based builds are appropriate][issue-musl] (static or dynamic)
+* Relies on the user's installation of `tar` and `Expand-Archive` to unpack the files
+* Relies on the the user's installation of `Net.Webclient` to fetch the files
+* [Won't work if run in cmd instead of powershell][issue-irm-iex]
+* [Will throw out all files except for the binary, so the binary can't rely on assets included in the archive][issue-unpack-all]
+* Cannot run any kind of custom install logic
+
+On the scale of Windows (where many people are still running Windows 7) commands like "Expand-Archive" and "tar" are in fact relatively new innovations. Any system that predates 2016 (PowerShell 5.0) certainly has no hope of working. I believe that someone running Windows 10 is basically guaranteed to work, and anything before that gets sketchier.
+
+In an ideal world most of these caveats improve (except for maybe the requirement of PowerShell >= 5.0 which is not pleasant to push past).
+
+
+## Adding things to PATH
+
+Here is a more fleshed out description of how the powershell installer attempts to add the [install-path][config-install-path] to the user's PATH, and the limitations of that process.
+
+The most fundamental limitation is that installers fundamentally cannot edit the PATH of the currently running shell (it's a parent process). Powershell does not have an equivalent of `source`, so to the best of our knowledge restarting the shell is the only option (which if using Windows Terminal seems to mean opening a whole new window, tabs aren't good enough). As such, it benefits an installer to try to install to a directory that will already be on PATH (such as [CARGO_HOME][cargo home]). ([rustup also sends a broadcast WM_SETTINGCHANGE message](https://github.com/rust-lang/rustup/blob/bcfac6278c7c2f16a41294f7533aeee2f7f88d07/src/cli/self_update/windows.rs#L397-L409), but we couldn't find any evidence that this does anything useful.)
+
+The process we use to add [install-path][config-install-path] to the user's PATH is roughly the same process that rustup uses (hopefully making us harmonious with running rustup before/after one of our installer scripts). In the following description we will use `$install-path` as a placeholder for the path computed at install-time where the binaries get installed. Its actual value will likely look something like `C:\Users\axo\.myapp` or `C:\Users\.cargo\bin`.
+
+* we load from the registry `HKCU:\Environment`'s "Path" Item
+* we check if `$install-path` is contained within it already
+* if not, we prepend it and write the value back
+ * prepending is used to ideally override system-installed binaries, as that is assumed to be desired when explicitly installing with not-your-system-package-manager
+* if we edited the registry, we prompt the user to restart their shell
+
+
+
+
+[issue-irm-iex]: https://github.com/axodotdev/oranda/issues/393
+[issue-musl]: https://github.com/axodotdev/cargo-dist/issues/75
+[issue-unpack-all]: https://github.com/axodotdev/cargo-dist/issues/307
+
+[config-install-path]: ../reference/config.md#install-path
+
+[archive]: ../artifacts/archives.md
+[artifact-url]: ../reference/artifact-url.md
+
+[cargo home]: https://doc.rust-lang.org/cargo/guide/cargo-home.html
diff --git a/book/src/installers/shell.md b/book/src/installers/shell.md
new file mode 100644
index 000000000..ca75b5510
--- /dev/null
+++ b/book/src/installers/shell.md
@@ -0,0 +1,61 @@
+# Shell Script Installer
+
+> since 0.0.3
+
+The "shell" installer provides a shell script (my-app-installer.sh) which detects the current platform, fetches the best possible [archive][] from your [Artifact URL][artifact-url], copies the binary into your [install-path][config-install-path], and attempts to add that path to the user's PATH (see the next section for details).
+
+This kind of installer is ideal for bootstrapping setup on a fairly bare-bones system.
+
+An "installer hint" will be provided that shows how to install via `curl | sh`, like so:
+
+```sh
+curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.sh | sh
+```
+
+Limitations/Caveats:
+
+* Requires a well-defined [Artifact URL][artifact-url]
+* Currently only really designed for "linux" and "macOS", and won't detect other platforms properly (and certainly won't play nice with things like nixOS).
+* [Cannot detect situations where musl-based builds are appropriate][issue-musl] (static or dynamic)
+* Relies on the user's installation of `tar` and `unzip` to unpack the files
+* Relies on the the user's installation of `curl` or `wget` to fetch the files
+* [Will throw out all files except for the binary, so the binary can't rely on assets included in the archive][issue-unpack-all]
+* Cannot run any kind of custom install logic
+
+In an ideal world all of these caveats improve (except for maybe relying on tar/unzip/curl/wget, that's kinda fundamental).
+
+
+
+## Adding things to PATH
+
+Here is a more fleshed out description of how the shell installer attempts to add the [install-path][config-install-path] to the user's PATH, and the limitations of that process.
+
+The most fundamental limitation is that installers fundamentally cannot edit the PATH of the currently running shell (it's a parent process). Only an explicit `source some_file` (or the more portable `. some_file`) can do that. As such, it benefits an installer to try to install to a directory that will already be on PATH (such as [CARGO_HOME][cargo home]). Otherwise all we can do is prompt the user to run `source` themselves after the installer has run (or restart their shell to freshly source rcfiles).
+
+The process we use to add [install-path][config-install-path] to the user's PATH is roughly the same process that rustup uses (hopefully making us harmonious with running rustup before/after one of our installer scripts). In the following description we will use `$install-path` as a placeholder for the path computed at install-time where the binaries get installed. Its actual value will likely look something like `$HOME/.myapp` or `$HOME/.cargo/bin`.
+
+* we generate a shell script and write it to `$install-path/env` (let's call this `$env-path`)
+ * the script checks if `$install-path` is in PATH already, and prepends it if not
+ * prepending is used to ideally override system-installed binaries, as that is assumed to be desired when explicitly installing with not-your-system-package-manager
+ * the `env` script will only be added if it doesn't already exist
+ * if `install-path = "CARGO_HOME"`, then `$env-path` will actually be in the parent directory, mirroring the behaviour of rustup
+* we add `. $env-path` to `$HOME/.profile`
+ * this is just a more portable version of `source $install-path/env`
+ * this line will only be added if it doesn't exist (we also check for the `source` equivalent)
+ * the file is created if it doesn't exist
+ * [rustup shotgun blasts this line into many more files like .bashrc and .zshenv](https://github.com/rust-lang/rustup/blob/bcfac6278c7c2f16a41294f7533aeee2f7f88d07/src/cli/self_update/shell.rs#L70-L76), while still [lacking proper support for fish](https://github.com/rust-lang/rustup/issues/478) and other more obscure shells -- we opted to start conservative with just .profile
+* if `$HOME/.profile` was edited, we prompt the user to `source "$env-path"` or restart their shell
+ * although this is less portable than `. "$env-path"`, it's very easy to misread/miscopy the portable version (not as much of a concern for an rcfile, but an issue for humans)
+ * hopefully folks on platforms where this matters are aware of this issue (or they can restart their shell)
+
+
+
+[issue-musl]: https://github.com/axodotdev/cargo-dist/issues/75
+[issue-unpack-all]: https://github.com/axodotdev/cargo-dist/issues/307
+
+[config-install-path]: ../reference/config.md#install-path
+
+[archive]: ../artifacts/archives.md
+[artifact-url]: ../reference/artifact-url.md
+
+[cargo home]: https://doc.rust-lang.org/cargo/guide/cargo-home.html
diff --git a/book/src/introduction.md b/book/src/introduction.md
index 2438c562f..4875e5dd8 100644
--- a/book/src/introduction.md
+++ b/book/src/introduction.md
@@ -1,45 +1,88 @@
# Introduction
-cargo-dist extends Cargo to support all the extra things you want to do when building the final shippable binaries for an application, so we can turn this:
+*cargo-dist distributes your binaries*
+
+The TL;DR is that with cargo-dist setup, just doing this:
```sh
-git commit -am "Chore: 0.1.0 release"
-git tag "v0.1.0"
+git commit -am "release: 0.2.0"
+git tag "v0.2.0"
git push
git push --tags
```
-into this:
+Will make [this Github Release](https://github.com/axodotdev/axolotlsay/releases/tag/v0.2.0):
+
+![A Github Release for "axolotlsay 0.2.0" with several installers and prebuilt binaries][simple-release]
+
+Or if you're using [oranda](https://opensource.axo.dev/oranda/), you'll get [this website](https://opensource.axo.dev/axolotlsay/):
+
+![A website for "axolotlsay" that has a widget that detects the user's platform and suggests installation methods][simple-oranda]
+
+
+
+
+## Plan, Build, Host, Publish, Announce
+
+Cutting releases of your apps and distributing binaries for them has a lot of steps, and cargo-dist is quickly growing to try to cover them all!
+
+To accomplish this, cargo-dist functionality can be broken up into two parts:
+
+* building (**planning** the release; **building** binaries and installers)
+* distributing (**hosting** artifacts; **publishing** packages; **announcing** releases)
+
+The build functionality can be used on its own if you just want some tarballs and installers, but everything really comes together when you use the distribution functionality too.
+
+
+## Building
+
+As a build tool, cargo-dist can do the following:
+
+* Pick good build flags for "shippable binaries"
+* Make [tarballs][] and [installers][] for the resulting binaries
+* Generate [machine-readable manifests][manifest] so other tools can understand the results
-![A Github Release for "my-app 0.1.0" with shell-script installers and tarballs of prebuilt binaries][simple-release]
+That's a short list because "we make [installers][]" is doing a lot of heavy lifting. Each installer could be (and sometimes is!) an entire standalone tool with its own documentation and ecosystem.
-Locally, cargo-dist can do the following:
-* Picking good build flags for "shippable binaries"
-* Making zips and [installers][] for the resulting binaries
-* Generating machine-readable manifests so other tools can understand the results
+## Distributing
-Being able to build a zip on your own machine is nice and all, but in practice you probably want to have infrastructure for building and hosting the binaries for all the platforms you care about. To help streamline this, cargo-dist has builtin support for bringing up your infra (currently only Github CI and Github Releases, but we intended to support other platforms in subsequent releases)!
+As a distribution tool, cargo-dist gets to flex its biggest superpower: **it generates [its own CI scripts][ci-providers]**. For instance, enabling [GitHub CI][github-ci] with `cargo dist init` will generate release.yml, which implements the full pipeline of plan, build, host, publish, announce:
-Just run `cargo dist init` and it will **generate its own CI scripts** which:
+* Plan
+ * Waits for you to push a git tag for a new version (v1.0.0, my-app-v1.0.0, my-app/1.0.0, ...)
+ * Selects what apps in your workspace to announce new releases for based on that tag
+ * Generates [a machine-readable manifest][manifest] with changelogs and build plans
+* Build
+ * Spins up machines for each platform you support
+ * Builds your [binaries and tarballs][tarballs]
+ * Builds [installers][installers] for your binaries
+* Publish:
+ * Uploads to package managers
+* Host + Announce:
+ * Creates (or edits and undrafts) a GitHub Release
+ * Uploads build artifacts to the Release
+ * Adds relevant release notes from your RELEASES/CHANGELOG
-* Waits for you to push a git tag for a new version (v1.0.0, my-app-v1.0.0, my-app/v1.0.0, ...)
-* Selects what apps in your workspace to announce new releases for based on that tag
-* Creates a draft Github Release to announce the apps in and host the downloads
-* Adds the relevant release notes from your RELEASES or CHANGELOG file
-* Spins up machines to build the selected apps for your supported platforms
-* Uploads the various zips/[installers][] to the Github Release
-* On success, publishes the Github Releases
+(Ideally "host" would come cleanly before "publish", but GitHub Releases doesn't really properly support this kind of staging, so we're forced to race the steps a bit here. Future work may provide a more robust release process.)
-The scripts are intentionally minimal, and each machine's job roughly amounts to "install cargo-dist", "run it exactly once", "upload the artifacts it reported". It will always be *easier* to do builds in CI, but we want to shrink that gap as much as possible.
+Most of the scripts roughly amount to "install cargo-dist", "run it exactly once", "upload the artifacts it reported". **We want you to be able to copy that one cargo-dist invocation CI did, run it on your machine, and get the same results without any fuss** (not to bit-level precision, but to the kinds of precision normal people expect from cargo builds). No setting up docker, no weird linux-only shell scripts that assume a bunch of tools were setup in earlier CI steps.
-**We want you to be able to copy that one cargo-dist invocation CI did, run it on your machine, and get the same results without any fuss** (not to bit-level precision, but to the kinds of precision normal people expect from cargo builds). No setting up docker, no weird linux-only shell scripts that assume a bunch of tools were setup in earlier CI steps.
+Of course even if we perfectly achieve this ideal, "you *can* run it locally" and "you *want to* run it locally" are different statements.
-The main obstacle to this is "[cross-compilation is hard][cross-comp]", but other folks are making that easier every day, and eventually we'll help you with that too.
+To that point, **release.yml can now run partially in pull-requests**. The default is to only run the "plan" step, which includes many integrity checks to help prevent "oops the release process is broken and we only found out when we tried to cut a release".
+You can also crank the pull-request mode up to include the "build" step, in which case the PR Workflow Summary will include an artifacts.zip containing all the build results. We don't recommend keeping this on all the time (it's slow and wasteful), but it can be useful to temporarily turn on while testing a PR.
+![A GitHub Workflow Summary from running cargo-dist's release.yml with an "artifacts" download link at the bottom][workflow-artifacts]
-[cross-comp]: https://github.com/axodotdev/cargo-dist/issues/74
[simple-release]: ./img/simple-github-release.png
-[installers]: ./installers.md
+[simple-oranda]: ./img/simple-oranda.png
+[workflow-artifacts]: ./img/workflow-artifacts.png
+
+[github-ci]: ./ci/github.md
+[ci-providers]: ./ci/index.md
+[installers]: ./installers/index.md
+[tarballs]: ./artifacts/archives.md
+[manifest]: ./reference/schema.md
\ No newline at end of file
diff --git a/book/src/reference/artifact-url.md b/book/src/reference/artifact-url.md
new file mode 100644
index 000000000..9013cc33c
--- /dev/null
+++ b/book/src/reference/artifact-url.md
@@ -0,0 +1,27 @@
+# Artifact URL
+
+[Fetching installers](../installers/index.md) need to know where to download the [actual binaries](../artifacts/archives.md) from, so cargo-dist needs to be aware of a base Artifact URL that it can derive download URLs from when it builds those kinds of installers.
+
+## GitHub
+
+Currently this functionality is restricted to [the "github" ci backend](../ci/github.md), which uploads your artifacts to a GitHub Release. Because cargo-dist is fully in control of the uploading of your artifacts, it can automatically compute the Artifact URL for you, as:
+
+```text
+{repo_url}/releases/download/{tag}
+```
+
+Where `repo_url` is the value of `repository` set in your Cargo.toml, and `tag` is the git tag of the release. For safety reasons, cargo-dist will refuse to define repo_url (and therefore the Artifact URL) unless all packages in your workspace that define `repository` agree on the value and have the format of `https://github.com/{owner}/{project}` (although we'll do some cleanups like trailing slashes or `.git`).
+
+For example, if we want the linux build of axolotlsay 0.1.0, we have:
+
+```
+* Cargo.toml "repository": `https://github.com/axodotdev/axolotlsay/`
+* git tag: `v0.1.0`
+* artifact url: `https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/`
+* download: `https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-unknown-linux-gnu.tar.gz`
+```
+
+
+## Other
+
+Future releases [will expose a more general mechanism for specifying artifact download URLs](https://github.com/axodotdev/cargo-dist/issues/236).
\ No newline at end of file
diff --git a/book/src/cli.md b/book/src/reference/cli.md
similarity index 56%
rename from book/src/cli.md
rename to book/src/reference/cli.md
index a76aa98d0..9b3b7fbd1 100644
--- a/book/src/cli.md
+++ b/book/src/reference/cli.md
@@ -2,6 +2,6 @@
-{{#include ../../cargo-dist/tests/snapshots/markdown-help.snap:7:}}
+{{#include ../../../cargo-dist/tests/snapshots/markdown-help.snap:7:}}
[workspace.metadata.dist]: ./config.md#metadatadist
diff --git a/book/src/concepts.md b/book/src/reference/concepts.md
similarity index 95%
rename from book/src/concepts.md
rename to book/src/reference/concepts.md
index a419b6a2a..84ecc690c 100644
--- a/book/src/concepts.md
+++ b/book/src/reference/concepts.md
@@ -66,7 +66,7 @@ First the easy part: `profile.dist` is the profile cargo-dist will build everyth
The other 3 fields are defining the various Artifacts that should be produced for each App in the workspace (because this is `[workspace.metadata]` and not `[package.metadata]`).
-For each entry in `targets` you will get a build of your App for [that platform][rust-platform] in the form of an [executable-zip][].
+For each entry in `targets` you will get a build of your App for [that platform][rust-platform] in the form of an [archive][].
For each entry in `installers` you get that kind of [installer][installers] for your App. There are two classes of installer: "global" and "local". This will be explained further in [the section on artifact modes][artifact-modes-section], but the tl;dr is that "global" installers are one-per-App while "local" installers are one-per-platform-per-app, similar to a [Github CI Matrix](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs).
@@ -124,7 +124,7 @@ Normally cargo-dist will error out if the Announcement Tag selects no Apps, beca
Now that we have a coherent Announcement and therefore have selected what apps we want to Release, we need to select what artifacts we want to build (or get a manifest for). Enumerating the exact artifacts for each invocation of cargo-dist would be tedious and error-prone, so we provide the `--artifacts=...` flag to specify the *Artifact Mode*, which is a certain subset of the Universe of all Artifacts:
-* "local": artifacts that are per-target platform ([executable-zips][executable-zip], symbols, msi installers...)
+* "local": artifacts that are per-target platform ([archives][archive], symbols, msi installers...)
* "global": artifacts that are one-per-app (shell installer, npm package...)
* "all": both global and local (so the whole Universe)
* "host": the default mode that kind of breaks the rules to let you test things out locally
@@ -188,7 +188,7 @@ In my case it's "x86_64-pc-windows-msvc", so let's try that:
cargo dist build --tag=v0.5.0 --artifacts=local --target=x86_64-pc-windows-msvc --no-local-paths
```
-![A local build producing only executable-zips for the current platform][local-build-example]
+![A local build producing only archives for the current platform][local-build-example]
Note that you can pass `--target` multiple times to select more than one. Note also that `--target` is not allowed to select targets that aren't specified by the config your Cargo.toml. This ensures that global installers are consistently aware of all the platform-specific artifacts they can fetch. ("host" mode breaks this rule.) ((Also in theory `--installer` should work the same for selecting specific installers but it's not well tested because there isn't any reason to ever use that outside of `cargo dist init`.))
@@ -218,7 +218,7 @@ Ok so here's what goes through cargo-dist's brains when you run it:
3. Determine what Targets we're building for
3. Call the specific Version of each App a "Release" ("my-app-v1.0.0")
4. For each Release-Target pair, create a "ReleaseVariant" ("my-app-v1.0.0-x86_64-apple-darwin")
-5. Add executable-zip Artifacts to each Release (broadcasted to each Variant, filtered by Artifact Mode)
+5. Add archive Artifacts to each Release (broadcasted to each Variant, filtered by Artifact Mode)
6. Add all the enabled Installers to each Release (local ones broadcasted to each Variant, filtered by Artifact Mode)
7. Compute the Build Steps necessary to produce each Artifact ("run cargo, copy this file, ...")
8. Generate top-level Announcement info like the body for a Github Release
@@ -237,24 +237,26 @@ CI will just invoke cargo-dist in the following sequence:
(All the upload-artifacts tasks are in parallel, and there are multiple "local" tasks to cover the target platforms.)
+[config-dist]: ../reference/config.md#dist
-[workspace-log]: img/workspace-log.png
-[announce-error]: img/announcement-error.png
-[human-manifest-example]: img/human-manifest-all.png
-[global-build-example]: img/global-build.png
-[local-build-example]: img/local-build.png
+[guide]: ../workspaces/index.md
+[installers]: ../installers/index.md
+[archive]: ../artifacts/archives.md
+[announcements-section]: #announcements-selecting-apps
+[artifact-modes-section]: #artifact-modes-selecting-artifacts
+[defining-your-apps-section]: #defining-your-apps
+
+[workspace-log]: ../img/workspace-log.png
+[announce-error]: ../img/announcement-error.png
+[human-manifest-example]: ../img/human-manifest-all.png
+[global-build-example]: ../img/global-build.png
+[local-build-example]: ../img/local-build.png
[binary targets]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries
[publish-false]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field
-[config-dist]: ./config.md#dist
[cdylibs]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library
[cargo-conflicts]: https://github.com/rust-lang/cargo/issues/6313
-[announcements-section]: #announcements-selecting-apps
[rust-platform]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
-[executable-zip]: ./artifacts.md#executable-zip
-[artifact-modes-section]: #artifact-modes-selecting-artifacts
-[defining-your-apps-section]: #defining-your-apps
[cargo-metadata]: https://doc.rust-lang.org/cargo/commands/cargo-metadata.html
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
-[guide]: ./guide.html
-[installers]: ./installers.md
+
diff --git a/book/src/config.md b/book/src/reference/config.md
similarity index 92%
rename from book/src/config.md
rename to book/src/reference/config.md
index f41c13d46..65cf5dd4c 100644
--- a/book/src/config.md
+++ b/book/src/reference/config.md
@@ -27,23 +27,19 @@ 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.)
### readme
-cargo-dist defaults to trying to include certain "important" static files in your executable-zips. A README is one of them.
+cargo-dist defaults to trying to include certain "important" static files in your archives. A README is one of them.
If you specify a path to a README file, cargo-dist will use that for all the packages it affects. If you don't, then cargo-dist will search for a README* file in the package's root directory and the workspace's root directory (preferring the package).
### license-file
-cargo-dist defaults to trying to include certain "important" static files in your executable-zips. A LICENSE is one of them.
+cargo-dist defaults to trying to include certain "important" static files in your archives. A LICENSE is one of them.
If you specify a path to a license file, cargo-dist will use that for all packages it affects. Otherwise, cargo-dist will search for LICENSE* or UNLICENSE* files in the package's root directory and the workspace's root directory (preferring the package). If multiple are defined in the same directory, we will grab them all (this is necessary for the extremely common dual MIT/Apache license, which often results in two LICENSE-* files).
@@ -153,7 +149,7 @@ See the [installers documentation][homebrew-installer] for more information on H
Example: `include = ["my-cool-file.txt", "../other-cool-file.txt", "./some/dir/"]`
-This is a list of additional *files* or *directories* to copy into the root of all [executable-zips][] that this setting affects. The paths are relative to the directory of the Cargo.toml that you placed this setting in. Globs are not supported.
+This is a list of additional *files* or *directories* to copy into the root of all [archives][] that this setting affects. The paths are relative to the directory of the Cargo.toml that you placed this setting in. Globs are not supported.
### auto-includes
@@ -161,7 +157,7 @@ This is a list of additional *files* or *directories* to copy into the root of a
Example: `auto-includes = false`
-Allows you to specify whether cargo-dist should auto-include README, (UN)LICENSE, and CHANGELOG/RELEASES files in [executable-zips][]. Defaults to true.
+Allows you to specify whether cargo-dist should auto-include README, (UN)LICENSE, and CHANGELOG/RELEASES files in [archives][]. Defaults to true.
### windows-archive
@@ -169,7 +165,7 @@ Allows you to specify whether cargo-dist should auto-include README, (UN)LICENSE
Example: `windows-archive = ".tar.gz"`
-Allows you to specify the file format to use for [executable-zips][] that target windows. The default is
+Allows you to specify the file format to use for [archives][] that target windows. The default is
".zip". Supported values:
* ".zip"
@@ -185,7 +181,7 @@ See also unix-archive below.
Example: `unix-archive = ".tar.gz"`
-Allows you to specify the file format to use for [executable-zips][] that target not-windows. The default is
+Allows you to specify the file format to use for [archives][] that target not-windows. The default is
".tar.xz". See "windows-archive" above for a complete list of supported values.
@@ -216,13 +212,13 @@ If no scope is specified the package will be global.
Example: `checksum = "sha512"`
-Specifies how to checksum [executable-zips][]. Supported values:
+Specifies how to checksum [archives][]. Supported values:
* "sha256" (default) - generate a .sha256 file for each archive
* "sha512" - generate a .sha512 file for each archive
* "false" - do not generate any checksums
-The hashes should match the result that sha256sum and sha512sum generate. The current format is just a file containing the hash of that file and nothing else.
+The hashes should match the result that sha256sum and sha512sum generate, and the file should be readable by those sorts of commands.
Future work is planned to [support more robust signed checksums][issue-sigstore].
@@ -335,6 +331,28 @@ already exists with the title/body you want, and just upload artifacts to it.
At the end of a successful publish it will undraft the Github Release.
+### publish-prereleases
+
+> since 0.2.0
+
+Example: `publish-prereleases = true`
+
+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.
+
+
+### pr-run-mode
+
+> since 0.3.0
+
+Example: `pr-run-mode = "skip"`
+
+This setting determines to what extent we run your Release CI on pull-requests:
+
+* "skip": don't check the release process in PRs
+* "plan": run 'cargo dist plan' on PRs (recommended, also the default)
+* "upload": build and upload an artifacts.zip to the PR (expensive)
+
+
### install-path
> since 0.1.0
@@ -418,24 +436,24 @@ See [Artifact Modes][artifact-modes] for how you might use this kind of subsetti
Caveat: the default "host" Artifact Mode does something fuzzier with `--target` to allow you to build binaries that are usable on the current platform. Again see [Artifact Modes][artifact-modes].
+[issue-sigstore]: https://github.com/axodotdev/cargo-dist/issues/120
+[concepts]: ../reference/concepts.md
+[installers]: ../installers/index.md
+[shell-installer]: ../installers/shell.md
+[powershell-installer]: ../installers/powershell.md
+[homebrew-installer]: ../installers/homebrew.md
+[npm installers]: ../installers/npm.md
+[artifact-url]: ../reference/artifact-url.md
+[generate]: ../reference/cli.md#cargo-dist-generate
+[archives]: ../artifacts/archives.md
+[artifact-modes]: ../reference/concepts.md#artifact-modes-selecting-artifacts
[workspace-metadata]: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-metadata-table
[cargo-manifest]: https://doc.rust-lang.org/cargo/reference/manifest.html
-[concepts]: ./concepts.md
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
-[generate]: ./cli.md#cargo-dist-generate
[semver-version]: https://docs.rs/semver/latest/semver/struct.Version.html
[rust-version]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field
[rustup]: https://rust-lang.github.io/rustup/
[platforms]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
-[executable-zips]: ./artifacts.md#executable-zip
-[artifact-modes]: ./concepts.md#artifact-modes-selecting-artifacts
-[installers]: ./installers.md
-[shell-installer]: ./installers.md#shell
-[powershell-installer]: ./installers.md#powershell
-[homebrew-installer]: ./installers.md#homebrew
-[artifact-url]: ./installers.md#artifact-download-url
[scope]: https://docs.npmjs.com/cli/v9/using-npm/scope
-[npm installers]: ./installers.md#npm
-[issue-sigstore]: https://github.com/axodotdev/cargo-dist/issues/120
diff --git a/book/src/reference.md b/book/src/reference/index.md
similarity index 100%
rename from book/src/reference.md
rename to book/src/reference/index.md
diff --git a/book/src/schema.md b/book/src/reference/schema.md
similarity index 83%
rename from book/src/schema.md
rename to book/src/reference/schema.md
index 25e15d342..4627ec8bd 100644
--- a/book/src/schema.md
+++ b/book/src/reference/schema.md
@@ -11,3 +11,7 @@ As a matter of forward-compat and back-compat, basically every field in the form
The latest schema can be found at:
https://github.com/axodotdev/cargo-dist/releases/latest/download/dist-manifest-schema.json
+
+An example dist-manifest can be found at:
+
+https://github.com/axodotdev/axolotlsay/releases/latest/download/dist-manifest.json
\ No newline at end of file
diff --git a/book/src/way-too-quickstart.md b/book/src/way-too-quickstart.md
index bba4655b8..a3502703e 100644
--- a/book/src/way-too-quickstart.md
+++ b/book/src/way-too-quickstart.md
@@ -2,15 +2,23 @@
-> TLDR: cargo-dist is a souped up version of `cargo build` which handles building tarballs/zips and [installers][]. It also knows how to generate Github CI for orchestrating itself and uploading its output to a new Github Release. You can use cargo-dist if you don't care about that CI stuff, but this guide assumes that you do.
+> TLDR: cargo-dist is a souped up version of `cargo build` which handles building [tarballs][] and [installers][installer]. It also knows how to generate Github CI for orchestrating itself and uploading its output to a new GitHub Release. You can use cargo-dist if you don't care about that CI stuff, but this guide assumes that you do.
>
-> This quickstart is a bit *too* quick because there's some important nuances to "announcing and building releases" that depend on the way you like to structure and version your workspace. We will blatantly ignore those nuances and show you the Happiest Happy Path (a workspace with one crate that defines a binary). Checkout [the guide][guide] for more details on what you should *actually* do.
+> This quickstart is a bit *too* quick because there's some important nuances to "announcing and building releases" that depend on the way you like to structure and version your workspace. We will blatantly ignore those nuances and show you the Happiest Happy Path (a workspace with one crate that defines a binary). Checkout [the workspace guide][guide] for more details on what you should *actually* do.
## Setup
-Setting up just requires you to [install cargo-dist][install] and then run `cargo dist init` in your [Cargo workspace][workspace]. This command interactively walks you through configuration options, and can be run again whenever you want to change your settings. Since this is the *way-too*-quickstart, we pass `--yes` to auto-accept all defaults!
+Setting up just requires you to [install cargo-dist][install] and then run `cargo dist init` in your [Cargo workspace][workspace]. This command interactively walks you through configuration options, **and should be run again whenever you want to change your settings or want to update cargo-dist**.
+
+Just to really emphasize that: `cargo dist init` is designed to be rerun over and over, and will preserve your settings while handling any necessary updates and migrations. Always Be Initing.
+
+
+
+### Initial Setup
+
+Since this is the *way-too*-quickstart, we pass `--yes` to auto-accept all defaults on our first setup!
```sh
# install tools (build from source is the most portable option)
@@ -19,19 +27,29 @@ cargo install cargo-dist
# setup cargo-dist in your project (--yes to accept defaults)
cargo dist init --yes
git add .
-git commit -am "wow shiny new cargo-dist CI!"
+git commit -am "chore: wow shiny new cargo-dist CI!"
```
The one-time setup will add a decent default configuration to your root Cargo.toml and generate CI for orchestrating itself in `.github/workflows/release.yml`. If the CI file isn't created, this probably means you don't have `repository = "https://github.com/..."` consistently set in your Cargo.toml(s).
+### Adding Installers
+
+The most common reason to update cargo-dist or mess with its config is to add a new [installer][], which is basically our blanket term for anything more fancy than [tarballs][] (curl-sh scripts, npm packages, msi installers, ...).
+
+You can skip this step for now and just test out the basics the initial setup gives you. Each individual [installer][] should have a guide that assumes you did the initial setup.
+
+The tl;dr of those guides is "run `cargo dist init` again, select the installer you want to add, and fill in any extra details that are needed".
+
-## Test Locally
-When testing out cargo-dist locally, the two biggest things you might be interested in are:
+## Test It Out
+
+There are a several ways to test out cargo-dist before committing to running a proper release:
1. build for the current platform (`cargo dist build`)
2. check what CI will build (`cargo dist plan`)
+3. check the release process on pull-requests
@@ -44,11 +62,10 @@ cargo dist build
![Running "cargo dist build" on a project, resulting in the application getting built and bundled into a .zip, and an "installer.ps1" script getting generated. Paths to these files are printed along with some metadata.][quickstart-build]
-The [build command][build] will by default try to build things for the computer you're running it on. So if you run it on linux you might get a `tar.xz` containing your binary and an installer shell script, but if you run it on windows you might get a `zip` and an installer *power*shell script.
+The [build command][build] will by default try to build things for the computer you're running it on. So if you run it on linux you might get a `tar.xz` containing your binary and an installer.sh, but if you run it on windows you might get a `zip` and an installer.ps1.
-cargo-dist will then spit out paths to the files it created, so you can inspect their contents and try running them (**note that installer scripts probably won't be locally runnable, because they will try to fetch their binaries from Github**).
+cargo-dist will then spit out paths to the files it created, so you can inspect their contents and try running them (**note that installer scripts probably won't be locally runnable, because they will try to fetch their binaries from GitHub**).
-See [artifact modes][artifact-modes] for more advanced details on selecting what things cargo-dist should build.
@@ -66,23 +83,31 @@ The [plan command][plan] should be running the exact same logic that cargo-dist'
+### Check The Release Process On Pull-Requests
+
+As of cargo-dist 0.3.0, we now by default run the "plan" step of your release CI on every pull-request so that we can catch breakage to your release process as early as possible. This will work even for a pull-request that sets up cargo-dist for the first time, so you can be confident you're landing something that works.
+
+You can also crank this up by setting `pr-run-mode = "upload"`, which will run all the build steps as well, and upload the results to the PR's Workflow Summary as an "artifacts.zip". This is great for making sure the windows build works even if you only have a linux machine, or vice-versa. Although you should probably only keep it on temporarily, as it's very slow and wasteful to build all those shippable artifacts for every PR.
+
+
+
## Cut A Release (Trigger Github CI)
-cargo-dist largely doesn't care about the details of how you prepare your release, and intentionally doesn't provide tools to streamline it (see the next section for some recommendations). All it cares about is you getting your main branch into the state you want, and then pushing a properly formatted git tag like "v0.1.0". Here's a super bare-bones release process:
+cargo-dist largely doesn't care about the details of how you prepare your release, and doesn't yet provide tools to streamline it. All it cares about is you getting your release branch into the state you want, and then pushing a properly formatted git tag like "v0.1.0". Here's a super bare-bones release process where we're releasing by just pushing a bunch of stuff to main branch (but it would work just as well with PRs and release branches):
```sh
#
# commit and push to main (can be done with a PR)
-git commit -am "chore: Release version 0.1.0"
+git commit -am "release: version 0.1.0"
git push
-# publish to crates.io (optional)
-cargo publish
-
# actually push the tag up (this triggers cargo-dist's CI)
git tag v0.1.0
git push --tags
+
+# publish to crates.io (optional)
+cargo publish
```
The important parts are that you update the crates you want to release/announce to the desired version and push a git tag with that version.
@@ -92,31 +117,17 @@ At this point you're done! The generated CI script should pick up the ball and c
-### Streamlining Cutting A Release
-
-You may have noticed "cut a release" still has a lot of tedious work. That's because we recommend using [cargo-release][] to streamline the last step, which in *simple workspaces* will do exactly the same thing as above (but more robustly):
-
-```sh
-# install tools
-cargo install cargo-release
-
-# cut a release
-cargo release 0.1.0
-```
-
-(I left off the `--execute` flag from `cargo-release` so you won't accidentally break anything if you really did just copy paste that 😇)
-
-For more details on using cargo-release with cargo-dist, see [the guide for that][cargo-release-guide].
+[quickstart-build]: ./img/quickstart-build.png
+[quickstart-plan]: ./img/quickstart-plan.png
+[guide]: ./workspaces/index.md
+[install]: ./install.md
+[cargo-release-guide]: ./workspaces/cargo-release-guide.md
+[artifact-modes]: ./reference/concepts.md#artifact-modes-selecting-artifacts
+[installer]: ./installers/index.md
+[tarballs]: ./artifacts/archives.md
+[build]: ./reference/cli.md#cargo-dist-build
+[plan]: ./reference/cli.md#cargo-dist-plan
[cargo-release]: https://github.com/crate-ci/cargo-release
-[guide]: ./guide.md
-[install]: ./install.md
-[cargo-release-guide]: ./cargo-release-guide.md
-[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
-[quickstart-build]: ./img/quickstart-build.png
-[quickstart-plan]: ./img/quickstart-plan.png
-[artifact-modes]: ./concepts.md#artifact-modes-selecting-artifacts
-[installers]: ./installers.md
-[build]: ./cli.md#cargo-dist-build
-[plan]: ./cli.md#cargo-dist-plan
+[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
\ No newline at end of file
diff --git a/book/src/cargo-release-guide.md b/book/src/workspaces/cargo-release-guide.md
similarity index 100%
rename from book/src/cargo-release-guide.md
rename to book/src/workspaces/cargo-release-guide.md
diff --git a/book/src/guide.md b/book/src/workspaces/index.md
similarity index 91%
rename from book/src/guide.md
rename to book/src/workspaces/index.md
index 8ad5cecae..0caefe8ca 100644
--- a/book/src/guide.md
+++ b/book/src/workspaces/index.md
@@ -12,8 +12,9 @@ Gonna be blunt and say that cargo-dist is still in early days and we still need
The guide will start by explaining the simple case, and then explain the more complicated cases.
-[concepts]: ./concepts.md
-[way-too-quickstart]: ./way-too-quickstart.md
+[concepts]: ../reference/concepts.md
+[way-too-quickstart]: ../way-too-quickstart.md
+[installers]: ../installers/index.md
+
[issues]: https://github.com/axodotdev/cargo-dist/issues
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
-[installers]: ./artifacts.md#installers
diff --git a/book/src/simple-guide.md b/book/src/workspaces/simple-guide.md
similarity index 95%
rename from book/src/simple-guide.md
rename to book/src/workspaces/simple-guide.md
index 0ddb26edb..c6d608610 100644
--- a/book/src/simple-guide.md
+++ b/book/src/workspaces/simple-guide.md
@@ -178,24 +178,30 @@ If you're publishing a Version with some prerelease bits like "1.0.0-prerelease.
If none of the previous rules apply, "1.0.0-prerelease.1" will also match a special "Unreleased" heading (i.e. "# Unreleased"), which will get rewritten to "# Version 1.0.0-prerelease.1". This lets you maintain a changelog for a pending release without having to commit to what version it will be.
+[issues]: https://github.com/axodotdev/cargo-dist/issues
+[simple-app-manifest]: ../img/simple-app-manifest.png
+[simple-app-manifest-with-files]: ../img/simple-app-manifest-with-files.png
+[simple-release]: ../img/simple-github-release.png
+
+[install]: ../install.md
+[concepts]: ../reference/concepts.md
+[way-too-quickstart]: ../way-too-quickstart.md
+[init]: ../reference/cli.md#cargo-dist-init
+[generate]: ../reference/cli.md#cargo-dist-generate
+[plan]: ../reference/cli.md#cargo-dist-plan
+[build]: ../reference/cli.md#cargo-dist-build
+[artifact-modes]: ../reference/concepts.md#artifact-modes-selecting-artifacts
+[config]: ../reference/config.html
+[cargo-release-guide]: ./cargo-release-guide.md
+[installers]: ../installers/index.md
-[simple-app-manifest]: ./img/simple-app-manifest.png
-[simple-app-manifest-with-files]: ./img/simple-app-manifest-with-files.png
-[simple-release]: ./img/simple-github-release.png
-[install]: ./install.html
-[concepts]: ./concepts.html
-[way-too-quickstart]: ./way-too-quickstart.md
-[issues]: https://github.com/axodotdev/cargo-dist/issues
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
-[installers]: ./installers.md
[bin]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries
-[config]: ./config.html
+
[cargo-release]: https://github.com/crate-ci/cargo-release
[git-tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging
-[init]: ./cli.md#cargo-dist-init
-[generate]: ./cli.md#cargo-dist-generate
[cargo-profile]: https://doc.rust-lang.org/cargo/reference/profiles.html
[thin-lto]: https://doc.rust-lang.org/cargo/reference/profiles.html#lto
[workspace-metadata]: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-metadata-table
@@ -204,8 +210,4 @@ If none of the previous rules apply, "1.0.0-prerelease.1" will also match a spec
[platforms]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
[release-yml]: https://github.com/axodotdev/cargo-dist/blob/main/.github/workflows/release.yml
[jq]: https://stedolan.github.io/jq/
-[plan]: ./cli.md#cargo-dist-plan
-[build]: ./cli.md#cargo-dist-build
-[artifact-modes]: ./concepts.md#artifact-modes-selecting-artifacts
[parse-changelog]: https://github.com/taiki-e/parse-changelog
-[cargo-release-guide]: ./cargo-release-guide.md
diff --git a/book/src/workspace-guide.md b/book/src/workspaces/workspace-guide.md
similarity index 97%
rename from book/src/workspace-guide.md
rename to book/src/workspaces/workspace-guide.md
index b5fe7a9d3..76c74ef64 100644
--- a/book/src/workspace-guide.md
+++ b/book/src/workspaces/workspace-guide.md
@@ -86,15 +86,17 @@ We'll probably have to add a config for specifying whether you want libraries to
See [the dedicated guide to using cargo-release with cargo-dist][cargo-release-guide], which covers all sorts of nasty workspaces (it's also just a more useful in-depth look at ).
-[simple-guide]: ./simple-guide.html
+[publish-config]: ../reference/config.md#publish
+[dist-config]: ../reference/config.md#dist
+
+[installers]: ../installers/index.md
+[simple-guide]: ./simple-guide.md
+[cargo-release-guide]: ./cargo-release-guide.md
+
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
[package]: https://doc.rust-lang.org/cargo/appendix/glossary.html#package
[virtual-workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace
[crate]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html
[crates-io]: https://crates.io/
[bins]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries
-[publish-config]: ./config.md#publish
-[dist-config]: ./config.md#dist
-[cargo-release-guide]: ./cargo-release-guide.md
-[installers]: ./installers.md
[cargo semver]: https://docs.rs/semver/latest/semver/struct.Version.html#errors
\ No newline at end of file
diff --git a/cargo-dist/src/cli.rs b/cargo-dist/src/cli.rs
index 2615ca3c5..17eb50222 100644
--- a/cargo-dist/src/cli.rs
+++ b/cargo-dist/src/cli.rs
@@ -174,7 +174,7 @@ pub struct BuildArgs {
/// Which subset of the Artifacts to build
///
/// Artifacts can be broken up into two major classes: "local" ones, which are
- /// made for each target system (executable-zips, symbols, msi installers...); and "global" ones,
+ /// made for each target system (archives, symbols, msi installers...); and "global" ones,
/// which are made once per app (curl-sh installers, npm package, metadata...).
///
/// Having this distinction lets us run cargo-dist independently on
@@ -197,7 +197,7 @@ pub struct BuildArgs {
/// How we should select the artifacts to build
#[derive(ValueEnum, Copy, Clone, Debug)]
pub enum ArtifactMode {
- /// Build target-specific artifacts like executable-zips and msi installers
+ /// Build target-specific artifacts like archives and msi installers
Local,
/// Build unique artifacts like curl-sh installers and npm packages
Global,
diff --git a/cargo-dist/src/config.rs b/cargo-dist/src/config.rs
index c64ae5d5e..60fac9ccb 100644
--- a/cargo-dist/src/config.rs
+++ b/cargo-dist/src/config.rs
@@ -103,7 +103,7 @@ pub struct DistMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub targets: Option>,
- /// Include the following static files in bundles like executable-zips.
+ /// Include the following static files in bundles like archives.
///
/// Paths are relative to the Cargo.toml this is defined in.
///
@@ -461,7 +461,7 @@ pub struct Config {
/// How we should select the artifacts to build
#[derive(Clone, Copy, Debug)]
pub enum ArtifactMode {
- /// Build target-specific artifacts like executable-zips, symbols, msi installers
+ /// Build target-specific artifacts like archives, symbols, msi installers
Local,
/// Build globally unique artifacts like curl-sh installers, npm packages, metadata...
Global,
diff --git a/cargo-dist/src/tasks.rs b/cargo-dist/src/tasks.rs
index 12fef57d2..4e9ea4263 100644
--- a/cargo-dist/src/tasks.rs
+++ b/cargo-dist/src/tasks.rs
@@ -10,7 +10,7 @@
//! 4. for each TargetTriple, create a ReleaseVariant of each Release
//! 5. add target-specific Binaries to each ReleaseVariant
//! 6. add Artifacts to each Release, which will be propagated to each ReleaseVariant as necessary
-//! 1. add executable-zips, propagated to ReleaseVariants
+//! 1. add archives, propagated to ReleaseVariants
//! 2. add installers, each one decides if it's global or local
//! 7. compute actual BuildSteps from the current graph (a Binary will only induce an actual `cargo build`
//! here if one of the Artifacts that was added requires outputs from it!)
@@ -436,7 +436,7 @@ pub struct Archive {
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum ArtifactKind {
- /// An executable zip
+ /// An Archive containing binaries (aka ExecutableZip)
ExecutableZip(ExecutableZip),
/// Symbols
Symbols(Symbols),
@@ -446,7 +446,7 @@ pub enum ArtifactKind {
Checksum(ChecksumImpl),
}
-/// An ExecutableZip Artifact
+/// An Archive containing binaries (aka ExecutableZip)
#[derive(Debug)]
pub struct ExecutableZip {
// everything important is already part of Artifact
@@ -505,7 +505,7 @@ pub struct Release {
pub checksum: ChecksumStyle,
/// The @scope to include in NPM packages
pub npm_scope: Option,
- /// Static assets that should be included in bundles like executable-zips
+ /// Static assets that should be included in bundles like archives
pub static_assets: Vec<(StaticAssetKind, Utf8PathBuf)>,
/// Strategy for selecting paths to install to
pub install_path: InstallPathStrategy,
@@ -523,7 +523,7 @@ pub struct ReleaseVariant {
pub id: String,
/// Binaries included in this Release Variant
pub binaries: Vec,
- /// Static assets that should be included in bundles like executable-zips
+ /// Static assets that should be included in bundles like archives
pub static_assets: Vec<(StaticAssetKind, Utf8PathBuf)>,
/// Artifacts that are "local" to this variant (binaries, symbols, msi-installer...)
pub local_artifacts: Vec,
@@ -937,7 +937,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
self.release(to_release).id
);
- // Create an executable-zip for each Variant
+ // Create an archive for each Variant
let release = self.release(to_release);
let variants = release.variants.clone();
let checksum = release.checksum;
diff --git a/cargo-dist/templates/ci/github_ci.yml.j2 b/cargo-dist/templates/ci/github_ci.yml.j2
index 0384fb98a..7eff2fb2d 100644
--- a/cargo-dist/templates/ci/github_ci.yml.j2
+++ b/cargo-dist/templates/ci/github_ci.yml.j2
@@ -4,7 +4,7 @@
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
{{%- if create_release %}}
diff --git a/cargo-dist/tests/snapshots/akaikatana_basic.snap b/cargo-dist/tests/snapshots/akaikatana_basic.snap
index 3ef9e2a35..67ed0db4a 100644
--- a/cargo-dist/tests/snapshots/akaikatana_basic.snap
+++ b/cargo-dist/tests/snapshots/akaikatana_basic.snap
@@ -1275,7 +1275,7 @@ Install-Binary "$Args"
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
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 3ef9e2a35..67ed0db4a 100644
--- a/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap
+++ b/cargo-dist/tests/snapshots/akaikatana_repo_with_dot_git.snap
@@ -1275,7 +1275,7 @@ Install-Binary "$Args"
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_basic.snap b/cargo-dist/tests/snapshots/axolotlsay_basic.snap
index dc64667eb..09ae86248 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_basic.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_basic.snap
@@ -2174,7 +2174,7 @@ maybeInstall(true).then(run);
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap b/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
index 4930a5c67..a77d3f92b 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_edit_existing.snap
@@ -2149,7 +2149,7 @@ maybeInstall(true).then(run);
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
index d72bbc9cd..b2647a506 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
@@ -2149,7 +2149,7 @@ maybeInstall(true).then(run);
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign.snap b/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign.snap
index b1ec10530..7f7f41a46 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign.snap
@@ -1267,7 +1267,7 @@ Install-Binary "$Args"
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign_prod.snap b/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign_prod.snap
index f6b978159..ad77b0e24 100644
--- a/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign_prod.snap
+++ b/cargo-dist/tests/snapshots/axolotlsay_ssldotcom_windows_sign_prod.snap
@@ -1267,7 +1267,7 @@ Install-Binary "$Args"
# CI that:
#
# * checks for a Git Tag that looks like a release
-# * builds artifacts with cargo-dist (executable-zips, installers, hashes)
+# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a Github Release™
#
diff --git a/cargo-dist/tests/snapshots/markdown-help.snap b/cargo-dist/tests/snapshots/markdown-help.snap
index 67fe7ab9f..f0851b4e2 100644
--- a/cargo-dist/tests/snapshots/markdown-help.snap
+++ b/cargo-dist/tests/snapshots/markdown-help.snap
@@ -106,7 +106,7 @@ cargo dist build [OPTIONS]
#### `-a, --artifacts `
Which subset of the Artifacts to build
-Artifacts can be broken up into two major classes: "local" ones, which are made for each target system (executable-zips, symbols, msi installers...); and "global" ones, which are made once per app (curl-sh installers, npm package, metadata...).
+Artifacts can be broken up into two major classes: "local" ones, which are made for each target system (archives, symbols, msi installers...); and "global" ones, which are made once per app (curl-sh installers, npm package, metadata...).
Having this distinction lets us run cargo-dist independently on multiple machines without collisions between the outputs.
@@ -117,7 +117,7 @@ The specifics of "host" mode are intentionally unspecified to enable us to provi
\[default: host]
Possible values:
-- local: Build target-specific artifacts like executable-zips and msi installers
+- local: Build target-specific artifacts like archives and msi installers
- global: Build unique artifacts like curl-sh installers and npm packages
- host: Fuzzily build "as much as possible" for the host system
- all: Build all the artifacts; useful for `cargo dist manifest`
@@ -208,7 +208,7 @@ cargo dist manifest [OPTIONS]
#### `-a, --artifacts `
Which subset of the Artifacts to build
-Artifacts can be broken up into two major classes: "local" ones, which are made for each target system (executable-zips, symbols, msi installers...); and "global" ones, which are made once per app (curl-sh installers, npm package, metadata...).
+Artifacts can be broken up into two major classes: "local" ones, which are made for each target system (archives, symbols, msi installers...); and "global" ones, which are made once per app (curl-sh installers, npm package, metadata...).
Having this distinction lets us run cargo-dist independently on multiple machines without collisions between the outputs.
@@ -219,7 +219,7 @@ The specifics of "host" mode are intentionally unspecified to enable us to provi
\[default: host]
Possible values:
-- local: Build target-specific artifacts like executable-zips and msi installers
+- local: Build target-specific artifacts like archives and msi installers
- global: Build unique artifacts like curl-sh installers and npm packages
- host: Fuzzily build "as much as possible" for the host system
- all: Build all the artifacts; useful for `cargo dist manifest`