Skip to content

Commit

Permalink
Implement release and commit sets
Browse files Browse the repository at this point in the history
  • Loading branch information
felipecrp committed Feb 25, 2025
1 parent 0e65874 commit dbb71ea
Show file tree
Hide file tree
Showing 13 changed files with 275 additions and 1,262 deletions.
1,153 changes: 0 additions & 1,153 deletions coverage.xml

This file was deleted.

3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pytest-cov = "^6.0.0"
pytest-profiling = "^1.8.1"
pytest-pyspec = "^0.10.0"

[tool.pytest.ini_options]
addopts = "--pyspec"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
38 changes: 0 additions & 38 deletions releasy/change.py

This file was deleted.

73 changes: 73 additions & 0 deletions releasy/commit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

from __future__ import annotations
from datetime import datetime
from typing import List, Set
from releasy.old.repository_old import Repository


class Commit:
"""
A change in a release, such as a commit
"""
def __init__(self, id: str, parents: List[Commit], timestamp: datetime) -> None:
self._id = id
self.parents = parents
self.timestamp = datetime

@property
def id(self) -> str:
return self._id

def __hash__(self) -> int:
if self.id:
return hash(self.id)
else:
return super.__hash__()

def __eq__(self, other: object) -> bool:
if not isinstance(other, Commit):
return False

return self.id == other.id


class CommitGroup:
def __init__(self, commits: CommitSet = None):
self._all = commits

@property
def all(self) -> Set[Commit]:
return self._all

def add(self, commits: Set[Commit]) -> None:
for commit in commits:
self._all.add(commit)


class CommitSet:
def __init__(self, commits: Set[Commit] = None):
if not commits:
self._commits = {}
else:
self._commits = {commit.id: commit for commit in commits}

def __len__(self) -> int:
return len(self._commits)

def add(self, commit: Commit) -> None:
self._commits[commit.id] = commit

def __getitem__(self, commit_id: str) -> Commit:
if commit_id not in self._commits:
return KeyError(f"Commit {commit_id} not found")
return self._commits[commit_id]


class ChangeAssignmentStrategy:
pass


class HistoryBasedStrategy(ChangeAssignmentStrategy):
def assign(releases: Set, repository: Repository):
return releases

2 changes: 1 addition & 1 deletion releasy/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ def mine_changes(self,
releases: Set[Release],
strategy) -> Set[Release]:
for release in releases:
release.add_changes(strategy.assign(release))
release.set_commits(strategy.assign(release))


4 changes: 2 additions & 2 deletions releasy/miner/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from abc import ABC, abstractmethod
from typing import Callable, List, Self, Set, Tuple
from releasy.change import Change
from releasy.commit import Commit
from releasy.repository import Repository

from releasy.old.project2 import Project
Expand Down Expand Up @@ -43,7 +43,7 @@ def mine(
self,
releases: Set[Release],
repository: Repository
) -> Set[Tuple[Release,List[Change]]]:
) -> Set[Tuple[Release,List[Commit]]]:
pass


Expand Down
4 changes: 2 additions & 2 deletions releasy/old/release2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
SemanticVersion,
SimpleReleaseVersion
)
from releasy.change import Change
from releasy.commit import Commit


class Release(ABC):
Expand All @@ -18,7 +18,7 @@ def __init__(self, name: str, version: ReleaseVersion) -> None:
self.description = ''
self.developer: str = None
self.timestamp: datetime = None
self.changes: Set[Change] = ()
self.changes: Set[Commit] = ()
self.lifecycle: ReleaseLifeCycle = None
self.cycle: timedelta = None
self.base_releases: Set[Release] = ()
Expand Down
45 changes: 37 additions & 8 deletions releasy/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@
import re
from typing import Iterable, Set

from releasy.change import Change
from releasy.commit import Commit, CommitGroup
from releasy.contributor import Contributor
from releasy.version import VersionType, ReleaseVersion


class Release:
"""
A Release is a group of changes ready to be delivered to its stakeholders
A Release is a group of commits ready to be delivered to its stakeholders
"""
def __init__(self,
version: ReleaseVersion,
timestamp: datetime,
head: Change,
head: Commit,
author: Contributor) -> None:
self.version = version
self.timestamp = timestamp
self.head = head
self.author = author
self.changes = set[Change]()
self.previous: Set[Release] = None
self.commits = CommitGroup()
self.base_releases = ReleaseSet()
self.pre_releases = ReleaseSet()

@property
def name(self) -> str:
Expand All @@ -36,11 +37,39 @@ def type(self) -> VersionType:

return self.version.type

def add_changes(self, changes: Iterable[Change]) -> None:
self.changes.update(changes)
def set_commits(self, commits: Iterable[Commit]) -> None:
self.commits = CommitGroup(commits)

def add_base_release(self, release: Release) -> None:
if not self.base_releases:
self.base_releases = set()
self.base_releases.add(release)

def add_pre_release(self, release: Release) -> None:
if not self.pre_releases:
self.pre_releases = set()
self.pre_releases.add(release)


