cuelang.org/go@v0.13.0/internal/ci/github/trybot.cue (about)

     1  // Copyright 2022 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 github
    16  
    17  import (
    18  	"list"
    19  	"cue.dev/x/githubactions"
    20  )
    21  
    22  // The trybot workflow.
    23  workflows: trybot: _repo.bashWorkflow & {
    24  	name: _repo.trybot.name
    25  
    26  	on: {
    27  		push: {
    28  			branches: list.Concat([[_repo.testDefaultBranch], _repo.protectedBranchPatterns]) // do not run PR branches
    29  			"tags-ignore": [_repo.releaseTagPattern]
    30  		}
    31  		// Note that pull_request_target gives PR CI jobs full access to our secrets,
    32  		// which is necessary to fetch dependencies from the registry via NOTCUECKOO_CUE_TOKEN.
    33  		// Giving access to secrets is OK given that we must approve PR jobs to run on CI,
    34  		// which mirrors the approval workflow for CI on Gerrit.
    35  		pull_request_target: {}
    36  	}
    37  
    38  	jobs: {
    39  		test: {
    40  			strategy:  _testStrategy
    41  			"runs-on": "${{ matrix.runner }}"
    42  
    43  			let _setupGoActionsCaches = _repo.setupGoActionsCaches & {
    44  				#goVersion: goVersionVal
    45  				#os:        runnerOSVal
    46  				_
    47  			}
    48  
    49  			let installGo = _repo.installGo & {
    50  				#setupGo: with: "go-version": goVersionVal
    51  				_
    52  			}
    53  
    54  			// Only run the trybot workflow if we have the trybot trailer, or
    55  			// if we have no special trailers. Note this condition applies
    56  			// after and in addition to the "on" condition above.
    57  			if: "\(_repo.containsTrybotTrailer) || ! \(_repo.containsDispatchTrailer)"
    58  
    59  			steps: [
    60  				for v in _repo.checkoutCode {v},
    61  
    62  				for v in installGo {v},
    63  
    64  				// cachePre must come after installing Node and Go, because the cache locations
    65  				// are established by running each tool.
    66  				for v in _setupGoActionsCaches {v},
    67  
    68  				_repo.loginCentralRegistry,
    69  
    70  				_repo.earlyChecks & {
    71  					// These checks don't vary based on the Go version or OS,
    72  					// so we only need to run them on one of the matrix jobs.
    73  					if: _isLatestLinux
    74  				},
    75  				_goTest & {
    76  					if: "\(_repo.isProtectedBranch) || !\(_isLatestLinux)"
    77  				},
    78  				_goTestRace,
    79  				_goTest32bit,
    80  				_goTestWasm,
    81  				for v in _e2eTestSteps {v},
    82  				for v in _goChecks {v},
    83  				_checkTags,
    84  				// Run code generation towards the very end, to ensure it succeeds and makes no changes.
    85  				// Note that doing this before any Go tests or checks may lead to test cache misses,
    86  				// as Go uses modtimes to approximate whether files have been modified.
    87  				// Moveover, Go test failures on CI due to changed generated code are very confusing
    88  				// as the user might not notice that checkGitClean is also failing towards the end.
    89  				_goGenerate,
    90  				_repo.checkGitClean,
    91  			]
    92  		}
    93  	}
    94  
    95  	let runnerOS = "runner.os"
    96  	let runnerOSVal = "${{ \(runnerOS) }}"
    97  	let matrixRunner = "matrix.runner"
    98  	let goVersion = "matrix.go-version"
    99  	let goVersionVal = "${{ \(goVersion) }}"
   100  
   101  	_testStrategy: {
   102  		"fail-fast": false
   103  		matrix: {
   104  			"go-version": _repo.matrixGo
   105  			runner: [_repo.linuxMachine, _repo.macosMachine, _repo.windowsMachine]
   106  		}
   107  	}
   108  
   109  	// _isLatestLinux returns a GitHub expression that evaluates to true if the job
   110  	// is running on Linux with the latest version of Go. This expression is often
   111  	// used to run certain steps just once per CI workflow, to avoid duplicated
   112  	// work.
   113  	_isLatestLinux: "(\(goVersion) == '\(_repo.latestGo)' && \(matrixRunner) == '\(_repo.linuxMachine)')"
   114  
   115  	_goGenerate: githubactions.#Step & {
   116  		name: "Generate"
   117  		run:  "go generate ./..."
   118  		// The Go version corresponds to the precise version specified in
   119  		// the matrix. Skip windows for now until we work out why re-gen is flaky
   120  		if: _isLatestLinux
   121  	}
   122  
   123  	_goTest: githubactions.#Step & {
   124  		name: "Test"
   125  		run:  "go test ./..."
   126  	}
   127  
   128  	_e2eTestSteps: [... githubactions.#Step & {
   129  		// The end-to-end tests require a github token secret and are a bit slow,
   130  		// so we only run them on pushes to protected branches and on one
   131  		// environment in the source repo.
   132  		if: "github.repository == '\(_repo.githubRepositoryPath)' && (\(_repo.isProtectedBranch) || \(_repo.isTestDefaultBranch)) && \(_isLatestLinux)"
   133  	}] & [
   134  		// Two setup steps per the upstream docs:
   135  		// https://github.com/google-github-actions/setup-gcloud#service-account-key-json
   136  		{
   137  			name: "gcloud auth for end-to-end tests"
   138  			id:   "auth"
   139  			uses: "google-github-actions/auth@v2"
   140  			// E2E_GCLOUD_KEY is a key for the service account cue-e2e-ci,
   141  			// which has the Artifact Registry Repository Administrator role.
   142  			with: credentials_json: "${{ secrets.E2E_GCLOUD_KEY }}"
   143  		},
   144  		{
   145  			name: "gcloud setup for end-to-end tests"
   146  			uses: "google-github-actions/setup-gcloud@v2"
   147  		},
   148  		{
   149  			name: "End-to-end test"
   150  			env: {
   151  				// E2E_PORCUEPINE_CUE_TOKEN is a token generated on registry.cue.works
   152  				// as the GitHub porcuepine user, with description "e2e cue repo".
   153  				CUE_TEST_TOKEN: "${{ secrets.E2E_PORCUEPINE_CUE_TOKEN }}"
   154  			}
   155  			// Our regular tests run with both `go test ./...` and `go test -race ./...`.
   156  			// The end-to-end tests should only be run once, given the slowness and API rate limits.
   157  			// We want to catch any data races they spot as soon as possible, and they aren't CPU-bound,
   158  			// so running them only with -race seems reasonable.
   159  			run: """
   160  				cd internal/_e2e
   161  				go test -race
   162  				"""
   163  		},
   164  	]
   165  
   166  	_goChecks: [...githubactions.#Step & {
   167  		// These checks can vary between platforms, as different code can be built
   168  		// based on GOOS and GOARCH build tags.
   169  		// However, CUE does not have any such build tags yet, and we don't use
   170  		// dependencies that vary wildly between platforms.
   171  		// For now, to save CI resources, just run the checks on one matrix job.
   172  		if: _isLatestLinux
   173  	}] & [
   174  		{
   175  			name: "Go checks"
   176  			// Also ensure that the end-to-end tests in ./internal/_e2e, which are only run
   177  			// on pushes to protected branches, still build correctly before merging.
   178  			//
   179  			// TODO: consider adding more checks as per https://github.com/golang/go/issues/42119.
   180  			run: """
   181  				go vet ./...
   182  				go mod tidy
   183  				(cd internal/_e2e && go test -run=-)
   184  				"""
   185  		}, {
   186  			name: "staticcheck"
   187  			// TODO(mvdan): once we can do 'go tool staticcheck' with Go 1.24+,
   188  			// then using this action is probably no longer worthwhile.
   189  			// Note that we should then persist staticcheck's cache too.
   190  			uses: "dominikh/staticcheck-action@v1"
   191  			with: {
   192  				version:      "2025.1" // Pin a version for determinism.
   193  				"install-go": false    // We install Go ourselves.
   194  			}
   195  		},
   196  	]
   197  
   198  	_checkTags: githubactions.#Step & {
   199  		// Ensure that GitHub and Gerrit agree on the full list of available tags.
   200  		// This way, if there is any discrepancy, we will get a useful go-cmp diff.
   201  		//
   202  		// We use `git ls-remote` to list all tags from each remote git repository
   203  		// because it does not depend on custom REST API endpoints and is very fast.
   204  		// Note that it sorts tag names as strings, which is not the best, but works OK.
   205  		if:   _isLatestLinux
   206  		name: "Check all git tags are available"
   207  		run: """
   208  			cd $(mktemp -d)
   209  
   210  			git ls-remote --tags https://github.com/cue-lang/cue >github.txt
   211  			echo "GitHub tags:"
   212  			sed 's/^/    /' github.txt
   213  
   214  			git ls-remote --tags https://review.gerrithub.io/cue-lang/cue >gerrit.txt
   215  
   216  			if ! diff -u github.txt gerrit.txt; then
   217  				echo "GitHub and Gerrit do not agree on the list of tags!"
   218  				echo "Did you forget about refs/attic branches? https://github.com/cue-lang/cue/wiki/Notes-for-project-maintainers"
   219  				exit 1
   220  			fi
   221  			"""
   222  	}
   223  
   224  	_goTestRace: githubactions.#Step & {
   225  		// Windows and Mac on CI are slower than Linux, and most data races are not specific
   226  		// to any OS or Go version in particular, so only run all tests with -race on Linux
   227  		// to not slow down CI unnecessarily.
   228  		if:   _isLatestLinux
   229  		name: "Test with -race"
   230  		env: GORACE: "atexit_sleep_ms=10" // Otherwise every Go package being tested sleeps for 1s; see https://go.dev/issues/20364.
   231  		run: "go test -race ./..."
   232  	}
   233  
   234  	_goTest32bit: githubactions.#Step & {
   235  		// Ensure that the entire build and all tests succeed on a 32-bit platform as well.
   236  		// This should catch if any of the code or test cases rely on bit sizes,
   237  		// such as int being 64 bits, which could cause portability bugs for 32-bit platforms.
   238  		// While GOARCH=386 isn't particularly popular anymore, it can run on an amd64 machine,
   239  		// and the Linux runners on GitHub Actions use amd64.
   240  		//
   241  		// Running just the short tests is enough for now.
   242  		if:   _isLatestLinux
   243  		name: "Test on 32 bits"
   244  		env: GOARCH: "386"
   245  		run: "go test -short ./..."
   246  	}
   247  
   248  	_goTestWasm: githubactions.#Step & {
   249  		name: "Test with -tags=cuewasm"
   250  		// The wasm interpreter is only bundled into cmd/cue with the cuewasm build tag.
   251  		// Test the related packages with the build tag enabled as well.
   252  		run: "go test -tags cuewasm ./cmd/cue/cmd ./cue/interpreter/wasm"
   253  	}
   254  }