Base Provider Classes

These base classes can be subclassed to create a new provider.

class modify_repos.script.base.Script(*, submit=False)

Defines how to select repositories and modify them. Typically, you’ll want to subclass a more specific class that is already set up to work with a remote host. You’d subclass this class if you wanted to define such a class for a new host.

Parameters:

submit (bool) – Whether to submit the changes. This is disabled by default, to give you a chance to develop the changes first.

target: str = 'main'

The name of the target branch to branch off of and merge into.

branch: str

The name of the work branch to create.

title: str

A short title describing the change. Used as the first line of the automatic commit, as well as the title of the PR. By convention, this should be at most 50 characters.

root_dir: Path

The directory containing the running script. Used to reference resource files and templates.

jinja_env: Environment

A Jinja environment configured to use root_dir as a template folder. See render_template().

clones_dir: Path

Directory where repos are cloned to. Uses the appropriate user cache dir for the platform.

body: str

Additional description about the change. Used in the commit message after the title, separated by an empty line. Also used as the body of the PR. This will be re-wrapped to 72 characters to match convention.

enable_submit

Whether to submit the changes. This is disabled by default, to give you a chance to develop the changes first. It is set from the submit param.

render_template(name, /, **kwargs)

Render the named template file with context. Uses jinja_env, which finds templates next to the script file.

Parameters:
  • name (str) – Template name to load.

  • kwargs (Any) – Context to pass to the render call.

Return type:

str

list_all_repos()

Get the list of all repos that may be cloned. Override this to define how to generate this list. Called by list_repos().

Return type:

list[RepoType]

list_repos()

Get the filtered list of repos that will be cloned. Override list_all_repos() and select_for_clone() to control what is returned here. Called by run().

Return type:

list[RepoType]

property full_target: str

The upstream target branch, which is target prefixed by origin/.

property commit_message: str

The message to use for the automatic commit in commit(). Defaults to title and body separated by a blank line.

select_for_clone(repo)

Select what repos are returned by list_repos(). Each repo from list_all_repos() is passed, and will be used if this method returns true for it.

For example, override this to return true if the repo name matches a set of names.

Parameters:

repo (Repo) – The repo to filter.

Return type:

bool

select_for_modify(repo)

Select whether modify() will be called on the repo. Called by run() while the current directory is the cloned repo dir.

For example, override this to return false if the repo does not contain a file to be removed, or already contains a file to be added.

Parameters:

repo (Repo) – The repo to filter.

Return type:

bool

modify(repo)

Perform modifications to the repo. Called by run() while the current directory is the cloned repo dir.

If this leaves uncommitted changes, Repo.commit_if_needed() will detect that and commit automatically. You can also add and commit manually to skip that behavior.

Parameters:

repo (Repo) – The repo to modify.

Return type:

None

run()

Call Repo.run() for each selected repo.

Return type:

None

read_text(path, strip=True)

Read a text file, where path is relative to the script’s directory root_dir. The file will be read as UTF-8.

Parameters:
  • path (str | PathLike[str]) – Path to file to read. Relative paths are relative to root_dir.

  • strip (bool) – Strip leading and trailing empty spaces and lines. Enabled by default. The text is often formatted into an existing file, so stripping spaces makes working with it more predictable.

Return type:

str

class modify_repos.repo.base.Repo(script, remote_id)

Defines how to manipulate a repository. Script.list_repos() will return instances of a subclass of this that are set up to work with a specific type of repo, and most of the methods will be called as part of running the script. You’d subclass this class if you wanted to define such a class for a new type of repo.

Parameters:
  • script (Script[t.Any]) – The script being run to modify this repo.

  • remote_id (str) – A value that identifies where this repo was cloned from.

script

The script being run to modify this repo.

remote_id: str

A value that identifies where this repo was cloned from. The format depends on how the script finds repos.

property local_dir: Path

The path where this repo is cloned.

clone()

Clone the repository unconditionally. This is called by clone_if_needed().

Return type:

None

clone_if_needed()

Clone the repository if the local directory doesn’t exist. Calls clone(). Called by run().

Return type:

None

reset_target()

Reset the base branch that will be branched off of and merged into. This should ensure the repository is clean and up to date, discarding any changes from previous unsuccessful runs. Called by run().

Return type:

None

reset_branch()

Create or reset the work branch. This should ensure the branch is freshly created from the target branch. Called by run().

Return type:

None

needs_commit()

Check if there are uncommitted changes. Called by auto_commit_if_needed().

Return type:

bool

auto_commit()

Create a commit unconditionally. This is called by auto_commit_if_needed() to create the automatic commit when there are uncommitted changes, and should add those changes to the commit. It should not be called to create other intermediate commits. It should use Script.message as the commit message.

Return type:

None

auto_commit_if_needed()

Create a commit if there are uncommitted changes. Calls needs_commit() and auto_commit_if_needed(). Called by run().

Return type:

None

needs_submit()

Check if there are commits that have not been pushed upstream. Called by submit_if_needed().

Return type:

bool

submit()

Submit the changes upstream. What this means depends on the implementation; whether it merges, creates a PR, or something else.

Return type:

None

submit_if_needed()

Submit the changes if there are any changes. Is disabled by default by Script.enable_submit, to prevent accidental submission of a script in development. Calls needs_submit() and submit(). Called by run().

Return type:

None

run()

Run the full workflow for this repo: clone, reset, modify, commit, submit. Calls many of the other methods defined in this class. Called by Script.run().

Return type:

None