diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98dcbfcd8..5018528f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,18 +4,12 @@ # CI that: # # * checks for a Git Tag that looks like a release -# * creates a draft Github Release™ and fills in its text -# * builds artifacts with cargo-dist (executable-zips, installers, hashes) -# * uploads those artifacts to the Github Release™ -# * undrafts the Github Release™ on success +# * 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 before the artifacts, -# so there will be a few minutes where the release has no artifacts -# and then they will slowly trickle in, possibly failing. To make -# this more pleasant we mark the release as a "draft" until all -# artifacts have been successfully uploaded. This allows you to -# choose what to do with partial successes and avoids spamming -# anyone with notifications before the release is actually ready. +# Note that the Github Release™ will be created with a generated +# title/body based on your changelogs. name: Release permissions: @@ -46,112 +40,116 @@ on: push: tags: - "v[0-9]+*" + pull_request: jobs: # Run 'cargo dist plan' to determine what tasks we need to do - # and create a draft github release with the computed title/body plan: runs-on: ubuntu-latest outputs: - has-releases: ${{ steps.plan.outputs.has-releases }} - releases: ${{ steps.plan.outputs.releases }} + 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@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - uses: moonrepo/setup-rust@v1 - with: - cache: false - name: Install cargo-dist - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.3.0/cargo-dist-installer.sh | sh" - id: plan run: | - cargo dist plan --tag=${{ github.ref_name }} --output-format=json > dist-manifest.json - echo "dist plan ran successfully" + cargo dist plan ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} --output-format=json > dist-manifest.json + echo "cargo dist plan ran successfully" cat dist-manifest.json - - # Create the Github Release™ based on what cargo-dist thinks it should be - ANNOUNCEMENT_TITLE=$(jq --raw-output ".announcement_title" dist-manifest.json) - IS_PRERELEASE=$(jq --raw-output ".announcement_is_prerelease" dist-manifest.json) - jq --raw-output ".announcement_github_body" dist-manifest.json > new_dist_announcement.md - gh release create ${{ github.ref_name }} --draft --prerelease="$IS_PRERELEASE" --title="$ANNOUNCEMENT_TITLE" --notes-file=new_dist_announcement.md - echo "created announcement!" - - # Upload the manifest to the Github Release™ - gh release upload ${{ github.ref_name }} dist-manifest.json - echo "uploaded manifest!" - - # Disable all the upload-artifacts tasks if we have no actual releases - HAS_RELEASES=$(jq --raw-output ".releases != null" dist-manifest.json) - echo "has-releases=$HAS_RELEASES" >> "$GITHUB_OUTPUT" - echo "releases=$(jq --compact-output ".releases" dist-manifest.json)" >> "$GITHUB_OUTPUT" + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: dist-manifest.json # Build and packages all the platform-specific things upload-local-artifacts: # Let the initial task tell us to not run (currently very blunt) needs: plan - if: ${{ needs.plan.outputs.has-releases == 'true' }} + if: ${{ fromJson(needs.plan.outputs.val).releases != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} strategy: fail-fast: false - matrix: - # For these target platforms - include: - - os: "macos-11" - dist-args: "--artifacts=local --target=aarch64-apple-darwin" - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" - - os: "macos-11" - dist-args: "--artifacts=local --target=x86_64-apple-darwin" - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" - - os: "windows-2019" - dist-args: "--artifacts=local --target=x86_64-pc-windows-msvc" - install-dist: "irm https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.ps1 | iex" - - os: "ubuntu-20.04" - dist-args: "--artifacts=local --target=x86_64-unknown-linux-gnu" - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" - runs-on: ${{ matrix.os }} + # 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 }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - uses: moonrepo/setup-rust@v1 - with: - cache: false + - uses: swatinem/rust-cache@v2 - name: Install cargo-dist - run: ${{ matrix.install-dist }} - - name: Run cargo-dist - # This logic is a bit janky because it's trying to be a polyglot between - # powershell and bash since this will run on windows, macos, and linux! - # The two platforms don't agree on how to talk about env vars but they - # do agree on 'cat' and '$()' so we use that to marshal values between commands. + run: ${{ matrix.install_dist }} + - id: cargo-dist + # 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. cargo-dist and jq work fine + # in powershell. + shell: bash run: | # Actually do builds and make zips and whatnot - cargo dist build --tag=${{ github.ref_name }} --output-format=json ${{ matrix.dist-args }} > dist-manifest.json - echo "dist ran successfully" - cat dist-manifest.json + cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "cargo dist ran successfully" # Parse out what we just built and upload it to the Github Release™ - jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt - echo "uploading..." - cat uploads.txt - gh release upload ${{ github.ref_name }} $(cat uploads.txt) - echo "uploaded!" + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + - name: "Upload artifacts" + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: ${{ steps.cargo-dist.outputs.paths }} + + should-publish: + needs: + - plan + - upload-local-artifacts + if: ${{ needs.plan.outputs.publishing == 'true' }} + runs-on: ubuntu-latest + steps: + - name: print tag + run: echo "ok we're publishing!" - # Mark the Github Release™ as a non-draft now that everything has succeeded! + # Create a Github Release with all the results once everything is done, publish-release: - # Only run after all the other tasks, but it's ok if upload-artifacts was skipped - needs: [plan, upload-local-artifacts] - if: ${{ always() && needs.plan.result == 'success' && (needs.upload-local-artifacts.result == 'skipped' || needs.upload-local-artifacts.result == 'success') }} + needs: [plan, should-publish] runs-on: ubuntu-latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - name: mark release as non-draft - run: | - gh release edit ${{ github.ref_name }} --draft=false + - name: "Download artifacts" + uses: actions/download-artifact@v3 + with: + name: artifacts + path: artifacts + - name: Create Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ needs.plan.outputs.tag }} + name: ${{ fromJson(needs.plan.outputs.val).announcement_title }} + body: ${{ fromJson(needs.plan.outputs.val).announcement_github_body }} + prerelease: ${{ fromJson(needs.plan.outputs.val).announcement_is_prerelease }} + artifacts: "artifacts/*" diff --git a/Cargo.lock b/Cargo.lock index 018637f50..87a0d75fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "ambient-authority" version = "0.0.2" @@ -316,13 +322,14 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cached" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eb5776f28a149524d1d8623035760b4454ec881e8cf3838fa8d7e1b11254b3" +checksum = "8cead8ece0da6b744b2ad8ef9c58a4cdc7ef2921e60a6ddfb9eaaa86839b5fc5" dependencies = [ + "ahash", "cached_proc_macro", "cached_proc_macro_types", - "hashbrown 0.13.2", + "hashbrown 0.14.0", "instant", "once_cell", "thiserror", @@ -474,9 +481,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.4" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" +checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3" dependencies = [ "clap_builder", "clap_derive", @@ -484,9 +491,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.4" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" +checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab" dependencies = [ "anstream", "anstyle", @@ -496,11 +503,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4110a1e6af615a9e6d0a36f805d5c99099f8bab9b8042f5bc1fa220a4a89e36f" +checksum = "8baeccdb91cd69189985f87f3c7e453a3a451ab5746cf3be6acc92120bd16d24" dependencies = [ - "clap 4.4.4", + "clap 4.4.5", ] [[package]] @@ -946,13 +953,14 @@ checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", "tempfile", + "thiserror", "zeroize", ] @@ -1509,6 +1517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ "ahash", + "allocator-api2", ] [[package]] @@ -1707,9 +1716,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", "instant", @@ -2331,7 +2340,7 @@ name = "proto_cli" version = "0.18.5" dependencies = [ "chrono", - "clap 4.4.4", + "clap 4.4.5", "clap_complete", "convert_case", "dialoguer", @@ -2419,7 +2428,7 @@ dependencies = [ "proto_pdk_api", "proto_wasm_plugin", "serde_json", - "toml 0.8.0", + "toml 0.8.1", ] [[package]] @@ -2855,9 +2864,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" dependencies = [ "serde", ] @@ -2938,9 +2947,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -3162,7 +3171,7 @@ dependencies = [ "starbase_styles", "thiserror", "tokio", - "toml 0.8.0", + "toml 0.8.1", "tracing", "wax", ] @@ -3313,18 +3322,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", @@ -3483,14 +3492,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" +checksum = "1bc1433177506450fe920e46a4f9812d0c211f5dd556da10e731a0a3dfa151f0" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.0", + "toml_edit 0.20.1", ] [[package]] @@ -3517,9 +3526,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" +checksum = "ca676d9ba1a322c1b64eb8045a5ec5c0cfb0c9d08e15e9ff622589ad5221c8fe" dependencies = [ "indexmap 2.0.0", "serde", diff --git a/Cargo.toml b/Cargo.toml index 69b63a062..99e4f5232 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ members = ["crates/*"] default-members = ["crates/cli"] [workspace.dependencies] -cached = "0.45.1" -clap = "4.4.4" -clap_complete = "4.4.1" +cached = "0.46.0" +clap = "4.4.5" +clap_complete = "4.4.2" convert_case = "0.6.0" extism = "0.5.2" extism-pdk = "0.3.4" @@ -16,10 +16,10 @@ once_cell = "1.18.0" once_map = "0.4.8" regex = "1.9.5" reqwest = { version = "0.11.20", default-features = false } -semver = "1.0.18" +semver = "1.0.19" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" -sha2 = "0.10.7" +sha2 = "0.10.8" starbase_archive = { version = "0.2.2", features = [ "tar-gz", "tar-xz", @@ -33,27 +33,30 @@ starbase_utils = { version = "0.3.2", default-features = false, features = [ "json", "toml", ] } -thiserror = "1.0.48" +thiserror = "1.0.49" tokio = { version = "1.32.0", features = ["full", "tracing"] } tracing = "0.1.37" # Config for 'cargo dist' [workspace.metadata.dist] # The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.2.0" -# CI backends to support (see 'cargo dist generate-ci') +cargo-dist-version = "0.3.0" +# CI backends to support ci = ["github"] # Target platforms to build apps for (Rust target-triple syntax) targets = [ "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", "aarch64-apple-darwin", + "x86_64-apple-darwin", "x86_64-pc-windows-msvc", ] # The installers to generate for each app installers = [] # Path that installers should place binaries in install-path = "~/.proto/bin" +# Publish jobs to run in CI +pr-run-mode = "plan" +allow-dirty = ["ci"] [profile.dist] inherits = "release" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 3ded120d2..bcd07e35e 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -34,11 +34,11 @@ chrono = "0.4.31" clap = { workspace = true, features = ["derive", "env"] } clap_complete = { workspace = true } convert_case = { workspace = true } -dialoguer = "0.10.4" +dialoguer = "0.11.0" dirs = "5.0.1" futures = "0.3.28" human-sort = { workspace = true } -indicatif = "0.17.6" +indicatif = "0.17.7" miette = { workspace = true } reqwest = { workspace = true, features = ["rustls-tls-native-roots", "stream"] } semver = { workspace = true } diff --git a/crates/pdk-test-utils/Cargo.toml b/crates/pdk-test-utils/Cargo.toml index d04a9592c..5a82b9600 100644 --- a/crates/pdk-test-utils/Cargo.toml +++ b/crates/pdk-test-utils/Cargo.toml @@ -13,7 +13,7 @@ proto_pdk_api = { version = "0.7.2", path = "../pdk-api" } proto_wasm_plugin = { version = "0.6.7", path = "../wasm-plugin" } extism = { workspace = true } serde_json = { workspace = true } -toml = { version = "0.8.0", optional = true } +toml = { version = "0.8.1", optional = true } [features] default = [] diff --git a/crates/warpgate/src/error.rs b/crates/warpgate/src/error.rs index 2f5190862..99b8245ba 100644 --- a/crates/warpgate/src/error.rs +++ b/crates/warpgate/src/error.rs @@ -10,8 +10,10 @@ pub enum WarpgateError { Serde(String), #[diagnostic(code(plugin::http))] - #[error("Failed to make HTTP request.")] + #[error("Failed to make HTTP request for {}.", .url.style(Style::Url))] Http { + url: String, + #[source] error: reqwest::Error, }, diff --git a/crates/warpgate/src/helpers.rs b/crates/warpgate/src/helpers.rs index 431ada3ec..096bb0b1a 100644 --- a/crates/warpgate/src/helpers.rs +++ b/crates/warpgate/src/helpers.rs @@ -49,7 +49,10 @@ pub async fn download_from_url_to_file( .get(url) .send() .await - .map_err(|error| WarpgateError::Http { error })?; + .map_err(|error| WarpgateError::Http { + error, + url: source_url.to_owned(), + })?; let status = response.status(); if status.as_u16() == 404 { @@ -73,7 +76,10 @@ pub async fn download_from_url_to_file( response .bytes() .await - .map_err(|error| WarpgateError::Http { error })?, + .map_err(|error| WarpgateError::Http { + error, + url: source_url.to_owned(), + })?, )?; Ok(()) diff --git a/crates/warpgate/src/loader.rs b/crates/warpgate/src/loader.rs index 141ccb622..ee0880e76 100644 --- a/crates/warpgate/src/loader.rs +++ b/crates/warpgate/src/loader.rs @@ -230,22 +230,21 @@ impl PluginLoader { "Attempting to download plugin from GitHub release", ); + let handle_error = |error: reqwest::Error| WarpgateError::Http { + error, + url: api_url.clone(), + }; + // Otherwise make an HTTP request to the GitHub releases API, // and loop through the assets to find a matching one. - let mut request = client.get(api_url); + let mut request = client.get(&api_url); if let Ok(auth_token) = env::var("GITHUB_TOKEN") { request = request.bearer_auth(auth_token); } - let response = request - .send() - .await - .map_err(|error| WarpgateError::Http { error })?; - let release: GitHubApiRelease = response - .json() - .await - .map_err(|error| WarpgateError::Http { error })?; + let response = request.send().await.map_err(handle_error)?; + let release: GitHubApiRelease = response.json().await.map_err(handle_error)?; // Find a direct WASM asset first for asset in &release.assets { @@ -322,8 +321,15 @@ impl PluginLoader { ); // Otherwise make a GraphQL request to the WAPM registry API. + let url = "https://registry.wapm.io/graphql".to_owned(); + + let handle_error = |error: reqwest::Error| WarpgateError::Http { + error, + url: url.clone(), + }; + let response = client - .post("https://registry.wapm.io/graphql") + .post(&url) .json(&WapmPackageRequest { query: WAPM_GQL_QUERY.to_owned(), variables: WapmPackageRequestVariables { @@ -334,12 +340,9 @@ impl PluginLoader { }) .send() .await - .map_err(|error| WarpgateError::Http { error })?; + .map_err(handle_error)?; - let package: WapmPackageResponse = response - .json() - .await - .map_err(|error| WarpgateError::Http { error })?; + let package: WapmPackageResponse = response.json().await.map_err(handle_error)?; let package = package.data.package_version; // Check modules first for a direct WASM file to use