1+ name : Release
2+
3+ on :
4+ push :
5+ tags :
6+ - ' v*.*.*'
7+ workflow_dispatch :
8+ inputs :
9+ version :
10+ description : ' Version to release (e.g., v0.4.2)'
11+ required : true
12+ type : string
13+
14+ env :
15+ CARGO_TERM_COLOR : always
16+ SCCACHE_GHA_ENABLED : " true"
17+ RUSTC_WRAPPER : sccache
18+
19+ jobs :
20+ create-release :
21+ name : Create Release
22+ runs-on : ubuntu-latest
23+ outputs :
24+ version : ${{ steps.get_version.outputs.version }}
25+ steps :
26+ - name : Checkout
27+ uses : actions/checkout@v4
28+ with :
29+ fetch-depth : 0
30+
31+ - name : Get version
32+ id : get_version
33+ run : |
34+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
35+ echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
36+ else
37+ echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
38+ fi
39+
40+ - name : Generate changelog
41+ id : changelog
42+ run : |
43+ # Get previous tag
44+ PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n 2 | tail -n 1)
45+ if [ -z "$PREV_TAG" ]; then
46+ PREV_TAG=$(git rev-list --max-parents=0 HEAD)
47+ fi
48+
49+ # Generate changelog
50+ echo "## What's Changed" > changelog.md
51+ echo "" >> changelog.md
52+ git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD >> changelog.md
53+ echo "" >> changelog.md
54+ echo "" >> changelog.md
55+ echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/$PREV_TAG...${{ steps.get_version.outputs.version }}" >> changelog.md
56+
57+ # Set output
58+ echo "changelog<<EOF" >> $GITHUB_OUTPUT
59+ cat changelog.md >> $GITHUB_OUTPUT
60+ echo "EOF" >> $GITHUB_OUTPUT
61+
62+ - name : Create Release
63+ id : create_release
64+ uses : softprops/action-gh-release@v1
65+ env :
66+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
67+ with :
68+ tag_name : ${{ steps.get_version.outputs.version }}
69+ name : Release ${{ steps.get_version.outputs.version }}
70+ body : ${{ steps.changelog.outputs.changelog }}
71+ draft : false
72+ prerelease : ${{ contains(steps.get_version.outputs.version, '-') }}
73+
74+ build-artifacts :
75+ name : Build ${{ matrix.target }}
76+ runs-on : ${{ matrix.os }}
77+ needs : create-release
78+ strategy :
79+ matrix :
80+ include :
81+ - target : x86_64-unknown-linux-gnu
82+ os : ubuntu-latest
83+ - target : x86_64-pc-windows-gnu
84+ os : windows-latest
85+ - target : x86_64-apple-darwin
86+ os : macos-latest
87+ - target : aarch64-apple-darwin
88+ os : macos-latest
89+
90+ steps :
91+ - name : Checkout
92+ uses : actions/checkout@v4
93+
94+ - name : Setup sccache
95+ uses :
mozilla-actions/[email protected] 96+ timeout-minutes : 5
97+ continue-on-error : true
98+
99+ - name : Setup Rust
100+ uses : actions-rust-lang/setup-rust-toolchain@v1
101+ with :
102+ target : ${{ matrix.target }}
103+
104+ - name : Setup Go
105+ uses : actions/setup-go@v4
106+ with :
107+ go-version : ' 1.22'
108+
109+
110+
111+ - name : Build Rust artifacts
112+ run : |
113+ cargo build --release --target ${{ matrix.target }}
114+
115+ - name : Build CLI
116+ run : |
117+ cargo build --release --target ${{ matrix.target }} -p rust2go-cli
118+
119+ - name : Package artifacts
120+ shell : bash
121+ run : |
122+ mkdir -p artifacts
123+
124+ # Create target-specific directory
125+ TARGET_DIR="artifacts/rust2go-${{ needs.create-release.outputs.version }}-${{ matrix.target }}"
126+ mkdir -p "$TARGET_DIR"
127+
128+ # Function to copy files - fail fast on missing files
129+ copy_if_exists() {
130+ local pattern="$1"
131+ local destination="$2"
132+
133+ if ls $pattern 1> /dev/null 2>&1; then
134+ cp $pattern "$destination/"
135+ echo "✅ Copied $(basename $pattern)"
136+ fi
137+ }
138+
139+ # Copy files based on target platform
140+ if [ "${{ matrix.target }}" = "x86_64-pc-windows-gnu" ]; then
141+ copy_if_exists "target/${{ matrix.target }}/release/*.dll" "$TARGET_DIR"
142+ cp "target/${{ matrix.target }}/release/rust2go-cli.exe" "$TARGET_DIR/"
143+ ARCHIVE_NAME="rust2go-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.zip"
144+ (cd artifacts && zip -r "$ARCHIVE_NAME" "rust2go-${{ needs.create-release.outputs.version }}-${{ matrix.target }}/")
145+ else
146+ copy_if_exists "target/${{ matrix.target }}/release/*.so" "$TARGET_DIR"
147+ copy_if_exists "target/${{ matrix.target }}/release/*.dylib" "$TARGET_DIR"
148+ cp "target/${{ matrix.target }}/release/rust2go-cli" "$TARGET_DIR/"
149+ ARCHIVE_NAME="rust2go-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.tar.gz"
150+ (cd artifacts && tar -czf "$ARCHIVE_NAME" "rust2go-${{ needs.create-release.outputs.version }}-${{ matrix.target }}/")
151+ fi
152+
153+ # Copy important files
154+ cp README.md "$TARGET_DIR/"
155+ cp LICENSE-MIT "$TARGET_DIR/"
156+ cp LICENSE-APACHE "$TARGET_DIR/"
157+
158+ echo "ARCHIVE_NAME=$ARCHIVE_NAME" >> $GITHUB_ENV
159+
160+ - name : Upload artifacts
161+ uses : softprops/action-gh-release@v1
162+ env :
163+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
164+ with :
165+ tag_name : ${{ needs.create-release.outputs.version }}
166+ files : artifacts/${{ env.ARCHIVE_NAME }}
167+
168+ publish-crates :
169+ name : Publish to crates.io
170+ runs-on : ubuntu-latest
171+ needs : create-release
172+ if : startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-')
173+ steps :
174+ - name : Checkout
175+ uses : actions/checkout@v4
176+
177+ - name : Setup sccache
178+ uses :
mozilla-actions/[email protected] 179+ timeout-minutes : 5
180+ continue-on-error : true
181+
182+ - name : Setup Rust
183+ uses : actions-rust-lang/setup-rust-toolchain@v1
184+
185+ - name : Publish to crates.io
186+ env :
187+ CARGO_REGISTRY_TOKEN : ${{ secrets.CARGO_REGISTRY_TOKEN }}
188+ run : |
189+ # Publish crates in dependency order - fail fast on errors
190+ cargo publish -p rust2go-common
191+ sleep 10
192+ cargo publish -p rust2go-convert
193+ sleep 10
194+ cargo publish -p rust2go-macro
195+ sleep 10
196+ cargo publish -p rust2go-mem-ffi
197+ sleep 10
198+ cargo publish -p mem-ring
199+ sleep 10
200+ cargo publish -p rust2go-cli
201+ sleep 10
202+ cargo publish -p rust2go
0 commit comments