1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Jenkins Job Configuration Requirements:
// - Multibranch Pipeline: Add "Discover tags" behavior in Branch Sources → Git → Behaviors
// - Or configure GitHub webhook to trigger builds on tag push events
// - The "Package & Release" and "Publish to crates.io" stages only run when building tags
// - Windows cross-compilation requires: mingw-w64 (gcc + g++), rustup target x86_64-pc-windows-gnu
// - macOS builds are handled by GitHub Actions (.github/workflows/macos-release.yml)
pipeline {
agent any
environment {
CARGO_HOME = "${env.HOME}/.cargo"
RUSTUP_HOME = "${env.HOME}/.rustup"
PATH = "/usr/local/bin:${env.HOME}/.cargo/bin:${env.PATH}"
REPO = 'rileyseaburg/codetether-agent'
BINARY_NAME = 'codetether'
// sccache backed by MinIO S3
RUSTC_WRAPPER = 'sccache'
SCCACHE_BUCKET = 'sccache'
SCCACHE_ENDPOINT = 'http://192.168.50.223:9000'
SCCACHE_REGION = 'us-east-1'
SCCACHE_S3_KEY_PREFIX = 'codetether'
SCCACHE_S3_USE_SSL = 'false'
}
options {
timestamps()
timeout(time: 60, unit: 'MINUTES')
disableConcurrentBuilds()
}
stages {
stage('Checkout') {
steps {
checkout scm
// Clean stale .cargo from workspace (CARGO_HOME is now $HOME/.cargo)
sh 'rm -rf "${WORKSPACE}/.cargo"'
}
}
stage('Build') {
parallel {
stage('Linux x86_64') {
steps {
withCredentials([
string(credentialsId: 'minio-access-key', variable: 'AWS_ACCESS_KEY_ID'),
string(credentialsId: 'minio-secret-key', variable: 'AWS_SECRET_ACCESS_KEY')
]) {
sh '''
rustc --version
sccache --start-server 2>/dev/null || true
sccache --show-stats 2>&1 | grep "Cache location" || true
cargo build --release --features functiongemma
echo "=== sccache stats ==="
sccache --show-stats || true
'''
}
}
}
stage('Windows x86_64') {
steps {
withCredentials([
string(credentialsId: 'minio-access-key', variable: 'AWS_ACCESS_KEY_ID'),
string(credentialsId: 'minio-secret-key', variable: 'AWS_SECRET_ACCESS_KEY')
]) {
sh '''
echo "Cross-compiling for Windows..."
cargo build --target x86_64-pc-windows-gnu --release --features functiongemma
'''
}
}
}
}
}
stage('Package & Release') {
when {
buildingTag()
}
steps {
script {
env.VERSION = env.TAG_NAME
}
sh """
mkdir -p dist
# Linux x86_64
LINUX_ARTIFACT="${BINARY_NAME}-${VERSION}-x86_64-unknown-linux-gnu"
cp target/release/${BINARY_NAME} "dist/\${LINUX_ARTIFACT}"
cd dist && tar czf "\${LINUX_ARTIFACT}.tar.gz" "\${LINUX_ARTIFACT}" && cd ..
# Windows x86_64
WIN_ARTIFACT="${BINARY_NAME}-${VERSION}-x86_64-pc-windows-gnu.exe"
cp target/x86_64-pc-windows-gnu/release/${BINARY_NAME}.exe "dist/\${WIN_ARTIFACT}"
cd dist && tar czf "\${WIN_ARTIFACT%.exe}.tar.gz" "\${WIN_ARTIFACT}" && cd ..
# Checksums for all artifacts
cd dist && sha256sum *.tar.gz *.exe > SHA256SUMS-${VERSION}.txt && cd ..
"""
archiveArtifacts artifacts: 'dist/*.tar.gz, dist/*.exe, dist/SHA256SUMS-*.txt', fingerprint: true
withCredentials([string(credentialsId: 'github-token', variable: 'GH_TOKEN')]) {
sh """
# Extract release notes from annotated tag (generated by release.sh via codetether)
TAG_BODY=\$(git tag -l --format='%(contents:body)' ${env.TAG_NAME} 2>/dev/null || echo '')
if [ -n "\$TAG_BODY" ]; then
echo "\$TAG_BODY" > /tmp/release-notes.md
NOTES_FLAG="--notes-file /tmp/release-notes.md"
else
NOTES_FLAG="--generate-notes"
fi
gh release create ${env.TAG_NAME} \
dist/*.tar.gz \
dist/*.exe \
dist/SHA256SUMS-${VERSION}.txt \
--repo ${REPO} \
--title "${env.TAG_NAME} - CodeTether Agent" \
\$NOTES_FLAG \
--latest \
--verify-tag || \
gh release upload ${env.TAG_NAME} \
dist/*.tar.gz \
dist/*.exe \
dist/SHA256SUMS-${VERSION}.txt \
--repo ${REPO} --clobber
"""
}
}
}
stage('Publish to crates.io') {
when {
buildingTag()
}
steps {
withCredentials([
string(credentialsId: 'cargo-registry-token', variable: 'CARGO_REGISTRY_TOKEN'),
string(credentialsId: 'minio-access-key', variable: 'AWS_ACCESS_KEY_ID'),
string(credentialsId: 'minio-secret-key', variable: 'AWS_SECRET_ACCESS_KEY')
]) {
sh '''
echo "Publishing ${TAG_NAME} to crates.io ..."
cargo publish --allow-dirty --features functiongemma
'''
}
}
}
}
post {
success {
echo "Build successful: ${env.TAG_NAME ?: env.BRANCH_NAME}"
}
failure {
echo "Build failed: ${env.TAG_NAME ?: env.BRANCH_NAME}"
}
}
}