Skip to content

State

Source code in nava/platform/templates/state.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@dataclass
class TemplateVersionAnswer:
    answer_value: str
    """What is saved in the answers file as `_commit` (it's the output from a `git describe`)"""
    version: Version | None
    """A PEP 440 object corresponding to `answer_value` (if possible)"""

    @property
    def display_str(self) -> str:
        """Public facing representation of the version.

        `copier.Template.version`/the PEP 440 value is what Copier uses in its
        messaging ("Updating to template version <foo>"), so match that if
        possible, otherwise fall back to raw answer value.
        """
        if self.version:
            return str(self.version)

        return self.answer_value

What is saved in the answers file as _commit (it's the output from a git describe)

Public facing representation of the version.

copier.Template.version/the PEP 440 value is what Copier uses in its messaging ("Updating to template version "), so match that if possible, otherwise fall back to raw answer value.

A PEP 440 object corresponding to answer_value (if possible)

Parse the string as a Version.

This is an imperfect, but minimally-complicated effort to match copier.Template.version behavior. It mostly diverges from the upstream value when version string is not a valid PEP 440 identifier (e.g., the template uses a date stamp as it's version), as we can't fully match Copier's behavior without access to the full git history, since upstream discards all tags that are not PEP 440 compliant before generating its value (and if there are no PEP 440 compliant tags at all in the template, will spit out something like: 0.0.0.post<count of commits since beginning of project>.dev0+<current commit short hash>).

Source code in nava/platform/templates/state.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def get_version_from_git_describe(v: str) -> Version:
    """Parse the string as a `Version`.

    This is an imperfect, but minimally-complicated effort to match
    `copier.Template.version` behavior. It mostly diverges from the upstream
    value when version string is not a valid PEP 440 identifier (e.g., the
    template uses a date stamp as it's version), as we can't fully match
    Copier's behavior without access to the full git history, since upstream
    discards all tags that are not PEP 440 compliant before generating its value
    (and if there are no PEP 440 compliant tags at all in the template, will
    spit out something like: `0.0.0.post<count of commits since beginning of
    project>.dev0+<current commit short hash>`).
    """
    if not re.match(r"^.+-\d+-g\w+$", v):
        raise ValueError(f"Not a valid git describe: {v}")

    base, count, git_hash = v.rsplit("-", 2)

    dunamai_version = dunamai.Version(
        base=base.removeprefix("v"), distance=int(count), commit=git_hash.removeprefix("g")
    )

    # We could just:
    #
    #   Version(f"{base}.post{count}+{git_hash}")
    #
    # but dunamai adds a default `.dev0` in there during the serialization
    # logic, which is what upstream uses[1], so match upstream's version logic
    # for correct comparisions against git templates (i.e., calls to
    # `template.version`).
    #
    # [1] https://github.com/copier-org/copier/blob/63fec9a500d9319f332b489b6d918ecb2e0598e3/copier/template.py#L584-L588
    return Version(dunamai_version.serialize(style=dunamai.Style.Pep440))