Skip to content
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
37 changes: 17 additions & 20 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ jobs:
fail-fast: false
matrix:
python-version:
- 3.8
- 3.9
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
- name: Set up Docker Compose
uses: docker/setup-compose-action@v1
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r test_requirements.txt
run: uv sync --locked
- name: Run pre-commit checks
run: pre-commit run --all-files
run: uv run pre-commit run --all-files
- name: Test with pytest
run: pytest --junitxml=test-reports/test-results.xml
run: uv run pytest --junitxml=test-reports/test-results.xml
- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
Expand All @@ -44,19 +44,16 @@ jobs:
with:
# Fetch all history in order to get the commit count for the version in setup.py
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: 3.8
- name: Remove version file
# This is just in case something else created it, destroy it so we'll get a fresh version
run: rm -f pydc_control/VERSION
- name: Install wheel
run: pip install wheel
python-version: 3.9
- name: Set version
run: uv version --no-sync "$(uv version --short).$(git rev-list --count HEAD)"
- name: Build
run: python setup.py sdist bdist_wheel
run: uv build
- name: Check upload
run: pip install twine && twine check dist/*
run: uv run --with twine twine check dist/*
- name: Publish to PyPi
# Only publish if this was a push
if: github.event_name == 'push'
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@ dist/
*.swp
pytest_cache

# This is generated on every build
pydc_control/VERSION

./docker-compose.env
./docker-compose.yml
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.1.7
rev: v0.12.7
hooks:
# Run the linter.
- id: ruff
- id: ruff-check
args: [ --fix ]
# Run the formatter.
- id: ruff-format
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.11.4
3.11
2 changes: 0 additions & 2 deletions MANIFEST.in

This file was deleted.

12 changes: 4 additions & 8 deletions README-example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,10 @@ this project.
* `Docker <https://www.docker.com/>`_ must be installed on your machine and the ``docker-compose`` command must
be available from the command line.
* The ``git`` command must be available if using Git repositories and ``appctl`` will be used for cloning them.
* A python environment or virtualenv. `pyenv <https://github.com/pyenv/pyenv>`_ is highly recommended to manage
your python installation for different versions.
* The `pydc-control <https://github.com/adobe/pydc-control>`_ python module must be installed into your current
python environment or virtualenv before using ``appctl``. This may be installed from pypi by running:

.. code-block:: console

pip install pydc-control
* `uv <https://github.com/astral-sh/uv>`_ is highly recommended to manage virtualenvs and python versions.
If using ``uv``, ensure that the ``uv`` command is available from the command line.
* If ``uv`` is not used, the ``pydc-control`` module must be installed in your current Python environment.
This may be done by running ``pip install pydc-control``.

Project setup
#############
Expand Down
41 changes: 34 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ upstream docker images or developing using local code.
installing in each configured project


## Development

To develop pydc-control itself, you'll need to set up the development environment:

1. Install [uv](https://docs.astral.sh/uv/) if you haven't already
2. Clone the repository and navigate to the project directory
3. Install dependencies: `uv sync`
4. Run tests: `uv run pytest`

The development dependencies include pytest, ruff for linting/formatting, and other tools needed for development.

## Setup

### Application filesystem layout
Expand Down Expand Up @@ -79,19 +90,27 @@ it into a local environment for easy execution.
#### Control script

Add a single python script to the project. Using naming such as `<app>ctl` is
recommended to make it easy to execute.
recommended to make it easy to execute. It is recommended to make this script run with
``uv`` as that will ensure that the correct python version and dependencies are used.

```python
#!/usr/bin/env python3
#!/usr/bin/env -S uv run --script
#
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "pydc-control",
# ]
# ///

import os
import sys
import pydc_control
from pathlib import Path

import pydc_control

if __name__ == '__main__':
# The base path is the location of your control project
base_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
base_path = Path(__file__).parent.parent.resolve()
# Run pydc_control, returns an exit code
sys.exit(pydc_control.run(base_path))
```
Expand Down Expand Up @@ -362,11 +381,19 @@ is enabled with s3).
It is easy to create additional commands using pydc_control.

```python
#!/usr/bin/env python3
#!/usr/bin/env -S uv run --script
#
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "pydc-control",
# ]
# ///

import argparse
import os
import sys
from pathlib import Path

import pydc_control

Expand All @@ -393,7 +420,7 @@ def configure_parsers(parser: argparse.ArgumentParser, commands_parser: argparse


if __name__ == '__main__':
base_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
base_path = Path(__file__).parent.parent.resolve()
sys.exit(pydc_control.run(base_path, configure_parsers))
```

Expand Down
7 changes: 4 additions & 3 deletions pydc_control/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

import argparse
import os
from typing import Callable, List, Optional, Sequence
from pathlib import Path
from typing import Callable, List, Optional, Sequence, Union

from . import commands, config, log
from .data import Project, Service
Expand Down Expand Up @@ -289,7 +290,7 @@ def _detect_current_project(dev_project_names: List[str]) -> None:


def run(
base_dir: str,
base_dir: Union[str, Path],
configure_parsers: Callable = None,
args: Optional[Sequence[str]] = None,
) -> int:
Expand All @@ -302,7 +303,7 @@ def run(
:return: The exit code
"""
# Initialize config based on the base dir
config.initialize(base_dir)
config.initialize(str(base_dir))

args = _parse_args(configure_parsers, args)

Expand Down
8 changes: 4 additions & 4 deletions pydc_control/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def _run_docker_compose_with_projects(
docker_compose_args: List[str],
) -> int:
# Always use the same project name to allow containers to be started/stopped from any repo
commands = ["docker-compose", "-p", config.get_dc_project()]
commands = ["docker", "compose", "-p", config.get_dc_project()]
commands.extend(["-f", config.get_docker_compose_path()])
for project in dev_projects:
commands.extend(["-f", os.path.join(project.path, config.DOCKER_COMPOSE_FILE)])
Expand All @@ -87,7 +87,7 @@ def _run_docker_compose_with_projects(
core_commands.extend(core_service_names)

log.get_logger().info(
f'Starting {len(core_service_names)} core service(s) (detached) by calling {" ".join(core_commands)}'
f"Starting {len(core_service_names)} core service(s) (detached) by calling {' '.join(core_commands)}"
)
exit_code = call_commands(core_commands)
if exit_code:
Expand Down Expand Up @@ -115,7 +115,7 @@ def _run_docker_compose_with_projects(
base_commands.extend(base_services)

log.get_logger().info(
f'Starting {len(base_services)} base service(s) (detached) by calling {" ".join(base_commands)}'
f"Starting {len(base_services)} base service(s) (detached) by calling {' '.join(base_commands)}"
)
exit_code = subprocess.call(base_commands)
if exit_code:
Expand All @@ -139,7 +139,7 @@ def _run_docker_compose_with_projects(
)
commands.extend(all_services)

log.get_logger().info(f'Calling {" ".join(commands)}')
log.get_logger().info(f"Calling {' '.join(commands)}")
return call_commands(commands)


Expand Down
3 changes: 2 additions & 1 deletion pydc_control/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
NOTICE: Adobe permits you to use, modify, and distribute this file in accordance
with the terms of the Adobe license agreement accompanying it.
"""

import argparse
import os
from functools import lru_cache
Expand Down Expand Up @@ -42,7 +43,7 @@ def container_name(self):
The actual container name.
"""
prefix = get_service_prefix("core" if self.core else "service")
return f'{prefix}{self.data.get("name")}'
return f"{prefix}{self.data.get('name')}"

@property
def dc_name(self):
Expand Down
73 changes: 73 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[build-system]
requires = ["uv_build"]
build-backend = "uv_build"

[project]
name = "pydc-control"
version = "1.49"
description = "Used to control multiple docker compose projects in a coordinated way."
readme = "README.md"
license = {text = "MIT"}
authors = [
{name = "Adobe", email = "noreply@adobe.com"}
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
requires-python = ">=3.9"
dependencies = [
"Jinja2>=2.7.2",
"PyYAML>=5.1.2",
"requests",
"pre-commit>=2",
]

[project.urls]
Homepage = "https://github.com/adobe/pydc-control"
Repository = "https://github.com/adobe/pydc-control"

[dependency-groups]
dev = [
"pytest>=6.2.4",
"pytest-randomly>=3.10.1",
"pytest-cov>=2.12.1",
"ruff>=0.12.7",
"ruff-lsp>=0.0.45",
"pre-commit>=3.6",
"docker>=7",
"tox-pyenv",
]

[tool.uv.build-backend]
module-name = "pydc_control"
module-root = ""
source-exclude = ["pydc_control/test"]
wheel-exclude = ["pydc_control/test"]

[tool.ruff]
# Enable the copyright rule
preview = true

[tool.ruff.lint]
extend-select = ["CPY"]

[tool.ruff.lint.extend-per-file-ignores]
"sample_project/*" = ["CPY"]

[tool.ruff.lint.flake8-copyright]
min-file-size = 200
notice-rgx = '''"""
Copyright [(2)\d{3}]* Adobe
All Rights Reserved.

NOTICE: Adobe permits you to use, modify, and distribute this file in accordance
with the terms of the Adobe license agreement accompanying it.
"""'''
2 changes: 0 additions & 2 deletions pytest.ini

This file was deleted.

4 changes: 0 additions & 4 deletions requirements.in

This file was deleted.

Loading