Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.

Commit f9c7027

Browse files
committed
feat: implement cargo-workspace plugin and unified versioning for Rust workspaces
- Add cargo-workspace plugin to release-please for proper Rust workspace handling - Implement workspace-level versioning for both SDK and components - SDK workspace: unified at v0.12.0 (ftl-sdk + ftl-sdk-macros) - Components workspace: unified at v0.14.0 (mcp-gateway + mcp-authorizer) - Replace individual component workflow with unified release-components.yml - Fix all version validation workflows to handle workspace inheritance - Update release-validation.yml to check workspace versions instead of individual crates - Add wasm32-wasip1 target to SDK release workflow This establishes the correct architecture from the start, following patterns proven successful in projects like AWS CDK v2, Babel, and Angular.
1 parent 162b178 commit f9c7027

File tree

14 files changed

+176
-172
lines changed

14 files changed

+176
-172
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
name: Release Component
1+
name: Release Components
22

33
on:
44
push:
55
tags:
6-
- 'component-*-v*'
6+
- 'components-v*'
77

88
env:
99
CARGO_TERM_COLOR: always
@@ -17,7 +17,6 @@ jobs:
1717
name: Verify Tag on Main Branch
1818
runs-on: ubuntu-latest
1919
outputs:
20-
component: ${{ steps.parse.outputs.component }}
2120
version: ${{ steps.parse.outputs.version }}
2221
steps:
2322
- uses: actions/checkout@v4
@@ -27,56 +26,47 @@ jobs:
2726
- name: Parse tag
2827
id: parse
2928
run: |
30-
# Extract component name and version from tag
31-
# Format: component-{name}-v{version}
29+
# Extract version from tag
30+
# Format: components-v{version}
3231
TAG="${GITHUB_REF#refs/tags/}"
33-
if [[ ! "$TAG" =~ ^component-([a-z-]+)-v(.+)$ ]]; then
32+
if [[ ! "$TAG" =~ ^components-v(.+)$ ]]; then
3433
echo "❌ Invalid tag format: $TAG"
35-
echo "Expected format: component-{name}-v{version}"
34+
echo "Expected format: components-v{version}"
3635
exit 1
3736
fi
38-
COMPONENT="${BASH_REMATCH[1]}"
39-
VERSION="${BASH_REMATCH[2]}"
40-
echo "component=$COMPONENT" >> $GITHUB_OUTPUT
37+
VERSION="${BASH_REMATCH[1]}"
4138
echo "version=$VERSION" >> $GITHUB_OUTPUT
42-
echo "📦 Component: $COMPONENT"
4339
echo "🔢 Version: $VERSION"
4440
4541
- name: Verify tag is on main branch
4642
uses: ./.github/actions/verify-tag
4743

48-
- name: Verify component exists
44+
- name: Verify workspace version matches tag
4945
run: |
50-
COMPONENT="${{ steps.parse.outputs.component }}"
51-
if [ ! -d "components/$COMPONENT" ]; then
52-
echo "❌ Component directory not found: components/$COMPONENT"
53-
exit 1
54-
fi
55-
echo "✅ Component directory exists"
56-
57-
- name: Verify version matches Cargo.toml
58-
run: |
59-
COMPONENT="${{ steps.parse.outputs.component }}"
6046
VERSION="${{ steps.parse.outputs.version }}"
61-
CARGO_VERSION=$(grep '^version' "components/$COMPONENT/Cargo.toml" | head -1 | cut -d'"' -f2)
62-
if [ "$CARGO_VERSION" != "$VERSION" ]; then
63-
echo "❌ Tag version ($VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
47+
# Check workspace version
48+
WORKSPACE_VERSION=$(grep '^\s*version' components/Cargo.toml | head -1 | cut -d'"' -f2)
49+
if [ "$WORKSPACE_VERSION" != "$VERSION" ]; then
50+
echo "❌ Tag version ($VERSION) does not match workspace version ($WORKSPACE_VERSION)"
6451
exit 1
6552
fi
66-
echo "✅ Version matches Cargo.toml"
53+
echo "✅ Workspace version matches tag: $VERSION"
6754
6855
build-and-publish:
69-
name: Build and Publish Component
56+
name: Build and Publish ${{ matrix.component }}
7057
needs: verify-tag
7158
runs-on: ubuntu-latest
59+
strategy:
60+
matrix:
61+
component: [mcp-gateway, mcp-authorizer]
7262
steps:
7363
- uses: actions/checkout@v4
7464

7565
- name: Setup Rust for WASM
7666
uses: ./.github/actions/setup-rust
7767
with:
7868
targets: wasm32-wasip1
79-
cache-key: release-component-${{ matrix.component }}-v189
69+
cache-key: release-components-${{ matrix.component }}-v189
8070

8171
- name: Install cargo-component
8272
uses: taiki-e/install-action@v2
@@ -98,20 +88,20 @@ jobs:
9888

