public/tidy3d/python-client-release #75
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "public/tidy3d/python-client-release" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: 'Release Tag (e.g., v2.10.0, v2.10.0rc1)' | |
| required: true | |
| type: string | |
| release_type: | |
| description: 'Release Type (determines deployment targets)' | |
| type: choice | |
| default: 'draft' | |
| required: false | |
| options: | |
| - draft | |
| - testpypi | |
| - pypi | |
| workflow_control: | |
| description: 'Workflow Stage Control' | |
| default: 'start-tag' | |
| required: false | |
| type: choice | |
| options: | |
| - start-tag | |
| - start-tests | |
| - start-deploy | |
| - only-tag | |
| - only-tests | |
| - only-tag-tests | |
| - only-tag-deploy | |
| client_tests: | |
| description: 'Run python-client-tests' | |
| type: boolean | |
| default: true | |
| cli_tests: | |
| description: 'Run develop-cli tests' | |
| type: boolean | |
| default: true | |
| submodule_tests: | |
| description: 'Run submodule tests' | |
| type: boolean | |
| default: true | |
| extras_integration_tests: | |
| description: 'Run tidy3d-extras integration tests (full)' | |
| type: boolean | |
| default: true | |
| workflow_call: | |
| inputs: | |
| release_tag: | |
| description: 'Release Tag (e.g., v2.10.0, v2.10.0rc1)' | |
| required: true | |
| type: string | |
| release_type: | |
| description: 'Release Type (determines deployment targets)' | |
| type: string | |
| default: 'draft' | |
| required: false | |
| workflow_control: | |
| description: 'Workflow Stage Control' | |
| default: 'start-tag' | |
| required: false | |
| type: string | |
| client_tests: | |
| description: 'Run python-client-tests' | |
| type: boolean | |
| default: true | |
| cli_tests: | |
| description: 'Run develop-cli tests' | |
| type: boolean | |
| default: true | |
| submodule_tests: | |
| description: 'Run submodule tests' | |
| type: boolean | |
| default: true | |
| extras_integration_tests: | |
| description: 'Run tidy3d-extras integration tests (full)' | |
| type: boolean | |
| default: true | |
| deploy_testpypi: | |
| description: 'Deploy to TestPyPI' | |
| type: boolean | |
| default: false | |
| deploy_pypi: | |
| description: 'Deploy to production PyPI' | |
| type: boolean | |
| default: false | |
| secrets: | |
| TEST_PYPI_API_TOKEN: | |
| description: 'API token used to publish artifacts to TestPyPI' | |
| required: false | |
| PYPI_API_TOKEN: | |
| description: 'API token used to publish artifacts to PyPI' | |
| required: false | |
| outputs: | |
| workflow_success: | |
| description: 'Overall release workflow success status' | |
| value: ${{ jobs.compile-tests-results.outputs.proceed_deploy == 'true' || jobs.compile-tests-results.result == 'skipped' }} | |
| permissions: | |
| contents: read | |
| jobs: | |
| determine-workflow-scope: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release_tag: ${{ env.RELEASE_TAG }} | |
| release_type: ${{ env.RELEASE_TYPE }} | |
| is_rc_release: ${{ steps.determine-workflow-steps.outputs.is_rc_release }} | |
| run_tag: ${{ steps.determine-workflow-steps.outputs.run_tag }} | |
| run_tests: ${{ steps.determine-workflow-steps.outputs.run_tests }} | |
| run_deploy: ${{ steps.determine-workflow-steps.outputs.run_deploy }} | |
| run_client_tests: ${{ steps.determine-workflow-steps.outputs.run_client_tests }} | |
| run_cli_tests: ${{ steps.determine-workflow-steps.outputs.run_cli_tests }} | |
| run_submodule_tests: ${{ steps.determine-workflow-steps.outputs.run_submodule_tests }} | |
| run_extras_integration_tests: ${{ steps.determine-workflow-steps.outputs.run_extras_integration_tests }} | |
| deploy_github_release: ${{ steps.determine-workflow-steps.outputs.deploy_github_release }} | |
| deploy_testpypi: ${{ steps.determine-workflow-steps.outputs.deploy_testpypi }} | |
| deploy_pypi: ${{ steps.determine-workflow-steps.outputs.deploy_pypi }} | |
| env: | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag || inputs.release_tag }} | |
| RELEASE_TYPE: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_type || inputs.release_type }} | |
| WORKFLOW_CONTROL: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.workflow_control || inputs.workflow_control }} | |
| CLIENT_TESTS: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.client_tests || inputs.client_tests }} | |
| CLI_TESTS: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.cli_tests || inputs.cli_tests }} | |
| SUBMODULE_TESTS: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.submodule_tests || inputs.submodule_tests }} | |
| EXTRAS_INTEGRATION_TESTS: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.extras_integration_tests || inputs.extras_integration_tests }} | |
| DEPLOY_TESTPYPI: ${{ inputs.deploy_testpypi || false }} | |
| DEPLOY_PYPI: ${{ inputs.deploy_pypi || false }} | |
| steps: | |
| - name: validate-tag-format | |
| run: | | |
| set -e | |
| echo "Validating release tag format..." | |
| echo "Release tag: $RELEASE_TAG" | |
| echo "Release type: $RELEASE_TYPE" | |
| # Only enforce strict validation for PyPI releases | |
| if [[ "$RELEASE_TYPE" == "pypi" ]]; then | |
| echo "PyPI release detected - applying strict tag validation" | |
| # Tag must match semantic versioning: v{major}.{minor}.{patch}[rc{num}|.dev{num}] | |
| TAG_REGEX='^v[0-9]+\.[0-9]+\.[0-9]+(rc[0-9]+|\.dev[0-9]+)?$' | |
| if [[ ! "$RELEASE_TAG" =~ $TAG_REGEX ]]; then | |
| echo "Invalid tag format: $RELEASE_TAG" | |
| echo " Expected format: v{major}.{minor}.{patch}[rc{num}|.dev{num}]" | |
| echo " Examples: v2.10.0, v2.10.0rc1, v2.10.1rc2, v2.11.0.dev0" | |
| exit 1 | |
| fi | |
| echo "Tag format is valid" | |
| else | |
| echo "Non-PyPI release - skipping strict tag validation" | |
| echo "Tag accepted: $RELEASE_TAG" | |
| fi | |
| - name: determine-workflow-steps | |
| id: determine-workflow-steps | |
| run: | | |
| set -v | |
| echo "=== Input Parameters ===" | |
| echo "RELEASE_TAG: $RELEASE_TAG" | |
| echo "RELEASE_TYPE: $RELEASE_TYPE" | |
| echo "WORKFLOW_CONTROL: $WORKFLOW_CONTROL" | |
| echo "CLIENT_TESTS: $CLIENT_TESTS" | |
| echo "CLI_TESTS: $CLI_TESTS" | |
| echo "SUBMODULE_TESTS: $SUBMODULE_TESTS" | |
| echo "EXTRAS_INTEGRATION_TESTS: $EXTRAS_INTEGRATION_TESTS" | |
| echo "DEPLOY_TESTPYPI: $DEPLOY_TESTPYPI" | |
| echo "DEPLOY_PYPI: $DEPLOY_PYPI" | |
| echo "" | |
| # ============================================ | |
| # PART 1: WORKFLOW FLOW CONTROL | |
| # ============================================ | |
| run_tag=false | |
| run_tests=false | |
| run_deploy=false | |
| case "$WORKFLOW_CONTROL" in | |
| start-tag) | |
| run_tag=true | |
| run_tests=true | |
| run_deploy=true | |
| ;; | |
| start-tests) | |
| run_tests=true | |
| run_deploy=true | |
| ;; | |
| start-deploy) | |
| run_deploy=true | |
| ;; | |
| only-tag) | |
| run_tag=true | |
| ;; | |
| only-tests) | |
| run_tests=true | |
| ;; | |
| only-tag-tests) | |
| run_tag=true | |
| run_tests=true | |
| ;; | |
| only-tag-deploy) | |
| run_tag=true | |
| run_deploy=true | |
| ;; | |
| *) | |
| echo "Invalid WORKFLOW_CONTROL: $WORKFLOW_CONTROL" | |
| exit 1 | |
| ;; | |
| esac | |
| echo "=== Workflow Stage Control ===" | |
| echo "run_tag: $run_tag" | |
| echo "run_tests: $run_tests" | |
| echo "run_deploy: $run_deploy" | |
| echo "" | |
| # ============================================ | |
| # PART 2: DETERMINE RC STATUS | |
| # ============================================ | |
| is_rc_release=false | |
| if [[ "$RELEASE_TAG" == *"rc"* ]]; then | |
| is_rc_release=true | |
| fi | |
| echo "=== Release Type ===" | |
| echo "is_rc_release: $is_rc_release" | |
| echo "" | |
| # ============================================ | |
| # PART 3: TEST CONTROL | |
| # ============================================ | |
| run_client_tests=false | |
| run_cli_tests=false | |
| run_submodule_tests=false | |
| run_extras_integration_tests=false | |
| if [[ "$run_tests" == "true" ]]; then | |
| [[ "$CLIENT_TESTS" == "true" ]] && run_client_tests=true | |
| [[ "$CLI_TESTS" == "true" ]] && run_cli_tests=true | |
| [[ "$EXTRAS_INTEGRATION_TESTS" == "true" ]] && run_extras_integration_tests=true | |
| # Auto-enable client tests if extras integration tests are requested | |
| # (extras tests run within the client tests workflow) | |
| if [[ "$run_extras_integration_tests" == "true" && "$run_client_tests" == "false" ]]; then | |
| run_client_tests=true | |
| echo "✓ Client tests auto-enabled because extras integration tests are requested" | |
| fi | |
| # Submodule tests: user input OR auto-enable for PyPI non-RC releases | |
| if [[ "$SUBMODULE_TESTS" == "true" ]]; then | |
| run_submodule_tests=true | |
| echo "✓ Submodule tests enabled by user input" | |
| elif [[ "$RELEASE_TYPE" == "pypi" && "$is_rc_release" == "false" ]]; then | |
| run_submodule_tests=true | |
| echo "✓ Submodule tests auto-enabled for PyPI non-RC release" | |
| fi | |
| fi | |
| echo "=== Test Control ===" | |
| echo "run_client_tests: $run_client_tests" | |
| echo "run_cli_tests: $run_cli_tests" | |
| echo "run_submodule_tests: $run_submodule_tests" | |
| echo "run_extras_integration_tests: $run_extras_integration_tests" | |
| echo "" | |
| # ============================================ | |
| # PART 4: DEPLOYMENT CONTROL | |
| # ============================================ | |
| deploy_github_release=false | |
| deploy_testpypi=false | |
| deploy_pypi=false | |
| if [[ "$run_deploy" == "true" ]]; then | |
| # Always create GitHub release when the deploy path is active | |
| deploy_github_release=true | |
| # Deployment target logic: | |
| # 1. If any deployment checkbox is explicitly set, use those | |
| # 2. Otherwise, use automatic defaults based on release_type | |
| if [[ "$DEPLOY_TESTPYPI" == "true" || "$DEPLOY_PYPI" == "true" ]]; then | |
| # Manual override: use checkbox selections | |
| echo "Using manual deployment target selections" | |
| deploy_testpypi=$DEPLOY_TESTPYPI | |
| deploy_pypi=$DEPLOY_PYPI | |
| else | |
| # Automatic defaults based on release_type | |
| echo "Using automatic deployment defaults for release_type: $RELEASE_TYPE" | |
| case "$RELEASE_TYPE" in | |
| pypi) | |
| # PyPI releases: deploy to PyPI and TestPyPI | |
| deploy_testpypi=true | |
| deploy_pypi=true | |
| ;; | |
| testpypi) | |
| # TestPyPI releases: deploy to TestPyPI | |
| deploy_testpypi=true | |
| ;; | |
| draft) | |
| # Draft releases: no deployment | |
| echo "Draft release - no automatic deployments" | |
| ;; | |
| *) | |
| echo "Unknown release_type: $RELEASE_TYPE - no automatic deployments" | |
| ;; | |
| esac | |
| fi | |
| fi | |
| echo "=== Deployment Control ===" | |
| echo "deploy_github_release: $deploy_github_release" | |
| echo "deploy_testpypi: $deploy_testpypi" | |
| echo "deploy_pypi: $deploy_pypi" | |
| echo "" | |
| # ============================================ | |
| # PART 5: SAVE ALL OUTPUTS | |
| # ============================================ | |
| echo "is_rc_release=$is_rc_release" >> $GITHUB_OUTPUT | |
| echo "run_tag=$run_tag" >> $GITHUB_OUTPUT | |
| echo "run_tests=$run_tests" >> $GITHUB_OUTPUT | |
| echo "run_deploy=$run_deploy" >> $GITHUB_OUTPUT | |
| echo "run_client_tests=$run_client_tests" >> $GITHUB_OUTPUT | |
| echo "run_cli_tests=$run_cli_tests" >> $GITHUB_OUTPUT | |
| echo "run_submodule_tests=$run_submodule_tests" >> $GITHUB_OUTPUT | |
| echo "run_extras_integration_tests=$run_extras_integration_tests" >> $GITHUB_OUTPUT | |
| echo "deploy_github_release=$deploy_github_release" >> $GITHUB_OUTPUT | |
| echo "deploy_testpypi=$deploy_testpypi" >> $GITHUB_OUTPUT | |
| echo "deploy_pypi=$deploy_pypi" >> $GITHUB_OUTPUT | |
| echo "? Workflow scope determined" | |
| create-tag: | |
| name: create-and-push-tag | |
| needs: determine-workflow-scope | |
| if: needs.determine-workflow-scope.outputs.run_tag == 'true' | |
| uses: ./.github/workflows/tidy3d-python-client-create-tag.yml | |
| permissions: | |
| contents: write | |
| with: | |
| release_tag: ${{ needs.determine-workflow-scope.outputs.release_tag }} | |
| release_type: ${{ needs.determine-workflow-scope.outputs.release_type }} | |
| secrets: inherit # zizmor: ignore[secrets-inherit] | |
| run-client-tests: | |
| name: run-python-client-tests | |
| needs: [determine-workflow-scope, create-tag] | |
| if: | | |
| always() && | |
| needs.determine-workflow-scope.outputs.run_client_tests == 'true' | |
| uses: ./.github/workflows/tidy3d-python-client-tests.yml | |
| permissions: | |
| contents: read | |
| security-events: write | |
| pull-requests: write | |
| with: | |
| release_tag: ${{ needs.determine-workflow-scope.outputs.release_tag }} | |
| local_tests: true | |
| remote_tests: true | |
| cli_tests: ${{ needs.determine-workflow-scope.outputs.run_cli_tests == 'true' }} | |
| submodule_tests: ${{ needs.determine-workflow-scope.outputs.run_submodule_tests == 'true' }} | |
| version_match_tests: true | |
| extras_integration_tests: ${{ needs.determine-workflow-scope.outputs.run_extras_integration_tests == 'true' }} | |
| test_type: full | |
| test_selection: full | |
| secrets: inherit # zizmor: ignore[secrets-inherit] | |
| compile-tests-results: | |
| name: compile-tests-results | |
| if: | | |
| always() && | |
| needs.determine-workflow-scope.outputs.run_tests == 'true' && | |
| needs.determine-workflow-scope.outputs.run_deploy == 'true' | |
| needs: | |
| - determine-workflow-scope | |
| - run-client-tests | |
| runs-on: ubuntu-latest | |
| outputs: | |
| proceed_deploy: ${{ steps.check-tests.outputs.proceed_deploy }} | |
| steps: | |
| - name: check-tests | |
| id: check-tests | |
| env: | |
| RUN_CLIENT_TESTS: ${{ needs.determine-workflow-scope.outputs.run_client_tests }} | |
| CLIENT_TESTS_RESULT: ${{ needs.run-client-tests.result }} | |
| WORKFLOW_SUCCESS: ${{ needs.run-client-tests.outputs.workflow_success }} | |
| run: | | |
| echo "=== Checking Test Results ===" | |
| echo "" | |
| proceed_deploy=true | |
| # Check client tests using the workflow_success output from tests workflow. | |
| # This output validates the retained local, remote, CLI, submodule, | |
| # version consistency, and extras integration suites. | |
| if [[ "$RUN_CLIENT_TESTS" == "true" ]]; then | |
| echo "Client tests workflow result: $CLIENT_TESTS_RESULT" | |
| echo "Client tests validation status: $WORKFLOW_SUCCESS" | |
| if [[ "$CLIENT_TESTS_RESULT" != "success" ]] || [[ "$WORKFLOW_SUCCESS" != "true" ]]; then | |
| echo "Client tests failed - see workflow-validation job in tests workflow for details" | |
| proceed_deploy=false | |
| else | |
| echo "All client tests passed (local, remote, CLI, submodule, version, and extras checks)" | |
| fi | |
| else | |
| echo "Client tests: not required (skipped)" | |
| fi | |
| echo "" | |
| echo "=== Final Decision ===" | |
| if [[ "$proceed_deploy" == "true" ]]; then | |
| echo "All required tests passed - deployment can proceed" | |
| else | |
| echo "One or more required tests failed - deployment blocked" | |
| exit 1 | |
| fi | |
| echo "proceed_deploy=$proceed_deploy" >> $GITHUB_OUTPUT | |
| github-release: | |
| name: create-github-release | |
| needs: [determine-workflow-scope, compile-tests-results, deploy-packages] | |
| if: | | |
| always() && | |
| (needs.compile-tests-results.outputs.proceed_deploy == 'true' || needs.compile-tests-results.result == 'skipped') && | |
| needs.determine-workflow-scope.outputs.deploy_github_release == 'true' && | |
| needs.determine-workflow-scope.outputs.deploy_pypi == 'true' && | |
| needs.deploy-packages.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| RELEASE_TAG: ${{ needs.determine-workflow-scope.outputs.release_tag }} | |
| IS_RC_RELEASE: ${{ needs.determine-workflow-scope.outputs.is_rc_release }} | |
| steps: | |
| - name: checkout-tag | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ env.RELEASE_TAG }} | |
| persist-credentials: false | |
| - name: create-github-release | |
| uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 | |
| with: | |
| tag_name: ${{ env.RELEASE_TAG }} | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_PAT }} | |
| deploy-packages: | |
| name: deploy-to-package-repositories | |
| needs: [determine-workflow-scope, compile-tests-results] | |
| if: | | |
| always() && | |
| (needs.compile-tests-results.outputs.proceed_deploy == 'true' || needs.compile-tests-results.result == 'skipped') && | |
| needs.determine-workflow-scope.outputs.run_deploy == 'true' && | |
| (needs.determine-workflow-scope.outputs.deploy_testpypi == 'true' || | |
| needs.determine-workflow-scope.outputs.deploy_pypi == 'true') | |
| uses: ./.github/workflows/tidy3d-python-client-deploy.yml | |
| permissions: | |
| contents: read | |
| id-token: write | |
| with: | |
| release_tag: ${{ needs.determine-workflow-scope.outputs.release_tag }} | |
| deploy_testpypi: ${{ needs.determine-workflow-scope.outputs.deploy_testpypi == 'true' }} | |
| deploy_pypi: ${{ needs.determine-workflow-scope.outputs.deploy_pypi == 'true' }} | |
| secrets: | |
| TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} | |
| PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} |