Skip to content

Commit 9483af2

Browse files
authoredJan 30, 2025
Merge pull request #21 from globau/main
Apply linting, add missing type hints
2 parents 30ab35c + 07ddf31 commit 9483af2

19 files changed

+143
-90
lines changed
 

‎.github/workflows/docker-compose.yml ‎.github/workflows/docker_compose.yml

+1-10
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,4 @@ jobs:
2121

2222
- name: Execute tests in the running services
2323
run: |
24-
docker compose run sync
25-
26-
- name: Pytest coverage comment
27-
uses: MishaKav/pytest-coverage-comment@main
28-
with:
29-
pytest-xml-coverage-path: tests_output/coverage.xml
30-
title: Integration tests Coverage
31-
badge-title: Integration tests Coverage
32-
junitxml-path: tests_output/pytest.xml
33-
junitxml-title: JUnit Xml Summary
24+
docker compose run sync

‎.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ jobs:
1111
python-version: 3.11
1212
- name: Install tox
1313
run: pip install tox
14-
- name: Lint with ruff, black and mypy
14+
- name: Lint
1515
run: tox -e lint

‎.github/workflows/test.yml

+2-10
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,10 @@ jobs:
1212
cache: 'pip'
1313
- name: Install dependencies
1414
run: |
15-
python -m pip install --upgrade pip pytest pytest-mock pytest-cov
15+
python -m pip install --upgrade pip pytest pytest-mock
1616
pip install -e .
1717
./install_git-cinnabar.sh
1818
echo "${{ github.workspace }}" >> $GITHUB_PATH
1919
- name: Test with pytest
2020
run: |
21-
pytest --junitxml=pytest.xml --cov-report "xml:coverage.xml" --cov=git_hg_sync tests/
22-
- name: Pytest coverage comment
23-
uses: MishaKav/pytest-coverage-comment@main
24-
with:
25-
pytest-xml-coverage-path: coverage.xml
26-
title: Unit tests Coverage
27-
badge-title: Unit tests Coverage
28-
junitxml-path: pytest.xml
29-
junitxml-title: JUnit Xml Summary
21+
pytest --junitxml=pytest.xml

‎.gitignore

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
clones
2-
.tox
31
**/__pycache__/
2+
/.coverage
3+
/.tox
4+
/clones
45
/config.toml
5-
.coverage
6-
tests_output
6+
/tests_output

‎Dockerfile

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
FROM python:3.12-slim
22

3-
WORKDIR /app
4-
53
RUN groupadd --gid 10001 app \
6-
&& useradd -m -g app --uid 10001 -s /usr/sbin/nologin app
4+
&& useradd -m -g app --uid 10001 -d /app -s /usr/sbin/nologin app
75

86
RUN apt-get update && \
97
apt-get install --yes git mercurial curl vim && \
108
apt-get -q --yes autoremove && \
119
apt-get clean && \
1210
rm -rf /root/.cache
1311

12+
WORKDIR /app
13+
1414
# git-cinnabar
1515
COPY install_git-cinnabar.sh .
1616
RUN ./install_git-cinnabar.sh
1717
RUN mv git-cinnabar git-remote-hg /usr/bin/
1818

1919
# install test dependencies
20-
RUN pip install -U pip pytest pytest-mock pytest-cov
20+
RUN pip install -U pip pytest pytest-mock pip-tools
2121

22-
# Copy local code to the container image.
23-
COPY . /app
24-
RUN chown -R app: /app
22+
# setup just the venv so changes to the source won't require a full venv
23+
# rebuild
24+
COPY --chown=app:app README.md .
25+
COPY --chown=app:app pyproject.toml .
26+
RUN pip-compile --verbose pyproject.toml
27+
RUN pip install -r requirements.txt
2528

29+
# copy app and install
30+
COPY --chown=app:app . /app
31+
RUN pip install /app
2632
USER app
27-
RUN pip install -e .

‎README.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ process the next message in the queue.
2020

2121
## build and test
2222

23+
Format and test/lint code:
24+
25+
```console
26+
$ tox -e format,lint
27+
```
28+
29+
Run tests:
30+
2331
```console
24-
$ mkdir -p tests_output
25-
$ chmod a+w tests_output
26-
$ docker-compose build
27-
$ docker-compose run --rm sync
32+
$ docker compose run --build sync
33+
$ docker compose down
2834
```
2935

