Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions autoform_cli/project/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
from pathlib import Path, PurePosixPath
from urllib.parse import urlsplit

from .. import scaffold
from ..claims import _reject_json_constant, _strict_json_object
from ..graph import _parse_node
from ..scaffold import (
DEFAULT_AUTOFORM_SOURCE,
ScaffoldError,
_FULL_SHA,
_TEMPLATES,
_checkout_pin,
_normalize_autoform_source,
_read_templates,
_require_complete_templates,
Expand All @@ -33,7 +33,6 @@
PROJECT_CREATION_SCHEMA = "autoform-project-creation/v1"
_CREATION_RELEASE_SCHEMA = "autoform-project-creation-release/v1"
_PACKAGE_NAME = re.compile(r"[A-Z][A-Za-z0-9]*")
_FULL_SHA = re.compile(r"[0-9a-f]{40}")
_RESERVED_PACKAGE_NAMES = frozenset({"Prop", "Sort", "Type"})
_RELEASE_ID = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]*")
_STAGE_ATTEMPTS = 32
Expand Down Expand Up @@ -437,12 +436,8 @@ def _resolve_workflow_pin(source: str, ref: str, *, templates: tuple[tuple[str,
"The Autoform workflow source must be a safe credential-free HTTPS Git URL ending in .git.",
)
return given_source, given_ref
# Looked up on the module so one replacement governs `init` and `project new`.
pinned_source, pinned_ref = scaffold.plugin_pin(templates)
safe_pinned_source = _normalize_autoform_source(pinned_source, allow_github_scp=True)
if safe_pinned_source is None or _FULL_SHA.fullmatch(pinned_ref.lower()) is None:
safe_pinned_source, pinned_ref = None, ""
return safe_pinned_source or DEFAULT_AUTOFORM_SOURCE, given_ref or pinned_ref.lower()
pinned_source, pinned_ref = _checkout_pin(templates)
return pinned_source, given_ref or pinned_ref


def _validate_target(target: str | Path | None) -> Path:
Expand Down
20 changes: 12 additions & 8 deletions autoform_cli/scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,16 @@ def plugin_pin(
return source, ref


def _checkout_pin(templates: tuple[tuple[str, bytes, int], ...]) -> tuple[str, str]:
"""`plugin_pin` reduced to a safe source and lowercase commit, else the default source and no commit."""

pinned_source, pinned_ref = plugin_pin(templates)
safe_source = _normalize_autoform_source(pinned_source, allow_github_scp=True)
if safe_source is None or not _FULL_SHA.fullmatch(pinned_ref.lower()):
return DEFAULT_AUTOFORM_SOURCE, ""
return safe_source, pinned_ref.lower()


class ScaffoldError(ValueError):
"""The project could not be scaffolded safely."""

Expand Down Expand Up @@ -1048,18 +1058,12 @@ def scaffold_project(
# from the commit named by the workflows.
templates = _read_templates(_TEMPLATES)
_require_complete_templates(templates)
pinned_source, pinned_ref = ("", "") if given_source else plugin_pin(templates)
safe_pinned_source = _normalize_autoform_source(pinned_source, allow_github_scp=True)
if safe_pinned_source is None or not _FULL_SHA.fullmatch(pinned_ref.lower()):
pinned_source, pinned_ref = "", ""
else:
pinned_source, pinned_ref = safe_pinned_source, pinned_ref.lower()
source = given_source or pinned_source or DEFAULT_AUTOFORM_SOURCE
source, pinned_ref = (given_source, "") if given_source else _checkout_pin(templates)
# A ref identifies a commit in one repository. Naming a different source
# while inheriting this checkout's HEAD produces `git+other.git@our-sha`,
# which does not resolve there, so an explicit source carries its own ref
# or none at all.
ref = given_ref or ("" if given_source else pinned_ref)
ref = given_ref or pinned_ref
# CI installs Autoform from a Git ref. Where Autoform lives is a fixed fact
# worth defaulting; which commit is not, and a guessed one publishes a
# project whose first CI step fails for a reason no file in it explains. So
Expand Down
Loading