Skip to content

Commit

Permalink
Merge pull request #130 from lsst-sqre/tickets/DM-44453
Browse files Browse the repository at this point in the history
DM-44453: Fix handling of release versions in v2 API.
  • Loading branch information
jonathansick authored May 23, 2024
2 parents a027c32 + 16c7b0d commit 2a0cd86
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 17 deletions.
19 changes: 9 additions & 10 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,22 @@ jobs:
db:
- sqlite
- postgres
- mysql
# - mysql

steps:
- uses: actions/checkout@v3

- name: Install build tools
run: sudo apt-get install build-essential

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}

- name: Install tox
run: |
pip install 'requests<2.32.0'
pip install tox
pip install --pre tox-docker
Expand All @@ -73,11 +77,13 @@ jobs:
LTD_KEEPER_TEST_AWS_ID: ${{ secrets.LTD_KEEPER_TEST_AWS_ID }}
LTD_KEEPER_TEST_AWS_SECRET: ${{ secrets.LTD_KEEPER_TEST_AWS_SECRET }}
LTD_KEEPER_TEST_BUCKET: ${{ secrets.LTD_KEEPER_TEST_BUCKET }}
run: tox -e typing,${{matrix.db}},coverage-report # run tox using Python in path
# run: tox -e typing,${{matrix.db}},coverage-report # run tox using Python in path
run: tox -e ${{matrix.db}},coverage-report # run tox using Python in path

- name: Run tox without external services
if: ${{ !(matrix.python != '3.10' && matrix.db != 'postgres') }}
run: tox -e typing,${{matrix.db}},coverage-report # run tox using Python in path
# run: tox -e typing,${{matrix.db}},coverage-report # run tox using Python in path
run: tox -e ${{matrix.db}},coverage-report # run tox using Python in path

