Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ebfc4e5812 | |||
| 33eddecd6e | |||
| ee779cec4d | |||
| df7bd253d4 |
@@ -0,0 +1,17 @@
|
|||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
reviewers:
|
||||||
|
- "qmk/collaborators"
|
||||||
|
- package-ecosystem: "pip" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
reviewers:
|
||||||
|
- "qmk/collaborators"
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: CLI Lint
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'qmk_cli/**'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- '.github/workflows/cli_lint.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
|
||||||
|
- name: Activate virtualenv
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
python -m venv .ci_venv
|
||||||
|
source .ci_venv/bin/activate
|
||||||
|
echo PATH=$PATH >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: python -m pip install --group dev
|
||||||
|
|
||||||
|
- name: Run lint
|
||||||
|
run: ruff check --no-cache --output-format=github
|
||||||
|
|
||||||
|
- name: Run format
|
||||||
|
run: yapf -r --diff qmk_cli test
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
name: CLI Setup
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test_cli_base_container:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: ghcr.io/qmk/qmk_base_container
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: apt-get update && apt-get install -y python3-venv
|
||||||
|
|
||||||
|
- name: Run unit test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
python3 -m venv .ci_venv
|
||||||
|
source .ci_venv/bin/activate
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
python3 -m pip install --group dev
|
||||||
|
pytest
|
||||||
|
|
||||||
|
- name: Run ci_tests
|
||||||
|
run: ./ci_tests
|
||||||
|
|
||||||
|
test_cli_linux_macos:
|
||||||
|
needs: test_cli_base_container
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, ubuntu-latest]
|
||||||
|
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Run ci_tests
|
||||||
|
run: ./ci_tests
|
||||||
|
|
||||||
|
test_cli_win:
|
||||||
|
needs: test_cli_base_container
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: (MSYS2) Setup and install dependencies
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
install: git mingw-w64-x86_64-toolchain mingw-w64-x86_64-python-pip mingw-w64-x86_64-python-build mingw-w64-x86_64-python-pillow mingw-w64-x86_64-rust mingw-w64-x86_64-python-halo mingw-w64-x86_64-python-nh3 mingw-w64-x86_64-python-rpds-py mingw-w64-x86_64-python-ruff
|
||||||
|
|
||||||
|
# Upgrade pip due to msys packaging + pypa/build/pull/736 issues
|
||||||
|
- name: (MSYS2) Install Python dependencies
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --break-system-packages --force-reinstall --upgrade pip
|
||||||
|
|
||||||
|
- name: Run ci_tests
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: ./ci_tests
|
||||||
|
|
||||||
|
test_docker_container:
|
||||||
|
needs: test_cli_base_container
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
TEST_TAG: qmkfm/qmk_cli:test
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
pip install setuptools wheel
|
||||||
|
pip install --group dev
|
||||||
|
|
||||||
|
- name: Build Python
|
||||||
|
run: |
|
||||||
|
python3 -m build
|
||||||
|
|
||||||
|
- name: Build Test Container
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.TEST_TAG }}
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
docker run --rm -v ${{ github.workspace }}:/qmk_cli -w /qmk_cli ${{ env.TEST_TAG }} /qmk_cli/ci_tests
|
||||||
|
|
||||||
|
- name: Build All Containers
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
target: full
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '22 18 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||||
|
# Learn more:
|
||||||
|
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v4
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v4
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v4
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
name: Rebuild Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
redeploy:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get Previous tag
|
||||||
|
id: previoustag
|
||||||
|
uses: "WyriHaximus/github-action-get-previous-tag@v2"
|
||||||
|
|
||||||
|
- name: Download previous artifact
|
||||||
|
run: |
|
||||||
|
pip download -d "${GITHUB_WORKSPACE}/dist" qmk=="${{ steps.previoustag.outputs.tag }}"
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push slim to Docker Hub
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
target: slim
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
ghcr.io/qmk/qmk_cli:slim
|
||||||
|
qmkfm/qmk_cli:slim
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ steps.previoustag.outputs.tag }}-slim
|
||||||
|
qmkfm/qmk_cli:${{ steps.previoustag.outputs.tag }}-slim
|
||||||
|
|
||||||
|
- name: Build and Push full to Docker Hub
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
target: full
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
ghcr.io/qmk/qmk_cli:latest
|
||||||
|
qmkfm/qmk_cli:latest
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ github.sha }}
|
||||||
|
qmkfm/qmk_cli:${{ github.sha }}
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ steps.previoustag.outputs.tag }}
|
||||||
|
qmkfm/qmk_cli:${{ steps.previoustag.outputs.tag }}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# This workflow will upload a Python Package using Twine when a release is created
|
||||||
|
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
||||||
|
|
||||||
|
name: Upload Python Package
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version_part:
|
||||||
|
description: 'Which part of the version to increment (patch, minor, major)'
|
||||||
|
required: true
|
||||||
|
default: 'patch'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
pip install setuptools wheel
|
||||||
|
pip install --group dev
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: |
|
||||||
|
git config --local user.email "hello@qmk.fm"
|
||||||
|
git config --local user.name "QMK Bot"
|
||||||
|
bumpversion --dry-run --list ${{ github.event.inputs.version_part }} | grep new_version= | sed "s/new_version/NEW_CLI_VERSION/" >> "$GITHUB_ENV"
|
||||||
|
bumpversion ${{ github.event.inputs.version_part }}
|
||||||
|
|
||||||
|
- name: Push changes
|
||||||
|
uses: ad-m/github-push-action@master
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: master
|
||||||
|
tags: true
|
||||||
|
|
||||||
|
- name: Build and publish
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: __token__
|
||||||
|
TWINE_PASSWORD: ${{ secrets.PYPI_APITOKEN }}
|
||||||
|
run: |
|
||||||
|
python3 -m build
|
||||||
|
twine upload dist/*
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push slim to Docker Hub
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
target: slim
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
ghcr.io/qmk/qmk_cli:slim
|
||||||
|
qmkfm/qmk_cli:slim
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ env.NEW_CLI_VERSION }}-slim
|
||||||
|
qmkfm/qmk_cli:${{ env.NEW_CLI_VERSION }}-slim
|
||||||
|
|
||||||
|
- name: Build and Push full to Docker Hub
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
target: full
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
ghcr.io/qmk/qmk_cli:latest
|
||||||
|
qmkfm/qmk_cli:latest
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ github.sha }}
|
||||||
|
qmkfm/qmk_cli:${{ github.sha }}
|
||||||
|
ghcr.io/qmk/qmk_cli:${{ env.NEW_CLI_VERSION }}
|
||||||
|
qmkfm/qmk_cli:${{ env.NEW_CLI_VERSION }}
|
||||||
|
|
||||||
@@ -24,7 +24,6 @@ wheels/
|
|||||||
.installed.cfg
|
.installed.cfg
|
||||||
*.egg
|
*.egg
|
||||||
MANIFEST
|
MANIFEST
|
||||||
*.lock
|
|
||||||
|
|
||||||
# PyInstaller
|
# PyInstaller
|
||||||
# Usually these files are written by a python script from a template
|
# Usually these files are written by a python script from a template
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
FROM ghcr.io/qmk/qmk_base_container:latest AS builder
|
||||||
|
|
||||||
|
# Copy package in
|
||||||
|
ADD dist /tmp/dist
|
||||||
|
|
||||||
|
# Install QMK CLI via bootstrap script
|
||||||
|
RUN mkdir -p /opt/uv/bin \
|
||||||
|
&& export UV_PYTHON_INSTALL_DIR=/opt/uv/bin \
|
||||||
|
&& /bin/bash -c "curl -fsSL https://install.qmk.fm | sh -s -- --confirm --uv-install-dir=/usr/local/bin --uv-tool-dir=/opt/uv/tools --qmk-distrib-dir=/opt/qmk"
|
||||||
|
|
||||||
|
# Do the equivalent of entering the virtual environment
|
||||||
|
ENV PATH=/opt/qmk/bin:/opt/uv/tools/qmk/bin:/usr/local/bin:$PATH \
|
||||||
|
VIRTUAL_ENV=/opt/uv/tools/qmk
|
||||||
|
|
||||||
|
# Install python packages
|
||||||
|
RUN python3 -m pip uninstall -y qmk || true
|
||||||
|
RUN python3 -m pip install --upgrade pip setuptools wheel nose2 && \
|
||||||
|
python3 -m pip install /tmp/dist/qmk-*.whl
|
||||||
|
|
||||||
|
# Allow the uv-installed python to be usable by others
|
||||||
|
RUN chmod -R go=u,go-w /opt/uv /opt/qmk
|
||||||
|
|
||||||
|
# 2nd stage so we don't have /tmp/dist in the final image
|
||||||
|
FROM ghcr.io/qmk/qmk_base_container:latest AS slim
|
||||||
|
|
||||||
|
COPY --from=builder /opt/uv /opt/uv
|
||||||
|
|
||||||
|
# Do the equivalent of entering the virtual environment
|
||||||
|
ENV PATH=/opt/uv/tools/qmk/bin:$PATH \
|
||||||
|
VIRTUAL_ENV=/opt/uv/tools/qmk \
|
||||||
|
QMK_HOME=/qmk_firmware \
|
||||||
|
QMK_USERSPACE=/qmk_userspace
|
||||||
|
|
||||||
|
# 2nd stage so we don't have /tmp/dist in the final image
|
||||||
|
FROM ghcr.io/qmk/qmk_base_container:latest AS full
|
||||||
|
|
||||||
|
COPY --from=builder /opt/uv /opt/uv
|
||||||
|
COPY --from=builder /opt/qmk /opt/qmk
|
||||||
|
|
||||||
|
# Do the equivalent of entering the virtual environment
|
||||||
|
ENV PATH=/opt/qmk/bin:/opt/uv/tools/qmk/bin:$PATH \
|
||||||
|
VIRTUAL_ENV=/opt/uv/tools/qmk \
|
||||||
|
QMK_DISTRIB_DIR=/opt/qmk \
|
||||||
|
QMK_HOME=/qmk_firmware \
|
||||||
|
QMK_USERSPACE=/qmk_userspace
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
#set -x
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
|
||||||
|
trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
|
||||||
|
CI_VENV="$TMPDIR/.ci_venv"
|
||||||
|
|
||||||
|
# Avoid issues with building pillow as we install mingw-w64-x86_64-python-pillow
|
||||||
|
if [[ "$(uname -s)" =~ ^MINGW64_NT.* ]]; then
|
||||||
|
CI_VENV_ARGS="--system-site-packages"
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 -m venv $CI_VENV_ARGS $CI_VENV
|
||||||
|
source $CI_VENV/bin/activate
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
python3 -m pip install -U pip wheel
|
||||||
|
python3 -m pip install .
|
||||||
|
python3 -m pip install --group dev
|
||||||
|
|
||||||
|
pytest -vv -m system --qmk=real
|
||||||
+12
-1
@@ -40,6 +40,7 @@ dependencies = [
|
|||||||
dev = [
|
dev = [
|
||||||
"build",
|
"build",
|
||||||
"bumpversion",
|
"bumpversion",
|
||||||
|
"pytest",
|
||||||
"ruff",
|
"ruff",
|
||||||
"twine",
|
"twine",
|
||||||
"yapf",
|
"yapf",
|
||||||
@@ -63,7 +64,10 @@ find = {namespaces = false}
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
include = ['qmk_cli/**/*.py']
|
include = [
|
||||||
|
"qmk_cli/**/*.py",
|
||||||
|
"test/**/*.py",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "B", "N", "W", "COM", "C901", "PGH004"]
|
select = ["E", "F", "B", "N", "W", "COM", "C901", "PGH004"]
|
||||||
@@ -133,3 +137,10 @@ split_penalty_for_added_line_split = 30
|
|||||||
split_penalty_import_names = 0
|
split_penalty_import_names = 0
|
||||||
split_penalty_logical_operator = 300
|
split_penalty_logical_operator = 300
|
||||||
use_tabs = false
|
use_tabs = false
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
markers = [
|
||||||
|
"integration",
|
||||||
|
"system",
|
||||||
|
]
|
||||||
|
addopts = "-m 'not (integration or system)'"
|
||||||
|
|||||||
+59
-15
@@ -1,24 +1,24 @@
|
|||||||
"""Helpers for working with git.
|
"""Helpers for working with git."""
|
||||||
"""
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from .helpers import rmtree
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
default_repo = 'qmk_firmware'
|
DEFAULT_UPSTREAM = 'https://github.com/qmk/qmk_firmware'
|
||||||
default_fork = 'qmk/' + default_repo
|
|
||||||
default_branch = 'master'
|
|
||||||
|
|
||||||
|
|
||||||
def git_clone(url, destination, branch):
|
def git_clone(destination, url, branch):
|
||||||
|
"""Add the qmk/qmk_firmware upstream to a qmk_firmware clone."""
|
||||||
git_clone = [
|
git_clone = [
|
||||||
'git',
|
'git',
|
||||||
'clone',
|
'clone',
|
||||||
'--recurse-submodules',
|
'--recurse-submodules',
|
||||||
'--branch=' + branch,
|
f'--branch={branch}',
|
||||||
url,
|
url,
|
||||||
str(destination),
|
str(destination),
|
||||||
]
|
]
|
||||||
cli.log.debug('Git clone command: %s', git_clone)
|
cli.log.debug(f'Git clone command: {git_clone}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with subprocess.Popen(git_clone, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding='utf-8') as p:
|
with subprocess.Popen(git_clone, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding='utf-8') as p:
|
||||||
@@ -28,13 +28,57 @@ def git_clone(url, destination, branch):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
git_cmd = ' '.join([s.replace(' ', r'\ ') for s in git_clone])
|
git_cmd = ' '.join([s.replace(' ', r'\ ') for s in git_clone])
|
||||||
|
|
||||||
cli.log.error("Could not run '%s': %s: %s", git_cmd, e.__class__.__name__, e)
|
cli.log.error(f"Could not run '{git_cmd}': {e.__class__.__name__}:{e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if p.returncode == 0:
|
if p.returncode != 0:
|
||||||
cli.log.info('Successfully cloned %s to %s!', url, destination)
|
cli.log.error(f'git clone exited {p.returncode}')
|
||||||
return True
|
|
||||||
|
|
||||||
else:
|
|
||||||
cli.log.error('git clone exited %d', p.returncode)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
cli.log.info(f'Successfully cloned {url} to {destination}!')
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def git_set_upstream(destination):
|
||||||
|
"""Add the qmk/qmk_firmware upstream to a qmk_firmware clone."""
|
||||||
|
git_remote = [
|
||||||
|
'git',
|
||||||
|
'-C',
|
||||||
|
str(destination),
|
||||||
|
'remote',
|
||||||
|
'add',
|
||||||
|
'upstream',
|
||||||
|
DEFAULT_UPSTREAM,
|
||||||
|
]
|
||||||
|
cli.log.debug(f'Git remote command: {git_remote}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with subprocess.Popen(git_remote, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding='utf-8') as p:
|
||||||
|
for line in p.stdout:
|
||||||
|
print(line, end='')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
git_cmd = ' '.join([s.replace(' ', r'\ ') for s in git_remote])
|
||||||
|
|
||||||
|
cli.log.error(f"Could not run '{git_cmd}': {e.__class__.__name__}:{e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if p.returncode != 0:
|
||||||
|
cli.log.error(f'git remote add exited {p.returncode}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
cli.log.info(f'Added {DEFAULT_UPSTREAM} as remote upstream.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def git_clone_fork(destination, baseurl, fork, branch, force=False):
|
||||||
|
"""Clone fork and configure upstream."""
|
||||||
|
url = '/'.join((baseurl, fork))
|
||||||
|
|
||||||
|
if force:
|
||||||
|
rmtree(destination)
|
||||||
|
|
||||||
|
if not git_clone(destination, url, branch):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return git_set_upstream(destination)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ def is_qmk_firmware(qmk_firmware):
|
|||||||
paths = [
|
paths = [
|
||||||
qmk_firmware,
|
qmk_firmware,
|
||||||
qmk_firmware / 'quantum',
|
qmk_firmware / 'quantum',
|
||||||
|
qmk_firmware / 'requirements.txt',
|
||||||
|
qmk_firmware / 'requirements-dev.txt',
|
||||||
qmk_firmware / 'lib/python/qmk/cli/__init__.py',
|
qmk_firmware / 'lib/python/qmk/cli/__init__.py',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ def clone(cli):
|
|||||||
# Exists (but not an empty dir)
|
# Exists (but not an empty dir)
|
||||||
if cli.args.destination.exists() and any(cli.args.destination.iterdir()):
|
if cli.args.destination.exists() and any(cli.args.destination.iterdir()):
|
||||||
cli.log.error('Destination already exists: %s', cli.args.destination)
|
cli.log.error('Destination already exists: %s', cli.args.destination)
|
||||||
exit(1)
|
return False
|
||||||
|
|
||||||
return git_clone(git_url, cli.args.destination, cli.args.branch)
|
return git_clone(cli.args.destination, git_url, cli.args.branch)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Prints environment information.
|
"""Prints environment information.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
@@ -26,6 +27,10 @@ def env(cli):
|
|||||||
data[converted_key] = val
|
data[converted_key] = val
|
||||||
|
|
||||||
if cli.args.var:
|
if cli.args.var:
|
||||||
|
if cli.args.var not in data:
|
||||||
|
print(f'Variable "{cli.args.var}" does not exist!', file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
# dump out requested arg
|
# dump out requested arg
|
||||||
print(data[cli.args.var])
|
print(data[cli.args.var])
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -2,66 +2,28 @@
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
from milc.questions import choice, question, yesno
|
from milc.questions import choice, question, yesno
|
||||||
from qmk_cli.git import git_clone
|
from qmk_cli.git import git_clone_fork
|
||||||
from qmk_cli.helpers import AbsPath, is_qmk_firmware, rmtree
|
from qmk_cli.helpers import AbsPath, is_qmk_firmware
|
||||||
|
|
||||||
default_base = 'https://github.com'
|
DEFAULT_BASE = 'https://github.com'
|
||||||
default_repo = 'qmk_firmware'
|
DEFAULT_REPO = 'qmk_firmware'
|
||||||
default_fork = 'qmk/' + default_repo
|
DEFAULT_FORK = 'qmk/' + DEFAULT_REPO
|
||||||
default_branch = 'master'
|
DEFAULT_BRANCH = 'master'
|
||||||
|
|
||||||
|
|
||||||
def git_upstream(destination):
|
|
||||||
"""Add the qmk/qmk_firmware upstream to a qmk_firmware clone.
|
|
||||||
"""
|
|
||||||
git_url = '/'.join((cli.args.baseurl, default_fork))
|
|
||||||
git_cmd = [
|
|
||||||
'git',
|
|
||||||
'-C',
|
|
||||||
destination,
|
|
||||||
'remote',
|
|
||||||
'add',
|
|
||||||
'upstream',
|
|
||||||
git_url,
|
|
||||||
]
|
|
||||||
|
|
||||||
with subprocess.Popen(git_cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding='utf-8') as p:
|
|
||||||
for line in p.stdout:
|
|
||||||
print(line, end='')
|
|
||||||
|
|
||||||
if p.returncode == 0:
|
|
||||||
cli.log.info('Added %s as remote upstream.', git_url)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
cli.log.error('%s exited %d', ' '.join(git_cmd), p.returncode)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def git_clone_fork(fork, branch, force=False):
|
|
||||||
if force:
|
|
||||||
rmtree(cli.args.home)
|
|
||||||
|
|
||||||
git_url = '/'.join((cli.args.baseurl, fork))
|
|
||||||
if git_clone(git_url, cli.args.home, branch):
|
|
||||||
git_upstream(cli.args.home)
|
|
||||||
else:
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-n', '--no', arg_only=True, action='store_true', help='Answer no to all questions')
|
@cli.argument('-n', '--no', arg_only=True, action='store_true', help='Answer no to all questions')
|
||||||
@cli.argument('-y', '--yes', arg_only=True, action='store_true', help='Answer yes to all questions')
|
@cli.argument('-y', '--yes', arg_only=True, action='store_true', help='Answer yes to all questions')
|
||||||
@cli.argument('--baseurl', arg_only=True, default=default_base, help='The URL all git operations start from. Default: %s' % default_base)
|
@cli.argument('--baseurl', arg_only=True, default=DEFAULT_BASE, help='The URL all git operations start from. Default: %s' % DEFAULT_BASE)
|
||||||
@cli.argument('-b', '--branch', arg_only=True, default=default_branch, help='The branch to clone. Default: %s' % default_branch)
|
@cli.argument('-b', '--branch', arg_only=True, default=DEFAULT_BRANCH, help='The branch to clone. Default: %s' % DEFAULT_BRANCH)
|
||||||
@cli.argument('-H', '--home', arg_only=True, default=Path(os.environ['QMK_HOME']), type=AbsPath, help='The location for QMK Firmware. Default: %s' % os.environ['QMK_HOME'])
|
@cli.argument('-H', '--home', arg_only=True, default=Path(os.environ['QMK_HOME']), type=AbsPath, help='The location for QMK Firmware. Default: %s' % os.environ['QMK_HOME'])
|
||||||
@cli.argument('fork', arg_only=True, default=default_fork, nargs='?', help='The qmk_firmware fork to clone. Default: %s' % default_fork)
|
@cli.argument('fork', arg_only=True, default=DEFAULT_FORK, nargs='?', help='The qmk_firmware fork to clone. Default: %s' % DEFAULT_FORK)
|
||||||
@cli.subcommand('Setup your computer for qmk_firmware.')
|
@cli.subcommand('Setup your computer for qmk_firmware.')
|
||||||
def setup(cli):
|
def setup(cli): # noqa: C901
|
||||||
"""Guide the user through setting up their QMK environment.
|
"""Guide the user through setting up their QMK environment.
|
||||||
"""
|
"""
|
||||||
clone_prompt = 'Would you like to clone {fg_cyan}%s{fg_reset} to {fg_cyan}%s{fg_reset}?' % (cli.args.fork, shlex.quote(str(cli.args.home)))
|
clone_prompt = 'Would you like to clone {fg_cyan}%s{fg_reset} to {fg_cyan}%s{fg_reset}?' % (cli.args.fork, shlex.quote(str(cli.args.home)))
|
||||||
@@ -70,7 +32,7 @@ def setup(cli):
|
|||||||
# Sanity checks
|
# Sanity checks
|
||||||
if cli.args.yes and cli.args.no:
|
if cli.args.yes and cli.args.no:
|
||||||
cli.log.error("Can't use both --yes and --no at the same time.")
|
cli.log.error("Can't use both --yes and --no at the same time.")
|
||||||
exit(1)
|
return False
|
||||||
|
|
||||||
# Check on qmk_firmware
|
# Check on qmk_firmware
|
||||||
# If it exists, ask the user what to do with it
|
# If it exists, ask the user what to do with it
|
||||||
@@ -88,18 +50,20 @@ def setup(cli):
|
|||||||
found_action = choice(found_prompt, options=found_options, default=2)
|
found_action = choice(found_prompt, options=found_options, default=2)
|
||||||
if found_action == f"Delete and reclone {cli.args.fork}":
|
if found_action == f"Delete and reclone {cli.args.fork}":
|
||||||
if not yesno(delete_confirm, default=False):
|
if not yesno(delete_confirm, default=False):
|
||||||
exit(1)
|
return False
|
||||||
|
|
||||||
git_clone_fork(cli.args.fork, cli.args.branch, force=True)
|
if not git_clone_fork(cli.args.home, cli.args.baseurl, cli.args.fork, cli.args.branch, force=True):
|
||||||
|
return False
|
||||||
|
|
||||||
elif found_action == "Delete and clone a different fork":
|
elif found_action == "Delete and clone a different fork":
|
||||||
fork_name = question("Enter the name of the fork:", default=cli.args.fork)
|
fork_name = question("Enter the name of the fork:", default=cli.args.fork)
|
||||||
branch_name = question("Enter the branch name to clone:", default=cli.args.branch)
|
branch_name = question("Enter the branch name to clone:", default=cli.args.branch)
|
||||||
|
|
||||||
if not yesno(delete_confirm, default=False):
|
if not yesno(delete_confirm, default=False):
|
||||||
exit(1)
|
return False
|
||||||
|
|
||||||
git_clone_fork(fork_name, branch_name, force=True)
|
if not git_clone_fork(cli.args.home, cli.args.baseurl, fork_name, branch_name, force=True):
|
||||||
|
return False
|
||||||
|
|
||||||
# Exists (but not an empty dir)
|
# Exists (but not an empty dir)
|
||||||
elif cli.args.home.exists() and any(cli.args.home.iterdir()):
|
elif cli.args.home.exists() and any(cli.args.home.iterdir()):
|
||||||
@@ -109,12 +73,13 @@ def setup(cli):
|
|||||||
cli.log.warning('Warning: %s does not end in "qmk_firmware". Did you mean to use "--home %s/qmk_firmware"?' % (path_str, path_str))
|
cli.log.warning('Warning: %s does not end in "qmk_firmware". Did you mean to use "--home %s/qmk_firmware"?' % (path_str, path_str))
|
||||||
|
|
||||||
cli.log.error("Path '%s' exists but is not a qmk_firmware clone!", path_str)
|
cli.log.error("Path '%s' exists but is not a qmk_firmware clone!", path_str)
|
||||||
exit(1)
|
return False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
cli.log.error('Could not find qmk_firmware!')
|
cli.log.error('Could not find qmk_firmware!')
|
||||||
if yesno(clone_prompt):
|
if yesno(clone_prompt):
|
||||||
git_clone_fork(cli.args.fork, cli.args.branch)
|
if not git_clone_fork(cli.args.home, cli.args.baseurl, cli.args.fork, cli.args.branch):
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
cli.log.warning('Not cloning qmk_firmware due to user input or --no flag.')
|
cli.log.warning('Not cloning qmk_firmware due to user input or --no flag.')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
--index-url https://pypi.python.org/simple/
|
||||||
|
|
||||||
|
-e .
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import tempfile
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import create_autospec, PropertyMock, MagicMock
|
||||||
|
|
||||||
|
from milc import MILCInterface
|
||||||
|
from milc.configuration import Configuration
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption(
|
||||||
|
'--qmk',
|
||||||
|
action='store',
|
||||||
|
default='wrapper',
|
||||||
|
help='options: ./qmk wrapper or real qmk from path',
|
||||||
|
choices=('wrapper', 'real'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def temp_directory():
|
||||||
|
"""Similar behavior to the default tmpdir fixture except the folder is cleaned up."""
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_path:
|
||||||
|
yield Path(tmp_path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_cli():
|
||||||
|
"""Mock cli to pass to cli subcommands,"""
|
||||||
|
ret = create_autospec(MILCInterface)
|
||||||
|
|
||||||
|
# default behavior
|
||||||
|
type(ret).config = Configuration()
|
||||||
|
ret.config.general.unicode = True
|
||||||
|
ret.config.general.color = True
|
||||||
|
type(ret).write_config_option = MagicMock()
|
||||||
|
type(ret.args).var = PropertyMock(return_value=None)
|
||||||
|
|
||||||
|
return ret
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, PropertyMock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subcommand(temp_directory):
|
||||||
|
tmp = temp_directory.as_posix()
|
||||||
|
with patch.dict('os.environ', {'ORIG_CWD': tmp, 'QMK_HOME': tmp}, clear=True):
|
||||||
|
import qmk_cli.subcommands.clone as clone
|
||||||
|
|
||||||
|
yield clone
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def git_clone(subcommand):
|
||||||
|
with patch.object(subcommand, 'git_clone') as git_clone:
|
||||||
|
yield git_clone
|
||||||
|
|
||||||
|
|
||||||
|
def test_clone(subcommand, mock_cli, git_clone):
|
||||||
|
type(mock_cli.args).baseurl = PropertyMock(return_value='asdf')
|
||||||
|
type(mock_cli.args).fork = PropertyMock(return_value='fork')
|
||||||
|
git_clone.return_value = True
|
||||||
|
|
||||||
|
ret = subcommand.clone(mock_cli)
|
||||||
|
|
||||||
|
git_clone.assert_called_once()
|
||||||
|
assert ret is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_clone_not_empty(subcommand, mock_cli, temp_directory, git_clone):
|
||||||
|
type(mock_cli.args).baseurl = PropertyMock(return_value='asdf')
|
||||||
|
type(mock_cli.args).fork = PropertyMock(return_value='fork')
|
||||||
|
type(mock_cli.args).destination = PropertyMock(return_value=temp_directory)
|
||||||
|
(temp_directory / 'asdf').touch()
|
||||||
|
|
||||||
|
ret = subcommand.clone(mock_cli)
|
||||||
|
|
||||||
|
git_clone.assert_not_called()
|
||||||
|
assert ret is False
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, PropertyMock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subcommand(temp_directory):
|
||||||
|
tmp = temp_directory.as_posix()
|
||||||
|
with patch.dict('os.environ', {'ORIG_CWD': tmp, 'QMK_HOME': tmp}, clear=True):
|
||||||
|
import qmk_cli.subcommands.env as env
|
||||||
|
|
||||||
|
yield env
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def is_qmk_firmware(subcommand):
|
||||||
|
with patch.object(subcommand, 'is_qmk_firmware') as is_qmk_firmware:
|
||||||
|
is_qmk_firmware.return_value = True
|
||||||
|
|
||||||
|
yield is_qmk_firmware
|
||||||
|
|
||||||
|
|
||||||
|
def test_request_qmk_firmware_exists(subcommand, mock_cli, capsys, temp_directory, is_qmk_firmware):
|
||||||
|
subcommand.env(mock_cli)
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert f'QMK_HOME="{temp_directory}"' in captured
|
||||||
|
assert f'QMK_FIRMWARE="{temp_directory}"' in captured
|
||||||
|
|
||||||
|
|
||||||
|
def test_request_all_variables(subcommand, mock_cli, capsys, temp_directory):
|
||||||
|
subcommand.env(mock_cli)
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert f'QMK_HOME="{temp_directory}"' in captured
|
||||||
|
assert 'QMK_FIRMWARE=""' in captured
|
||||||
|
assert 'QMK_UNICODE="True"' in captured
|
||||||
|
|
||||||
|
|
||||||
|
def test_request_single_variable(subcommand, mock_cli, capsys, temp_directory):
|
||||||
|
type(mock_cli.args).var = PropertyMock(return_value='QMK_HOME')
|
||||||
|
|
||||||
|
subcommand.env(mock_cli)
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert captured == f'{temp_directory}\n'
|
||||||
|
|
||||||
|
|
||||||
|
def test_request_single_variable_no_exits(subcommand, mock_cli, capsys):
|
||||||
|
type(mock_cli.args).var = PropertyMock(return_value='ASDF')
|
||||||
|
|
||||||
|
ret = subcommand.env(mock_cli)
|
||||||
|
captured = capsys.readouterr().err
|
||||||
|
assert captured == 'Variable "ASDF" does not exist!\n'
|
||||||
|
assert ret is False
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, PropertyMock, ANY
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subcommand(temp_directory):
|
||||||
|
tmp = temp_directory.as_posix()
|
||||||
|
with patch.dict('os.environ', {'ORIG_CWD': tmp, 'QMK_HOME': tmp}, clear=True):
|
||||||
|
import qmk_cli.subcommands.setup as setup
|
||||||
|
|
||||||
|
yield setup
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def is_qmk_firmware(subcommand):
|
||||||
|
with patch.object(subcommand, 'is_qmk_firmware') as is_qmk_firmware:
|
||||||
|
is_qmk_firmware.return_value = True
|
||||||
|
|
||||||
|
yield is_qmk_firmware
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def yesno(subcommand):
|
||||||
|
with patch.object(subcommand, 'yesno') as yesno:
|
||||||
|
yesno.return_value = True
|
||||||
|
|
||||||
|
yield yesno
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def choice(subcommand):
|
||||||
|
with patch.object(subcommand, 'choice') as choice:
|
||||||
|
yield choice
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def question(subcommand):
|
||||||
|
with patch.object(subcommand, 'question') as question:
|
||||||
|
yield question
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def git_clone_fork(subcommand):
|
||||||
|
with patch.object(subcommand, 'git_clone_fork') as git_clone_fork:
|
||||||
|
yield git_clone_fork
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_both_yes_no_invalid(subcommand, mock_cli):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=True)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=True)
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_reclone(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
type(mock_cli.args).fork = 'asdf'
|
||||||
|
choice.return_value = 'Delete and reclone asdf'
|
||||||
|
yesno.return_value = True
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'This will delete your current qmk_firmware directory.' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_reclone_failed(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
type(mock_cli.args).fork = 'asdf'
|
||||||
|
choice.return_value = 'Delete and reclone asdf'
|
||||||
|
yesno.return_value = True
|
||||||
|
git_clone_fork.return_value = False
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'This will delete your current qmk_firmware directory.' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_reclone_no(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
type(mock_cli.args).fork = 'asdf'
|
||||||
|
choice.return_value = 'Delete and reclone asdf'
|
||||||
|
yesno.return_value = False
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
git_clone_fork.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_clone_diff_fork(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, question, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
choice.return_value = 'Delete and clone a different fork'
|
||||||
|
yesno.return_value = True
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'This will delete your current qmk_firmware directory.' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_clone_diff_fork_failed(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, question, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
choice.return_value = 'Delete and clone a different fork'
|
||||||
|
yesno.return_value = True
|
||||||
|
git_clone_fork.return_value = False
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'This will delete your current qmk_firmware directory.' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_clone_diff_fork_no(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, choice, question, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
choice.return_value = 'Delete and clone a different fork'
|
||||||
|
yesno.return_value = False
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
git_clone_fork.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_home_exists_not_empty(subcommand, mock_cli, is_qmk_firmware, temp_directory):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
is_qmk_firmware.return_value = False
|
||||||
|
(temp_directory / 'asdf').touch()
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_missing(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
is_qmk_firmware.return_value = False
|
||||||
|
yesno.return_value = True
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'Would you like to clone' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_missing_failed(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
is_qmk_firmware.return_value = False
|
||||||
|
yesno.return_value = True
|
||||||
|
git_clone_fork.return_value = False
|
||||||
|
|
||||||
|
ret = subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'Would you like to clone' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_called_once()
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_missing_no(subcommand, mock_cli, is_qmk_firmware, temp_directory, yesno, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).home = PropertyMock(return_value=temp_directory)
|
||||||
|
is_qmk_firmware.return_value = False
|
||||||
|
yesno.return_value = False
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
yesno.assert_called_once()
|
||||||
|
assert 'Would you like to clone' in yesno.call_args.args[0]
|
||||||
|
git_clone_fork.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_chains_args_to_doctor(subcommand, mock_cli, is_qmk_firmware, yesno, choice, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=True)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=False)
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
mock_cli.run.assert_called_once()
|
||||||
|
assert mock_cli.run.call_args.args[0] == [ANY, '--color', '--unicode', 'doctor', '-y']
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_chains_args_to_doctor_no(subcommand, mock_cli, is_qmk_firmware, yesno, choice, git_clone_fork):
|
||||||
|
type(mock_cli.args).yes = PropertyMock(return_value=False)
|
||||||
|
type(mock_cli.args).no = PropertyMock(return_value=True)
|
||||||
|
mock_cli.config.general.color = False
|
||||||
|
mock_cli.config.general.unicode = False
|
||||||
|
|
||||||
|
subcommand.setup(mock_cli)
|
||||||
|
|
||||||
|
mock_cli.run.assert_called_once()
|
||||||
|
assert mock_cli.run.call_args.args[0] == [ANY, '--no-color', '--no-unicode', 'doctor', '-n']
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import pytest
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def temp_env(temp_directory, monkeypatch):
|
||||||
|
qmk_firmware = temp_directory / 'qmk_firmware'
|
||||||
|
monkeypatch.setenv("QMK_HOME", qmk_firmware.as_posix())
|
||||||
|
yield qmk_firmware
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def run_cli(request):
|
||||||
|
def run_cli_wrapper(args):
|
||||||
|
cmd = f'{request.config.rootpath}/qmk' if request.config.getoption("--qmk") == 'wrapper' else 'qmk'
|
||||||
|
|
||||||
|
return subprocess.run([cmd, *args], capture_output=True, text=True)
|
||||||
|
|
||||||
|
return run_cli_wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.system
|
||||||
|
def test_cli_help(run_cli):
|
||||||
|
completed_process = run_cli(['clone', '--help'])
|
||||||
|
|
||||||
|
assert 'usage:' in completed_process.stdout
|
||||||
|
assert completed_process.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.system
|
||||||
|
def test_cli_setup_no(run_cli):
|
||||||
|
completed_process = run_cli(['setup', '-n'])
|
||||||
|
|
||||||
|
assert 'Could not find qmk_firmware!' in completed_process.stderr
|
||||||
|
assert 'Not cloning qmk_firmware due to user input or --no flag.' in completed_process.stderr
|
||||||
|
assert completed_process.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.system
|
||||||
|
def test_cli_setup_yes(run_cli):
|
||||||
|
completed_process = run_cli(['setup', '-y'])
|
||||||
|
|
||||||
|
assert 'Successfully cloned https://github.com/qmk/qmk_firmware' in completed_process.stderr
|
||||||
|
assert 'Added https://github.com/qmk/qmk_firmware as remote upstream' in completed_process.stderr
|
||||||
|
assert 'QMK Doctor is checking your environment' in completed_process.stderr
|
||||||
|
assert completed_process.returncode == 0
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import pytest
|
||||||
|
import subprocess
|
||||||
|
from unittest.mock import patch, PropertyMock
|
||||||
|
|
||||||
|
import qmk_cli.git
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen", side_effect=Exception("foobar"))
|
||||||
|
@patch("qmk_cli.git.cli.log.error")
|
||||||
|
def test_git_clone_except(mock_log_error, mock_popen):
|
||||||
|
ret = qmk_cli.git.git_clone('/tmp', 'https://github.com/qmk/qmk_firmware', 'master')
|
||||||
|
|
||||||
|
assert "Could not run" in str(mock_log_error.call_args_list)
|
||||||
|
assert "Exception:foobar" in str(mock_log_error.call_args_list)
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen")
|
||||||
|
def test_git_clone_logs_output(mock_popen, capsys):
|
||||||
|
type(mock_popen().__enter__()).returncode = PropertyMock(return_value=0)
|
||||||
|
type(mock_popen().__enter__()).stdout = PropertyMock(return_value=['asdf'])
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_clone('/tmp', 'https://github.com/qmk/qmk_firmware', 'master')
|
||||||
|
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert 'asdf' in captured
|
||||||
|
assert ret is True
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen")
|
||||||
|
def test_git_clone_captures_exit_code(mock_popen):
|
||||||
|
type(mock_popen().__enter__()).returncode = PropertyMock(return_value=1)
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_clone('/tmp', 'https://github.com/qmk/qmk_firmware', 'master')
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen", side_effect=Exception("foobar"))
|
||||||
|
@patch("qmk_cli.git.cli.log.error")
|
||||||
|
def test_git_set_upstream_except(mock_log_error, mock_popen):
|
||||||
|
ret = qmk_cli.git.git_set_upstream('/tmp')
|
||||||
|
|
||||||
|
assert "Could not run" in str(mock_log_error.call_args_list)
|
||||||
|
assert "Exception:foobar" in str(mock_log_error.call_args_list)
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen")
|
||||||
|
def test_git_set_upstream_logs_output(mock_popen, capsys):
|
||||||
|
type(mock_popen().__enter__()).returncode = PropertyMock(return_value=0)
|
||||||
|
type(mock_popen().__enter__()).stdout = PropertyMock(return_value=['asdf'])
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_set_upstream('/tmp')
|
||||||
|
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert 'asdf' in captured
|
||||||
|
assert ret is True
|
||||||
|
|
||||||
|
|
||||||
|
@patch("qmk_cli.git.subprocess.Popen")
|
||||||
|
def test_git_set_upstream_captures_exit_code(mock_popen):
|
||||||
|
type(mock_popen().__enter__()).returncode = PropertyMock(return_value=1)
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_set_upstream('/tmp')
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(qmk_cli.git, 'git_clone')
|
||||||
|
@patch.object(qmk_cli.git, 'git_set_upstream')
|
||||||
|
def test_git_clone_fork_fail(git_set_upstream, git_clone, temp_directory):
|
||||||
|
git_clone.return_value = False
|
||||||
|
git_set_upstream.return_value = False
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_clone_fork(temp_directory.as_posix(), 'https://github.com', 'qmk/qmk_firmware', 'master', False)
|
||||||
|
|
||||||
|
assert ret is False
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(qmk_cli.git, 'git_clone')
|
||||||
|
@patch.object(qmk_cli.git, 'git_set_upstream')
|
||||||
|
def test_git_clone_fork_force(git_set_upstream, git_clone, temp_directory):
|
||||||
|
(temp_directory / 'asdf').touch()
|
||||||
|
|
||||||
|
git_clone.return_value = True
|
||||||
|
git_set_upstream.return_value = True
|
||||||
|
|
||||||
|
ret = qmk_cli.git.git_clone_fork(temp_directory.as_posix(), 'https://github.com', 'qmk/qmk_firmware', 'master', True)
|
||||||
|
|
||||||
|
assert ret is True
|
||||||
|
assert (temp_directory / 'asdf').exists() is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
def test_git_clone(temp_directory):
|
||||||
|
qmk_firmware = temp_directory / 'qmk_firmware'
|
||||||
|
ret = qmk_cli.git.git_clone(qmk_firmware.as_posix(), 'https://github.com/qmk/qmk_firmware', 'master')
|
||||||
|
|
||||||
|
from qmk_cli.helpers import is_qmk_firmware
|
||||||
|
|
||||||
|
assert is_qmk_firmware(qmk_firmware) is True
|
||||||
|
assert ret is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
def test_git_clone_fork(temp_directory):
|
||||||
|
qmk_firmware = temp_directory / 'qmk_firmware'
|
||||||
|
qmk_firmware.mkdir()
|
||||||
|
(qmk_firmware / 'asdf').touch()
|
||||||
|
ret = qmk_cli.git.git_clone_fork(qmk_firmware.as_posix(), 'https://github.com', 'qmk/qmk_firmware', 'master', True)
|
||||||
|
|
||||||
|
from qmk_cli.helpers import is_qmk_firmware
|
||||||
|
|
||||||
|
assert is_qmk_firmware(qmk_firmware) is True
|
||||||
|
assert 'https://github.com/qmk/qmk_firmware' in subprocess.run(['git', '-C', qmk_firmware.as_posix(), 'remote', 'get-url', 'upstream'], capture_output=True, text=True).stdout
|
||||||
|
assert ret is True
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch, PropertyMock
|
||||||
|
|
||||||
|
import qmk_cli.helpers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def reset_env():
|
||||||
|
cur_dir = os.getcwd()
|
||||||
|
|
||||||
|
yield cur_dir
|
||||||
|
|
||||||
|
os.chdir(cur_dir)
|
||||||
|
qmk_cli.helpers.find_qmk_firmware.cache_clear()
|
||||||
|
qmk_cli.helpers.in_qmk_firmware.cache_clear()
|
||||||
|
qmk_cli.helpers.find_qmk_userspace.cache_clear()
|
||||||
|
qmk_cli.helpers.in_qmk_userspace.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
|
def test_abspath(temp_directory):
|
||||||
|
tmp = temp_directory.absolute()
|
||||||
|
ret = qmk_cli.helpers.AbsPath(tmp)
|
||||||
|
assert ret.samefile(tmp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_abspath_str(temp_directory):
|
||||||
|
tmp = temp_directory.absolute().as_posix()
|
||||||
|
ret = qmk_cli.helpers.AbsPath(tmp)
|
||||||
|
assert ret.samefile(tmp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_abspath_rel(temp_directory):
|
||||||
|
with patch.dict('os.environ', {'ORIG_CWD': temp_directory.as_posix()}, clear=True):
|
||||||
|
tmp = './asdf'
|
||||||
|
ret = qmk_cli.helpers.AbsPath(tmp)
|
||||||
|
assert ret.as_posix() == (temp_directory / 'asdf').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_rmtree(temp_directory):
|
||||||
|
tmp = temp_directory / 'asdf.txt'
|
||||||
|
tmp.touch()
|
||||||
|
|
||||||
|
qmk_cli.helpers.rmtree(temp_directory)
|
||||||
|
|
||||||
|
assert tmp.exists() is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(os.name != "nt", reason="Only triggers issue on windows")
|
||||||
|
def test_rmtree_readonly(temp_directory):
|
||||||
|
tmp = temp_directory / 'asdf.txt'
|
||||||
|
tmp.touch()
|
||||||
|
os.chmod(tmp, stat.S_IREAD)
|
||||||
|
|
||||||
|
qmk_cli.helpers.rmtree(temp_directory)
|
||||||
|
|
||||||
|
assert tmp.exists() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_firmware(temp_directory):
|
||||||
|
(temp_directory / 'quantum').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'requirements.txt').touch()
|
||||||
|
(temp_directory / 'requirements-dev.txt').touch()
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.is_qmk_firmware(temp_directory) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_firmware_partially_missing(temp_directory):
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.is_qmk_firmware(temp_directory) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware(temp_directory):
|
||||||
|
(temp_directory / 'quantum').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'requirements.txt').touch()
|
||||||
|
(temp_directory / 'requirements-dev.txt').touch()
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware_env(temp_directory):
|
||||||
|
with patch.dict('os.environ', {'QMK_HOME': temp_directory.as_posix()}, clear=True):
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware_env_missing(temp_directory):
|
||||||
|
with patch.dict('os.environ', {'QMK_HOME': (temp_directory / 'asdf').as_posix()}, clear=True):
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == (temp_directory / 'asdf').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware_config(temp_directory):
|
||||||
|
with patch.object(qmk_cli.helpers, 'cli') as cli:
|
||||||
|
type(cli.config.user).qmk_home = PropertyMock(return_value=temp_directory.as_posix())
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware_config_user():
|
||||||
|
with patch.object(qmk_cli.helpers, 'cli') as cli:
|
||||||
|
type(cli.config.user).qmk_home = PropertyMock(return_value='~/asdf')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == (Path.home() / 'asdf').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_firmware_default(temp_directory):
|
||||||
|
with patch('pathlib.Path.home') as home:
|
||||||
|
home.return_value = temp_directory
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_firmware().as_posix() == (temp_directory / 'qmk_firmware').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_firmware(temp_directory):
|
||||||
|
(temp_directory / 'quantum').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'requirements.txt').touch()
|
||||||
|
(temp_directory / 'requirements-dev.txt').touch()
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_firmware_sub(temp_directory):
|
||||||
|
(temp_directory / 'quantum').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'requirements.txt').touch()
|
||||||
|
(temp_directory / 'requirements-dev.txt').touch()
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
os.chdir(temp_directory / 'quantum')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_firmware_sub_sub(temp_directory):
|
||||||
|
(temp_directory / 'quantum').mkdir(parents=True)
|
||||||
|
(temp_directory / 'lib/python/qmk/cli').mkdir(parents=True)
|
||||||
|
(temp_directory / 'requirements.txt').touch()
|
||||||
|
(temp_directory / 'requirements-dev.txt').touch()
|
||||||
|
(temp_directory / 'lib/python/qmk/cli/__init__.py').touch()
|
||||||
|
os.chdir(temp_directory / 'lib' / 'python')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_firmware().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_firmware_invalid(temp_directory):
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_firmware() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_userspace(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('{"userspace_version": 2}')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.is_qmk_userspace(temp_directory) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_userspace_missing(temp_directory):
|
||||||
|
assert qmk_cli.helpers.is_qmk_userspace(temp_directory) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_userspace_invalid(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('asdf')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.is_qmk_userspace(temp_directory) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_qmk_userspace_empty(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').touch()
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.is_qmk_userspace(temp_directory) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('{"userspace_version": 2}')
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace_env(temp_directory):
|
||||||
|
with patch.dict('os.environ', {'QMK_USERSPACE': temp_directory.as_posix()}, clear=True):
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace_env_missing(temp_directory):
|
||||||
|
with patch.dict('os.environ', {'QMK_USERSPACE': (temp_directory / 'asdf').as_posix()}, clear=True):
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == (temp_directory / 'asdf').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace_config(temp_directory):
|
||||||
|
with patch.object(qmk_cli.helpers, 'cli') as cli:
|
||||||
|
type(cli.config.user).overlay_dir = PropertyMock(return_value=temp_directory.as_posix())
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace_config_user():
|
||||||
|
with patch.object(qmk_cli.helpers, 'cli') as cli:
|
||||||
|
type(cli.config.user).overlay_dir = PropertyMock(return_value='~/asdf')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == (Path.home() / 'asdf').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_qmk_userspace_default(temp_directory):
|
||||||
|
with patch('pathlib.Path.home') as home:
|
||||||
|
home.return_value = temp_directory
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.find_qmk_userspace().as_posix() == (temp_directory / 'qmk_userspace').as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_userspace(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('{"userspace_version": 2}')
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_userspace_sub(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('{"userspace_version": 2}')
|
||||||
|
(temp_directory / 'keymaps' / 'test').mkdir(parents=True)
|
||||||
|
os.chdir(temp_directory / 'keymaps')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_userspace_sub_sub(temp_directory):
|
||||||
|
(temp_directory / 'qmk.json').write_text('{"userspace_version": 2}')
|
||||||
|
(temp_directory / 'keymaps' / 'test').mkdir(parents=True)
|
||||||
|
os.chdir(temp_directory / 'keymaps' / 'test')
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_userspace().as_posix() == temp_directory.as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_qmk_userspace_invalid(temp_directory):
|
||||||
|
os.chdir(temp_directory)
|
||||||
|
|
||||||
|
assert qmk_cli.helpers.in_qmk_userspace() is None
|
||||||
Reference in New Issue
Block a user