Skip to content
rlsbl.ownership
On this page

The questions answered here alone: whether a path is rlsbl's own tool-owned bookkeeping, which workspace member owns it (most specific path wins), and what a releasable's changelog scope claims beyond its members' files.

#rlsbl.ownership

#rlsbl.ownership

File ownership: the tool-owned exempt set, single-owner attribution, and the scope claims a releasable makes on its own state directory.

The questions answered here, and nowhere else:

  1. Is this path tool-owned? :func:is_tool_owned_path decides from static

path rules alone -- no config reads, no git calls, no workspace lookups. A tool-owned path is rlsbl's own bookkeeping (changelog state, release state, the workspace directory, the generated CI router), so it never needs a changelog owner and never participates in attribution.

  1. Which workspace member owns this path? :func:owner_of answers with

exactly one member: the most specific declared member path wins, and the root member (path = ".") owns everything no other member claims.

  1. Is this path inside the scope I am asking about?

:class:OwnershipScope answers, and it is the only question a releasable participates in: a releasable is not a member, so it owns no file, but its scope claims its own state directory (.rlsbl-monorepo/releasables/<name>/) on top of its members' files.

Kept free of imports from git, workspace, targets and checks so every layer can depend on it -- :mod:rlsbl.workspace_types is the one exception, for the directory names, and it imports nothing but :mod:rlsbl.errors. Commit-level attribution (which needs git) is in :mod:rlsbl.git_util, which imports this module.

#OwnershipError

File attribution could not be performed.

#releasable_state_dir

python
def releasable_state_dir(releasable_name) -> str

Repo-relative path of a releasable's own state directory.

.rlsbl-monorepo/releasables/<name> -- the changelog, the release archives, the version, the transition record and the config of one releasable. No member's declared path claims it (it is tool-owned, and a releasable is not a member), so it is the releasable itself that claims it, at the scope level: see :meth:OwnershipScope.for_releasable.

#state_dir_releasable

python
def state_dir_releasable(path) -> str | None

The releasable whose state directory path sits in, or None.

The inverse of :func:releasable_state_dir. A path under .rlsbl-monorepo/releasables/<name>/ belongs to no member -- it is tool-owned, and a releasable is not a member -- so this is the only way to answer "whose is this?" for it. Used by messages that have to name the owner of a file the asking scope does not claim.

#normalize_path

python
def normalize_path(path) -> str

Return path with \ separators folded and trailing slashes gone.

#is_root_path

python
def is_root_path(path) -> bool

True when path is one of the spellings that mean the repository root.

The root member declares path = "."; "" and "./" are the other accepted spellings of the same territory. Anything that prefixes a member path has to ask, because prefixing the root produces a path with a leading ./ that is not the repository root's real spelling -- and for a git tag it is not even a legal ref name.

#tool_owned_rule

python
def tool_owned_rule(path) -> str | None

Return the static rule making path tool-owned, or None.

The returned string is the rule itself (".rlsbl/changes/**", "CHANGELOG.md"), suitable for putting in a message that has to explain why a path needs no owner. Root-relative rules answer only for a path at the repository root; the rest answer at any depth.

#is_tool_owned_path

python
def is_tool_owned_path(path) -> bool

Is path rlsbl's own bookkeeping, and therefore exempt from ownership?

#member_path

python
def member_path(member) -> str

Return a member's declared path, normalized ("" for the root member).

#member_name

python
def member_name(member) -> str

Return a member's name.

#is_root_member

python
def is_root_member(member) -> bool

Does member declare the repository root as its territory?

#member_prefix

python
def member_prefix(member) -> str

Return the path prefix a member's files carry.

"" for the root member -- it claims every path -- and "pkg/" for a member at pkg. The root member's prefix used to be computed as "./", which matches no path git ever prints, so a root member owned nothing at all.

#find_root_member

python
def find_root_member(members)

Return the root member of members, or None when there is none.

#owner_of

python
def owner_of(filepath, members)

Return the single member owning filepath, or None.

None means one of two things, both of which the caller must be able to live with: the path is tool-owned (:func:is_tool_owned_path), or the member list has no root member and no declared path claims the file. A loaded workspace always has a root member, so within a real workspace only the first case occurs.

Most specific wins: with members at ., pkg and pkg/inner, the file pkg/inner/a.py belongs to pkg/inner alone.

#member_for_directory

python
def member_for_directory(dirpath, members, *, include_root)

Return the member whose territory a directory falls in.

The same most-specific-path rule :func:owner_of uses, minus the tool-owned exclusion: a directory is a place to run a command from, not a file needing a changelog owner.

include_root decides whether the root member may answer. It is mandatory because the two questions it separates are genuinely different: file attribution always gives the root member the residual, while "which project am I standing in?" is a question several commands answer with "none of them, you are at the workspace root" and act on. Callers state which they are asking.

#_most_specific_claim

python
def _most_specific_claim(normalized, members)

The most specific member path claiming normalized; root is the residual.

#owner_name_of

python
def owner_name_of(filepath, members) -> str | None

Name of the member owning filepath, or None (see :func:owner_of).

#owner_names_of_files

python
def owner_names_of_files(files, members) -> set

Return the set of member names owning any path in files.

#OwnershipScope

A question asked of attribution: which members' files am I after?

Attribution needs the whole member list to answer at all -- a file under pkg/inner belongs to pkg/inner even when the caller only cares about pkg, and a root file belongs to the root member even when the caller only cares about pkg. Handing a function the members it cares about and nothing else is what let a file be claimed by two members at once, so the two halves travel together: members is every member in the workspace, owned names the subset in scope.

state_dirs is the third half, and the one thing here that is not a member question. A releasable's own state directory -- its changelog, its release archives, its version -- belongs to no member: no declared path claims it, and inventing a phantom member for it would break the invariant that every file has exactly one member owner. A RELEASABLE's scope claims it directly instead, so archiving that releasable's release file and finalizing its changelog are commits inside that releasable's scope rather than outside every scope in the workspace.

#for_members

python
def for_members(cls, all_members, scope_members) -> 'OwnershipScope'

Scope covering scope_members, claiming no state directory.

#for_releasable

python
def for_releasable(cls, all_members, scope_members, releasable_name) -> 'OwnershipScope'

Scope covering a releasable: its members AND its state directory.

#for_member

python
def for_member(cls, all_members, one_member) -> 'OwnershipScope'

Scope covering exactly one member.

#owner_name_of

python
def owner_name_of(self, filepath) -> str | None

Name of the member owning filepath (any member, in scope or not).

#claims_state_dir

python
def claims_state_dir(self, filepath) -> bool

Does filepath sit inside a state directory this scope claims?

#claims

python
def claims(self, filepath) -> bool

Is filepath in scope -- owned by a member, or in a state directory?

The two answers cannot collide: a state directory is tool-owned, so it has no member owner to disagree with. Being claimed here says which releasable a path belongs to; it says nothing about whether a changelog entry is REQUIRED for it, which the tool-owned exempt set still answers with "no".

#claims_any

python
def claims_any(self, files) -> bool

Is any path in files owned by a member in scope?

#owned_members

python
def owned_members(self) -> list

The in-scope members themselves, in workspace declaration order.

#describe

python
def describe(self) -> str

A short human name for the scope, for error messages.

A releasable's state-directory claim is named alongside its members: the directory belongs to no member, so a description built from the member names alone reads as if it were outside the scope -- and the message that carries it would then contradict what :meth:claims answers.

Search