diff --git a/.github/scripts/release-linux-architectures-test.py b/.github/scripts/release-linux-architectures-test.py new file mode 100644 index 00000000000..95fcb6bc19f --- /dev/null +++ b/.github/scripts/release-linux-architectures-test.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# Copyright 2023 Greptime Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +import os +import subprocess +import unittest +from pathlib import Path + + +SCRIPT = Path(__file__).with_name("release-linux-architectures.sh") +ARCHITECTURES = ("amd64", "arm64", "riscv64") + + +class ReleaseLinuxArchitecturesTest(unittest.TestCase): + def resolve(self, selected, event="workflow_dispatch", publish=False, images=False): + env = dict( + os.environ, + GITHUB_EVENT_NAME=event, + PUBLISH_GITHUB_RELEASE=str(publish).lower(), + RELEASE_IMAGES=str(images).lower(), + ) + for arch in ARCHITECTURES: + key = f"BUILD_LINUX_{arch.upper()}_ARTIFACTS" + env.pop(key, None) + if selected is not None: + env[key] = str(arch in selected).lower() + return subprocess.run( + ["bash", str(SCRIPT)], env=env, text=True, capture_output=True, check=False + ) + + def assert_targets(self, result, targets): + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stderr, "") + self.assertEqual( + result.stdout, + "".join(f"{arch}={str(arch in targets).lower()}\n" for arch in ARCHITECTURES), + ) + + def test_checkbox_combinations(self): + for flags in itertools.product((False, True), repeat=3): + selected = {arch for arch, enabled in zip(ARCHITECTURES, flags) if enabled} + for event, publish, images in itertools.product( + ("workflow_dispatch", "push", "schedule"), (False, True), (False, True) + ): + with self.subTest(selected=selected, event=event, publish=publish, images=images): + expected = ( + set(ARCHITECTURES) + if event != "workflow_dispatch" or publish or images + else selected + ) + self.assert_targets(self.resolve(selected, event, publish, images), expected) + + def test_default_and_omitted_inputs_preserve_previous_behavior(self): + for selected in (None, set()): + for event, publish, images in itertools.product( + ("workflow_dispatch", "push", "schedule"), (False, True), (False, True) + ): + with self.subTest(selected=selected, event=event, publish=publish, images=images): + # The old build_linux_artifacts switch defaulted to false. + old_build_linux = publish or images or event in ("push", "schedule") + self.assert_targets( + self.resolve(selected, event, publish, images), + set(ARCHITECTURES) if old_build_linux else set(), + ) + + def test_unsupported_event(self): + result = self.resolve(set(), event="pull_request") + self.assertNotEqual(result.returncode, 0) + self.assertIn("Unsupported release event", result.stderr) + self.assertEqual(result.stdout, "") + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/release-linux-architectures.sh b/.github/scripts/release-linux-architectures.sh new file mode 100644 index 00000000000..cf6f819e84f --- /dev/null +++ b/.github/scripts/release-linux-architectures.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Publishing keeps the existing full-build behavior, regardless of checkboxes. +build_all=false +if [[ "${PUBLISH_GITHUB_RELEASE:-false}" == true || "${RELEASE_IMAGES:-false}" == true ]]; then + build_all=true +fi +case "${GITHUB_EVENT_NAME}" in + push|schedule) build_all=true ;; + workflow_dispatch) ;; + *) echo "Unsupported release event: ${GITHUB_EVENT_NAME}" >&2; exit 1 ;; +esac + +for arch in amd64 arm64 riscv64; do + input="BUILD_LINUX_${arch^^}_ARTIFACTS" + selected=false + if [[ "$build_all" == true || "${!input:-false}" == true ]]; then + selected=true + fi + printf '%s=%s\n' "$arch" "$selected" +done diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 030a8e2fcbb..55dcc34ccf3 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -82,6 +82,8 @@ jobs: version: "latest" - name: Run check-version script tests run: uv run --no-project python .github/scripts/check-version-test.py + - name: Run release Linux architecture tests + run: python3 .github/scripts/release-linux-architectures-test.py - name: Run previous-release-tag script tests run: python3 .github/scripts/previous-release-tag-test.py - name: Run enterprise license check tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a309c224568..bc5d045099c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,6 @@ on: # NIGHTLY_RELEASE_MAX_AGE_DAYS days, see the 'Check nightly release necessity' step. - cron: '0 0 * * 1-5' workflow_dispatch: # Allows you to run this workflow manually. - # Notes: The GitHub Actions ONLY support 10 inputs; this final input is the tenth. inputs: linux_amd64_runner: type: choice @@ -57,9 +56,19 @@ on: description: Do not run integration tests during the build type: boolean default: true - build_linux_artifacts: + build_linux_amd64_artifacts: type: boolean - description: Build linux artifacts (amd64, arm64, and riscv64) + description: Build linux-amd64 artifacts (publishing always builds all Linux architectures) + required: false + default: false + build_linux_arm64_artifacts: + type: boolean + description: Build linux-arm64 artifacts (publishing always builds all Linux architectures) + required: false + default: false + build_linux_riscv64_artifacts: + type: boolean + description: Build linux-riscv64 artifacts (publishing always builds all Linux architectures) required: false default: false build_macos_artifacts: @@ -115,6 +124,9 @@ jobs: if: ${{ github.repository == 'GreptimeTeam/greptimedb' }} runs-on: ubuntu-latest outputs: + build-linux-amd64: ${{ steps.linux-architectures.outputs.amd64 }} + build-linux-arm64: ${{ steps.linux-architectures.outputs.arm64 }} + build-linux-riscv64: ${{ steps.linux-architectures.outputs.riscv64 }} linux-amd64-runner: ${{ steps.start-linux-amd64-runner.outputs.label }} linux-arm64-runner: ${{ steps.start-linux-arm64-runner.outputs.label }} macos-runner: ${{ inputs.macos_runner || vars.DEFAULT_MACOS_RUNNER }} @@ -143,6 +155,17 @@ jobs: fetch-depth: 0 persist-credentials: false + # Publishing and automatic releases retain the full Linux build. + - name: Resolve Linux architectures + id: linux-architectures + env: + BUILD_LINUX_AMD64_ARTIFACTS: ${{ inputs.build_linux_amd64_artifacts }} + BUILD_LINUX_ARM64_ARTIFACTS: ${{ inputs.build_linux_arm64_artifacts }} + BUILD_LINUX_RISCV64_ARTIFACTS: ${{ inputs.build_linux_riscv64_artifacts }} + PUBLISH_GITHUB_RELEASE: ${{ inputs.publish_github_release }} + RELEASE_IMAGES: ${{ inputs.release_images }} + run: bash .github/scripts/release-linux-architectures.sh >> "$GITHUB_OUTPUT" + - name: Check Rust toolchain version shell: bash run: | @@ -182,7 +205,7 @@ jobs: ./.github/scripts/check-version.sh "${{ steps.create-version.outputs.version }}" - name: Allocate linux-amd64 runner - if: ${{ (inputs.build_linux_artifacts || inputs.publish_github_release || inputs.release_images || github.event_name == 'push' || github.event_name == 'schedule') && steps.check-nightly.outputs.nightly-required == 'true' }} + if: ${{ (steps.linux-architectures.outputs.amd64 == 'true' || steps.linux-architectures.outputs.riscv64 == 'true') && steps.check-nightly.outputs.nightly-required == 'true' }} uses: ./.github/actions/start-runner id: start-linux-amd64-runner with: @@ -196,7 +219,7 @@ jobs: subnet-id: ${{ vars.EC2_RUNNER_SUBNET_ID }} - name: Allocate linux-arm64 runner - if: ${{ (inputs.build_linux_artifacts || inputs.publish_github_release || inputs.release_images || github.event_name == 'push' || github.event_name == 'schedule') && steps.check-nightly.outputs.nightly-required == 'true' }} + if: ${{ steps.linux-architectures.outputs.arm64 == 'true' && steps.check-nightly.outputs.nightly-required == 'true' }} uses: ./.github/actions/start-runner id: start-linux-arm64-runner with: @@ -211,7 +234,7 @@ jobs: build-linux-amd64-artifacts: name: Build linux-amd64 artifacts - if: ${{ (inputs.build_linux_artifacts || inputs.publish_github_release || inputs.release_images || github.event_name == 'push' || github.event_name == 'schedule') && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} + if: ${{ needs.allocate-runners.outputs.build-linux-amd64 == 'true' && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} needs: [ allocate-runners, ] @@ -237,7 +260,7 @@ jobs: build-linux-arm64-artifacts: name: Build linux-arm64 artifacts - if: ${{ (inputs.build_linux_artifacts || inputs.publish_github_release || inputs.release_images || github.event_name == 'push' || github.event_name == 'schedule') && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} + if: ${{ needs.allocate-runners.outputs.build-linux-arm64 == 'true' && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} needs: [ allocate-runners, ] @@ -264,7 +287,7 @@ jobs: build-linux-riscv64-artifacts: name: Build linux-riscv64 artifacts - if: ${{ (inputs.build_linux_artifacts || inputs.publish_github_release || inputs.release_images || github.event_name == 'push' || github.event_name == 'schedule') && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} + if: ${{ needs.allocate-runners.outputs.build-linux-riscv64 == 'true' && (github.event_name != 'schedule' || needs.allocate-runners.outputs.nightly-required == 'true') }} needs: [ allocate-runners, ]