3036
## Known limitations

‎docker-compose.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
services:
22
sync:
33
build: .
4-
command: ['pytest', '--junitxml=./tests_output/pytest.xml', '--cov-report', 'term', '--cov-report', 'xml:./tests_output/coverage.xml', '--cov=git_hg_sync', 'tests/']
4+
command: ['pytest', '--junitxml=./tests_output/pytest.xml', 'tests/']
55
volumes:
66
- ./tests_output:/app/tests_output
77
environment:

‎git_hg_sync/__main__.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import argparse
22
import sys
3-
import logging
43
from pathlib import Path
54

65
import sentry_sdk
@@ -13,7 +12,7 @@
1312
from git_hg_sync.repo_synchronizer import RepoSynchronizer
1413

1514

16-
def get_parser():
15+
def get_parser() -> argparse.ArgumentParser:
1716
parser = argparse.ArgumentParser()
1817
parser.add_argument(
1918
"-c",
@@ -25,7 +24,7 @@ def get_parser():
2524
return parser
2625

2726

28-
def get_connection(config: PulseConfig):
27+
def get_connection(config: PulseConfig) -> Connection:
2928
return Connection(
3029
hostname=config.host,
3130
port=config.port,
@@ -36,7 +35,7 @@ def get_connection(config: PulseConfig):
3635
)
3736

3837

39-
def get_queue(config):
38+
def get_queue(config: Config | PulseConfig) -> Queue:
4039
exchange = Exchange(config.exchange, type="topic")
4140
return Queue(
4241
name=config.queue,
@@ -47,7 +46,7 @@ def get_queue(config):
4746

4847

4948
def start_app(
50-
config: Config, logger: logging.Logger, *, one_shot: bool = False
49+
config: Config, logger: commandline.StructuredLogger, *, one_shot: bool = False
5150
) -> None:
5251
pulse_config = config.pulse
5352
connection = get_connection(pulse_config)

‎git_hg_sync/application.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import signal
22
import sys
3+
from collections.abc import Sequence
34
from types import FrameType
4-
from typing import Optional, Sequence
55

66
from mozlog import get_proxy_logger
77

@@ -14,20 +14,19 @@
1414

1515

1616
class Application:
17-
1817
def __init__(
1918
self,
2019
worker: PulseWorker,
2120
repo_synchronizers: dict[str, RepoSynchronizer],
2221
mappings: Sequence[Mapping],
23-
):
22+
) -> None:
2423
self._worker = worker
2524
self._worker.event_handler = self._handle_event
2625
self._repo_synchronizers = repo_synchronizers
2726
self._mappings = mappings
2827

2928
def run(self) -> None:
30-
def signal_handler(sig: int, frame: Optional[FrameType]) -> None:
29+
def signal_handler(_sig: int, _frame: FrameType | None) -> None:
3130
if self._worker.should_stop:
3231
logger.info("Process killed by user")
3332
sys.exit(1)

‎git_hg_sync/config.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pathlib
2-
import tomllib
32
from typing import Self
43

54
import pydantic
5+
import tomllib
66

77
from git_hg_sync.mapping import BranchMapping, TagMapping
88

@@ -43,7 +43,6 @@ class Config(pydantic.BaseModel):
4343
def verify_all_mappings_reference_tracked_repositories(
4444
self,
4545
) -> Self:
46-
4746
tracked_urls = [tracked_repo.url for tracked_repo in self.tracked_repositories]
4847
for mapping in self.branch_mappings:
4948
if mapping.source_url not in tracked_urls:
@@ -55,6 +54,6 @@ def verify_all_mappings_reference_tracked_repositories(
5554
@staticmethod
5655
def from_file(file_path: pathlib.Path) -> "Config":
5756
assert file_path.exists(), f"config file {file_path} doesn't exists"
58-
with open(file_path, "rb") as config_file:
57+
with file_path.open("rb") as config_file:
5958
config = tomllib.load(config_file)
6059
return Config(**config)

‎git_hg_sync/mapping.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import re
2+
from collections.abc import Sequence
23
from dataclasses import dataclass
34
from functools import cached_property
4-
from typing import Sequence, TypeAlias
5+
from typing import TypeAlias
56

67
import pydantic
78

‎git_hg_sync/pulse_worker.py

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
from typing import Protocol
1+
from typing import Any, Protocol
22

3+
import kombu
34
from kombu.mixins import ConsumerMixin
45
from mozlog import get_proxy_logger
56

67
from git_hg_sync.events import Push, Tag
78

8-
logger = get_proxy_logger("pluse_consumer")
9+
logger = get_proxy_logger("pulse_consumer")
910

1011

1112
class EventHandler(Protocol):
12-
def __call__(self, event: Push | Tag):
13+
def __call__(self, event: Push | Tag) -> None:
1314
pass
1415

1516

@@ -21,13 +22,19 @@ class PulseWorker(ConsumerMixin):
2122
event_handler: EventHandler | None
2223
"""Function that will be called whenever an event is received"""
2324

24-
def __init__(self, connection, queue, *, one_shot=False):
25+
def __init__(
26+
self,
27+
connection: kombu.Connection,
28+
queue: kombu.Queue,
29+
*,
30+
one_shot: bool = False,
31+
) -> None:
2532
self.connection = connection
2633
self.task_queue = queue
2734
self.one_shot = one_shot
2835

2936
@staticmethod
30-
def parse_entity(raw_entity):
37+
def parse_entity(raw_entity: Any) -> Push | Tag:
3138
logger.debug(f"parse_entity: {raw_entity}")
3239
message_type = raw_entity.pop("type")
3340
match message_type:
@@ -38,13 +45,17 @@ def parse_entity(raw_entity):
3845
case _:
3946
raise EntityTypeError(f"unsupported type {message_type}")
4047

41-
def get_consumers(self, Consumer, channel):
42-
consumer = Consumer(
48+
def get_consumers(
49+
self,
50+
consumer_class: type[kombu.Consumer],
51+
_channel: Any,
52+
) -> list[kombu.Consumer]:
53+
consumer = consumer_class(
4354
self.task_queue, auto_declare=False, callbacks=[self.on_task]
4455
)
4556
return [consumer]
4657

47-
def on_task(self, body, message):
58+
def on_task(self, body: Any, message: kombu.Message) -> None:
4859
logger.info(f"Received message: {body}")
4960
raw_entity = body["payload"]
5061
event = PulseWorker.parse_entity(raw_entity)

‎git_hg_sync/repo_synchronizer.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from pathlib import Path
22

3-
43
from git import Repo, exc
5-
from git_hg_sync.mapping import SyncOperation, SyncBranchOperation, SyncTagOperation
64
from mozlog import get_proxy_logger
75

6+
from git_hg_sync.mapping import SyncBranchOperation, SyncOperation, SyncTagOperation
7+
88
logger = get_proxy_logger("sync_repo")
99

1010

@@ -17,12 +17,11 @@ class MercurialMetadataNotFoundError(RepoSyncError):
1717

1818

1919
class RepoSynchronizer:
20-
2120
def __init__(
2221
self,
2322
clone_directory: Path,
2423
url: str,
25-
):
24+
) -> None:
2625
self._clone_directory = clone_directory
2726
self._src_remote = url
2827

@@ -42,7 +41,7 @@ def _get_clone_repo(self) -> Repo:
4241

4342
def _commit_has_mercurial_metadata(self, repo: Repo, git_commit: str) -> bool:
4443
stdout = repo.git.cinnabar(["git2hg", git_commit])
45-
return not all([char == "0" for char in stdout.strip()])
44+
return not all(char == "0" for char in stdout.strip())
4645

4746
def _fetch_all_from_remote(self, repo: Repo, remote: str) -> None:
4847
try:
@@ -89,7 +88,7 @@ def sync(self, destination_url: str, operations: list[SyncOperation]) -> None:
8988
]
9089

9190
# Create tag branches locally
92-
tag_branches = set([op.tags_destination_branch for op in tag_ops])
91+
tag_branches = {op.tags_destination_branch for op in tag_ops}
9392
for tag_branch in tag_branches:
9493
repo.git.fetch(
9594
[

0 commit comments

Comments
 (0)
Failed to load comments.