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"