9989
- name: Build component
10090
run: |
101-
cd "components/${{ needs.verify-tag.outputs.component }}"
91+
cd "components/${{ matrix.component }}"
10292
cargo component build --target wasm32-wasip1 --release
10393
10494
- name: Determine WASM file name
10595
id: wasm
10696
run: |
107-
COMPONENT="${{ needs.verify-tag.outputs.component }}"
97+
COMPONENT="${{ matrix.component }}"
10898
# Replace hyphens with underscores (Cargo uses underscores in output names)
10999
WASM_NAME="${COMPONENT//-/_}.wasm"
110100
echo "name=$WASM_NAME" >> $GITHUB_OUTPUT
111101
112102
- name: Publish to ghcr.io
113103
run: |
114-
COMPONENT="${{ needs.verify-tag.outputs.component }}"
104+
COMPONENT="${{ matrix.component }}"
115105
VERSION="${{ needs.verify-tag.outputs.version }}"
116106
WASM_FILE="../target/wasm32-wasip1/release/${{ steps.wasm.outputs.name }}"
117107
@@ -131,26 +121,59 @@ jobs:
131121
132122
echo "✅ Published $COMPONENT v$VERSION to ghcr.io"
133123
124+
- name: Upload WASM artifact
125+
uses: actions/upload-artifact@v4
126+
with:
127+
name: ${{ matrix.component }}-wasm
128+
path: components/target/wasm32-wasip1/release/${{ steps.wasm.outputs.name }}
129+
130+
create-release:
131+
name: Create Unified Release
132+
needs: [verify-tag, build-and-publish]
133+
runs-on: ubuntu-latest
134+
steps:
135+
- uses: actions/checkout@v4
136+
137+
- name: Download artifacts
138+
uses: actions/download-artifact@v4
139+
with:
140+
path: artifacts
141+
134142
- name: Create Release
135143
uses: softprops/action-gh-release@v2
136144
with:
137-
name: "${{ needs.verify-tag.outputs.component }} v${{ needs.verify-tag.outputs.version }}"
145+
name: "FTL Components v${{ needs.verify-tag.outputs.version }}"
138146
draft: false
139147
prerelease: false
140148
generate_release_notes: true
149+
files: |
150+
artifacts/**/*.wasm
141151
body: |
142-
## Component: ${{ needs.verify-tag.outputs.component }}
152+
## FTL Components v${{ needs.verify-tag.outputs.version }}
153+
154+
This release includes both FTL components with unified versioning:
155+
- **mcp-gateway** - MCP gateway component
156+
- **mcp-authorizer** - MCP authorization component
143157
144158
### Installation
145159
160+
#### MCP Gateway
146161
Add to your `spin.toml`:
147162
```toml
148-
[component.${{ needs.verify-tag.outputs.component }}]
149-
source = { registry = "ghcr.io", package = "fastertools:${{ needs.verify-tag.outputs.component }}", version = "${{ needs.verify-tag.outputs.version }}" }
163+
[component.mcp-gateway]
164+
source = { registry = "ghcr.io", package = "fastertools:mcp-gateway", version = "${{ needs.verify-tag.outputs.version }}" }
150165
```
151166
152-
Or use the latest version:
167+
#### MCP Authorizer
168+
Add to your `spin.toml`:
153169
```toml
154-
[component.${{ needs.verify-tag.outputs.component }}]
155-
source = { registry = "ghcr.io", package = "fastertools:${{ needs.verify-tag.outputs.component }}", version = "latest" }
156-
```
170+
[component.mcp-authorizer]
171+
source = { registry = "ghcr.io", package = "fastertools:mcp-authorizer", version = "${{ needs.verify-tag.outputs.version }}" }
172+
```
173+
174+
### Using Latest Version
175+
You can also use `version = "latest"` to always get the most recent release.
176+
177+
### Documentation
178+
- [MCP Gateway README](https://github.com/fastertools/ftl/tree/main/components/mcp-gateway)
179+
- [MCP Authorizer README](https://github.com/fastertools/ftl/tree/main/components/mcp-authorizer)

.github/workflows/release-rust-crates.yml

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,35 +38,21 @@ jobs:
3838
run: |
3939
VERSION="${{ inputs.version }}"
4040
41-
# Check main SDK version
42-
SDK_VERSION=$(grep '^version = ' sdk/rust/Cargo.toml | head -1 | cut -d'"' -f2)
43-
if [[ "${SDK_VERSION}" != "${VERSION}" ]]; then
44-
echo "Version mismatch in sdk/rust/Cargo.toml: found ${SDK_VERSION}, expected ${VERSION}"
41+
# Check workspace version
42+
WORKSPACE_VERSION=$(grep '^\s*version = ' sdk/Cargo.toml | head -1 | cut -d'"' -f2)
43+
if [[ "${WORKSPACE_VERSION}" != "${VERSION}" ]]; then
44+
echo "Version mismatch in sdk/Cargo.toml workspace: found ${WORKSPACE_VERSION}, expected ${VERSION}"
4545
exit 1
4646
fi
4747
48-
# Check macros version
49-
MACROS_VERSION=$(grep '^version = ' sdk/rust-macros/Cargo.toml | head -1 | cut -d'"' -f2)
50-
if [[ "${MACROS_VERSION}" != "${VERSION}" ]]; then
51-
echo "Version mismatch in sdk/rust-macros/Cargo.toml: found ${MACROS_VERSION}, expected ${VERSION}"
52-
exit 1
53-
fi
54-
55-
# Check that SDK depends on correct macros version
56-
MACROS_DEP=$(grep 'ftl-sdk-macros.*version' sdk/rust/Cargo.toml | cut -d'"' -f2)
57-
if [[ "${MACROS_DEP}" != "=${VERSION}" ]]; then
58-
echo "SDK depends on wrong macros version: ${MACROS_DEP}, expected =${VERSION}"
59-
exit 1
60-
fi
61-
62-
# Check manifest version
63-
JSON_VERSION=$(jq -r '."sdk/rust"' .release-please-manifest.json)
48+
# Check manifest version (now uses "sdk" key)
49+
JSON_VERSION=$(jq -r '.sdk' .release-please-manifest.json)
6450
if [[ "${JSON_VERSION}" != "${VERSION}" ]]; then
6551
echo "Version mismatch in manifest: found ${JSON_VERSION}, expected ${VERSION}"
6652
exit 1
6753
fi
6854
69-
echo "All versions validated: ${VERSION}"
55+
echo "✅ Workspace version validated: ${VERSION}"
7056
7157
test-crates:
7258
name: Test Crates

.github/workflows/release-sdk-rust.yml

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,14 @@ jobs:
3737
run: |
3838
VERSION="${{ steps.parse.outputs.version }}"
3939
40-
# Check ftl-sdk version
41-
SDK_VERSION=$(grep '^version' sdk/rust/Cargo.toml | head -1 | cut -d'"' -f2)
42-
if [ "$SDK_VERSION" != "$VERSION" ]; then
43-
echo "❌ Tag version ($VERSION) does not match ftl-sdk version ($SDK_VERSION)"
40+
# Check workspace version
41+
WORKSPACE_VERSION=$(grep '^\s*version' sdk/Cargo.toml | head -1 | cut -d'"' -f2)
42+
if [ "$WORKSPACE_VERSION" != "$VERSION" ]; then
43+
echo "❌ Tag version ($VERSION) does not match workspace version ($WORKSPACE_VERSION)"
4444
exit 1
4545
fi
4646
47-
# Check ftl-sdk-macros version
48-
MACROS_VERSION=$(grep '^version' sdk/rust-macros/Cargo.toml | head -1 | cut -d'"' -f2)
49-
echo "📦 ftl-sdk-macros version: $MACROS_VERSION"
50-
51-
# Verify ftl-sdk depends on the correct macros version
52-
MACROS_DEP=$(grep 'ftl-sdk-macros' sdk/rust/Cargo.toml | grep version | cut -d'"' -f2)
53-
if [ "$MACROS_DEP" != "$MACROS_VERSION" ]; then
54-
echo "❌ ftl-sdk depends on ftl-sdk-macros $MACROS_DEP but macros is at version $MACROS_VERSION"
55-
exit 1
56-
fi
57-
58-
echo "✅ All versions are consistent"
47+
echo "✅ Workspace version matches tag: $VERSION"
5948
6049
publish:
6150
name: Publish to crates.io
@@ -85,14 +74,14 @@ jobs:
8574
- name: Publish ftl-sdk-macros
8675
run: |
8776
cd sdk/rust-macros
88-
MACROS_VERSION=$(grep '^version' Cargo.toml | head -1 | cut -d'"' -f2)
77+
VERSION="${{ needs.verify-tag.outputs.version }}"
8978
9079
# Check if already published
91-
if cargo search ftl-sdk-macros --limit 1 | grep -q "^ftl-sdk-macros = \"$MACROS_VERSION\""; then
92-
echo "⚠️ ftl-sdk-macros v$MACROS_VERSION already published"
80+
if cargo search ftl-sdk-macros --limit 1 | grep -q "^ftl-sdk-macros = \"$VERSION\""; then
81+
echo "⚠️ ftl-sdk-macros v$VERSION already published"
9382
else
9483
cargo publish
95-
echo "✅ Published ftl-sdk-macros v$MACROS_VERSION"
84+
echo "✅ Published ftl-sdk-macros v$VERSION"
9685
fi
9786
env:
9887
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

0 commit comments

Comments
 (0)