Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **rust/package-crate** - Package Rust crates for publishing to crates.io
- Workspace support with `--package` flag for workspace crates
- Handles workspace version inheritance (`version.workspace = true`)
- Configurable allow-dirty flag
- Additional cargo arguments support
- Verification output showing packaged `.crate` files
- **rust/publish-crate** - Publish Rust crates to crates.io
- Workspace support with `--package` flag for workspace crates
- Handles workspace version inheritance (`version.workspace = true`)
- Secure token handling (hidden in logs)
- Dry-run mode for testing
- Configurable allow-dirty flag
- Additional cargo arguments support
- **rust/build-library** - Build Rust libraries with flexible profile and feature control
- **rust/lint** - Run cargo fmt and cargo clippy for code quality checks
- **rust/verify-toolchain** - Reusable action to verify Rust toolchain and components are installed
Expand Down
134 changes: 134 additions & 0 deletions rust/package-crate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Package Rust Crate

Composite action to package a Rust crate for publishing to crates.io. Supports both workspace and standalone crates.

## Features

- ✅ **Workspace Support**: Handles workspace crates with `version.workspace = true`
- ✅ **Standalone Support**: Works with single-crate projects
- ✅ **Allow Dirty**: Optional flag to package with uncommitted changes
- ✅ **Flexible Arguments**: Pass additional cargo arguments
- ✅ **Verification Output**: Lists packaged `.crate` files after successful packaging

## Usage

### Workspace Crate

For crates that use workspace version inheritance (`version.workspace = true`):

```yaml
- name: Package workspace crate
uses: firestoned/github-actions/rust/package-crate@v1.2.4
with:
package: my-crate-name
workspace: true
allow-dirty: true
```

### Standalone Crate

For standalone crates (single Cargo.toml):

```yaml
- name: Package crate
uses: firestoned/github-actions/rust/package-crate@v1.2.4
with:
allow-dirty: false
```

### With Additional Arguments

```yaml
- name: Package crate with features
uses: firestoned/github-actions/rust/package-crate@v1.2.4
with:
package: my-crate
workspace: true
cargo-args: '--no-verify'
```

## Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `package` | Package name to package (for workspace crates) | No | `''` |
| `workspace` | Whether this is a workspace crate (uses --package flag) | No | `false` |
| `allow-dirty` | Allow packaging with uncommitted changes | No | `true` |
| `cargo-args` | Additional arguments to pass to cargo package | No | `''` |

## Outputs

This action produces a `.crate` file in `target/package/` directory.

## Prerequisites

- Rust toolchain must be installed (use `firestoned/github-actions/rust/setup-rust-build`)
- For workspace crates, must be run from workspace root

## Example: Complete Release Workflow

```yaml
jobs:
package-crates:
runs-on: ubuntu-latest
strategy:
matrix:
crate:
- name: my-derive-crate
- name: my-runtime-crate
steps:
- uses: actions/checkout@v4

- name: Setup Rust
uses: firestoned/github-actions/rust/setup-rust-build@v1.2.4
with:
target: x86_64-unknown-linux-gnu

- name: Update workspace version
run: |
sed -i 's/^version = ".*"/version = "1.0.0"/' Cargo.toml

- name: Package crate
uses: firestoned/github-actions/rust/package-crate@v1.2.4
with:
package: ${{ matrix.crate.name }}
workspace: true

- name: Upload package
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.crate.name }}-package
path: target/package/${{ matrix.crate.name }}-*.crate
```

## Why Use This Action?

### Problem: Workspace Version Management

When using workspace version inheritance:

```toml
# Cargo.toml (workspace root)
[workspace.package]
version = "1.0.0"

# my-crate/Cargo.toml
[package]
version.workspace = true
```

Running `cd my-crate && cargo package` fails because the workspace version is not accessible from the crate directory.

### Solution: Package from Workspace Root

This action runs `cargo package --package <name>` from the workspace root, allowing cargo to properly resolve workspace-inherited fields.

## Notes

- The action uses `--allow-dirty` by default since CI often modifies `Cargo.toml` to update versions
- For workspace crates, `workspace: true` and `package: <name>` must both be specified
- The packaged `.crate` file is placed in `target/package/`

## License

MIT
74 changes: 74 additions & 0 deletions rust/package-crate/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (c) 2025 Erick Bourgeois, firestoned
# SPDX-License-Identifier: MIT

name: 'Package Rust Crate'
description: 'Package a Rust crate for publishing to crates.io, supporting both workspace and standalone crates'
author: 'Erick Bourgeois'

inputs:
package:
description: 'Package name to package (for workspace crates, use --package flag)'
required: false
default: ''
workspace:
description: 'Whether this is a workspace crate (uses --package flag)'
required: false
default: 'false'
allow-dirty:
description: 'Allow packaging with uncommitted changes'
required: false
default: 'true'
cargo-args:
description: 'Additional arguments to pass to cargo package'
required: false
default: ''

runs:
using: 'composite'
steps:
- name: Verify Rust toolchain
uses: firestoned/github-actions/rust/verify-toolchain@main
with:
require-cargo: true

- name: Package crate
shell: bash
run: |
set -e

# Build cargo command
CMD="cargo package --verbose"

# Add package flag for workspace crates
if [ "${{ inputs.workspace }}" = "true" ] && [ -n "${{ inputs.package }}" ]; then
CMD="$CMD --package ${{ inputs.package }}"
echo "Packaging workspace crate: ${{ inputs.package }}"
elif [ -n "${{ inputs.package }}" ]; then
echo "WARNING: package specified but workspace=false. The package flag requires workspace=true."
echo "Packaging current crate in directory"
else
echo "Packaging current crate"
fi

# Add allow-dirty flag
if [ "${{ inputs.allow-dirty }}" = "true" ]; then
CMD="$CMD --allow-dirty"
fi

# Add any additional cargo arguments
if [ -n "${{ inputs.cargo-args }}" ]; then
CMD="$CMD ${{ inputs.cargo-args }}"
fi

echo "Running: $CMD"
$CMD

echo ""
echo "Package created successfully"

# List the packaged crate
if [ -d "target/package" ]; then
echo ""
echo "Packaged crate(s):"
ls -lh target/package/*.crate 2>/dev/null || echo "No .crate files found in target/package"
fi
Loading
Loading