Lead with the unquoted command form, and take -- the way every tool does #114
Workflow file for this run
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: CI | |
| on: | |
| push: | |
| branches: | |
| - master | |
| tags: | |
| - "v*" | |
| pull_request: | |
| branches: | |
| - master | |
| # Cancel in-flight runs when newer commits are pushed to the same | |
| # branch/PR, but never cancel a tag run mid-publish. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| jobs: | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install only ruff | |
| run: uv sync --only-group ruff | |
| - name: Lint | |
| run: uv run --no-sync ruff check --output-format=github . | |
| - name: Format | |
| run: uv run --no-sync ruff format --check . | |
| typecheck: | |
| name: Typecheck | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| # ty needs the runtime dependencies installed to resolve their | |
| # imports, so this installs the project itself, unlike the lint job | |
| - name: Install ty and runtime dependencies | |
| run: uv sync --no-default-groups --group ty | |
| - name: Typecheck | |
| run: uv run --no-sync ty check --output-format=github --error-on-warning | |
| test: | |
| name: Test on ${{ matrix.name }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # every platform on the latest python, plus a single job on the | |
| # oldest supported one to catch anything newer than it allows | |
| - name: Linux py314 | |
| os: ubuntu-latest | |
| pyversion: "3.14" | |
| - name: macOS py314 | |
| os: macos-latest | |
| pyversion: "3.14" | |
| - name: Windows py314 | |
| os: windows-latest | |
| pyversion: "3.14" | |
| - name: Linux py313 | |
| os: ubuntu-latest | |
| pyversion: "3.13" | |
| env: | |
| # the test suite exercises a real OS keyring; this makes it fail | |
| # instead of skipping those tests if the setup below breaks | |
| KEYCMD_REQUIRE_OS_KEYRING: "1" | |
| # the keyrings created below only ever hold test credentials | |
| KEYCMD_KEYRING_PASSWORD: keycmd-test | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install uv and Python ${{ matrix.pyversion }} | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| python-version: ${{ matrix.pyversion }} | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| cache-suffix: py${{ matrix.pyversion }} | |
| - name: Install dependencies | |
| run: uv sync | |
| # windows runners expose the credential manager to the session out of | |
| # the box; the other two need a keyring that unlocks without a prompt | |
| - name: Install gnome-keyring | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install --yes --no-install-recommends gnome-keyring dbus-x11 | |
| - name: Create a keychain | |
| if: runner.os == 'macOS' | |
| run: | | |
| security create-keychain -p "$KEYCMD_KEYRING_PASSWORD" "$KEYCHAIN" | |
| # no auto lock, neither on a timeout nor on sleep | |
| security set-keychain-settings "$KEYCHAIN" | |
| security unlock-keychain -p "$KEYCMD_KEYRING_PASSWORD" "$KEYCHAIN" | |
| # the keyring package talks to the default keychain | |
| security list-keychains -d user -s "$KEYCHAIN" login.keychain | |
| security default-keychain -s "$KEYCHAIN" | |
| env: | |
| KEYCHAIN: keycmd-test.keychain | |
| # the secret service is bound to a d-bus session, so the tests have to | |
| # run inside one, with the keyring daemon unlocked and running in it | |
| - name: Test in a d-bus session | |
| if: runner.os == 'Linux' | |
| run: | | |
| dbus-run-session -- bash -c ' | |
| printf "%s" "$KEYCMD_KEYRING_PASSWORD" | | |
| gnome-keyring-daemon --unlock --components=secrets | |
| uv run --no-sync pytest -v --cov=keycmd --cov-report=term-missing \ | |
| --cov-fail-under=95 tests | |
| ' | |
| - name: Test | |
| if: runner.os != 'Linux' | |
| run: > | |
| uv run --no-sync pytest -v --cov=keycmd --cov-report=term-missing | |
| --cov-fail-under=95 tests | |
| test-wsl: | |
| name: Test on WSL | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| env: | |
| KEYCMD_REQUIRE_OS_KEYRING: "1" | |
| KEYCMD_TEST_WSL: "1" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install uv and Python 3.14 | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| python-version: "3.14" | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| cache-suffix: py3.14 | |
| - name: Install dependencies | |
| run: uv sync | |
| # WSL only provides the shell keycmd is invoked from; keycmd itself | |
| # runs as a windows process, reading the windows credential manager | |
| - name: Install WSL | |
| uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7.0.0 | |
| with: | |
| # the smallest distribution, on the WSL version that needs no | |
| # virtual machine: the tests only need a shell on the other side | |
| # of the interop boundary, and provisioning WSLv2 with a store | |
| # distribution has taken anywhere from one to twenty minutes | |
| distribution: Alpine-3.23 | |
| wsl-version: 1 | |
| - name: Test | |
| run: uv run --no-sync pytest -v tests/test_wsl.py | |
| build: | |
| name: Build and test wheel | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| - name: Build sdist and wheel | |
| run: uv build | |
| - name: Twine check | |
| run: uvx twine check dist/* | |
| - name: Upload wheel artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| path: dist | |
| name: dist | |
| publish: | |
| name: Publish to Github and Pypi | |
| runs-on: ubuntu-latest | |
| needs: [lint, typecheck, test, test-wsl, build] | |
| if: success() && startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download wheel artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: dist | |
| path: dist | |
| - name: Release to GitHub | |
| uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| files: | | |
| dist/*.tar.gz | |
| dist/*.whl | |
| draft: true | |
| prerelease: false | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| user: __token__ | |
| password: ${{ secrets.PYPI_PASSWORD }} |