github.com/solo-io/cue@v0.4.7/internal/ci/workflows.cue (about) 1 // Copyright 2021 The CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ci 16 17 import ( 18 "github.com/SchemaStore/schemastore/src/schemas/json" 19 encjson "encoding/json" 20 ) 21 22 workflowsDir: *"./" | string @tag(workflowsDir) 23 24 _#masterBranch: "master" 25 _#releaseTagPattern: "v*" 26 27 workflows: [...{file: string, schema: (json.#Workflow & {})}] 28 workflows: [ 29 { 30 file: "test.yml" 31 schema: test 32 }, 33 { 34 file: "repository_dispatch.yml" 35 schema: repository_dispatch 36 }, 37 { 38 file: "release.yml" 39 schema: release 40 }, 41 { 42 file: "tip_triggers.yml" 43 schema: tip_triggers 44 }, 45 { 46 file: "new_version_triggers.yml" 47 schema: new_version_triggers 48 }, 49 { 50 file: "mirror.yml" 51 schema: mirror 52 }, 53 ] 54 55 test: _#bashWorkflow & { 56 57 name: "Test" 58 on: { 59 push: { 60 branches: ["**"] // any branch (including '/' namespaced branches) 61 "tags-ignore": [_#releaseTagPattern] 62 } 63 } 64 65 jobs: { 66 start: { 67 "runs-on": _#linuxMachine 68 steps: [...(_ & {if: "${{ \(_#isCLCITestBranch) }}"})] 69 steps: [ 70 _#writeCookiesFile, 71 _#startCLBuild, 72 ] 73 } 74 test: { 75 needs: "start" 76 strategy: _#testStrategy 77 "runs-on": "${{ matrix.os }}" 78 steps: [ 79 _#writeCookiesFile, 80 _#installGo, 81 _#checkoutCode, 82 _#cacheGoModules, 83 _#setGoBuildTags & { 84 _#tags: "long" 85 if: "${{ \(_#isMaster) }}" 86 }, 87 _#goGenerate, 88 _#goTest, 89 _#goTestRace & { 90 if: "${{ \(_#isMaster) || \(_#isCLCITestBranch) && matrix.go-version == '\(_#latestStableGo)' && matrix.os == '\(_#linuxMachine)' }}" 91 }, 92 _#goReleaseCheck, 93 _#checkGitClean, 94 _#pullThroughProxy, 95 _#failCLBuild, 96 ] 97 } 98 mark_ci_success: { 99 "runs-on": _#linuxMachine 100 if: "${{ \(_#isCLCITestBranch) }}" 101 needs: "test" 102 steps: [ 103 _#writeCookiesFile, 104 _#passCLBuild, 105 ] 106 } 107 delete_build_branch: { 108 "runs-on": _#linuxMachine 109 if: "${{ \(_#isCLCITestBranch) && always() }}" 110 needs: "test" 111 steps: [ 112 _#step & { 113 run: """ 114 \(_#tempCueckooGitDir) 115 git push https://github.com/cuelang/cue :${GITHUB_REF#\(_#branchRefPrefix)} 116 """ 117 }, 118 ] 119 } 120 } 121 122 // _#isCLCITestBranch is an expression that evaluates to true 123 // if the job is running as a result of a CL triggered CI build 124 _#isCLCITestBranch: "startsWith(github.ref, '\(_#branchRefPrefix)ci/')" 125 126 // _#isMaster is an expression that evaluates to true if the 127 // job is running as a result of a master commit push 128 _#isMaster: "github.ref == '\(_#branchRefPrefix+_#masterBranch)'" 129 130 _#pullThroughProxy: _#step & { 131 name: "Pull this commit through the proxy on \(_#masterBranch)" 132 run: """ 133 v=$(git rev-parse HEAD) 134 cd $(mktemp -d) 135 go mod init mod.com 136 GOPROXY=https://proxy.golang.org go get -d cuelang.org/go/cmd/cue@$v 137 """ 138 if: "${{ \(_#isMaster) }}" 139 } 140 141 _#startCLBuild: _#step & { 142 name: "Update Gerrit CL message with starting message" 143 run: (_#gerrit._#setCodeReview & { 144 #args: { 145 message: "Started the build... see progress at ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}" 146 } 147 }).res 148 } 149 150 _#failCLBuild: _#step & { 151 if: "${{ \(_#isCLCITestBranch) && failure() }}" 152 name: "Post any failures for this matrix entry" 153 run: (_#gerrit._#setCodeReview & { 154 #args: { 155 message: "Build failed for ${{ runner.os }}-${{ matrix.go-version }}; see ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }} for more details" 156 labels: { 157 "Code-Review": -1 158 } 159 } 160 }).res 161 } 162 163 _#passCLBuild: _#step & { 164 name: "Update Gerrit CL message with success message" 165 run: (_#gerrit._#setCodeReview & { 166 #args: { 167 message: "Build succeeded for ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}" 168 labels: { 169 "Code-Review": 1 170 } 171 } 172 }).res 173 } 174 175 _#gerrit: { 176 // _#setCodeReview assumes that it is invoked from a job where 177 // _#isCLCITestBranch is true 178 _#setCodeReview: { 179 #args: { 180 tag: "trybot" 181 message: string 182 labels?: { 183 "Code-Review": int 184 } 185 } 186 res: #""" 187 \#(_#curl) -H "Content-Type: application/json" --request POST --data '\#(encjson.Marshal(#args))' -b ~/.gitcookies https://cue-review.googlesource.com/a/changes/$(basename $(dirname $GITHUB_REF))/revisions/$(basename $GITHUB_REF)/review 188 """# 189 } 190 } 191 } 192 193 repository_dispatch: _#bashWorkflow & { 194 // These constants are defined by github.com/cue-sh/tools/cmd/cueckoo 195 _#runtrybot: "runtrybot" 196 _#mirror: "mirror" 197 _#importpr: "importpr" 198 _#unity: "unity" 199 200 _#dispatchJob: _#job & { 201 _#type: string 202 "runs-on": _#linuxMachine 203 if: "${{ github.event.client_payload.type == '\(_#type)' }}" 204 } 205 206 name: "Repository Dispatch" 207 on: ["repository_dispatch"] 208 jobs: { 209 "\(_#runtrybot)": _#dispatchJob & { 210 _#type: _#runtrybot 211 steps: [ 212 _#step & { 213 name: "Trigger trybot" 214 run: """ 215 \(_#tempCueckooGitDir) 216 git fetch https://cue-review.googlesource.com/cue ${{ github.event.client_payload.payload.ref }} 217 git checkout -b ci/${{ github.event.client_payload.payload.changeID }}/${{ github.event.client_payload.payload.commit }} FETCH_HEAD 218 git push https://github.com/cuelang/cue ci/${{ github.event.client_payload.payload.changeID }}/${{ github.event.client_payload.payload.commit }} 219 """ 220 }, 221 ] 222 } 223 "\(_#mirror)": _#dispatchJob & { 224 _#type: _#mirror 225 steps: _#copybaraSteps & {_ 226 _#name: "Mirror Gerrit to GitHub" 227 _#cmd: "github" 228 } 229 } 230 "\(_#importpr)": _#dispatchJob & { 231 _#type: _#importpr 232 steps: _#copybaraSteps & {_ 233 _#name: "Import PR #${{ github.event.client_payload.commit }} from GitHub to Gerrit" 234 _#cmd: "github-pr ${{ github.event.client_payload.payload.pr }}" 235 } 236 } 237 } 238 } 239 240 mirror: _#bashWorkflow & { 241 name: "Scheduled repo mirror" 242 on: 243 schedule: [{ 244 cron: "*/30 * * * *" // every 30 mins 245 }] 246 247 jobs: { 248 "mirror": { 249 "runs-on": _#linuxMachine 250 steps: _#copybaraSteps & {_ 251 _#name: "Mirror Gerrit to GitHub" 252 _#cmd: "github" 253 } 254 } 255 } 256 } 257 258 release: _#bashWorkflow & { 259 260 name: "Release" 261 on: push: tags: [_#releaseTagPattern] 262 jobs: { 263 goreleaser: { 264 "runs-on": _#linuxMachine 265 steps: [ 266 _#checkoutCode & { 267 with: "fetch-depth": 0 268 }, 269 _#installGo & { 270 with: version: _#latestStableGo 271 }, 272 _#step & { 273 name: "Run GoReleaser" 274 env: GITHUB_TOKEN: "${{ secrets.ACTIONS_GITHUB_TOKEN }}" 275 uses: "goreleaser/goreleaser-action@v2" 276 with: { 277 args: "release --rm-dist" 278 version: "v0.155.1" 279 } 280 }, 281 ] 282 } 283 docker: { 284 name: "docker" 285 "runs-on": _#linuxMachine 286 steps: [ 287 _#checkoutCode, 288 _#step & { 289 name: "Set version environment" 290 run: """ 291 CUE_VERSION=$(echo ${GITHUB_REF##refs/tags/v}) 292 echo \"CUE_VERSION=$CUE_VERSION\" 293 echo \"CUE_VERSION=$(echo $CUE_VERSION)\" >> $GITHUB_ENV 294 """ 295 }, 296 _#step & { 297 name: "Push to Docker Hub" 298 env: { 299 DOCKER_BUILDKIT: 1 300 GOLANG_VERSION: 1.14 301 CUE_VERSION: "${{ env.CUE_VERSION }}" 302 } 303 uses: "docker/build-push-action@v1" 304 with: { 305 tags: "${{ env.CUE_VERSION }},latest" 306 repository: "cuelang/cue" 307 username: "${{ secrets.DOCKER_USERNAME }}" 308 password: "${{ secrets.DOCKER_PASSWORD }}" 309 tag_with_ref: false 310 tag_with_sha: false 311 target: "cue" 312 always_pull: true 313 build_args: "GOLANG_VERSION=${{ env.GOLANG_VERSION }},CUE_VERSION=v${{ env.CUE_VERSION }}" 314 add_git_labels: true 315 } 316 }, 317 ] 318 } 319 } 320 } 321 322 tip_triggers: _#bashWorkflow & { 323 324 name: "Push to tip triggers" 325 on: push: branches: [_#masterBranch] 326 jobs: push: { 327 "runs-on": _#linuxMachine 328 steps: [ 329 { 330 name: "Rebuild tip.cuelang.org" 331 run: "\(_#curl) -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.CuelangOrgTipRebuildHook }}" 332 }, 333 { 334 name: "Trigger unity build" 335 run: #""" 336 \#(_#curl) -H "Content-Type: application/json" -u cueckoo:${{ secrets.CUECKOO_GITHUB_PAT }} --request POST --data-binary "{\"event_type\": \"Check against ${GITHUB_SHA}\", \"client_payload\": {\"type\": \"unity\", \"payload\": {\"versions\": \"\\\"commit:${GITHUB_SHA}\\\"\"}}}" https://api.github.com/repos/cue-sh/unity/dispatches 337 """# 338 }, 339 ] 340 } 341 } 342 343 new_version_triggers: _#bashWorkflow & { 344 345 name: "New release triggers" 346 on: push: tags: [_#releaseTagPattern] 347 jobs: push: { 348 "runs-on": _#linuxMachine 349 steps: [ 350 { 351 name: "Rebuild tip.cuelang.org" 352 run: #""" 353 \#(_#curl) -H "Content-Type: application/json" -u cueckoo:${{ secrets.CUECKOO_GITHUB_PAT }} --request POST --data-binary "{\"event_type\": \"Re-test post release of ${GITHUB_REF##refs/tags/}\"}" https://api.github.com/repos/cuelang/cuelang.org/dispatches 354 """# 355 }, 356 { 357 name: "Trigger unity build" 358 run: #""" 359 \#(_#curl) -H "Content-Type: application/json" -u cueckoo:${{ secrets.CUECKOO_GITHUB_PAT }} --request POST --data-binary "{\"event_type\": \"Check against CUE ${GITHUB_REF##refs/tags/}\", \"client_payload\": {\"type\": \"unity\", \"payload\": {\"versions\": \"\\\"${GITHUB_REF##refs/tags/}\\\"\"}}}" https://api.github.com/repos/cue-sh/unity/dispatches 360 """# 361 }, 362 ] 363 } 364 } 365 366 _#bashWorkflow: json.#Workflow & { 367 jobs: [string]: defaults: run: shell: "bash" 368 } 369 370 // TODO: drop when cuelang.org/issue/390 is fixed. 371 // Declare definitions for sub-schemas 372 _#job: ((json.#Workflow & {}).jobs & {x: _}).x 373 _#step: ((_#job & {steps: _}).steps & [_])[0] 374 375 // We need at least go1.14 for code generation 376 _#codeGenGo: "1.14.14" 377 378 // Use a specific latest version for release builds 379 _#latestStableGo: "1.15.8" 380 381 _#linuxMachine: "ubuntu-18.04" 382 _#macosMachine: "macos-10.15" 383 _#windowsMachine: "windows-2019" 384 385 _#testStrategy: { 386 "fail-fast": false 387 matrix: { 388 // Use a stable version of 1.14.x for go generate 389 "go-version": [_#codeGenGo, _#latestStableGo, "1.16"] 390 os: [_#linuxMachine, _#macosMachine, _#windowsMachine] 391 } 392 } 393 394 _#setGoBuildTags: _#step & { 395 _#tags: string 396 name: "Set go build tags" 397 run: """ 398 go env -w GOFLAGS=-tags=\(_#tags) 399 """ 400 } 401 402 _#installGo: _#step & { 403 name: "Install Go" 404 uses: "actions/setup-go@v2" 405 with: { 406 "go-version": *"${{ matrix.go-version }}" | string 407 stable: false 408 } 409 } 410 411 _#checkoutCode: _#step & { 412 name: "Checkout code" 413 uses: "actions/checkout@v2" 414 } 415 416 _#cacheGoModules: _#step & { 417 name: "Cache Go modules" 418 uses: "actions/cache@v1" 419 with: { 420 path: "~/go/pkg/mod" 421 key: "${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }}" 422 "restore-keys": """ 423 ${{ runner.os }}-${{ matrix.go-version }}-go- 424 """ 425 } 426 } 427 428 _#goGenerate: _#step & { 429 name: "Generate" 430 run: "go generate ./..." 431 // The Go version corresponds to the precise version specified in 432 // the matrix. Skip windows for now until we work out why re-gen is flaky 433 if: "matrix.go-version == '\(_#codeGenGo)' && matrix.os != '\(_#windowsMachine)'" 434 } 435 436 _#goTest: _#step & { 437 name: "Test" 438 run: "go test ./..." 439 } 440 441 _#goTestRace: _#step & { 442 name: "Test with -race" 443 run: "go test -race ./..." 444 } 445 446 _#goReleaseCheck: _#step & { 447 name: "gorelease check" 448 run: "go run golang.org/x/exp/cmd/gorelease" 449 } 450 451 _#checkGitClean: _#step & { 452 name: "Check that git is clean post generate and tests" 453 run: "test -z \"$(git status --porcelain)\" || (git status; git diff; false)" 454 } 455 456 _#writeCookiesFile: _#step & { 457 name: "Write the gitcookies file" 458 run: "echo \"${{ secrets.gerritCookie }}\" > ~/.gitcookies" 459 } 460 461 _#branchRefPrefix: "refs/heads/" 462 463 _#tempCueckooGitDir: """ 464 mkdir tmpgit 465 cd tmpgit 466 git init 467 git config user.name cueckoo 468 git config user.email cueckoo@gmail.com 469 git config http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n cueckoo:${{ secrets.CUECKOO_GITHUB_PAT }} | base64)" 470 """ 471 472 // The cueckoo/copybara Docker image to use 473 _#cueckooCopybaraImage: "cueckoo/copybara:afc4ae03eed00b0c9d7415141cd1b5dfa583da7c" 474 475 // Define the base command for copybara 476 _#copybaraCmd: { 477 _#cmd: string 478 #""" 479 cd _scripts 480 docker run --rm -v $PWD/cache:/root/copybara/cache -v $PWD:/usr/src/app --entrypoint="" \#(_#cueckooCopybaraImage) bash -c " \ 481 set -eu; \ 482 echo \"${{ secrets.gerritCookie }}\" > ~/.gitcookies; \ 483 chmod 600 ~/.gitcookies; \ 484 git config --global user.name cueckoo; \ 485 git config --global user.email cueckoo@gmail.com; \ 486 git config --global http.cookiefile \$HOME/.gitcookies; \ 487 echo https://cueckoo:${{ secrets.CUECKOO_GITHUB_PAT }}@github.com > ~/.git-credentials; \ 488 chmod 600 ~/.git-credentials; \ 489 java -jar /opt/copybara/copybara_deploy.jar migrate copy.bara.sky \#(_#cmd); \ 490 " 491 """# 492 } 493 494 _#copybaraSteps: { 495 _#name: string 496 _#cmd: string 497 let cmdCmd = _#cmd 498 [ 499 _#checkoutCode, // needed for copy.bara.sky file 500 _#step & { 501 name: _#name 502 run: _#copybaraCmd & {_, _#cmd: cmdCmd} 503 }, 504 ] 505 } 506 507 _#curl: "curl -f -s"