Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Add git and venv info to doctor's output #13405

Merged
merged 1 commit into from
Jul 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions lib/python/qmk/cli/doctor/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
from milc.questions import yesno

from qmk import submodules
from qmk.constants import QMK_FIRMWARE
from .check import CheckStatus, check_binaries, check_binary_versions, check_submodules, check_git_repo
from qmk.constants import QMK_FIRMWARE, QMK_FIRMWARE_UPSTREAM
from .check import CheckStatus, check_binaries, check_binary_versions, check_submodules
from qmk.commands import git_check_repo, git_get_branch, git_is_dirty, git_get_remotes, git_check_deviation, in_virtualenv


def os_tests():
Expand All @@ -32,6 +33,37 @@ def os_tests():
return CheckStatus.WARNING


def git_tests():
"""Run Git-related checks
"""
status = CheckStatus.OK

# Make sure our QMK home is a Git repo
git_ok = git_check_repo()
if not git_ok:
cli.log.warning("{fg_yellow}QMK home does not appear to be a Git repository! (no .git folder)")
status = CheckStatus.WARNING
else:
git_branch = git_get_branch()
if git_branch:
cli.log.info('Git branch: %s', git_branch)
git_dirty = git_is_dirty()
if git_dirty:
cli.log.warning('{fg_yellow}Git has unstashed/uncommitted changes.')
status = CheckStatus.WARNING
git_remotes = git_get_remotes()
if 'upstream' not in git_remotes.keys() or QMK_FIRMWARE_UPSTREAM not in git_remotes['upstream'].get('url', ''):
cli.log.warning('{fg_yellow}The official repository does not seem to be configured as git remote "upstream".')
status = CheckStatus.WARNING
else:
git_deviation = git_check_deviation(git_branch)
if git_branch in ['master', 'develop'] and git_deviation:
cli.log.warning('{fg_yellow}The local "%s" branch contains commits not found in the upstream branch.', git_branch)
status = CheckStatus.WARNING

return status


@cli.argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.')
@cli.argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.')
@cli.subcommand('Basic QMK environment checks')
Expand All @@ -49,12 +81,11 @@ def doctor(cli):

status = os_tests()

# Make sure our QMK home is a Git repo
git_ok = check_git_repo()
status = git_tests()

if git_ok == CheckStatus.WARNING:
cli.log.warning("QMK home does not appear to be a Git repository! (no .git folder)")
status = CheckStatus.WARNING
venv = in_virtualenv()
if venv:
cli.log.info('CLI installed in virtualenv.')

# Make sure the basic CLI tools we need are available and can be executed.
bin_ok = check_binaries()
Expand Down
71 changes: 70 additions & 1 deletion lib/python/qmk/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
import json
import os
import sys
import shutil
from pathlib import Path
from subprocess import DEVNULL
Expand All @@ -10,7 +11,7 @@
from milc import cli

import qmk.keymap
from qmk.constants import KEYBOARD_OUTPUT_PREFIX
from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
from qmk.json_schema import json_load

time_fmt = '%Y-%m-%d-%H:%M:%S'
Expand Down Expand Up @@ -237,3 +238,71 @@ def parse_configurator_json(configurator_file):
user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']]

return user_keymap


def git_check_repo():
"""Checks that the .git directory exists inside QMK_HOME.

This is a decent enough indicator that the qmk_firmware directory is a
proper Git repository, rather than a .zip download from GitHub.
"""
dot_git_dir = QMK_FIRMWARE / '.git'

return dot_git_dir.is_dir()


def git_get_branch():
"""Returns the current branch for a repo, or None.
"""
git_branch = cli.run(['git', 'branch', '--show-current'])
if not git_branch.returncode != 0 or not git_branch.stdout:
# Workaround for Git pre-2.22
git_branch = cli.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])

if git_branch.returncode == 0:
return git_branch.stdout.strip()


def git_is_dirty():
"""Returns 1 if repo is dirty, or 0 if clean
"""
git_diff_staged_cmd = ['git', 'diff', '--quiet']
git_diff_unstaged_cmd = [*git_diff_staged_cmd, '--cached']

unstaged = cli.run(git_diff_staged_cmd)
staged = cli.run(git_diff_unstaged_cmd)

return unstaged.returncode != 0 or staged.returncode != 0


def git_get_remotes():
"""Returns the current remotes for a repo.
"""
remotes = {}

git_remote_show_cmd = ['git', 'remote', 'show']
git_remote_get_cmd = ['git', 'remote', 'get-url']

git_remote_show = cli.run(git_remote_show_cmd)
if git_remote_show.returncode == 0:
for name in git_remote_show.stdout.splitlines():
git_remote_name = cli.run([*git_remote_get_cmd, name])
remotes[name.strip()] = {"url": git_remote_name.stdout.strip()}

return remotes


def git_check_deviation(active_branch):
"""Return True if branch has custom commits
"""
cli.run(['git', 'fetch', 'upstream', active_branch])
deviations = cli.run(['git', '--no-pager', 'log', f'upstream/{active_branch}...{active_branch}'])
return bool(deviations.returncode)


def in_virtualenv():
"""Check if running inside a virtualenv.
Based on https://stackoverflow.com/a/1883251
"""
active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
return active_prefix != sys.prefix
3 changes: 3 additions & 0 deletions lib/python/qmk/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
# The root of the qmk_firmware tree.
QMK_FIRMWARE = Path.cwd()

# Upstream repo url
QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware'

# This is the number of directories under `qmk_firmware/keyboards` that will be traversed. This is currently a limitation of our make system.
MAX_KEYBOARD_SUBFOLDERS = 5

Expand Down