1
- name : Rust Build and Test
1
+ name : CI/CD Pipeline
2
2
3
3
on :
4
4
push :
5
- branches :
6
- - master
5
+ branches : [master, main]
7
6
pull_request :
8
- workflow_dispatch :
7
+ branches : [master, main]
9
8
release :
10
- types : [created, edited]
9
+ types : [published]
10
+ workflow_dispatch :
11
11
12
12
env :
13
13
CARGO_TERM_COLOR : always
14
- CICD_INTERMEDIATES_DIR : " intermediates "
14
+ RUST_BACKTRACE : 1
15
15
16
16
jobs :
17
- # run build first to populate caches
18
- build-dev :
19
- name : Build
17
+ # Security and code quality checks
18
+ security :
19
+ name : Security Audit
20
20
runs-on : ubuntu-latest
21
21
steps :
22
- - uses : actions/checkout@v4
23
- - uses : actions/cache@v4
22
+ - name : Checkout
23
+ uses : actions/checkout@v4
24
+
25
+ - name : Setup Rust
26
+ uses : dtolnay/rust-toolchain@stable
27
+
28
+ - name : Install cargo-audit
29
+ run : cargo install cargo-audit
30
+
31
+ - name : Cache dependencies
32
+ uses : Swatinem/rust-cache@v2
24
33
with :
25
- path : |
26
- ~/.cargo/bin/
27
- ~/.cargo/registry/index/
28
- ~/.cargo/registry/cache/
29
- ~/.cargo/git/db/
30
- target/
31
- key : ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-v2
32
- - uses : actions-rust-lang/setup-rust-toolchain@v1
34
+ key : test-${{ hashFiles('**/Cargo.lock') }}
35
+
36
+ - name : Security audit
37
+ run : cargo audit
38
+
39
+ # Code quality and testing
40
+ test :
41
+ name : Test Suite
42
+ runs-on : ubuntu-latest
43
+ steps :
44
+ - name : Checkout
45
+ uses : actions/checkout@v4
46
+
47
+ - name : Setup Rust
48
+ uses : dtolnay/rust-toolchain@stable
33
49
with :
34
- components : rustfmt,clippy
35
-
36
- # - name: Rustfmt Check
37
- # uses: actions-rust-lang/rustfmt@v1
38
- # - run: cargo check --workspace
39
- # - uses: clechasseur/rs-clippy-check@main
40
- # with:
41
- # args: --all-features
42
- - run : cargo test --workspace --all-features
43
- - run : cargo build --workspace --all-targets --all-features
44
-
45
- - name : " Artifact upload"
46
- uses : actions/upload-artifact@master
50
+ components : rustfmt, clippy
51
+
52
+ - name : Cache dependencies
53
+ uses : Swatinem/rust-cache@v2
47
54
with :
48
- name : redproxy-rs_debug_${{github.sha}}
49
- path : target/debug/redproxy-rs
55
+ key : test-${{ hashFiles('**/Cargo.lock') }}
56
+
57
+ - name : Format check
58
+ run : cargo fmt --all -- --check
50
59
60
+ - name : Clippy check
61
+ run : cargo clippy --workspace --all-targets --all-features -- -D warnings
51
62
52
- build-corss :
53
- needs : build-dev
63
+ - name : Run tests
64
+ run : cargo test --workspace --all-features --verbose
65
+
66
+ - name : Build debug
67
+ run : cargo build --workspace --all-targets --all-features
68
+
69
+ - name : Upload debug artifact
70
+ uses : actions/upload-artifact@v4
71
+ with :
72
+ name : redproxy-rs-debug-${{ github.sha }}
73
+ path : target/debug/redproxy-rs
74
+ retention-days : 7
75
+
76
+ # Cross-platform release builds
77
+ build-cross :
78
+ needs : [security, test]
54
79
name : ${{ matrix.job.os }} (${{ matrix.job.target }})
55
80
runs-on : ${{ matrix.job.os }}
56
81
strategy :
@@ -62,150 +87,127 @@ jobs:
62
87
- { os: macos-latest, target: x86_64-apple-darwin }
63
88
- { os: windows-latest, target: x86_64-pc-windows-msvc }
64
89
steps :
65
- - name : Checkout source code
66
- uses : actions/checkout@v2
90
+ - name : Checkout
91
+ uses : actions/checkout@v4
67
92
68
- - uses : actions/cache@v4
93
+ - name : Setup Rust
94
+ uses : dtolnay/rust-toolchain@stable
69
95
with :
70
- path : |
71
- ~/.cargo/bin/
72
- ~/.cargo/registry/index/
73
- ~/.cargo/registry/cache/
74
- ~/.cargo/git/db/
75
- target/
76
- key : ${{ runner.os }}-${{ matrix.job.target }}-${{ hashFiles('**/Cargo.lock') }}
77
-
78
- - name : Install prerequisites
96
+ targets : ${{ matrix.job.target }}
97
+
98
+ - name : Cache dependencies
99
+ uses : Swatinem/rust-cache@v2
100
+ with :
101
+ key : release-${{ matrix.job.target }}-${{ hashFiles('**/Cargo.lock') }}
102
+
103
+ - name : Install cross-compilation tools
104
+ if : matrix.job.use-cross
105
+ run : cargo install cross --git https://github.com/cross-rs/cross
106
+
107
+ - name : Install system dependencies
108
+ if : matrix.job.os == 'ubuntu-latest' && !matrix.job.use-cross
79
109
shell : bash
80
110
run : |
81
111
case ${{ matrix.job.target }} in
82
- arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
83
- aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
112
+ aarch64-unknown-linux-gnu)
113
+ sudo apt-get update
114
+ sudo apt-get install -y gcc-aarch64-linux-gnu
115
+ ;;
84
116
esac
85
117
86
- - name : Extract crate information
118
+ - name : Extract project metadata
119
+ id : metadata
87
120
shell : bash
88
121
run : |
89
- echo "PROJECT_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
90
- echo "PROJECT_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
91
- echo "PROJECT_MAINTAINER=$(sed -n 's/^authors = \["\(.*\)"\]/\1/p' Cargo.toml)" >> $GITHUB_ENV
92
- echo "PROJECT_HOMEPAGE=$(sed -n 's/^homepage = "\(.*\)"/\1/p' Cargo.toml)" >> $GITHUB_ENV
93
-
94
- - name : Install target
95
- run : rustup target add ${{ matrix.job.target }}
96
-
97
- - name : Install cross
98
- if : ${{ matrix.job.use-cross }}
99
- shell : bash
100
- run : cargo install cross --force
101
-
102
- - name : Show version information (Rust, cargo, GCC)
122
+ cargo metadata --no-deps --format-version 1 | jq -r --arg id "$(cargo pkgid)" '.packages[] | select(.id == $id) | "name=\(.name)\nversion=\(.version)"' >> $GITHUB_OUTPUT
123
+
124
+ - name : Build release binary
103
125
shell : bash
104
126
run : |
105
- gcc --version || true
106
- rustup -V
107
- rustup toolchain list
108
- rustup default
109
- cargo -V
110
- rustc -V
111
-
112
- - if : ${{ ! matrix.job.use-cross }}
113
- run : cargo build --locked --release --target=${{ matrix.job.target }} --workspace --all-features
114
-
115
- - if : ${{ matrix.job.use-cross }}
116
- run : cross build --locked --release --target=${{ matrix.job.target }} --workspace --all-features
127
+ if [ "${{ matrix.job.use-cross }}" = "true" ]; then
128
+ cross build --locked --release --target=${{ matrix.job.target }} --workspace --all-features
129
+ else
130
+ cargo build --locked --release --target=${{ matrix.job.target }} --workspace --all-features
131
+ fi
117
132
118
- - name : Strip debug information from executable
119
- id : strip
133
+ - name : Prepare release artifacts
134
+ id : artifact
120
135
shell : bash
121
136
run : |
122
- # Figure out suffix of binary
123
- EXE_suffix=""
124
- case ${{ matrix.job.target }} in
125
- *-pc-windows-*) EXE_suffix=".exe" ;;
126
- esac;
127
- # Figure out what strip tool to use if any
128
- STRIP="strip"
129
- case ${{ matrix.job.target }} in
130
- arm-unknown-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
131
- aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
132
- *-pc-windows-msvc) STRIP="" ;;
133
- esac;
134
- # Setup paths
135
- BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/"
136
- mkdir -p "${BIN_DIR}"
137
- BIN_NAME="${PROJECT_NAME}${EXE_suffix}"
138
- BIN_PATH="${BIN_DIR}/${BIN_NAME}"
139
- # Copy the release build binary to the result location
140
- cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}"
141
- # Also strip if possible
142
- if [ -n "${STRIP}" ]; then
143
- "${STRIP}" "${BIN_PATH}"
137
+ # Determine file extension
138
+ if [[ "${{ matrix.job.target }}" == *"windows"* ]]; then
139
+ EXT=".exe"
140
+ ARCHIVE_EXT=".zip"
141
+ else
142
+ EXT=""
143
+ ARCHIVE_EXT=".tar.gz"
144
+ fi
145
+
146
+ BIN_NAME="${{ steps.metadata.outputs.name }}${EXT}"
147
+ PKG_NAME="${{ steps.metadata.outputs.name }}-v${{ steps.metadata.outputs.version }}-${{ matrix.job.target }}${ARCHIVE_EXT}"
148
+
149
+ # Copy and optionally strip binary
150
+ mkdir -p artifacts
151
+ cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "artifacts/"
152
+
153
+ # Strip debug symbols on Unix systems
154
+ if [[ "${{ matrix.job.target }}" != *"windows"* ]]; then
155
+ case "${{ matrix.job.target }}" in
156
+ aarch64-unknown-linux-gnu)
157
+ if command -v aarch64-linux-gnu-strip >/dev/null 2>&1; then
158
+ aarch64-linux-gnu-strip "artifacts/${BIN_NAME}"
159
+ fi
160
+ ;;
161
+ *)
162
+ strip "artifacts/${BIN_NAME}" 2>/dev/null || true
163
+ ;;
164
+ esac
165
+ fi
166
+
167
+ # Create archive
168
+ cd artifacts
169
+ if [[ "${{ matrix.job.target }}" == *"windows"* ]]; then
170
+ 7z a "../${PKG_NAME}" "${BIN_NAME}"
171
+ else
172
+ tar czf "../${PKG_NAME}" "${BIN_NAME}"
144
173
fi
145
- # Let subsequent steps know where to find the (stripped) bin
146
- echo ::set-output name=BIN_PATH::${BIN_PATH}
147
- echo ::set-output name=BIN_NAME::${BIN_NAME}
174
+ cd ..
175
+
176
+ echo "pkg_name=${PKG_NAME}" >> $GITHUB_OUTPUT
177
+ echo "pkg_path=${PKG_NAME}" >> $GITHUB_OUTPUT
148
178
149
- - name : Create tarball
150
- id : package
151
- shell : bash
152
- run : |
153
- PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
154
- PKG_BASENAME=${PROJECT_NAME}-v${PROJECT_VERSION}-${{ matrix.job.target }}
155
- PKG_NAME=${PKG_BASENAME}${PKG_suffix}
156
- echo ::set-output name=PKG_NAME::${PKG_NAME}
157
- PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
158
- ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
159
- mkdir -p "${ARCHIVE_DIR}"
160
- # Binary
161
- cp "${{ steps.strip.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
162
- # base compressed package
163
- pushd "${PKG_STAGING}/" >/dev/null
164
- case ${{ matrix.job.target }} in
165
- *-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;;
166
- *) tar czf "${PKG_NAME}" -C "${PKG_BASENAME}" "${{ steps.strip.outputs.BIN_NAME }}" ;;
167
- esac;
168
- popd >/dev/null
169
- # Let subsequent steps know where to find the compressed package
170
- echo ::set-output name=PKG_PATH::"${PKG_STAGING}/${PKG_NAME}"
171
-
172
- - name : " Artifact upload: tarball"
173
- uses : actions/upload-artifact@master
179
+ - name : Upload build artifacts
180
+ uses : actions/upload-artifact@v4
174
181
with :
175
- name : ${{ steps.package.outputs.PKG_NAME }}
176
- path : ${{ steps.package.outputs.PKG_PATH }}
177
-
178
- - name : Check for release
179
- id : is-release
180
- shell : bash
181
- run : |
182
- unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
183
- echo ::set-output name=IS_RELEASE::${IS_RELEASE}
182
+ name : ${{ steps.artifact.outputs.pkg_name }}
183
+ path : ${{ steps.artifact.outputs.pkg_path }}
184
+ retention-days : 30
184
185
185
- - name : Publish archives and packages
186
- uses : softprops/action-gh- release@v1
187
- if : steps.is- release.outputs.IS_RELEASE
186
+ - name : Upload to release
187
+ if : github.event_name == ' release'
188
+ uses : softprops/action-gh- release@v2
188
189
with :
189
- files : |
190
- ${{ steps.package.outputs.PKG_PATH }}
191
- env :
192
- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
190
+ files : ${{ steps.artifact.outputs.pkg_path }}
193
191
192
+ # Auto-merge dependabot PRs
194
193
dependabot :
195
- needs : [build-corss] # <-- important!
194
+ needs : [build-cross]
196
195
runs-on : ubuntu-latest
197
196
permissions :
198
197
pull-requests : write
199
198
contents : write
200
- if : ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}}
199
+ if : github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'
201
200
steps :
202
- - id : metadata
201
+ - name : Fetch dependabot metadata
202
+ id : metadata
203
203
uses : dependabot/fetch-metadata@v2
204
204
with :
205
- github-token : " ${{ secrets.GITHUB_TOKEN }}"
206
- - run : |
207
- gh pr review --approve "$PR_URL"
208
- gh pr merge --squash --auto "$PR_URL"
205
+ github-token : ${{ secrets.GITHUB_TOKEN }}
206
+
207
+ - name : Auto-approve and merge updates
209
208
env :
210
- PR_URL: ${{github.event.pull_request.html_url}}
211
- GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
209
+ PR_URL : ${{ github.event.pull_request.html_url }}
210
+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
211
+ run : |
212
+ gh pr review --approve "$PR_URL"
213
+ gh pr merge --auto --squash "$PR_URL"
0 commit comments