-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJenkinsFile
More file actions
182 lines (179 loc) · 5.33 KB
/
JenkinsFile
File metadata and controls
182 lines (179 loc) · 5.33 KB
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
@Library('AdminAppsSharedLibrary') _
def copyOperations = [
[
source: ".\\web\\bin\\Release\\net10.0\\publish",
testDestination: "%vipertestnet%",
prodDestination: "%viperprodnet%",
includeFiles: "*.*",
excludeFiles: "",
excludeDirectories: ""
]
]
def copyOfflineOperations = [
[
source: ".",
testDestination: "%vipertestnet%",
prodDestination: "%viperprodnet%",
includeFiles: "app_offline.htm",
excludeFiles: "",
excludeDirectories: ""
]
]
pipeline {
agent any
tools { nodejs "NodeJS 24.14.1" }
options {
skipStagesAfterUnstable()
skipDefaultCheckout()
}
stages {
stage('Clean Previous Build') {
steps {
checkout([$class: 'GitSCM',
branches: scm.branches,
extensions: [],
userRemoteConfigs: scm.userRemoteConfigs])
script {
if (params.ClearCache) {
echo 'ClearCache enabled - performing full clean (including node_modules)'
bat 'git reset --hard && git clean -fdx'
} else {
echo 'Preserving caches (node_modules with .tsbuildinfo inside)'
bat 'git reset --hard && git clean -fdx -e VueApp/node_modules/'
}
}
}
}
stage('Restore packages') {
steps {
script {
parallel(
npm: {
bat 'pushd VueApp && npm install --prefer-offline --no-audit --no-fund && popd'
catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
bat 'npm audit --prefix VueApp --omit=dev --audit-level=high'
}
},
dotnet: {
bat '"C:\\Program Files\\dotnet\\dotnet" tool restore'
bat 'pushd web && "C:\\Program Files\\dotnet\\dotnet" tool run libman restore && popd'
bat '"C:\\Program Files\\dotnet\\dotnet" restore Viper.sln'
}
)
}
}
}
stage('Build for test') {
when {
expression { params.Branch == 'Development' }
}
steps {
bat 'npm run --prefix VueApp build-test'
bat '"C:\\Program Files\\dotnet\\dotnet" publish ./web/Viper.csproj -c "Release" /p:EnvironmentName=Test --nologo -v:minimal'
}
}
stage('Build for prod') {
when {
expression { params.Branch == 'master' || params.Branch == "main" }
}
steps {
bat 'npm run --prefix VueApp build'
bat '"C:\\Program Files\\dotnet\\dotnet" publish ./web/Viper.csproj -c "Release" /p:EnvironmentName=Production --nologo -v:minimal'
}
}
stage('Tests') {
steps {
bat 'type NUL > app_offline.htm'
script {
parallel(
backend: {
bat '"C:\\Program Files\\dotnet\\dotnet" test ./test/Viper.test.csproj -e Test --logger "junit" --configuration release --nologo'
},
frontend: {
bat 'npm run --prefix VueApp test:run'
}
)
}
}
}
stage('Deploy to test') {
environment {
NETWORK_SHARE_CRED = credentials('ViperNetworkShare')
}
when {
expression { params.Branch == 'Development' }
}
steps {
networkShares()
filecopy copyOfflineOperations, 'test', env.WORKSPACE
filecopy copyOperations, 'test', env.WORKSPACE
powershell label: 'Verify /health returns 200', script: '''
$url = "https://secure-test.vetmed.ucdavis.edu/2/health"
$maxAttempts = 15
for ($i = 1; $i -le $maxAttempts; $i++) {
# 2s for the first few attempts then 4s - absorbs IIS app-pool warm-up
$delay = if ($i -le 5) { 2 } else { 4 }
try {
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
if ($response.StatusCode -eq 200) {
Write-Host "Attempt ${i}: $url returned 200 OK"
exit 0
}
Write-Host "Attempt ${i}: $url returned $($response.StatusCode)"
} catch {
Write-Host "Attempt ${i}: $($_.Exception.Message)"
}
if ($i -lt $maxAttempts) { Start-Sleep -Seconds $delay }
}
Write-Error "Health check at $url failed after $maxAttempts attempts"
exit 1
'''
}
}
stage('Deploy to prod') {
environment {
NETWORK_SHARE_CRED = credentials('ViperNetworkShare')
}
when {
expression { params.Branch == 'master' || params.Branch == "main" }
}
steps {
networkShares()
filecopy copyOfflineOperations, 'prod', env.WORKSPACE
filecopy copyOperations, 'prod', env.WORKSPACE
powershell label: 'Verify /health returns 200', script: '''
$url = "https://secure.vetmed.ucdavis.edu/2/health"
$maxAttempts = 15
for ($i = 1; $i -le $maxAttempts; $i++) {
$delay = if ($i -le 5) { 2 } else { 4 }
try {
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
if ($response.StatusCode -eq 200) {
Write-Host "Attempt ${i}: $url returned 200 OK"
exit 0
}
Write-Host "Attempt ${i}: $url returned $($response.StatusCode)"
} catch {
Write-Host "Attempt ${i}: $($_.Exception.Message)"
}
if ($i -lt $maxAttempts) { Start-Sleep -Seconds $delay }
}
Write-Error "Health check at $url failed after $maxAttempts attempts"
exit 1
'''
}
}
}
post {
always {
//Run junit on the test report to build output
script {
if(fileExists('test/TestResults/TestResults.xml')) {
junit testResults: 'test/TestResults/TestResults.xml', skipPublishingChecks: true
}
}
//Archive the artifacts - in this case, all files - so that the restore job can re-deploy them.
archiveArtifacts artifacts: 'web/bin/Release/net10.0/publish/**/*', fingerprint: true, onlyIfSuccessful: true
}
}
}