Add shared dev-workspace setup script and harden CI workflow #282
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
| # TODO: lock files on all platforms | |
| # TODO: test with all supported python versions | |
| name: CI | |
| on: | |
| merge_group: | |
| push: | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| publish_testpypi: | |
| description: 'Publish to TestPyPI' | |
| required: true | |
| type: boolean | |
| default: false | |
| # Cancel superseded runs only for PR pushes (rapid commits to the same branch). | |
| # Never cancel push/tag/merge_group runs — a tag push drives the PyPI publish | |
| # steps below and a merge_group run backs a required check in the merge queue; | |
| # either could be silently aborted by an unrelated event sharing the ref. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| # python version for dev workspace | |
| DEV_WORKSPACE_PYTHON_VERSION: '3.13' | |
| jobs: | |
| build: | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 40 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-24.04, macos-15, windows-2022] | |
| include: | |
| - os: ubuntu-24.04 | |
| name: Linux | |
| venv_bin: bin | |
| - os: macos-15 | |
| name: macOS | |
| venv_bin: bin | |
| - os: windows-2022 | |
| name: Windows | |
| venv_bin: Scripts | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| # setuptools-scm uses tags to get the current version, fetch history and tags | |
| # to get correct version | |
| fetch-depth: 0 | |
| fetch-tags: 'true' | |
| - name: Set up Python ${{ env.DEV_WORKSPACE_PYTHON_VERSION }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.DEV_WORKSPACE_PYTHON_VERSION }} | |
| # Every package in the monorepo has its own .venvs/ (root dev_workspace plus one | |
| # per project for envs created by `prepare-envs`, e.g. dev_no_runtime, runtime). | |
| # Exact-match only (no restore-keys): setup-dev-workspace.sh and prepare-envs | |
| # skip reinstalling whenever a restored venv already looks valid, so a stale | |
| # partial-match restore could mask a dependency that was added since the cache | |
| # was written. | |
| - name: Cache all venvs | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| .venvs | |
| **/.venvs | |
| key: ${{ runner.os }}-venvs-${{ hashFiles('**/pyproject.toml', '**/preset.toml') }} | |
| - name: Install dependencies | |
| run: | | |
| # CI must exercise this branch's local source, so finecode and its sibling | |
| # packages need an editable install, not a released version from PyPI — see | |
| # docs/guides/developing-finecode.md#continuous-integration. | |
| sh scripts/setup-dev-workspace.sh | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| shell: bash | |
| - name: Inspect code | |
| if: ${{ !cancelled() }} | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run inspect_code | |
| shell: bash | |
| - name: Audit code | |
| if: ${{ !cancelled() }} | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run audit_code | |
| shell: bash | |
| - name: Check formatting | |
| if: ${{ !cancelled() }} | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run check_formatting | |
| shell: bash | |
| - name: Build artifacts | |
| id: build | |
| if: runner.os == 'Linux' && !cancelled() | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run build_artifact | |
| shell: bash | |
| - name: Run unit tests | |
| if: ${{ !cancelled() }} | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| # TODO: test with all supported python versions | |
| python -m finecode run run_tests | |
| shell: bash | |
| - name: Publish to TestPyPI and verify | |
| if: runner.os == 'Linux' && github.event_name == 'workflow_dispatch' && inputs.publish_testpypi | |
| env: | |
| FINECODE_CONFIG_PUBLISH_AND_VERIFY_ARTIFACT__INIT_REPOSITORY_PROVIDER__REPOSITORIES: '[{"name": "testpypi", "url": "https://test.pypi.org/"}]' | |
| FINECODE_CONFIG_PUBLISH_AND_VERIFY_ARTIFACT__INIT_REPOSITORY_PROVIDER__CREDENTIALS_BY_REPOSITORY: '{"testpypi": {"username": "${{ secrets.TESTPYPI_USERNAME }}", "password": "${{ secrets.TESTPYPI_PASSWORD }}"}}' | |
| run: | | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run \ | |
| --map-payload-fields="src-artifact-def-path,dist-artifact-paths" \ | |
| publish_and_verify_artifact \ | |
| --src-artifact-def-path="build_artifact.src_artifact_def_path" \ | |
| --dist-artifact-paths="build_artifact.build_output_paths" | |
| shell: bash | |
| - name: Publish to PyPI and verify | |
| if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/') | |
| env: | |
| FINECODE_CONFIG_PUBLISH_AND_VERIFY_ARTIFACT__INIT_REPOSITORY_PROVIDER__REPOSITORIES: '[{"name": "pypi", "url": "https://pypi.org/"}]' | |
| FINECODE_CONFIG_PUBLISH_AND_VERIFY_ARTIFACT__INIT_REPOSITORY_PROVIDER__CREDENTIALS_BY_REPOSITORY: '{"pypi": {"username": "${{ secrets.PYPI_USERNAME }}", "password": "${{ secrets.PYPI_PASSWORD }}"}}' | |
| run: | | |
| # TODO: make sure git tag exists (for manual trigger) | |
| source .venvs/dev_workspace/${{ matrix.venv_bin }}/activate | |
| python -m finecode run \ | |
| --map-payload-fields="src-artifact-def-path,dist-artifact-paths" \ | |
| publish_and_verify_artifact \ | |
| --src-artifact-def-path="build_artifact.src_artifact_def_path" \ | |
| --dist-artifact-paths="build_artifact.build_output_paths" | |
| shell: bash | |
| # TODO: try to replace by finecode action | |
| - name: Store the distribution packages | |
| uses: actions/upload-artifact@v5 | |
| if: runner.os == 'Linux' | |
| with: | |
| name: python-package-distributions | |
| path: dist/ |