Migration to v1.1.3
These are the steps to migrate from v1.1.2 to v1.1.3.
Improve verification scripts
This improves .cargo/verify.* by switching to the project root first, so they work from any folder.
It also makes both scripts report failed commands, keep running the remaining checks, and exit non-zero at the end if any check failed.
Update .cargo/verify.sh
diff --git a/templates/general/src/.cargo/verify.sh b/templates/general/src/.cargo/verify.sh
index 2dbf0e5..3f5080c 100755
--- a/templates/general/src/.cargo/verify.sh
+++ b/templates/general/src/.cargo/verify.sh
@@ -7,0 +8,10 @@ set -e
+ORIGINAL_DIR="$(pwd)"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+cd "$PROJECT_ROOT"
+
+trap 'cd "$ORIGINAL_DIR"' EXIT
+
+EXIT_CODE=0
+FAILED_COMMANDS=()
+
@@ -10 +20,13 @@ run_cmd() {
- "$@"
+
+ if "$@"; then
+ return 0
+ fi
+
+ local status=$?
+ printf 'Command failed with exit code %s: %s\n' "$status" "$*" >&2
+ FAILED_COMMANDS+=("$*")
+ if [ "$EXIT_CODE" -eq 0 ]; then
+ EXIT_CODE=$status
+ fi
+
+ return 0
@@ -23 +45 @@ echo "Docs..."
-run_cmd RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --document-private-items --quiet
+run_cmd env RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --document-private-items --quiet
@@ -31 +53,9 @@ run_cmd cargo publish --dry-run --allow-dirty --quiet --workspace
-echo "All checks passed!"
+if [ "$EXIT_CODE" -eq 0 ]; then
+ echo "All checks passed!"
+else
+ echo "Verification failed."
+ echo "Failed commands:"
+ printf ' - %s\n' "${FAILED_COMMANDS[@]}"
+fi
+
+exit "$EXIT_CODE"
Update .cargo/verify.ps1
diff --git a/templates/general/src/.cargo/verify.ps1 b/templates/general/src/.cargo/verify.ps1
index 7630ea1..b256489 100644
--- a/templates/general/src/.cargo/verify.ps1
+++ b/templates/general/src/.cargo/verify.ps1
@@ -5 +5,26 @@
-$ErrorActionPreference = "Stop"
+$originalDir = Get-Location
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$projectRoot = Join-Path $scriptDir ".."
+$originalRustdocFlags = $env:RUSTDOCFLAGS
+Set-Location $projectRoot -ErrorAction Stop
+
+$script:exitCode = 0
+$script:failedCommands = @()
+
+function Register-CommandFailure {
+ param(
+ [string]$DisplayCommand,
+ [int]$Code,
+ [string]$Message = ""
+ )
+
+ Write-Host ("Command failed with exit code " + $Code + ": " + $DisplayCommand)
+ if ($Message -ne "") {
+ Write-Host $Message
+ }
+
+ $script:failedCommands += $DisplayCommand
+ if ($script:exitCode -eq 0) {
+ $script:exitCode = $Code
+ }
+}
@@ -13,2 +38,2 @@ function Invoke-LoggedCommand {
- if ($Arguments.Count -gt 0) {
- Write-Host ($Command + " " + ($Arguments -join " "))
+ $displayCommand = if ($Arguments.Count -gt 0) {
+ $Command + " " + ($Arguments -join " ")
@@ -16 +41 @@ function Invoke-LoggedCommand {
- Write-Host $Command
+ $Command
@@ -19 +44,13 @@ function Invoke-LoggedCommand {
- & $Command @Arguments
+ Write-Host $displayCommand
+
+ try {
+ & $Command @Arguments
+ $commandExitCode = $LASTEXITCODE
+ } catch {
+ Register-CommandFailure $displayCommand 1 $_.Exception.Message
+ return
+ }
+
+ if ($commandExitCode -ne 0) {
+ Register-CommandFailure $displayCommand $commandExitCode
+ }
@@ -22,2 +59,3 @@ function Invoke-LoggedCommand {
-Write-Host "Building..."
-Invoke-LoggedCommand "cargo" @("build", "--workspace", "--all-features", "--all-targets", "--quiet")
+try {
+ Write-Host "Building..."
+ Invoke-LoggedCommand "cargo" @("build", "--workspace", "--all-features", "--all-targets", "--quiet")
@@ -25,2 +63,2 @@ Invoke-LoggedCommand "cargo" @("build", "--workspace", "--all-features", "--all-targets", "--quiet")
-Write-Host "Testing..."
-Invoke-LoggedCommand "cargo" @("test", "--workspace", "--all-features", "--quiet")
+ Write-Host "Testing..."
+ Invoke-LoggedCommand "cargo" @("test", "--workspace", "--all-features", "--quiet")
@@ -28,2 +66,2 @@ Invoke-LoggedCommand "cargo" @("test", "--workspace", "--all-features", "--quiet")
-Write-Host "Clippy..."
-Invoke-LoggedCommand "cargo" @("clippy", "--workspace", "--all-features", "--quiet", "--", "-D", "warnings")
+ Write-Host "Clippy..."
+ Invoke-LoggedCommand "cargo" @("clippy", "--workspace", "--all-features", "--quiet", "--", "-D", "warnings")
@@ -31,3 +69,7 @@ Invoke-LoggedCommand "cargo" @("clippy", "--workspace", "--all-features", "--quiet", "--", "-D", "warnings")
-Write-Host "Docs..."
-$env:RUSTDOCFLAGS = "-D warnings"
-Invoke-LoggedCommand "cargo" @("doc", "--workspace", "--all-features", "--no-deps", "--document-private-items", "--quiet")
+ Write-Host "Docs..."
+ $env:RUSTDOCFLAGS = "-D warnings"
+ try {
+ Invoke-LoggedCommand "cargo" @("doc", "--workspace", "--all-features", "--no-deps", "--document-private-items", "--quiet")
+ } finally {
+ $env:RUSTDOCFLAGS = $originalRustdocFlags
+ }
@@ -35,2 +77,2 @@ Invoke-LoggedCommand "cargo" @("doc", "--workspace", "--all-features", "--no-deps", "--document-private-items", "--quiet")
-Write-Host "Formatting..."
-Invoke-LoggedCommand "cargo" @("fmt", "--all", "--quiet")
+ Write-Host "Formatting..."
+ Invoke-LoggedCommand "cargo" @("fmt", "--all", "--quiet")
@@ -38,2 +80,16 @@ Invoke-LoggedCommand "cargo" @("fmt", "--all", "--quiet")
-Write-Host "Publish dry-run..."
-Invoke-LoggedCommand "cargo" @("publish", "--dry-run", "--allow-dirty", "--quiet", "--workspace")
+ Write-Host "Publish dry-run..."
+ Invoke-LoggedCommand "cargo" @("publish", "--dry-run", "--allow-dirty", "--quiet", "--workspace")
+} finally {
+ $env:RUSTDOCFLAGS = $originalRustdocFlags
+ Set-Location $originalDir
+}
+
+if ($script:exitCode -eq 0) {
+ Write-Host "All checks passed!"
+} else {
+ Write-Host "Verification failed."
+ Write-Host "Failed commands:"
+ foreach ($failedCommand in $script:failedCommands) {
+ Write-Host (" - " + $failedCommand)
+ }
+}
@@ -41 +97 @@ Invoke-LoggedCommand "cargo" @("publish", "--dry-run", "--allow-dirty", "--quiet", "--workspace")
-Write-Host "All checks passed!"
+exit $script:exitCode
Disable YAML format-on-save for workflows
This avoids VSCode reformatting templated workflow files.
Add a top-level .vscode/settings.json beside README.MD:
+{
+ "[yaml]": {
+ "editor.formatOnSave": false
+ }
+}
Move CLI builds to a separate job
CLI builds may use nightly while library builds may stay on stable. A separate job avoids cache clashes between compilers.
Skip this section if your project has no cli/ crate.
Remove the CLI step from build-and-test
- - name: Build CLI Binary
- uses: Reloaded-Project/devops-rust-lightweight-binary@v1
- with:
- target: ${{ matrix.target }}
- use-pgo: ${{ matrix.use-pgo && env.build-with-pgo }}
- use-cross: ${{ matrix.use-cross }}
- build-library: false
- run-tests-and-coverage: false
- rust-project-path: src/cli
- workspace-path: src
- pgo-project-path: src/<your-crate>
- use-cache: false
Add a build-cli job
Add the new job first. You can reformat both matrices after this.
build-cli:
strategy:
matrix:
include:
# Copy the same matrix entries from build-and-test.
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Build CLI Binary
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
target: ${{ matrix.target }}
use-pgo: ${{ matrix.use-pgo && env.build-with-pgo }}
use-cross: ${{ matrix.use-cross }}
build-library: false
run-tests-and-coverage: false
rust-project-path: src/cli
workspace-path: src
pgo-project-path: src/<your-crate>
use-cache: true
Update publish-crate
Add build-cli to the needs list:
- needs: [build-and-test, ...]
+ needs: [build-and-test,build-cli, ...]
Reformat workflow matrices
After the CLI split is done, reformat both matrices to match the current template.
Use one-line entries with labels and group comments.
Use this group order when enabled: Linux, Windows, macOS, then Big Endian.
Do not add new targets here.
Keep the same matrix entries you already have, and only reformat them. The full example below shows how to label and group existing entries.
Reformat build-and-test
build-and-test:
+ name: ${{ matrix.label }}
strategy:
matrix:
include:
- - os: ubuntu-latest
- target: x86_64-unknown-linux-gnu
- use-pgo: true
- use-cross: false
+ # Linux
+ - { label: "Linux x64", os: ubuntu-latest, target: x86_64-unknown-linux-gnu, use-cross: false, use-pgo: true }
+ - { label: "Linux x86", os: ubuntu-latest, target: i686-unknown-linux-gnu, use-cross: false, use-pgo: true }
+ - { label: "Linux ARM64", os: ubuntu-latest, target: aarch64-unknown-linux-gnu, use-cross: true, use-pgo: false }
+ - { label: "Linux ARMv7", os: ubuntu-latest, target: armv7-unknown-linux-gnueabihf, use-cross: true, use-pgo: false }
+
+ # Windows
+ - { label: "Windows x64", os: windows-latest, target: x86_64-pc-windows-msvc, use-cross: false, use-pgo: true }
+ - { label: "Windows x86", os: windows-latest, target: i686-pc-windows-msvc, use-cross: false, use-pgo: true }
+
+ # macOS
+ - { label: "macOS Intel", os: macos-15-intel, target: x86_64-apple-darwin, use-cross: false, use-pgo: true }
+ - { label: "macOS Apple Silicon", os: macos-latest, target: aarch64-apple-darwin, use-cross: false, use-pgo: true }
+
+ # Big Endian
+ - { label: "Big Endian 32-bit", os: ubuntu-latest, target: powerpc-unknown-linux-gnu, use-cross: true, use-pgo: false }
+ - { label: "Big Endian 64-bit", os: ubuntu-latest, target: powerpc64-unknown-linux-gnu, use-cross: true, use-pgo: false }
Reformat build-cli
Use the same groups and targets, but prefix the labels with CLI:
build-cli:
name: ${{ matrix.label }}
strategy:
matrix:
include:
# Linux
- { label: "CLI Linux x64", os: ubuntu-latest, target: x86_64-unknown-linux-gnu, use-cross: false, use-pgo: true }
- { label: "CLI Linux x86", os: ubuntu-latest, target: i686-unknown-linux-gnu, use-cross: false, use-pgo: true }
- { label: "CLI Linux ARM64", os: ubuntu-latest, target: aarch64-unknown-linux-gnu, use-cross: true, use-pgo: false }
- { label: "CLI Linux ARMv7", os: ubuntu-latest, target: armv7-unknown-linux-gnueabihf, use-cross: true, use-pgo: false }
# Windows
- { label: "CLI Windows x64", os: windows-latest, target: x86_64-pc-windows-msvc, use-cross: false, use-pgo: true }
- { label: "CLI Windows x86", os: windows-latest, target: i686-pc-windows-msvc, use-cross: false, use-pgo: true }
# macOS
- { label: "CLI macOS Intel", os: macos-15-intel, target: x86_64-apple-darwin, use-cross: false, use-pgo: true }
- { label: "CLI macOS Apple Silicon", os: macos-latest, target: aarch64-apple-darwin, use-cross: false, use-pgo: true }
# Big Endian
- { label: "CLI Big Endian 32-bit", os: ubuntu-latest, target: powerpc-unknown-linux-gnu, use-cross: true, use-pgo: false }
- { label: "CLI Big Endian 64-bit", os: ubuntu-latest, target: powerpc64-unknown-linux-gnu, use-cross: true, use-pgo: false }
Run SemVer checks only on non-cross targets
This avoids build failures on cross targets.
- name: Run cargo-semver-checks
- if: github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/')
+ if: (github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/')) && !matrix.use-cross
Add crates.io metadata placeholders
Add these to src/<your-crate>/Cargo.toml. Use the links to choose real values later.
readme = "README.MD"
+# keywords (search terms): https://crates.io/keywords
+# keywords = ["api", "parser"]
+# categories (fixed list): https://crates.io/categories
+# categories = ["development-tools"]
Add these to src/cli/Cargo.toml too if you publish a CLI crate:
readme = "README.MD"
+# keywords (search terms): https://crates.io/keywords
+# keywords = ["cli", "command-line", "terminal"]
+# categories (fixed list): https://crates.io/categories
+# categories = ["command-line-utilities"]
Update src/AGENTS.md
This keeps the same guidance, but shorter.
-# Project Structure
+# Layout
- - `src/` - Library source code
+ - `src/` - Source
-# Code Guidelines
+# Code
- Optimize for performance; use zero-cost abstractions, avoid allocations. Use arrays instead of maps if size is known ahead of time.
+ Optimize for CPU and memory.
- Optimize for memory. Preallocate or trim if possible. Minimize memory use. Use smaller integers/types where appropriate. Use any other tricks that improve CPU or memory efficiency.
+ Use zero-cost abstractions, avoid allocations, prefer arrays when size is known.
+ Preallocate/trim memory, prefer smaller types when possible.
- Keep modules under 500 lines (excluding tests); split if larger.
+ Keep modules under 500 lines (excluding tests and docs); split if larger.
- Place `use` inside functions only for `#[cfg]` conditional compilation.
+ Function-local `use` only for `#[cfg]`.
-# Documentation Standards
+# Docs
- Add examples in docs where helpful
+ Add doc examples when helpful
- Use `//!` for module-level docs
+ Use `//!` for module docs
- Focus comments on "why" not "what"
+ Comments explain "why", not "what"
- Use [`TypeName`] rustdoc links, not backticks.
+ Use [`TypeName`] links, not backticks.
-# Verification
+# Verify
-After code changes or for checks (testing/linting/building/docs/formatting), run `.cargo/verify.sh` (`.cargo/verify.ps1` on Windows). It echoes each command and runs the full suite, including core tests and any extra checks. Do this before returning to the user.
+If you changed code, run `.cargo/verify.sh` or `.cargo/verify.ps1` before returning. It runs the full build/test/lint/docs/format suite.
Fix the panic = "abort" comment
This is a wording fix only.
-panic = "abort" # Automatically strip symbols from the binary
+panic = "abort" # Reduce binary size by omitting unwinding infrastructure
Update the template version marker
- reloaded-templates-rust:1.1.2
+ reloaded-templates-rust:1.1.3