Skip to content

Commit

Permalink
Add ability to run pre-commit and copy pre-commit config file
Browse files Browse the repository at this point in the history
Up python version locally
  • Loading branch information
saville committed Dec 14, 2023
1 parent 9ef83a6 commit b093187
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.2
3.11.4
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ upstream docker images or developing using local code.
this project can control them
* Allows easy development of a single project or multiple projects at the same time
* Generate dynamic docker-compose files using Jinja templates for any number of projects
* Manage a [pre-commit](https://pre-commit.com/) config file in one place to copy and
install in each project


## Setup
Expand All @@ -45,6 +47,8 @@ my-app/
config.yml
# Environment variable configuration, symlinked to all projects automatically
docker-compose.env
# Optional pre-commit config file that will be copied and installed in each project
.pre-commit-config.yaml
# Arbitrary projects
project1/
# The only required file for a project is a docker-compose file
Expand Down
80 changes: 55 additions & 25 deletions pydc_control/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import argparse
import os
import shutil
import signal
import subprocess
import time
Expand Down Expand Up @@ -224,6 +225,56 @@ def get_repo_status(args: argparse.Namespace):
subprocess.call(['git', 'status', '--short', '--branch', '--untracked-files=no'], cwd=project.path)


def _handle_extra_remotes(extra_remotes: List[str], project: Project) -> None:
if not extra_remotes:
return
log.get_logger().debug('Adding any remotes specified if not already added')
base_git_path = project.repository.split(':')[0]
for remote in extra_remotes:
org = name = remote[0]
if len(remote) == 2:
# an optional name to be specified for the remote
name = remote[1]

# check if remote exists
command = ['git', 'ls-remote', '-q', '--exit-code', name]
# ignore stdout as the check can be misleading if this is the first time we are adding a repo
with open(os.devnull, 'wb') as fnull:
exit_code = subprocess.call(command, cwd=project.path, stdout=fnull, stderr=subprocess.STDOUT)
if exit_code == 0:
log.get_logger().debug(f'Remote {name} already exists in project {project.name}')
continue
log.get_logger().info(f'Trying to add remote {name} at '
f'{base_git_path}:{org}/{project.directory}.git in project {project.name}')
command = ['git', 'remote', 'add', name, f'{base_git_path}:{org}/{project.directory}.git']
exit_code = subprocess.call(command, cwd=project.path)

if exit_code:
log.get_logger().warning(
f'There was a problem adding remote {remote} in project {project.name}'
)


def _handle_pre_commit(project: Project) -> None:
# If there is a pre-commit config file, then copy it to each repo, git add it, and install it
pre_commit_config_path = config.get_pre_commit_config_path()
if os.path.exists(pre_commit_config_path):
log.get_logger().debug(f'Pre-commit config file {pre_commit_config_path} exists, installing')
pre_commit_file_name = os.path.basename(pre_commit_config_path)
shutil.copy(
pre_commit_config_path,
os.path.join(project.path, pre_commit_file_name),
)
subprocess.call(['git', 'add', pre_commit_file_name], cwd=project.path)
exit_code = subprocess.call(['pre-commit', 'install'], cwd=project.path)
if exit_code:
log.get_logger().warning(
f'Could not run pre-commit install for {project.name} ({project.path}), see errors above'
)
else:
log.get_logger().debug(f'Pre-commit config file {pre_commit_config_path} does not exist, ignoring')


def run_checkout(args: argparse.Namespace):
# pylint: disable=too-many-branches
if args.all_projects or not args.dev_project_names:
Expand Down Expand Up @@ -260,31 +311,10 @@ def run_checkout(args: argparse.Namespace):
if exit_code:
log.get_logger().warning(f'Could not clone or update {project.name} ({project.path}), see errors above')
result = exit_code

if not result and len(args.extra_remotes) > 0:
log.get_logger().debug('Adding any remotes specified if not already added')
base_git_path = project.repository.split(':')[0]
for remote in args.extra_remotes:
org = name = remote[0]
if len(remote) == 2:
# an optional name to be specified for the remote
name = remote[1]

# check if remote exists
command = ['git', 'ls-remote', '-q', '--exit-code', name]
# ignore stdout as the check can be misleading if this is the first time we are adding a repo
with open(os.devnull, 'wb') as fnull:
exit_code = subprocess.call(command, cwd=project.path, stdout=fnull, stderr=subprocess.STDOUT)
if exit_code == 0:
log.get_logger().debug(f'Remote {name} already exists in project {project.name}')
continue
log.get_logger().info(f'Trying to add remote {name} at '
f'{base_git_path}:{org}/{project.directory}.git in project {project.name}')
command = ['git', 'remote', 'add', name, f'{base_git_path}:{org}/{project.directory}.git']
exit_code = subprocess.call(command, cwd=project.path)

if exit_code:
log.get_logger().warning(f'There was a problem adding remote {remote} in project {project.name}')
else:
# Cloning/updating was successful
_handle_extra_remotes(args.extra_remotes, project)
_handle_pre_commit(project)

return result

Expand Down
8 changes: 8 additions & 0 deletions pydc_control/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

import yaml

from pre_commit.constants import CONFIG_FILE as PRE_COMMIT_CONFIG_FILE

from .exceptions import KnownException


Expand Down Expand Up @@ -44,6 +46,12 @@ def get_env_file_path() -> str:
return os.path.join(_BASE_DIR, ENV_FILE)


# The following methods are cached so that we only retrieve/validate them once (config cannot be changed mid-run)
@lru_cache()
def get_pre_commit_config_path() -> str:
return os.path.join(_BASE_DIR, str(PRE_COMMIT_CONFIG_FILE))


@lru_cache()
def get_docker_compose_path() -> str:
return os.path.join(_BASE_DIR, DOCKER_COMPOSE_FILE)
Expand Down
4 changes: 4 additions & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Jinja2>=2.7.2
PyYAML>=5.1.2
requests
pre-commit>=2
56 changes: 53 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
Jinja2>=2.7.2
PyYAML>=5.1.2
requests
#
# This file is autogenerated by pip-compile with python 3.7
# To update, run:
#
# pip-compile
#
certifi==2023.11.17
# via requests
cfgv==3.3.1
# via pre-commit
charset-normalizer==3.3.2
# via requests
distlib==0.3.8
# via virtualenv
filelock==3.12.2
# via virtualenv
identify==2.5.24
# via pre-commit
idna==3.6
# via requests
importlib-metadata==6.7.0
# via
# pre-commit
# virtualenv
jinja2==3.1.2
# via -r requirements.in
markupsafe==2.1.3
# via jinja2
nodeenv==1.8.0
# via pre-commit
platformdirs==4.0.0
# via virtualenv
pre-commit==2.21.0
# via -r requirements.in
pyyaml==6.0.1
# via
# -r requirements.in
# pre-commit
requests==2.31.0
# via -r requirements.in
typing-extensions==4.7.1
# via
# importlib-metadata
# platformdirs
urllib3==2.0.7
# via requests
virtualenv==20.25.0
# via pre-commit
zipp==3.15.0
# via importlib-metadata

# The following packages are considered to be unsafe in a requirements file:
# setuptools
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
install_requires=(
'Jinja2>=2.7.2',
'PyYAML>=5.1.2',
'requests>=2',
'requests',
'pre-commit>3',
),
classifiers=[
'Development Status :: 5 - Production/Stable',
Expand Down

0 comments on commit b093187

Please sign in to comment.