From 87026d9b23b549a8dc22c8ef635eab33b2e87c24 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 13 Feb 2024 15:40:44 -0800 Subject: [PATCH 1/3] chore: switch to `cargo dist` for release publishing (#522) --- .github/workflows/release.yaml | 56 ------- .github/workflows/release.yml | 265 +++++++++++++++++++++++++++++++++ Cargo.toml | 24 +++ bin/release.sh | 2 + tokio-console/Cargo.toml | 6 + tokio-console/wix/main.wxs | 229 ++++++++++++++++++++++++++++ 6 files changed, 526 insertions(+), 56 deletions(-) delete mode 100644 .github/workflows/release.yaml create mode 100644 .github/workflows/release.yml create mode 100644 tokio-console/wix/main.wxs diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index ac7067930..000000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,56 +0,0 @@ -name: Upload Binaries - -on: - push: - tags: - - console-subscriber-v[0-9]+.* - - console-api-v[0-9]+.* - - tokio-console-v[0-9]+.* - -jobs: - create-release: - name: Create GitHub release - # only publish from the origin repository - if: github.repository_owner == 'tokio-rs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: taiki-e/create-gh-release-action@v1 - with: - prefix: "(console-subscriber)|(console-api)|(tokio-console)" - changelog: "$prefix/CHANGELOG.md" - title: "$prefix $version" - draft: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - upload-bins: - name: "Upload release binaries" - # only upload binaries if the tag is a`tokio-console` release - if: contains(github.ref, 'tokio-console') - needs: create-release - strategy: - matrix: - include: - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - - target: x86_64-apple-darwin - os: macos-latest - - target: x86_64-pc-windows-msvc - os: windows-latest - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - - target: aarch64-apple-darwin - os: macos-latest - - target: aarch64-pc-windows-msvc - os: windows-latest - - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: taiki-e/upload-rust-binary-action@v1 - with: - bin: tokio-console - target: ${{ matrix.target }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..7d2b8107d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,265 @@ +# Copyright 2022-2023, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with cargo-dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a Github Release +# +# Note that the Github Release will be created with a generated +# title/body based on your changelogs. + +name: Release + +permissions: + contents: write + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the announcement will be for that +# package (erroring out if it doesn't have the given version or isn't cargo-dist-able). +# +# If PACKAGE_NAME isn't specified, then the announcement will be for all +# (cargo-dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent announcement for each one. However Github +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the release(s) +# will be marked as a prerelease. +on: + push: + tags: + - '**[0-9]+.[0-9]+.[0-9]+*' + pull_request: + +jobs: + # Run 'cargo dist plan' (or host) to determine what tasks we need to do + plan: + runs-on: ubuntu-latest + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cargo-dist + # we specify bash to get pipefail; it guards against the `curl` command + # failing. otherwise `sh` won't catch that `curl` returned non-0 + shell: bash + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.10.0/cargo-dist-installer.sh | sh" + # sure would be cool if github gave us proper conditionals... + # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible + # functionality based on whether this is a pull_request, and whether it's from a fork. + # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* + # but also really annoying to build CI around when it needs secrets to work right.) + - id: plan + run: | + cargo dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "cargo dist ran successfully" + cat plan-dist-manifest.json + echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + name: artifacts-plan-dist-manifest + path: plan-dist-manifest.json + + # Build and packages all the platform-specific things + build-local-artifacts: + name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) + # Let the initial task tell us to not run (currently very blunt) + needs: + - plan + if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by cargo-dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to cargo dist + # - install-dist: expression to run to install cargo-dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: swatinem/rust-cache@v2 + - name: Install cargo-dist + run: ${{ matrix.install_dist }} + # Get the dist-manifest + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "cargo dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-local-${{ join(matrix.targets, '_') }} + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + # Build and package all the platform-agnostic(ish) things + build-global-artifacts: + needs: + - plan + - build-local-artifacts + runs-on: "ubuntu-20.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cargo-dist + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.10.0/cargo-dist-installer.sh | sh" + # Get all the local artifacts for the global tasks to use (for e.g. checksums) + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: cargo-dist + shell: bash + run: | + cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "cargo dist ran successfully" + + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-global + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + # Determines if we should publish/announce + host: + needs: + - plan + - build-local-artifacts + - build-global-artifacts + # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) + if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: "ubuntu-20.04" + outputs: + val: ${{ steps.host.outputs.manifest }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cargo-dist + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.10.0/cargo-dist-installer.sh | sh" + # Fetch artifacts from scratch-storage + - name: Fetch artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + # This is a harmless no-op for Github Releases, hosting for that happens in "announce" + - id: host + shell: bash + run: | + cargo dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + echo "artifacts uploaded and released successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + # Overwrite the previous copy + name: artifacts-dist-manifest + path: dist-manifest.json + + # Create a Github Release while uploading all files to it + announce: + needs: + - plan + - host + # use "always() && ..." to allow us to wait for all publish jobs while + # still allowing individual publish jobs to skip themselves (for prereleases). + # "host" however must run to completion, no skipping allowed! + if: ${{ always() && needs.host.result == 'success' }} + runs-on: "ubuntu-20.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: "Download Github Artifacts" + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: artifacts + merge-multiple: true + - name: Cleanup + run: | + # Remove the granular manifests + rm -f artifacts/*-dist-manifest.json + - name: Create Github Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ needs.plan.outputs.tag }} + name: ${{ fromJson(needs.host.outputs.val).announcement_title }} + body: ${{ fromJson(needs.host.outputs.val).announcement_github_body }} + prerelease: ${{ fromJson(needs.host.outputs.val).announcement_is_prerelease }} + artifacts: "artifacts/*" diff --git a/Cargo.toml b/Cargo.toml index 153d99d70..5d7bba0b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,27 @@ members = [ "xtask" ] resolver = "2" + +# Config for 'cargo dist' +[workspace.metadata.dist] +# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.10.0" +# CI backends to support +ci = ["github"] +# The installers to generate for each app +installers = ["shell", "powershell", "msi"] +# Target platforms to build apps for (Rust target-triple syntax) +targets = [ + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-pc-windows-msvc", +] +# Publish jobs to run in CI +pr-run-mode = "plan" + +# The profile that 'cargo dist' will build with +[profile.dist] +inherits = "release" +lto = "thin" diff --git a/bin/release.sh b/bin/release.sh index 59a8e8f08..1111e4f1c 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -317,6 +317,8 @@ if [[ "$dry_run" ]]; then fi echo "" +status "Running" "cargo dist plan" +cargo dist plan if confirm "commit?"; then echo "" diff --git a/tokio-console/Cargo.toml b/tokio-console/Cargo.toml index ca58b68f2..6db84ac81 100644 --- a/tokio-console/Cargo.toml +++ b/tokio-console/Cargo.toml @@ -26,6 +26,12 @@ keywords = [ "async", ] +[package.metadata.wix] +upgrade-guid = "A36733B4-B8CD-440A-8E06-549EAE8A6695" +path-guid = "3DF6EE78-06E2-42BF-99AA-9A463E328BBD" +license = false +eula = false + [dependencies] atty = "0.2" console-api = { version = "0.6.0", path = "../console-api", features = ["transport"] } diff --git a/tokio-console/wix/main.wxs b/tokio-console/wix/main.wxs new file mode 100644 index 000000000..bd07de2d2 --- /dev/null +++ b/tokio-console/wix/main.wxs @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + + + + + + + + + + + + + + + + From 823e3dfe2009bb2f39e7026c58f713d9111cd982 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 13 Feb 2024 15:41:39 -0800 Subject: [PATCH 2/3] chore: add FlakeHub publishing for Nix flake (#520) --- .github/workflows/flakehub-publish-tagged.yml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/flakehub-publish-tagged.yml diff --git a/.github/workflows/flakehub-publish-tagged.yml b/.github/workflows/flakehub-publish-tagged.yml new file mode 100644 index 000000000..59934717a --- /dev/null +++ b/.github/workflows/flakehub-publish-tagged.yml @@ -0,0 +1,27 @@ +name: "Publish tags to FlakeHub" +on: + push: + tags: + - "tokio-console-v[0-9]+.[0-9]+.[0-9]+*" + workflow_dispatch: + inputs: + tag: + description: "The existing tag to publish to FlakeHub" + type: "string" + required: true +jobs: + flakehub-publish: + runs-on: "ubuntu-latest" + permissions: + id-token: "write" + contents: "read" + steps: + - uses: "actions/checkout@v3" + with: + ref: "${{ (inputs.tag != null) && format('refs/tags/{0}', inputs.tag) || '' }}" + - uses: "DeterminateSystems/nix-installer-action@main" + - uses: "DeterminateSystems/flakehub-push@main" + with: + visibility: "public" + name: "tokio-rs/console" + tag: "${{ inputs.tag }}" From 28a27fcfeb3a0838e1f5f2d17a6fa18b3f33c508 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 13 Feb 2024 15:41:50 -0800 Subject: [PATCH 3/3] chore: redo nix flake (#521) --- flake.lock | 38 +++++++++++--- flake.nix | 117 ++++++++++++++++++++++++++++++++++++------ nix/tokio-console.nix | 3 +- rust-toolchain.toml | 3 ++ 4 files changed, 138 insertions(+), 23 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/flake.lock b/flake.lock index 3c0f64a8f..75d63b67e 100644 --- a/flake.lock +++ b/flake.lock @@ -20,22 +20,48 @@ }, "nixpkgs": { "locked": { - "lastModified": 1683594133, - "narHash": "sha256-iUhLhEAgOCnexSGDsYT2ouydis09uDoNzM7UC685XGE=", + "lastModified": 1707689078, + "narHash": "sha256-UUGmRa84ZJHpGZ1WZEBEUOzaPOWG8LZ0yPg1pdDF/yM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8d447c5626cfefb9b129d5b30103344377fe09bc", + "rev": "f9d39fb9aff0efee4a3d5f4a6d7c17701d38a1d8", "type": "github" }, "original": { - "id": "nixpkgs", - "type": "indirect" + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" } }, "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1707790272, + "narHash": "sha256-KQXPNl3BLdRbz7xx+mwIq/017fxLRk6JhXHxVWCKsTU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "8dfbe2dffc28c1a18a29ffa34d5d0b269622b158", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } }, "systems": { diff --git a/flake.nix b/flake.nix index f01107b94..992a1187a 100644 --- a/flake.nix +++ b/flake.nix @@ -2,23 +2,108 @@ description = "The Tokio console: a debugger for async Rust."; inputs = { - # nixpkgs.url = "github:nixos/nixpkgs/release-21.11"; - flake-utils = { - url = "github:numtide/flake-utils"; - inputs.nixpkgs.follows = "nixpkgs"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; }; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - tokio-console = import ./nix { inherit pkgs; }; - devShell = import ./nix/shell.nix { inherit pkgs; }; - in - { - inherit devShell; - packages = { inherit tokio-console; }; - defaultPackage = tokio-console; - }); + outputs = { self, nixpkgs, flake-utils, rust-overlay }: + flake-utils.lib.eachDefaultSystem + (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { inherit system overlays; }; + + #################################################################### + #### tokio-console package #### + #################################################################### + tokio-console = with pkgs; let + inherit (nix-gitignore) gitignoreFilterPure withGitignoreFile; + # Workaround for the builtins.filterSource issue mentioned in + # https://nixos.org/manual/nix/unstable/expressions/builtins.html + # Since this might be built from a flake, the source path may be a store path, + # so we need to provide our own version of gitignoreSource that avoids + # builtins.filterSource in favor of builtins.path. + gitignoreSource = patterns: path: + builtins.path { + filter = + gitignoreFilterPure (_: _: true) (withGitignoreFile patterns path) path; + path = path; + name = "src"; + }; + + # Ignore some extra things that don't factor into the main build to help with + # caching. + extraIgnores = '' + /.envrc + /*.nix + /flake.* + /netlify.toml + /.github + /assets + /*.md + /.gitignore + /LICENSE + ''; + + src = gitignoreSource extraIgnores ./.; + + cargoTOML = lib.importTOML "${src}/tokio-console/Cargo.toml"; + rustToolchain = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + rust = makeRustPlatform { + cargo = rustToolchain; + rustc = rustToolchain; + }; + in + rust.buildRustPackage + { + pname = cargoTOML.package.name; + version = cargoTOML.package.version; + + nativeBuildInputs = [ protobuf ]; + + inherit src; + + cargoLock = { lockFile = "${src}/Cargo.lock"; }; + + meta = { + inherit (cargoTOML.package) description homepage license; + maintainers = cargoTOML.package.authors; + }; + }; + + #################################################################### + #### dev shell #### + #################################################################### + devShell = with pkgs; + mkShell { + name = "tokio-console-env"; + buildInputs = tokio-console.buildInputs ++ lib.optional stdenv.isDarwin libiconv; + nativeBuildInputs = tokio-console.nativeBuildInputs; + RUST_SRC_PATH = "${rustPlatform.rustLibSrc}"; + CARGO_TERM_COLOR = "always"; + RUST_BACKTRACE = "full"; + }; + in + { + apps = { + tokio-console = { + type = "app"; + program = "${tokio-console}/bin/tokio-console"; + description = "The Tokio console: a debugger for async Rust."; + }; + default = self.apps.${system}.tokio-console; + }; + devShells.default = devShell; + packages = { + inherit tokio-console; + default = self.packages.${system}.tokio-console; + }; + }); } diff --git a/nix/tokio-console.nix b/nix/tokio-console.nix index bc43123f7..0eabaf9de 100644 --- a/nix/tokio-console.nix +++ b/nix/tokio-console.nix @@ -31,7 +31,8 @@ let src = gitignoreSource extraIgnores ../.; cargoTOML = lib.importTOML "${src}/tokio-console/Cargo.toml"; -in rustPlatform.buildRustPackage rec { +in +rustPlatform.buildRustPackage rec { pname = cargoTOML.package.name; version = cargoTOML.package.version; diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..4259fa81a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "stable" +profile = "default" \ No newline at end of file