docs:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -141,12 +147,6 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
Expand All @@ -160,7 +160,6 @@ jobs:
context: .
push: true
tags: |
lsstsqre/ltdkeeper:${{ steps.vars.outputs.tag }}
ghcr.io/lsst-sqre/ltd-keeper:${{ steps.vars.outputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ __pycache__/
*.so

# Distribution / packaging
venv
.venv
.Python
env/
build/
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repos:
- id: check-json

- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.13.2
hooks:
- id: isort
additional_dependencies:
Expand All @@ -20,7 +20,7 @@ repos:
hooks:
- id: black

- repo: https://gitlab.com/pycqa/flake8
- repo: https://github.com/pycqa/flake8
rev: 4.0.1
hooks:
- id: flake8
15 changes: 13 additions & 2 deletions keeper/editiontracking/lsstdocmode.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@

# The RFC-405/LPM-51 format for LSST semantic document versions.
# v<minor>.<major>
LSST_DOC_V_TAG = re.compile(r"^v(?P<major>[\d]+)\.(?P<minor>[\d]+)$")
LSST_DOC_V_TAG = re.compile(
r"^v?(?P<major>[\d]+)\.(?P<minor>[\d]+)(\.(?P<patch>[\d]+))?$"
)


class LsstDocTrackingMode(TrackingModeBase):
"""LSST document-specific tracking mode where an edition publishes the
most recent ``vN.M`` tag.
Semantic versions are also supported: ``N.M.P`` or ``vN.M.P``.
"""

@property
Expand Down Expand Up @@ -100,7 +104,10 @@ def __init__(self, version_str: str) -> None:
raise ValueError(
"{:r} is not a LSST document version tag".format(version_str)
)
self.version = (int(match.group("major")), int(match.group("minor")))
major = int(match.group("major"))
minor = int(match.group("minor"))
patch = int(match.group("patch") or 0)
self.version = (major, minor, patch)

@property
def major(self) -> int:
Expand All @@ -110,6 +117,10 @@ def major(self) -> int:
def minor(self) -> int:
return self.version[1]

@property
def patch(self) -> int:
return self.version[2]

def __repr__(self) -> str:
return "LsstDocVersion({:r})".format(self.version_str)

Expand Down
25 changes: 25 additions & 0 deletions keeper/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,31 @@ def mode_name(self) -> str:
else:
return self.default_mode_name

def set_kind(self, kind: str) -> None:
"""Set the edition kind.
Parameters
----------
kind : `str`
Kind identifier. Validated to be one defined in `EditionKind`.
Raises
------
ValidationError
Raised if `kind` is unknown.
"""
self.kind = EditionKind[kind]

@property
def kind_name(self) -> str:
"""Name of the kind (`str`).
See also
--------
EditionKind
"""
return self.kind.name

def update_slug(self, new_slug: str) -> None:
"""Update the edition's slug by migrating files on S3.
Expand Down
34 changes: 34 additions & 0 deletions keeper/services/createedition.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import re
import uuid
from typing import TYPE_CHECKING, Optional

Expand All @@ -21,6 +22,7 @@ def create_edition(
autoincrement_slug: Optional[bool] = False,
tracked_ref: Optional[str] = "main",
build: Optional[Build] = None,
kind: Optional[str] = None,
) -> Edition:
"""Create a new edition.
Expand Down Expand Up @@ -50,6 +52,8 @@ def create_edition(
is ``"git_refs"`` or ``"git_ref"``.
build : Build, optional
The build to initially publish with this edition.
kind : str, optional
The kind of the edition.
Returns
-------
Expand Down Expand Up @@ -83,6 +87,16 @@ def create_edition(
edition.tracked_ref = tracked_ref
edition.tracked_refs = [tracked_ref]

if edition.slug == "__main":
# Always mark the default edition as the main edition
edition.set_kind("main")
elif kind is not None:
# Manually set the edition kind
edition.set_kind(kind)
elif tracked_ref is not None:
# Set the EditionKind based on the tracked_ref value
edition.set_kind(determine_edition_kind(tracked_ref))

db.session.add(edition)
db.session.commit()

Expand All @@ -92,3 +106,23 @@ def create_edition(
request_dashboard_build(product)

return edition


SEMVER_PATTERN = re.compile(
r"^v?(?P<major>[\d]+)(\.(?P<minor>[\d]+)(\.(?P<patch>[\d]+))?)?$"
)


def determine_edition_kind(git_ref: str) -> str:
"""Determine the kind of edition based on the git ref."""
match = SEMVER_PATTERN.match(git_ref)
if match is None:
return "draft"

if match.group("patch") is not None and match.group("minor") is not None:
return "release"

if match.group("minor") is not None and match.group("patch") is None:
return "minor"

return "major"
4 changes: 4 additions & 0 deletions keeper/services/updateedition.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def update_edition(
tracking_mode: Optional[str] = None,
tracked_ref: Optional[str] = None,
pending_rebuild: Optional[bool] = None,
kind: Optional[str] = None,
) -> Edition:
"""Update the metadata of an existing edititon or to point at a new
build.
Expand Down Expand Up @@ -63,6 +64,9 @@ def update_edition(
)
edition.pending_rebuild = pending_rebuild

if kind is not None:
edition.set_kind(kind)

db.session.add(edition)
db.session.commit()

Expand Down
35 changes: 33 additions & 2 deletions keeper/v2api/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from keeper.editiontracking import EditionTrackingModes
from keeper.exceptions import ValidationError
from keeper.models import OrganizationLayoutMode
from keeper.models import EditionKind, OrganizationLayoutMode
from keeper.utils import (
format_utc_datetime,
validate_path_slug,
Expand Down Expand Up @@ -119,7 +119,6 @@ def from_organization(cls, org: Organization) -> OrganizationResponse:


class LayoutEnum(str, Enum):

subdomain = "subdomain"

path = "path"
Expand Down Expand Up @@ -576,6 +575,9 @@ class EditionResponse(BaseModel):
mode: str
"""The edition tracking mode."""

kind: str
"""The edition kind."""

@classmethod
def from_edition(
cls,
Expand Down Expand Up @@ -609,6 +611,7 @@ def from_edition(
"date_rebuilt": edition.date_rebuilt,
"date_ended": edition.date_ended,
"mode": edition.mode_name,
"kind": edition.kind_name,
"tracked_ref": tracked_ref,
"pending_rebuild": edition.pending_rebuild,
"surrogate_key": edition.surrogate_key,
Expand Down Expand Up @@ -661,6 +664,9 @@ class EditionPostRequest(BaseModel):
mode: str = "git_refs"
"""Tracking mode."""

kind: Optional[str] = None
"""The edition kind."""

tracked_ref: Optional[str] = None
"""Git ref being tracked if mode is ``git_ref``."""

Expand Down Expand Up @@ -708,6 +714,17 @@ def check_tracked_refs(
raise ValueError('tracked_ref must be set if mode is "git_ref"')
return v

@validator("kind")
def check_kind(cls, v: Optional[str]) -> Optional[str]:
if v is None:
return None

# Get all known kinds from the EditionKind enum
kind_names = [kind.name for kind in EditionKind]
if v not in kind_names:
raise ValueError(f"Kind {v!r} is not known.")
return v


class EditionPatchRequest(BaseModel):
"""The model for a PATCH /editions/:id request."""
Expand All @@ -731,6 +748,9 @@ class EditionPatchRequest(BaseModel):
mode: Optional[str] = None
"""The edition tracking mode."""

kind: Optional[str] = None
"""The edition kind."""

build_url: Optional[HttpUrl] = None
"""URL of the build to initially publish with the edition, if available.
"""
Expand All @@ -756,6 +776,17 @@ def check_mode(cls, v: Optional[str]) -> Optional[str]:
raise ValueError(f"Tracking mode {v!r} is not known.")
return v

@validator("kind")
def check_kind(cls, v: Optional[str]) -> Optional[str]:
if v is None:
return None

# Get all known kinds from the EditionKind enum
kind_names = [kind.name for kind in EditionKind]
if v not in kind_names:
raise ValueError(f"Kind {v!r} is not known.")
return v


class QueuedResponse(BaseModel):
"""Response that contains only a URL for the background task's status."""
Expand Down
2 changes: 2 additions & 0 deletions keeper/v2api/editions.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def post_edition(org: str, project: str) -> Tuple[str, int, Dict[str, str]]:
slug=request_data.slug,
autoincrement_slug=request_data.autoincrement,
tracked_ref=request_data.tracked_ref,
kind=request_data.kind,
build=build,
)
except Exception:
Expand Down Expand Up @@ -130,6 +131,7 @@ def patch_edition(
slug=request_data.slug,
tracking_mode=request_data.mode,
tracked_ref=request_data.tracked_ref,
kind=request_data.kind,
pending_rebuild=request_data.pending_rebuild,
)
except Exception:
Expand Down
10 changes: 9 additions & 1 deletion tests/test_lsstdocmode.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def test_lsst_doc_tag_order() -> None:
assert v311 > v39


def test_semver_tag() -> None:
version = LsstDocVersionTag("1.2.3")

assert version.major == 1
assert version.minor == 2
assert version.patch == 3


def test_invalid_lsst_doc_tag() -> None:
with pytest.raises(ValueError):
LsstDocVersionTag("1.2")
LsstDocVersionTag("1.2rc1")

0 comments on commit 2a0cd86

Please sign in to comment.