Skip to content

Remember which keyring backend was found, instead of searching every … #111

Remember which keyring backend was found, instead of searching every …

Remember which keyring backend was found, instead of searching every … #111

Workflow file for this run

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 }}