forked from hypothesis/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJenkinsfile
233 lines (198 loc) · 8.85 KB
/
Jenkinsfile
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!groovy
// `color` can be a color code or one of "good", "warning" or "danger".
// See https://www.jenkins.io/doc/pipeline/steps/slack/.
def postSlack(color, message) {
slackSend channel: "#eng-frontend", color: color, message: message
}
// Enable concurrent builds of this project to be throttled using the
// throttle-concurrents Jenkins plugin (https://plugins.jenkins.io/throttle-concurrents)
throttle(['client']) {
node {
checkout scm
workspace = pwd()
// Tag used when deploying to NPM.
npmTag = "latest"
// Git branch which releases are deployed from.
releaseFromBranch = "master"
// S3 bucket where the embedded client is served from.
s3Bucket = "cdn.hypothes.is"
// Pre-release suffix added to new package version number when deploying,
// eg. "testing".
//
// If this is empty, the new deployed version will become the live version.
//
// Note that once an npm package has been published with a given version,
// it is *not* possible to overwrite that version in future (eg. you cannot
// publish "v1.1-testing" twice).
versionSuffix = ""
if (versionSuffix != "") {
npmTag = "prerelease"
}
lastCommitHash = sh (
script: 'git show HEAD --no-patch --format="%h"',
returnStdout: true
).trim()
pkgName = sh (
script: 'cat package.json | jq -r .name',
returnStdout: true
).trim()
// Update local information about tags to match the remote,
// including removing any local tags that no longer exist.
//
// The `--prune-tags` option is not supported in Git 2.11 so we
// use the workaround from https://github.com/git/git/commit/97716d217c1ea00adfc64e4f6bb85c1236d661ff
sh "git fetch --quiet --prune origin 'refs/tags/*:refs/tags/*' "
// Determine version number for next release.
pkgVersion = sh (
script: 'git tag --list | sort --version-sort --reverse | head -n1 | tail -c +2',
returnStdout: true
).trim()
newPkgVersion = bumpMinorVersion(pkgVersion)
if (versionSuffix != "") {
newPkgVersion = newPkgVersion + "-" + versionSuffix
}
echo "Building and testing ${newPkgVersion}"
sh "docker build -t hypothesis-client-tests ."
nodeEnv = docker.image("hypothesis-client-tests")
stage('Setup') {
nodeEnv.inside("-e HOME=${workspace}") {
sh "yarn install"
}
}
stage('Test') {
nodeEnv.inside("-e HOME=${workspace}") {
withCredentials([
string(credentialsId: 'codecov-token', variable: 'CODECOV_TOKEN')
]) {
sh "make checkformatting lint test"
sh """
export CODECOV_TOKEN=${env.CODECOV_TOKEN}
yarn run report-coverage
"""
}
}
}
if (env.BRANCH_NAME != releaseFromBranch) {
echo "Skipping QA deployment because ${env.BRANCH_NAME} is not the ${releaseFromBranch} branch"
return
}
milestone()
stage('Publish to QA') {
postSlack 'good', "Starting QA deployment of ${lastCommitHash}"
try {
qaVersion = pkgVersion + "-${lastCommitHash}"
nodeEnv.inside("-e HOME=${workspace}") {
withCredentials([
string(credentialsId: 'npm-token', variable: 'NPM_TOKEN'),
usernamePassword(credentialsId: 'github-jenkins-user',
passwordVariable: 'GITHUB_TOKEN_NOT_USED',
usernameVariable: 'GITHUB_USERNAME'),
[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 's3-cdn']
]) {
sh """
git config --replace-all user.email ${env.GITHUB_USERNAME}@hypothes.is
git config --replace-all user.name ${env.GITHUB_USERNAME}
"""
// Build a prerelease version of the client, configured to load
// the sidebar from the qa h deployment.
sh """
export SIDEBAR_APP_URL=https://qa.hypothes.is/app.html
yarn version --no-git-tag-version --new-version ${qaVersion}
"""
// Deploy to S3, so the package can be served by
// https://qa.hypothes.is/embed.js.
//
// If we decide to build a QA browser extension using the QA
// client in future then we will need to deploy to npm as well.
sh """
export AWS_ACCESS_KEY_ID=${env.AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${env.AWS_SECRET_ACCESS_KEY}
scripts/deploy-to-s3.js --bucket ${s3Bucket} --tag qa --no-cache-entry
"""
}
}
postSlack 'good', "QA deployment of ${lastCommitHash} succeeded"
} catch (exc) {
postSlack 'danger', "QA deployment of ${lastCommitHash} failed"
throw exc
}
}
}
}
if (env.BRANCH_NAME != releaseFromBranch) {
echo "Skipping prod deployment because ${env.BRANCH_NAME} is not the ${releaseFromBranch} branch"
return
}
milestone()
stage('Publish') {
input(message: "Publish new client release?")
milestone()
node {
checkout scm
echo "Publishing ${pkgName} v${newPkgVersion} from ${releaseFromBranch} branch."
postSlack 'good', "Starting prod deployment of v${newPkgVersion} (${lastCommitHash})"
try {
nodeEnv.inside("-e HOME=${workspace} -e BRANCH_NAME=${env.BRANCH_NAME}") {
withCredentials([
string(credentialsId: 'npm-token', variable: 'NPM_TOKEN'),
usernamePassword(credentialsId: 'github-jenkins-user',
passwordVariable: 'GITHUB_TOKEN',
usernameVariable: 'GITHUB_USERNAME'),
[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 's3-cdn']
]) {
// Configure author for tag and auth credentials for pushing tag to GitHub.
// See https://git-scm.com/docs/git-credential-store.
sh """
git config --replace-all user.email ${env.GITHUB_USERNAME}@hypothes.is
git config --replace-all user.name ${env.GITHUB_USERNAME}
git config credential.helper store
echo https://${env.GITHUB_USERNAME}:${env.GITHUB_TOKEN}@github.com >> \$HOME/.git-credentials
"""
// Create and push a git tag.
sh "git tag v${newPkgVersion}"
sh "git push https://github.com/hypothesis/client.git v${newPkgVersion}"
sh "sleep 2" // Give GitHub a moment to realize the tag exists.
// Bump the package version and create the GitHub release.
sh """
export SIDEBAR_APP_URL=https://hypothes.is/app.html
yarn version --no-git-tag-version --new-version ${newPkgVersion}
"""
sh "scripts/create-github-release.js"
// Publish the updated package to the npm registry.
// Use `npm` rather than `yarn` for publishing.
// See https://github.com/yarnpkg/yarn/pull/3391.
sh "echo '//registry.npmjs.org/:_authToken=${env.NPM_TOKEN}' >> \$HOME/.npmrc"
sh "npm publish --tag ${npmTag}"
sh "scripts/wait-for-npm-release.sh ${npmTag}"
// Deploy the client to cdn.hypothes.is, where the embedded
// client is served from by https://hypothes.is/embed.js.
sh """
export AWS_ACCESS_KEY_ID=${env.AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${env.AWS_SECRET_ACCESS_KEY}
scripts/deploy-to-s3.js --bucket ${s3Bucket}
"""
}
}
postSlack 'good', "Prod deployment of v${newPkgVersion} (${lastCommitHash}) succeeded"
} catch (exc) {
postSlack 'danger', "Prod deployment of v${newPkgVersion} (${lastCommitHash}) failed"
throw exc
}
}
}
milestone()
stage('Update browser extension') {
build(job: 'browser-extension/master',
parameters: [
string(name: 'BUILD_TYPE', value: 'update-hypothesis-client')
])
}
// Increment the minor part of a `MAJOR.MINOR.PATCH` semver version.
String bumpMinorVersion(String version) {
def parts = version.tokenize('.')
if (parts.size() != 3) {
error "${version} is not a valid MAJOR.MINOR.PATCH version"
}
def newMinorVersion = parts[1].toInteger() + 1
return "${parts[0]}.${newMinorVersion}.${parts[2]}"
}