Skip to content

Commit 22cf39e

Browse files
authored
Sorting latest and which by SemVer (#161)
* make proper sorting * fix bug * codecov -- fail_ci_if_error: false
1 parent 4926966 commit 22cf39e

File tree

8 files changed

+173
-92
lines changed

8 files changed

+173
-92
lines changed

.github/workflows/check-test-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
- name: "Upload coverage to Codecov"
7373
uses: codecov/codecov-action@v2
7474
with:
75-
fail_ci_if_error: true
75+
fail_ci_if_error: false
7676
token: ${{ secrets.CODECOV_TOKEN }}
7777
deploy:
7878
name: PyPI Deploy

gto/api.py

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,24 @@ def parse_tag(name: str):
124124
def find_latest_version(
125125
repo: Union[str, Repo],
126126
name: str,
127+
all: bool = False,
128+
registered: bool = True,
127129
):
128130
"""Return latest version for artifact"""
129-
return GitRegistry.from_repo(repo).latest(name)
131+
return GitRegistry.from_repo(repo).latest(name, all=all, registered=registered)
130132

131133

132-
def find_promotion(repo: Union[str, Repo], name: str, stage: str):
134+
def find_versions_in_stage(
135+
repo: Union[str, Repo],
136+
name: str,
137+
stage: str,
138+
all: bool = False,
139+
registered_only: bool = False,
140+
):
133141
"""Return version of artifact with specific stage active"""
134-
return GitRegistry.from_repo(repo).which(name, stage, raise_if_not_found=False)
142+
return GitRegistry.from_repo(repo).which(
143+
name, stage, raise_if_not_found=False, all=all, registered_only=registered_only
144+
)
135145

136146

137147
def check_ref(repo: Union[str, Repo], ref: str):
@@ -155,13 +165,15 @@ def show(
155165
all_branches=False,
156166
all_commits=False,
157167
truncate_hexsha=False,
168+
registered_only=False,
158169
):
159170
return (
160171
_show_versions(
161172
repo,
162173
name=name,
163174
all_branches=all_branches,
164175
all_commits=all_commits,
176+
registered_only=registered_only,
165177
table=table,
166178
truncate_hexsha=truncate_hexsha,
167179
)
@@ -170,6 +182,7 @@ def show(
170182
repo,
171183
all_branches=all_branches,
172184
all_commits=all_commits,
185+
registered_only=registered_only,
173186
table=table,
174187
truncate_hexsha=truncate_hexsha,
175188
)
@@ -180,21 +193,27 @@ def _show_registry(
180193
repo: Union[str, Repo],
181194
all_branches=False,
182195
all_commits=False,
196+
registered_only=False,
183197
table: bool = False,
184198
truncate_hexsha: bool = False, # pylint: disable=unused-argument
185199
):
186200
"""Show current registry state"""
187201

202+
def format_hexsha(hexsha):
203+
return hexsha[:7] if truncate_hexsha else hexsha
204+
188205
reg = GitRegistry.from_repo(repo)
189206
stages = list(reg.get_stages())
190207
models_state = {
191208
o.name: {
192-
"version": o.get_latest_version(registered=True).name
193-
if o.get_latest_version(registered=True)
209+
"version": format_hexsha(o.get_latest_version(registered_only=True).name)
210+
if o.get_latest_version(registered_only=True)
194211
else None,
195212
"stage": {
196-
name: o.get_promotions()[name].version
197-
if name in o.get_promotions()
213+
name: format_hexsha(
214+
o.get_promotions(registered_only=registered_only)[name].version
215+
)
216+
if name in o.get_promotions(registered_only=registered_only)
198217
else None
199218
for name in stages
200219
},
@@ -221,6 +240,7 @@ def _show_versions(
221240
raw: bool = False,
222241
all_branches=False,
223242
all_commits=False,
243+
registered_only=False,
224244
table: bool = False,
225245
truncate_hexsha: bool = False,
226246
):
@@ -238,7 +258,9 @@ def format_hexsha(hexsha):
238258
name,
239259
all_branches=all_branches,
240260
all_commits=all_commits,
241-
).get_versions(include_non_explicit=True, include_discovered=True)
261+
).get_versions(
262+
include_non_explicit=not registered_only, include_discovered=True
263+
)
242264
]
243265
if not table:
244266
return versions
@@ -251,7 +273,15 @@ def format_hexsha(hexsha):
251273
v["stage"] = v["stage"]["stage"]
252274
v["commit_hexsha"] = format_hexsha(v["commit_hexsha"])
253275
v["ref"] = v["tag"] or v["commit_hexsha"]
254-
for key in "enrichments", "discovered", "tag", "commit_hexsha", "name":
276+
for key in (
277+
"enrichments",
278+
"discovered",
279+
"tag",
280+
"commit_hexsha",
281+
"name",
282+
"message",
283+
"author_email",
284+
):
255285
v.pop(key)
256286
# v["enrichments"] = [e["source"] for e in v["enrichments"]]
257287
v = OrderedDict(
@@ -262,10 +292,6 @@ def format_hexsha(hexsha):
262292
return versions_, "keys"
263293

264294

265-
def _is_ascending(sort):
266-
return sort in {"asc", "Asc", "ascending", "Ascending"}
267-
268-
269295
def describe(
270296
repo: Union[str, Repo], name: str, rev: str = None
271297
) -> List[EnrichmentInfo]:
@@ -286,7 +312,7 @@ def history( # pylint: disable=too-many-locals
286312
# action: str = None,
287313
all_branches=False,
288314
all_commits=False,
289-
sort: str = "desc",
315+
ascending: bool = False,
290316
table: bool = False,
291317
truncate_hexsha: bool = False,
292318
):
@@ -357,7 +383,7 @@ def format_hexsha(hexsha):
357383
commits + registration + promotion,
358384
key=lambda x: (x["timestamp"], events_order[x["event"]]),
359385
)
360-
if _is_ascending(sort):
386+
if ascending:
361387
events.reverse()
362388
if artifact:
363389
events = [event for event in events if event["artifact"] == artifact]

gto/base.py

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pydantic import BaseModel
66

77
from gto.config import RegistryConfig
8-
from gto.constants import Action
8+
from gto.constants import Action, VersionSort
99
from gto.ext import Enrichment
1010
from gto.versions import SemVer
1111

@@ -75,42 +75,82 @@ def __repr__(self) -> str:
7575
stages = ", ".join(f"'{l}'" for l in self.unique_stages)
7676
return f"Artifact(versions=[{versions}], stages=[{stages}])"
7777

78-
def get_latest_version(self, registered=False) -> Optional[BaseVersion]:
79-
versions = sorted(
80-
(
81-
v
82-
for v in self.versions
83-
if not v.discovered and (not registered or v.is_registered)
84-
),
85-
key=lambda x: x.created_at,
78+
def get_versions(
79+
self,
80+
include_non_explicit=False,
81+
include_discovered=False,
82+
sort=VersionSort.SemVer,
83+
ascending=False,
84+
) -> List[BaseVersion]:
85+
sort = sort if isinstance(sort, VersionSort) else VersionSort[sort]
86+
all_versions = [
87+
v
88+
for v in self.versions
89+
if (v.is_registered and not v.discovered)
90+
or (include_discovered and v.discovered)
91+
or (include_non_explicit and not v.is_registered)
92+
]
93+
if sort == VersionSort.SemVer:
94+
# sorting SemVer versions in a right way
95+
versions = sorted(
96+
(v for v in all_versions if not v.discovered and v.is_registered),
97+
key=lambda x: x.version,
98+
)
99+
# sorting hexsha versions alphabetically
100+
if include_non_explicit:
101+
versions.extend(
102+
sorted(
103+
(
104+
v
105+
for v in all_versions
106+
if not v.discovered and not v.is_registered
107+
),
108+
key=lambda x: x.name,
109+
)
110+
)
111+
else:
112+
versions = sorted(
113+
(
114+
v
115+
for v in all_versions
116+
if not v.discovered and (include_non_explicit or v.is_registered)
117+
),
118+
key=lambda x: x.created_at,
119+
)
120+
if ascending:
121+
versions.reverse()
122+
return versions
123+
124+
def get_latest_version(
125+
self, registered_only=False, sort=VersionSort.SemVer
126+
) -> Optional[BaseVersion]:
127+
versions = self.get_versions(
128+
include_non_explicit=not registered_only, sort=sort
86129
)
87130
if versions:
88131
return versions[-1]
89132
return None
90133

91-
def get_promotions(self) -> Dict[str, BasePromotion]:
92-
stages: Dict[str, BasePromotion] = {}
93-
# semver
94-
versions = sorted(
95-
(v for v in self.versions if v.is_registered),
96-
key=lambda x: x.version,
97-
reverse=True,
98-
)
99-
# TODO: regular commits - these should be sorted by stage tag creation maybe?
100-
# E.g. when you created "rf#prod" tag, then you created a version.
101-
# It's probably should be a flag on CLI that will tell how to sort promoted for return.
102-
versions.extend(
103-
sorted(
104-
(v for v in self.versions if not v.is_registered),
105-
key=lambda x: x.created_at,
106-
reverse=True,
107-
)
134+
def get_promotions(
135+
self, all=False, registered_only=False, sort=VersionSort.SemVer
136+
) -> Dict[str, Union[BasePromotion, List[BasePromotion]]]:
137+
versions = self.get_versions(
138+
include_non_explicit=not registered_only, sort=sort
108139
)
140+
if sort == VersionSort.Timestamp:
141+
# for this sort we need to sort not versions, as above ^
142+
# but promotions themselves
143+
raise NotImplementedError("Sorting by timestamp is not implemented yet")
144+
stages = {} # type: ignore
109145
for version in versions:
110146
promotion = version.stage
111147
if promotion:
112-
stages[promotion.stage] = stages.get(promotion.stage) or promotion
113-
return stages
148+
stages[promotion.stage] = stages.get(promotion.stage, []) + [promotion]
149+
# else:
150+
# stages[promotion.stage] = stages.get(promotion.stage) or promotion
151+
if all:
152+
return stages
153+
return {stage: promotions[-1] for stage, promotions in stages.items()}
114154

115155
def add_version(self, version: BaseVersion):
116156
self.versions.append(version)
@@ -159,15 +199,6 @@ def discovered(self):
159199
# ) -> List[BaseVersion]:
160200
# ...
161201

162-
def get_versions(self, include_non_explicit=False, include_discovered=False):
163-
return [
164-
v
165-
for v in self.versions
166-
if (v.is_registered and not v.discovered)
167-
or (include_discovered and v.discovered)
168-
or (include_non_explicit and not v.is_registered)
169-
]
170-
171202
def find_version(
172203
self,
173204
name: str = None,
@@ -245,9 +276,13 @@ def find_commit(self, name, version):
245276
.commit_hexsha
246277
)
247278

248-
def which(self, name, stage, raise_if_not_found=True):
279+
def which(
280+
self, name, stage, raise_if_not_found=True, all=False, registered_only=False
281+
):
249282
"""Return stage active in specific stage"""
250-
promoted = self.find_artifact(name).get_promotions()
283+
promoted = self.find_artifact(name).get_promotions(
284+
all=all, registered_only=registered_only
285+
)
251286
if stage in promoted:
252287
return promoted[stage]
253288
if raise_if_not_found:

0 commit comments

Comments
 (0)