From 25d12a87e46473abe91f43955177b91fba6fd5d7 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Wed, 8 Jan 2025 14:42:17 +0100 Subject: [PATCH] chore(ci): Setup release please workflow * chore: setup release plz workflow * chore: update to cargo dist 0.27.1, and let cargo-dist perform github release * Update reference from unleash-types-rs to unleash-edge --- .github/dependabot.yml | 16 +++ .github/mergify.yml | 14 ++ .github/workflows/continuous-deployment.yaml | 37 ++++++ .github/workflows/release.yml | 130 +++++++++++-------- .github/workflows/smart-release.yaml | 42 ------ dist-workspace.toml | 22 +--- release-plz.toml | 103 +++++++++++++++ 7 files changed, 249 insertions(+), 115 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/mergify.yml create mode 100644 .github/workflows/continuous-deployment.yaml delete mode 100644 .github/workflows/smart-release.yaml create mode 100644 release-plz.toml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..0280bb4c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + commit-message: + prefix: "dep-update: " + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + commit-message: + prefix: "dep-update: " + open-pull-requests-limit: 10 diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 00000000..a83631db --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,14 @@ +pull_request_rules: + - name: Automatic merge for Dependabot pull requests + conditions: + - author=dependabot[bot] + actions: + merge: + method: squash + - name: Automatic update to the main branch for pull requests + conditions: + - -conflict + - -draft + - -author=dependabot[bot] + actions: + update: diff --git a/.github/workflows/continuous-deployment.yaml b/.github/workflows/continuous-deployment.yaml new file mode 100644 index 00000000..1cad0502 --- /dev/null +++ b/.github/workflows/continuous-deployment.yaml @@ -0,0 +1,37 @@ +--- +name: Continuous Deployment + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_KEY }} + steps: + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.UNLEASH_BOT_APP_ID }} + private-key: ${{ secrets.UNLEASH_BOT_PRIVATE_KEY }} + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ steps.generate-token.outputs.token }} + - name: Install rust toolchain + uses: dtolnay/rust-toolchain@stable + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e4fa7427..136c706d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,20 +1,21 @@ -# Copyright 2022-2023, axodotdev +# This file was autogenerated by dist: https://opensource.axo.dev/cargo-dist/ +# +# Copyright 2022-2024, 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) +# * builds artifacts with dist (archives, installers, hashes) # * uploads those artifacts to temporary workflow zip -# * on success, uploads the artifacts to a Github Release +# * on success, uploads the artifacts to a GitHub Release # -# Note that the Github Release will be created with a generated +# Note that the GitHub Release will be created with a generated # title/body based on your changelogs. name: Release - permissions: - contents: write + "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. @@ -23,30 +24,30 @@ permissions: # 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). +# package (erroring out if it doesn't have the given version or isn't 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 +# (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 +# 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: + pull_request: push: tags: - - "**[0-9]+.[0-9]+.[0-9]+*" - pull_request: + - '**[0-9]+.[0-9]+.[0-9]+*' jobs: - # Run 'cargo dist plan' (or host) to determine what tasks we need to do + # Run 'dist plan' (or host) to determine what tasks we need to do plan: - runs-on: ubuntu-latest + runs-on: "ubuntu-20.04" outputs: val: ${{ steps.plan.outputs.manifest }} tag: ${{ !github.event.pull_request && github.ref_name || '' }} @@ -58,16 +59,16 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Install cargo-dist + - name: Install 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.23.0/cargo-dist-installer.sh | sh" - - name: Cache cargo-dist + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.27.1/cargo-dist-installer.sh | sh" + - name: Cache dist uses: actions/upload-artifact@v4 with: name: cargo-dist-cache - path: ~/.cargo/bin/cargo-dist + path: ~/.cargo/bin/dist # 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. @@ -75,8 +76,8 @@ jobs: # 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" + dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "dist ran successfully" cat plan-dist-manifest.json echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - name: "Upload dist-manifest.json" @@ -94,18 +95,19 @@ jobs: 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. + # Target platforms/runners are computed by 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 + # - dist-args: cli flags to pass to dist + # - install-dist: expression to run to install 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 }} + container: ${{ matrix.container && matrix.container.image || null }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json @@ -116,8 +118,15 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Install cargo-dist - run: ${{ matrix.install_dist }} + - name: Install Rust non-interactively if not already installed + if: ${{ matrix.container }} + run: | + if ! command -v cargo > /dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - name: Install dist + run: ${{ matrix.install_dist.run }} # Get the dist-manifest - name: Fetch local artifacts uses: actions/download-artifact@v4 @@ -131,8 +140,8 @@ jobs: - 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" + dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "dist ran successfully" - id: cargo-dist name: Post-build # We force bash here just because github makes it really hard to get values up @@ -142,7 +151,7 @@ jobs: run: | # Parse out what we just built and upload it to scratch storage echo "paths<> "$GITHUB_OUTPUT" - jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" cp dist-manifest.json "$BUILD_MANIFEST_NAME" @@ -153,12 +162,13 @@ jobs: path: | ${{ steps.cargo-dist.outputs.paths }} ${{ env.BUILD_MANIFEST_NAME }} - # Build and package all the platform-agnostic(ish) things + + # Build and package all the platform-agnostic(ish) things build-global-artifacts: needs: - plan - build-local-artifacts - runs-on: ubuntu-latest + runs-on: "ubuntu-20.04" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json @@ -166,12 +176,12 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - name: Install cached cargo-dist + - name: Install cached dist uses: actions/download-artifact@v4 with: name: cargo-dist-cache path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/cargo-dist + - run: chmod +x ~/.cargo/bin/dist # Get all the local artifacts for the global tasks to use (for e.g. checksums) - name: Fetch local artifacts uses: actions/download-artifact@v4 @@ -182,8 +192,8 @@ jobs: - 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" + dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "dist ran successfully" # Parse out what we just built and upload it to scratch storage echo "paths<> "$GITHUB_OUTPUT" @@ -198,7 +208,7 @@ jobs: path: | ${{ steps.cargo-dist.outputs.paths }} ${{ env.BUILD_MANIFEST_NAME }} - + # Determines if we should publish/announce host: needs: - plan @@ -208,19 +218,19 @@ jobs: 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-latest + runs-on: "ubuntu-20.04" outputs: val: ${{ steps.host.outputs.manifest }} steps: - uses: actions/checkout@v4 with: submodules: recursive - - name: Install cached cargo-dist + - name: Install cached dist uses: actions/download-artifact@v4 with: name: cargo-dist-cache path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/cargo-dist + - run: chmod +x ~/.cargo/bin/dist # Fetch artifacts from scratch-storage - name: Fetch artifacts uses: actions/download-artifact@v4 @@ -231,7 +241,7 @@ jobs: - id: host shell: bash run: | - cargo dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + 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" @@ -241,8 +251,30 @@ jobs: # Overwrite the previous copy name: artifacts-dist-manifest path: dist-manifest.json - # Create a Github Release while uploading all files to it - upload_artifacts: + # Create a GitHub Release while uploading all files to it + - 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 + env: + PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" + ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" + ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" + RELEASE_COMMIT: "${{ github.sha }}" + run: | + # Write and read notes from a file to avoid quoting breaking things + echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt + + gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* + + announce: needs: - plan - host @@ -250,26 +282,10 @@ jobs: # 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-latest" + 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: Upload assets to Github Release - uses: AButler/upload-release-assets@v3.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - files: "artifacts/*" - release-tag: ${{ needs.plan.outputs.tag }} diff --git a/.github/workflows/smart-release.yaml b/.github/workflows/smart-release.yaml deleted file mode 100644 index dc91ab42..00000000 --- a/.github/workflows/smart-release.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Run cargo smart-release - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -on: - workflow_dispatch: - inputs: - bump_version: - description: Which type of release would you like to make (patch, minor, major) - default: "patch" - type: "string" - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - name: Checkout code - with: - token: ${{ secrets.GH_PUSH_TOKEN }} - fetch-depth: 0 - - name: setup git config - run: | - git config user.name "Github Release Bot" - git config user.email "<>" - - name: Install rust - run: | - rustup set auto-self-update disable - rustup toolchain install stable --profile minimal - rustup show - - name: Use rust cache - uses: Swatinem/rust-cache@v2 - with: - cache-on-failure: true - - name: Install cargo smart-release - run: | - cargo install cargo-smart-release - - name: Run release - run: | - cargo smart-release -u -b ${{ github.event.inputs.bump_version }} --allow-fully-generated-changelogs --no-changelog-preview --execute diff --git a/dist-workspace.toml b/dist-workspace.toml index 5476de5f..77adc519 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -1,27 +1,17 @@ [workspace] members = ["cargo:."] -# Config for 'cargo dist' +# Config for 'dist' [dist] -# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.23.0" +# The preferred dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.27.1" # CI backends to support ci = "github" -# 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-pc-windows-msvc"] # The installers to generate for each app installers = ["shell", "msi"] -# Which actions to run on pull requests -pr-run-mode = "plan" -# Skip checking whether the specified configuration files are up to date -allow-dirty = ["ci"] +# Target platforms to build apps for (Rust target-triple syntax) +targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] # Path that installers should place binaries in install-path = "CARGO_HOME" # Whether to install an updater program -install-updater = false - -[dist.dependencies.apt] -libssl-dev = { version = '*', targets = ["aarch64-unknown-linux-gnu"] } -gcc-aarch64-linux-gnu = { version = '*', targets = [ - "aarch64-unknown-linux-gnu", -] } +install-updater = true diff --git a/release-plz.toml b/release-plz.toml new file mode 100644 index 00000000..e6e9d5fb --- /dev/null +++ b/release-plz.toml @@ -0,0 +1,103 @@ +[workspace] + +changelog_update = true + +dependencies_update = true + +git_tag_enable = true + +git_release_enable = false + +pr_labels = ["release"] + +allow_dirty = false + +publish_allow_dirty = false + +semver_check = false + + +[changelog] + +commit_parsers = [ + { message = "^feat", group = "๐Ÿš€ Features" }, + { message = "^fix", group = "๐Ÿ› Bug Fixes" }, + { message = "^doc", group = "๐Ÿ“š Documentation" }, + { message = "^perf", group = "โšก Performance" }, + { message = "^refactor", group = "๐Ÿšœ Refactor" }, + { message = "^style", group = "๐ŸŽจ Styling" }, + { message = "^test", group = "๐Ÿงช Testing" }, + { message = "^dep-update", group = " Dependency updates" }, + { message = "^build\\(deps\\)", group = " Dependency updates" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore|^ci", group = "โš™๏ธ Miscellaneous Tasks" }, + { body = ".*security", group = "๐Ÿ›ก๏ธ Security" }, + { message = "^revert", group = "โ—€๏ธ Revert" }, + { message = ".*", group = "๐Ÿ’ผ Other" }, +] + +commit_preprocessors = [ + # Replace `foo` with `bar` + { pattern = "foo", replace = "bar" }, + + # Replace `` in the template body with the repository URL + { pattern = '', replace = "https://github.com/unleash/unleash-edge" }, + + # Replace multiple spaces with a single space. + { pattern = " +", replace = " " }, + + # Replace the issue number with the link. + { pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/unleash/unleash-edge/issues/${1}))" }, + # Remove prefix + { pattern = 'Merged PR #[0-9]: (.*)', replace = "$1" }, + + # Remove gitmoji from commit messages, both actual UTF emoji and :emoji: + { pattern = ' *(:\w+:|[\p{Emoji_Presentation}\p{Extended_Pictographic}\u{200D}]) *', replace = "" }, + + # Hyperlink PR references from merge commits. + { pattern = "Merge pull request #([0-9]+) from [^ ]+", replace = "PR # [${1}](https://github.com/unleash/unleash-edge/pull/${1}):" }, + + # Hyperlink commit links, with short commit hash as description. + { pattern = "https://github.com/unleash/unleash-edge/commit/([a-f0-9]{7})[a-f0-9]*", replace = "commit # [${1}](${0})" }, + + # Hyperlink bare commit hashes like "abcd1234" in commit logs, with short commit hash as description. + { pattern = "([ \\n])(([a-f0-9]{7})[a-f0-9]*)", replace = "${1}commit # [${3}](https://github.com/unleash/unleash-edge/commit/${2})" }, +] + +body = """ + +## [{{ version | trim_start_matches(pat="v") }}]\ + {%- if release_link -%}\ + ({{ release_link }})\ + {% endif %} \ + - {{ timestamp | date(format="%Y-%m-%d") }} +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + {%- if commit.scope -%} + - *({{commit.scope}})* {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message }}{{ self::username(commit=commit) }}\ + {%- if commit.links %} \ + ({% for link in commit.links %}[{{link.text}}]({{link.href}}) {% endfor -%})\ + {% endif %} + {% else -%} + - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}{{ self::username(commit=commit) }}{{ self::pr(commit=commit) }} + {% endif -%} + {% endfor -%} +{% endfor %} +{%- if remote.contributors %} +### Contributors +{% for contributor in remote.contributors %} + * @{{ contributor.username }} +{%- endfor %} +{% endif -%} +{%- macro username(commit) -%} + {% if commit.remote.username %} (by @{{ commit.remote.username }}){% endif -%} +{% endmacro -%} +{%- macro pr(commit) -%} + {% if commit.remote.pr_number %} - #{{ commit.remote.pr_number }}{% endif -%} +{% endmacro -%} +"""