diff --git a/.github/workflows/build-k0s.yml b/.github/workflows/build-k0s.yml index c3dd9912d4b2..f63bdbf682f1 100644 --- a/.github/workflows/build-k0s.yml +++ b/.github/workflows/build-k0s.yml @@ -58,34 +58,35 @@ jobs: echo executable-suffix="$executableSuffix" >>"$GITHUB_OUTPUT" - name: "Cache :: embedded binaries" + id: cache-embedded-bins uses: actions/cache@v4 with: - key: build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-embedded-bins-${{ hashFiles('embedded-bins/**/*') }} - path: | - .bins.${{ inputs.target-os }}.stamp - bindata_${{ inputs.target-os }} - embedded-bins/staging/${{ inputs.target-os }}/bin/ - embedded-bins/Makefile.variables - pkg/assets/zz_generated_offsets_${{ inputs.target-os }}.go + key: "build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-embedded-bins-${{ hashFiles('embedded-bins/**/*') }}" + path: embedded-bins/staging/${{ inputs.target-os }}/bin/ - - name: "Cache :: GOCACHE" + - name: "Cache :: Go cache" + id: cache-gocache uses: actions/cache@v4 with: - key: build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-gocache-${{ github.ref_name }}-${{ github.sha }} - restore-keys: | - build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-gocache-${{ github.ref_name }}- - path: | - build/cache/go/build + key: "build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-gocache-go${{ env.GO_VERSION }}-${{ github.sha }}" + restore-keys: "build-k0s-${{ inputs.target-os }}-${{ inputs.target-arch }}-gocache-go${{ env.GO_VERSION }}-" + path: build/cache/go/build - - name: "Cache :: GOMODCACHE" - uses: actions/cache@v4 - with: - key: build-k0s-gomodcache-${{ hashFiles('go.sum') }} - path: build/cache/go/mod - enableCrossOsArchive: true + - name: "Cache :: Go cache :: Prepare" + if: steps.cache-gocache.outputs.cache-hit + run: | + touch -t "$(TZ=UTC+24 date +%Y%m%d%H%M.%S)" build/cache/_cache_sentinel + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -exec touch -r build/cache/_cache_sentinel {} + - name: "Build :: k0s" + env: + EMBEDDED_BINS_CACHED: "${{ steps.cache-embedded-bins.outputs.cache-hit }}" run: | + make .k0sbuild.docker-image.k0s + touch go.sum + if [ "$EMBEDDED_BINS_CACHED" == true ]; then + make --touch ".bins.$TARGET_OS.stamp" + fi make bindata make --touch codegen make build @@ -119,3 +120,8 @@ jobs: with: name: ipv6-test-image-list-${{ inputs.target-os }}-${{ inputs.target-arch }} path: ipv6-test-images.txt + + - name: "Cache :: Go cache :: Trim" + if: steps.cache-gocache.outputs.cache-hit + run: | + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -not -newer build/cache/_cache_sentinel -delete diff --git a/.github/workflows/go-completed.yaml b/.github/workflows/go-completed.yaml new file mode 100644 index 000000000000..c6ea8958f9f9 --- /dev/null +++ b/.github/workflows/go-completed.yaml @@ -0,0 +1,46 @@ +name: Go build completed + +on: + workflow_run: + workflows: [Go build] + types: [completed] + +jobs: + # Based on https://github.com/actions/cache/blob/v4.2.0/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy + cleanup-actions-caches: + name: Cleanup GitHub Actions caches + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + + steps: + # Group all caches that end with a Git commit hash by branch and keep only the most recently created one. + - name: Cleanup + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + GH_REPO: "${{ github.repository }}" + QUERY: | + [ .actions_caches[] + | . + { key_prefix: .key | sub("-[0-9a-f]{40}$"; "") } # Calculate cache prefix + | select(.key_prefix != .key) # Only keep caches which have the right suffix + ] + | [ + group_by([.ref, .key_prefix])[] # Look at all the caches per branch with the same prefix + | sort_by(.created_at) # Sort by creation date ... + | reverse # ... so that the newest cache is the first in the array + | del(.[0]) # Remove that newest cache, i.e. don't delete it + ] + | flatten # Remove the grouping + | .[] # Unpack the resulting flat array + | [.id, .ref, .key] # Extract the values to be returned + | @sh # Escape them to be used in POSIX shells + + run: | + set -euo pipefail + gh api -X GET repos/{owner}/{repo}/actions/caches -q "$QUERY" | while read -r args; do + eval "set -- $args" + echo Deleting cache with id "$1" from "$2": "$3" + gh api -X DELETE repos/{owner}/{repo}/actions/caches/"$1" || : + done diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index dc01a868b2bb..f9ab03e0ecb4 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -178,6 +178,8 @@ jobs: env: EMBEDDED_BINS_BUILDMODE: none + # Set SOURCE_DATE_EPOCH to optimize cache usage + MAKEFLAGS: -j SOURCE_DATE_EPOCH=315532800 steps: - name: Check out code into the Go module directory @@ -208,24 +210,30 @@ jobs: go-version: ${{ env.GO_VERSION }} cache: false - - name: Cache GOCACHE + - name: Cache Go cache + id: cache-gocache uses: actions/cache@v4 with: - key: unittests-k0s-${{ matrix.name }}-gocache-${{ github.ref_name }}-${{ github.sha }} - restore-keys: | - unittests-k0s-${{ matrix.name }}-gocache-${{ github.ref_name }}- - path: | - build/cache/go/build - - - name: Cache GOMODCACHE - uses: actions/cache@v4 - with: - key: unittests-k0s-gomodcache-${{ hashFiles('go.sum') }} - path: build/cache/go/mod - enableCrossOsArchive: true + key: "unittests-k0s-${{ matrix.name }}-gocache-go${{ env.GO_VERSION }}-${{ github.sha }}" + restore-keys: "unittests-k0s-${{ matrix.name }}-gocache-go${{ env.GO_VERSION }}-" + path: build/cache/go/build - name: Run unit tests - run: make check-unit $UNITTEST_EXTRA_ARGS + env: + CACHE_HIT_GOCACHE: "${{ steps.cache-gocache.outputs.cache-hit }}" + run: | + if [ -n "$CACHE_HIT_GOCACHE" ]; then + echo Preparing Go cache + touch -t "$(TZ=UTC+24 date +%Y%m%d%H%M.%S)" build/cache/_cache_sentinel + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -exec touch -r build/cache/_cache_sentinel {} + + fi + + make check-unit $UNITTEST_EXTRA_ARGS + + if [ -n "$CACHE_HIT_GOCACHE" ]; then + echo Trimming Go cache + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -not -newer build/cache/_cache_sentinel -delete + fi smoketests: strategy: @@ -308,35 +316,40 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Cache embedded binaries + id: cache-embedded-bins uses: actions/cache@v4 with: - key: ${{ runner.os }}-embedded-bins-arm-${{ hashFiles('**/embedded-bins/**/*') }} - path: | - .bins.linux.stamp - embedded-bins/staging/linux/bin/ - embedded-bins/Makefile.variables + key: "build-k0s-linux-arm-embedded-bins-${{ hashFiles('embedded-bins/**/*') }}" + path: embedded-bins/staging/linux/bin/ - - name: Cache GOCACHE + - name: Cache Go cache + id: cache-gocache uses: actions/cache@v4 with: - key: ${{ runner.os }}-smoketest-arm-gocache-arm-${{ github.ref_name }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-smoketest-arm-gocache-arm-${{ github.ref_name }}- - path: | - build/cache/go/build + key: "build-k0s-linux-arm-gocache-go${{ env.GO_VERSION }}-${{ github.sha }}" + restore-keys: "build-k0s-linux-arm-gocache-go${{ env.GO_VERSION }}-" + path: build/cache/go/build - - name: Cache GOMODCACHE - uses: actions/cache@v4 - with: - key: ${{ runner.os }}-smoketest-arm-gomodcache-arm-${{ hashFiles('go.sum') }} - path: | - build/cache/go/mod + - name: Prepare Go cache + if: steps.cache-gocache.outputs.cache-hit + run: | + touch -t "$(TZ=UTC+24 date +%Y%m%d%H%M.%S)" build/cache/_cache_sentinel + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -exec touch -r build/cache/_cache_sentinel {} + - name: Build + env: + EMBEDDED_BINS_CACHED: "${{ steps.cache-embedded-bins.outputs.cache-hit }}" run: | + gh --version || echo No gh installed + make .k0sbuild.docker-image.k0s + touch go.sum + if [ "$EMBEDDED_BINS_CACHED" == true ]; then + make --touch .bins.linux.stamp + fi make bindata make --touch codegen make build + echo "k0s binary size: **$(du -sh k0s | cut -f1)**" >>$GITHUB_STEP_SUMMARY - name: Upload compiled executable uses: actions/upload-artifact@v4 @@ -369,6 +382,11 @@ jobs: name: airgap-image-bundle-linux-arm.tar path: airgap-image-bundle-linux-arm.tar + - name: Trim Go cache + if: steps.cache-gocache.outputs.cache-hit + run: | + find build/cache/go/build -type f \( -name '*-a' -o -name '*-d' \) -not -newer build/cache/_cache_sentinel -delete + # TODO We probably want to separate the smoketest into a separate callable workflow which we can call from the build step # This way we could actually fully parallelize the build and smoketest steps. Currently we are limited by the fact that # smoke-test step only start after both arm and armv7 builds have finished. diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 5cf1e463755c..92d9f0a33836 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -30,6 +30,9 @@ env: MAKEFLAGS: -j EMBEDDED_BINS_BUILDMODE: none +permissions: + contents: read + jobs: lint-go: strategy: @@ -67,26 +70,33 @@ jobs: go-version: ${{ env.GO_VERSION }} cache: false - - name: "Cache :: golangci-lint" + - name: Cache golangci-lint cache + id: cache-golangci uses: actions/cache@v4 with: - key: lint-${{ matrix.target-os }}-amd64-golangci-${{ github.ref_name }}-${{ github.sha }} + key: "lint-${{ matrix.target-os }}-amd64-golangci-${{ env.GOLANGCI_LINT_VERSION }}-go-${{ env.GO_VERSION }}-${{ github.sha }}" restore-keys: | - lint-${{ matrix.target-os }}-amd64-golangci-${{ github.ref_name }}- - lint-${{ matrix.target-os }}-amd64-golangci-main- + lint-${{ matrix.target-os }}-amd64-golangci-${{ env.GOLANGCI_LINT_VERSION }}-go-${{ env.GO_VERSION }}- path: | build/cache/go/build build/cache/golangci-lint - - name: "Cache :: GOMODCACHE" - uses: actions/cache/restore@v4 - with: - key: build-k0s-gomodcache-${{ hashFiles('go.sum') }} - path: build/cache/go/mod - enableCrossOsArchive: true - - name: Run linter - run: make lint-go $MAKE_EXTRA_ARGS + env: + CACHE_HIT_GOLANGCI: "${{ steps.cache-golangci.outputs.cache-hit }}" + run: | + if [ -n "$CACHE_HIT_GOLANGCI" ]; then + echo Preparing golangci-lint cache + touch -t "$(TZ=UTC+24 date +%Y%m%d%H%M.%S)" build/cache/_cache_sentinel + find build/cache/go/build build/cache/golangci-lint -type f \( -name '*-a' -o -name '*-d' \) -exec touch -r build/cache/_cache_sentinel {} + + fi + + make lint-go $MAKE_EXTRA_ARGS + + if [ -n "$CACHE_HIT_GOLANGCI" ]; then + echo Trimming golangci-lint cache + find build/cache/go/build build/cache/golangci-lint -type f \( -name '*-a' -o -name '*-d' \) -not -newer build/cache/_cache_sentinel -delete + fi lint-codegen: name: Lint generated code @@ -95,23 +105,18 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + preserve-credentials: false - - name: "Cache :: GOCACHE" - uses: actions/cache/restore@v4 - with: - key: build-k0s-linux-amd64-gocache-${{ github.ref_name }}-${{ github.sha }} - restore-keys: | - build-k0s-linux-amd64-gocache-${{ github.ref_name }}- - build-k0s-linux-amd64-gocache-main- - path: | - build/cache/go/build + - name: Prepare build environment + run: .github/workflows/prepare-build-env.sh - - name: "Cache :: GOMODCACHE" + - name: Restore Go cache uses: actions/cache/restore@v4 with: - key: build-k0s-gomodcache-${{ hashFiles('go.sum') }} - path: build/cache/go/mod - enableCrossOsArchive: true + key: "build-k0s-linux-amd64-gocache-go${{ env.GO_VERSION }}-${{ github.sha }}" + restore-keys: | + build-k0s-linux-amd64-gocache-go${{ env.GO_VERSION }}- + path: build/cache/go/build - name: Check go.mod/go.sum to be consistent run: make --always-make go.sum && git diff --exit-code diff --git a/.github/workflows/ostests-nightly.yaml b/.github/workflows/ostests-nightly.yaml index 8863074d3cbd..4741b2cf6bdb 100644 --- a/.github/workflows/ostests-nightly.yaml +++ b/.github/workflows/ostests-nightly.yaml @@ -134,7 +134,7 @@ jobs: # Message format described here: https://api.slack.com/surfaces/messages#payloads # The block structure can be tested online: https://app.slack.com/block-kit-builder run: | - gh api "/repos/{owner}/{repo}/actions/runs/$GITHUB_RUN_ID/jobs" -q ' + gh api "repos/{owner}/{repo}/actions/runs/$GITHUB_RUN_ID/jobs" -q ' def fmt_duration: if . >= 3600 then "\(./3600|floor) h \((.%3600/60|floor)) min" elif . >= 60 then "\(./60|floor) min \(.%60) sec" diff --git a/.github/workflows/pr-closed.yaml b/.github/workflows/pr-closed.yaml index 8f8601b33c21..03e77421ec85 100644 --- a/.github/workflows/pr-closed.yaml +++ b/.github/workflows/pr-closed.yaml @@ -23,11 +23,11 @@ jobs: BRANCH: "refs/pull/${{ github.event.pull_request.number }}/merge" run: | set -euo pipefail - gh api -X GET /repos/{owner}/{repo}/actions/caches -f ref="$BRANCH" --paginate -q '.actions_caches[] | "\(.id) \(.key)"' | { + gh api -X GET repos/{owner}/{repo}/actions/caches -f ref="$BRANCH" --paginate -q '.actions_caches[] | "\(.id) \(.key)"' | { fail=0 while read -r id key; do echo Deleting cache with ID $id: $key - gh api -X DELETE /repos/{owner}/{repo}/actions/caches/"$id" || fail=1 + gh api -X DELETE repos/{owner}/{repo}/actions/caches/"$id" || fail=1 done [ $fail -eq 0 ] }