Skip to content

Commit

Permalink
Add crate release workflow (#393)
Browse files Browse the repository at this point in the history
Publishes crates in Rust repos to the repo designated registry
(crates.io default).

Co-authored-by: Joey Vagedes <[email protected]>
Signed-off-by: Michael Kubacki <[email protected]>
  • Loading branch information
makubacki and Javagedes authored Jan 14, 2025
1 parent eaadce4 commit e92a402
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
64 changes: 64 additions & 0 deletions .github/actions/rust-tool-cache/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# A GitHub action that loads rust tools and toolchains from cache. If there is a miss, it will install
# them. the tools are read from the tools section of the rust-toolchain.toml file at the root of the repository.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#

name: "Install Rust Tools"
description: "This action loads rust tools and toolchains from cache, or installs them."

runs:
using: composite
steps:
- name: Rust Tool Cache
id: tool-cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.rustup/toolchains/
key: ${{ runner.os }}-rust-tools-${{ hashFiles('**/rust-toolchain.toml' )}}

- name: Install cargo-binstall
uses: cargo-bins/[email protected]

# Read any tools from rust-toolchain.toml file and installs them
- name: Install Rust Tools
shell: bash
run: |
FILE="rust-toolchain.toml"
if [ ! -f "$FILE" ]; then
echo "::error::File $FILE not found."
exit 1
fi
if ! grep -q '^\[tools\]' "$FILE"; then
echo "::warning::[tools] section not found in $FILE."
exit 1
fi
# Extract tools section from rust-toolchain.toml
sed -n '/\[tools\]/,/^$/p' "$FILE" | grep -v '\[tools\]' | while read -r line; do
# Extract tool name and clean it
TOOL_NAME=${line%%=*}
TOOL_NAME=${TOOL_NAME//[[:space:]]/}
TOOL_NAME="${TOOL_NAME//$'\n'/}"
# Extract tool version and clean it
TOOL_VERSION=${line#*=}
TOOL_VERSION=${TOOL_VERSION//[[:space:]]/}
TOOL_VERSION=${TOOL_VERSION//\"/}
TOOL_VERSION="${TOOL_VERSION//$'\n'/}"
echo ""
echo "##################################################################"
echo "Installing $TOOL_NAME@$TOOL_VERSION"
echo "##################################################################"
echo ""
# Attempt to binstall the tool first. If it fails, install it using cargo
cargo binstall -y $TOOL_NAME --version $TOOL_VERSION || cargo install $TOOL_NAME --version $TOOL_VERSION
done
if: steps.tool-cache.outputs.cache-hit != 'true'
133 changes: 133 additions & 0 deletions .github/workflows/ReleaseWorkflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# @file ReleaseWorkflow.yml
#
# A reusable CI workflow that releases all crates in a repository.
#
##
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
name: Publish

on:
workflow_call:
secrets:
CRATES_IO_TOKEN:
description: 'The token to use for authenticating with crates.io'
required: true

jobs:
run:
name: Publish

runs-on: ubuntu-latest

permissions:
contents: write
actions: read

steps:
- name: ✅ Checkout Repository ✅
uses: actions/checkout@v4

- name: 🛠️ Download Rust Tools 🛠️
uses: microsoft/mu_devops/.github/actions/rust-tool-cache@main

- name: Get Current Draft Release
id: draft_release
uses: actions/github-script@v7
with:
script: |
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
});
const draftReleaseList = releases.data.filter(release => release.draft);
if (draftReleaseList.length === 0) {
core.setFailed("No draft release found. Exiting with error.");
} else if (draftReleaseList.length > 1) {
core.setFailed("Multiple draft releases found. Exiting with error.");
} else {
const draftRelease = draftReleaseList[0];
let tag = draftRelease.tag_name;
if (tag.startsWith('v')) {
tag = tag.slice(1);
}
core.setOutput("id", draftRelease.id);
core.setOutput("tag", tag);
console.log(`Draft Release ID: ${draftRelease.id}`);
console.log(`Draft Release Tag: ${tag}`);
}
- name: Cargo Release Dry Run
run: cargo release ${{ steps.draft_release.outputs.tag }} --workspace
env:
RUSTC_BOOTSTRAP: 1

- name: Login to Crates.io
run: cargo login ${{ secrets.CRATES_IO_TOKEN }}

- name: Update git credentials
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Cargo Release
run: cargo release ${{ steps.draft_release.outputs.tag }} -x --no-tag --no-confirm --workspace
env:
RUSTC_BOOTSTRAP: 1

- name: Wait for Release Draft Updater
uses: actions/github-script@v7
with:
script: |
const workflowId = "release-draft.yml";
const ref = "main";
const owner = context.repo.owner;
const repo = context.repo.repo;
// Try for 10 minutes. It should only take a few seconds
let maxAttempts = 40;
let attempt = 0;
let completed = false
while (attempt < maxAttempts && !completed) {
await new Promise(resolve => setTimeout(resolve, 15000));
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: workflowId,
branch: ref,
event: 'push',
status: 'in_progress',
});
if (runs.data.workflow_runs.length === 0) {
completed = true;
} else {
attempt++;
}
}
if (!completed) {
core.setFailed("Release Drafter did not complete in time. Please perform the release manually.");
}
- name: Publish Release
uses: actions/github-script@v7
with:
script: |
const releaseId = ${{ steps.draft_release.outputs.id }};
const response = await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: releaseId,
draft: false,
});
if (response.status !== 200) {
core.setFailed(`Failed to publish release. Exiting with error.`);
}
9 changes: 9 additions & 0 deletions .sync/Files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,15 @@ group:
repos: |
microsoft/mu_devops
# Leaf Workflow - Publish Release
- files:
- source: .sync/workflows/leaf/publish-release.yml
dest: .github/workflows/publish-release.yml
repos: |
microsoft/mu_rust_helpers
microsoft/mu_rust_hid
microsoft/mu_rust_pi
# Leaf Workflow - Pull Request Validator
- files:
- source: .sync/workflows/leaf/pull-request-formatting-validator.yml
Expand Down
39 changes: 39 additions & 0 deletions .sync/workflows/leaf/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# @file publish-release.yml
#
# A Github workflow that publishes all crates in a repository to crates.io and creates a release on
# GitHub.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##

name: Publish Release

on:
workflow_dispatch:

jobs:
validate_branch:
name: Validate Branch
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Validate Branch
run: |
if [ "${GITHUB_REF}" != "refs/heads/main" ]; then
echo "This workflow can only be run on the main branch."
exit 1
fi
release:
name: Release
needs: validate_branch
uses: microsoft/mu_devops/.github/workflows/ReleaseWorkflow.yml@main
secrets:
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
permissions:
contents: write
actions: read

0 comments on commit e92a402

Please sign in to comment.