def __repr__(self) -> str:
return self.name



class ReleaseSet:
def __init__(self, releases: Iterable[Release] = None) -> None:
self._releases = {release.name: release for release in releases} \
if releases else {}

def add(self, release: Release) -> None:
self._releases[release.name] = release

def __len__(self) -> int:
return len(self._releases)

def __getitem__(self, release_name: str) -> Release:
if release_name not in self._releases:
raise KeyError(f"Release {release_name} not found")
return self._releases[release_name]

def __iter__(self):
return iter(self._releases.values())
2 changes: 1 addition & 1 deletion tests/fixtures/fixtures_contributor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

@pytest.fixture
def alice() -> Contributor:
return Contributor("ALICE")
return Contributor("Alice")
104 changes: 83 additions & 21 deletions tests/fixtures/fixtures_release.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,56 @@
from datetime import datetime
from datetime import datetime, timedelta
from typing import Iterable
import pytest

from releasy.change import Change
from releasy.commit import Commit, CommitSet
from releasy.contributor import Contributor
from releasy.release import Release
from releasy.release import Release, ReleaseSet
from releasy.version import ReleaseVersion
from releasy.old.version_format import ReleaseVersionFormat, SemanticVersioningFormat

@pytest.fixture
def change_a() -> Change:
return Change("A")
def commit_a() -> Commit:
return Commit("A")

@pytest.fixture
def change_b() -> Change:
return Change("B")
def commit_b() -> Commit:
return Commit("B")

@pytest.fixture
def change_c() -> Change:
return Change("C")
def commit_c() -> Commit:
return Commit("C")

@pytest.fixture
def changes(change_a: Change, change_b: Change, change_c: Change):
def commits(commit_a: Commit, commit_b: Commit, commit_c: Commit):
return set([
change_a,
change_b,
change_c
commit_a,
commit_b,
commit_c
])

@pytest.fixture
def release(
version: ReleaseVersion,
alice: Contributor,
change_a: Change,
changes: Iterable[Change]):
commit_a: Commit,
commits: Iterable[Commit],
prev_release: Release) -> Release:
release = Release(
version=version,
timestamp=datetime(2024, 1, 1),
head=change_a,
timestamp=datetime(2024, 1, 3),
head=commit_a,
author=alice
)
release.add_changes(changes)
release.set_commits(commits)
release.add_previous(prev_release)
return release

@pytest.fixture
def release_a(version_a: ReleaseVersion, alice: Contributor):
def prev_release(version_a: ReleaseVersion, alice: Contributor, commit_a: Commit):
return Release(
version=version_a,
timestamp=datetime(2024, 1, 2),
timestamp=datetime(2024, 1, 1),
head=commit_a,
author=alice
)

Expand All @@ -63,6 +66,65 @@ def release_b(version_b: ReleaseVersion, alice: Contributor):
def release_c(version_c: ReleaseVersion, alice: Contributor):
return Release(
version=version_c,
timestamp=datetime(2024, 1, 4),
timestamp=datetime(2024, 1, 5),
author=alice
)


@pytest.fixture
def scenario_1(
semver_format: SemanticVersioningFormat,
alice: Contributor) -> tuple[CommitSet]:
commits_history = [
("0", [], [], [], [], alice),
("1", ["0"], ["1.0.0"], [], [], alice),
("2", ["1"], ["1.1.0"], ["1.0.0"], [], alice),
("3", ["2"], ["2.0.0-rc.1"], ["1.1.0"], [], alice),
("4", ["3"], ["2.0.0"], ["1.1.0"], ["2.0.0-rc.1"], alice)
]

commits = CommitSet()
releases = ReleaseSet()
timestamp = datetime(2025, 1, 1)
commit2release = {}

for id, parents_id, release_name, prev_release_names, pre_release_names, author \
in commits_history:
parents = [commits[parent_id] for parent_id in parents_id]
commit = Commit(id, parents, timestamp)
commits.add(commit)

for release_name in release_name:
version = semver_format.parse(release_name)
release = Release(version, timestamp, commit, author)
commit2release[commit] = release
release.set_commits([commit])
for prev_release_name in prev_release_names:
release.add_base_release(releases[prev_release_name])
for pre_release_name in pre_release_names:
release.add_pre_release(releases[pre_release_name])
releases.add(release)

release_commits = CommitSet()
queue = [release.head]
while queue:
commit = queue.pop()
release_commits.add(commit)
for parent in commit.parents:
if parent not in commit2release:
queue.append(parent)
release.set_commits(release_commits)

timestamp += timedelta(days=1)

return releases, commits

@pytest.fixture
def scenario_1_releases(scenario_1) -> ReleaseSet:
releases, _ = scenario_1
return releases

@pytest.fixture
def scenario_1_commits(scenario_1) -> CommitSet:
_, commits = scenario_1
return commits
Loading

0 comments on commit dbb71ea

Please sign in to comment.