Jump to >

rbtools.clients.base.scmclient

Base class for interfacing with source code management tools.

New in version 4.0.

Classes

BaseSCMClient([config, options])

A base class for interfacing with a source code management tool.

SCMClientCommitHistoryItem

A commit in a commit history.

SCMClientCommitMessage

A commit message from a local repository.

SCMClientDiffResult

The result of a diff operation.

SCMClientRevisionSpec

A revision specification parsed from command line arguments.

class rbtools.clients.base.scmclient.SCMClientRevisionSpec[source]

Bases: TypedDict

A revision specification parsed from command line arguments.

This class helps provide type hinting to results from BaseSCMClient.parse_revision_spec().

The dictionary may include other arbitrary keys.

New in version 4.0.

base: Optional[object]

A revision to use as the base of the resulting diff.

The value is considered an opaque value, dependent on the SCMClient.

This is required.

Type:

object

tip: Optional[object]

A revision to use as the tip of the resulting diff.

The value is considered an opaque value, dependent on the SCMClient.

This is required.

Type:

object

parent_base: Optional[object]

The revision to use as the base of a parent diff.

The value is considered an opaque value, dependent on the SCMClient.

This is optional.

Type:

object

commit_id: Optional[str]

The commit ID of the single commit being posted, if not using a range.

This is optional.

Type:

str

extra: Optional[Mapping[str, Any]]

Any extra revision state not used above.

If a SCMClient needs to provide information in addition or instead of the above, they should populate this field, rather than placing the information in the main revision dictionary. This helps ensure a stable, typed interface for all revision data.

New in version 4.0.

__optional_keys__ = frozenset({'commit_id', 'extra', 'parent_base'})
__orig_bases__ = (<function TypedDict>,)
__required_keys__ = frozenset({'base', 'tip'})
__total__ = True
class rbtools.clients.base.scmclient.SCMClientDiffResult[source]

Bases: TypedDict

The result of a diff operation.

This class helps provide type hinting to results from BaseSCMClient.diff().

New in version 4.0.

diff: Optional[bytes]

The contents of the diff to upload.

This should be None or an empty string if diff generation fails.

Type:

bytes

parent_diff: Optional[bytes]

The contents of the parent diff, if available.

Type:

bytes

changenum: Optional[str]

The change number to include when posting, if available.

Type:

str

commit_id: Optional[str]

The commit ID to include when posting, if available.

Type:

str

base_commit_id: Optional[str]

The ID of the commit that the change is based on, if available.

This is necessary for some hosting services that don’t provide individual file access.

Type:

str

review_request_extra_data: Optional[Dict[str, Any]]

This may contain structured data. It will be sent to the server as part of a JSON Merge Patch.

This requires Review Board 3.0 or higher.

New in version 3.1.

__optional_keys__ = frozenset({'base_commit_id', 'changenum', 'commit_id', 'parent_diff', 'review_request_extra_data'})
__orig_bases__ = (<function TypedDict>,)
__required_keys__ = frozenset({'diff'})
__total__ = True
class rbtools.clients.base.scmclient.SCMClientCommitHistoryItem[source]

Bases: TypedDict

A commit in a commit history.

This class helps provide type hinting to results from BaseSCMClient.get_commit_history().

New in version 4.0.

commit_id: str

The ID of the commit.

Type:

str

parent_id: Optional[str]

The ID of the parent commit.

Type:

str

commit_message: Optional[str]

The commit message.

Type:

str

author_name: Optional[str]

The name of the commit’s author.

Type:

str

author_email: Optional[str]

The e-mail address of the commit’s author.

Type:

str

author_date: Optional[str]

The date the commit was authored.

Type:

str

committer_name: Optional[str]

The name of the person or entity who committed the change.

Type:

str

committer_email: Optional[str]

The e-mail address of the person or entity who committed the change.

Type:

str

committer_date: Optional[str]

The date the commit was made.

Type:

str

__optional_keys__ = frozenset({'committer_date', 'committer_email', 'committer_name'})
__orig_bases__ = (<function TypedDict>,)
__required_keys__ = frozenset({'author_date', 'author_email', 'author_name', 'commit_id', 'commit_message', 'parent_id'})
__total__ = True
class rbtools.clients.base.scmclient.SCMClientCommitMessage[source]

Bases: TypedDict

A commit message from a local repository.

This class helps provide type hinting to results from BaseSCMClient.get_commit_message().

New in version 4.0.

summary: Optional[str]

The summary of a commit message.

This should generally match the first line of a commit.

Type:

str

description: Optional[str]

The description of a commit message.

This should generally match the remainder of the commit message after the summary, if any content remains.

Type:

str

__optional_keys__ = frozenset({'description'})
__orig_bases__ = (<function TypedDict>,)
__required_keys__ = frozenset({'summary'})
__total__ = True
class rbtools.clients.base.scmclient.BaseSCMClient(config: Optional[Dict[str, Any]] = None, options: Optional[Namespace] = None)[source]

Bases: object

A base class for interfacing with a source code management tool.

These are used for fetching repository information and generating diffs.

Callers must run setup() or has_dependencies() before calling methods on this tool.

Changed in version 4.0:

scmclient_id: str = ''

The unique ID of the client.

New in version 4.0: This will be required in RBTools 5.0.

Type:

str

name: str = ''

The name of the client.

Type:

str

server_tool_names: Optional[str] = None

A comma-separated list of SCMClient names on the server

New in version 3.0.

Type:

str

requires_diff_tool: Union[bool, List[str]] = False

Whether this tool requires a command line diff tool.

This may be a boolean or a list.

If a boolean, then this must be False if no command line tool is required, or True if any command line tool supported by RBTools is available (in which case the SCMClient is responsible for ensuring compatibility).

If a list, then this must be a list of registered diff tool IDs that are compatible.

New in version 4.0.

Type:

bool or list

supports_changesets: bool = False

Whether the SCM uses server-side changesets

New in version 3.0.

Type:

bool

supports_commit_history: bool = False

Whether the SCM client can generate a commit history.

Type:

bool

supports_diff_extra_args: bool = False

Whether the SCM client’s diff method takes the extra_args parameter.

Type:

bool

supports_diff_exclude_patterns: bool = False

Whether the SCM client supports excluding files from the diff.

Type:

bool

supports_no_renames: bool = False

Whether the SCM client can generate diffs without renamed files.

Type:

bool

supports_parent_diffs: bool = False

Whether the SCM client supports generating parent diffs.

New in version 3.0.

Type:

bool

supports_patch_revert: bool = False

Whether the SCM client supports reverting patches.

Type:

bool

can_amend_commit: bool = False

Whether commits can be amended.

Type:

bool

can_merge: bool = False

Whether the SCM can create merges.

Type:

bool

can_push_upstream: bool = False

Whether commits can be pushed upstream.

Type:

bool

can_delete_branch: bool = False

Whether branch names can be deleted.

Type:

bool

can_branch: bool = False

Whether new branches can be created.

Type:

bool

can_bookmark: bool = False

Whether new bookmarks can be created.

Type:

bool

can_squash_merges: bool = False

Whether commits can be squashed during merge.

Type:

bool

__init__(config: Optional[Dict[str, Any]] = None, options: Optional[Namespace] = None) None[source]

Initialize the client.

Parameters:
  • config (dict, optional) – The loaded user config.

  • options (argparse.Namespace, optional) – The parsed command line arguments.

config: Dict[str, Any]

User configuration.

Any user configuration loaded via .reviewboardrc files. This may be empty.

Type:

dict

options: Optional[Namespace]

Command line arguments passed to this client.

This may be empty, and makes assumptions about which command line arguments are registered with a command. It’s intended for use within RBTools.

This may be None.

Type:

argparse.Namespace

capabilities: Optional[Capabilities]

Capabilities returned by the server.

This will be None if not set by the server.

Type:

rbtools.api.capabilities.Capabilities

is_setup: bool

Whether the client is set up and ready for operations.

Operations may fail or crash if this is False.

Callers must call setup() or has_dependencies() before performing operations using this client.

New in version 4.0.

Type:

bool

property entrypoint_name: str[source]

An alias for the SCMClient ID.

This is here for backwards-compatibility purposes.

Deprecated since version 4.0: Callers should use scmclient_id. This attribute will be removed in RBTools 5.0.

setup() None[source]

Set up the client.

This will perform checks to ensure the client can be used. Callers should make sure to either call this method or has_dependencies() before performing any other operations on this client.

If checks succeed, is_setup will be True, and operations using this client can be performed.

If checks fail, an exception may be raised, and is_setup will be False.

Note that this will not check requires_diff_tool, as that is only required for certain operations. Checking for a compatible diff tool is the responsibility of the caller whenever working with diffs.

New in version 4.0.

Raises:

rbtools.clients.errors.SCMClientDependencyError – One or more required dependencies are missing.

has_dependencies(expect_checked: bool = False) bool[source]

Return whether all dependencies for the client are available.

Either this or setup() must be called before any operations are performed with this client.

New in version 4.0.

Parameters:

expect_checked (bool, optional) –

Whether the caller expects that dependency checking has already been done.

If True, and dependencies have not yet been checked via check_dependencies(), this will raise a deprecation warning.

Starting in RBTools 4.0, this will raise an exception if check_dependencies() hasn’t yet been called.

Returns:

True if dependencies are all available. False if one or more are not.

Return type:

bool

check_dependencies() None[source]

Check whether the base dependencies needed are available.

This is responsible for checking for any command line tools or Python modules required to consider this client as an option when scanning repositories or selecting a specific client.

This should not check for diff implementations or anything specific about a local filesystem. It’s merely a first-pass dependency check.

This function is normally called via setup() (which will re-raise any exceptions here) or has_dependencies(). It doesn’t need to be called manually unless attempting to re-generate the exception.

Subclasses can log any failed checks in the debug log, to help with debugging missing tools. If checking against multiple possible names, they may also record information needed to locate the matching executable for future operations.

It’s recommended to use rbtools.utils.checks.check_install() to help with executable dependency checks.

New in version 4.0.

Raises:

rbtools.clients.errors.SCMClientDependencyError – One or more required dependencies are missing.

is_remote_only() bool[source]

Return whether this repository is operating in remote-only mode.

For some SCMs and some operations, it may be possible to operate exclusively with a remote server and have no working directory.

New in version 3.0.

Returns:

Whether this repository is operating in remote-only mode.

Return type:

bool

get_local_path() Optional[str][source]

Return the local path to the working tree.

This is expected to be overridden by subclasses.

New in version 3.0.

Returns:

The filesystem path of the repository on the client system.

Return type:

str

get_repository_info() Optional[RepositoryInfo][source]

Return repository information for the current working tree.

This is expected to be overridden by subclasses.

New in version 3.0.

Returns:

The repository info structure.

Return type:

rbtools.clients.base.repository.RepositoryInfo

get_diff_tool() Optional[BaseDiffTool][source]

Return a diff tool for use with this client.

This can be used by subclasses, and by callers that want to check if a compatible diff tool is available before calling diff().

The value is cached for the client.

New in version 4.0.

Returns:

The diff instance, if a compatible instance is found.

This will be None if requires_diff_tool is False.

Return type:

rbtools.diffs.tools.base.BaseDiffTool

Raises:
find_matching_server_repository(repositories: ListResource) Tuple[Optional[ItemResource], Optional[ItemResource]][source]

Find a match for the repository on the server.

New in version 3.0.

Parameters:

repositories (rbtools.api.resource.ListResource) – The fetched repositories.

Returns:

A 2-tuple of matching repository information:

Tuple:

Return type:

tuple

get_repository_name() Optional[str][source]

Return any repository name configured in the repository.

This is used as a fallback from the standard config options, for repository types that support configuring the name in repository metadata.

New in version 3.0.

Returns:

The configured repository name, or None.

Return type:

str

check_options() None[source]

Verify the command line options.

This is expected to be overridden by subclasses, if they need to do specific validation of the command line.

Raises:

rbtools.clients.errors.OptionsCheckError – The supplied command line options were incorrect. In particular, if a file has history scheduled with the commit, the user needs to explicitly choose what behavior they want.

get_changenum(revisions: SCMClientRevisionSpec) Optional[str][source]

Return the change number for the given revisions.

This is only used when the client is supposed to send a change number to the server (such as with Perforce).

Parameters:

revisions (dict) – A revisions dictionary as returned by parse_revision_spec().

Returns:

The change number to send to the Review Board server.

Return type:

str

scan_for_server(repository_info: RepositoryInfo) Optional[str][source]

Find the server path.

This will search for the server name in the .reviewboardrc config files. These are loaded with the current directory first, and searching through each parent directory, and finally $HOME/.reviewboardrc last.

Parameters:

repository_info (rbtools.clients.base.repository.RepositoryInfo) – The repository information structure.

Returns:

The Review Board server URL, if available.

Return type:

str

parse_revision_spec(revisions: List[str] = []) SCMClientRevisionSpec[source]

Parse the given revision spec.

The ‘revisions’ argument is a list of revisions as specified by the user. Items in the list do not necessarily represent a single revision, since the user can use SCM-native syntaxes such as “r1..r2” or “r1:r2”. SCMTool-specific overrides of this method are expected to deal with such syntaxes.

Parameters:

revisions (list of str, optional) – A list of revisions as specified by the user. Items in the list do not necessarily represent a single revision, since the user can use SCM-native syntaxes such as r1..r2 or r1:r2. SCMTool-specific overrides of this method are expected to deal with such syntaxes.

Returns:

A dictionary containing keys found in SCMClientRevisionSpec.

Additional keys may be included by subclasses for their own internal use.

These will be used to generate the diffs to upload to Review Board (or print). The diff for review will include the changes in (base, tip], and the parent diff (if necessary) will include (parent, base].

If a single revision is passed in, this will return the parent of that revision for “base” and the passed-in revision for “tip”.

If zero revisions are passed in, this will return revisions relevant for the “current change”. The exact definition of what “current” means is specific to each SCMTool backend, and documented in the implementation classes.

Return type:

dict

Raises:
get_tree_matches_review_request(review_request: ReviewRequestResource, *, revisions: SCMClientRevisionSpec, **kwargs) Optional[bool][source]

Return whether a review request matches revisions or tree state.

This works along with review request matching in tools like rbt post to match state in a review request (such as in extra_data) with the state in the local tree (such as the local branch or SCM-specific identifiers other than a commit ID).

Subclasses can override this to implement their own matching logic. By default, no additional logic is implemented.

New in version 3.1.

Parameters:
Returns:

True if the review request is considered an exact match.

False if the review request should be explicitly discarded as a possible match.

None if a match could not be determined based on available information.

Return type:

bool

diff(revisions: SCMClientRevisionSpec, *, include_files: List[str] = [], exclude_patterns: List[str] = [], no_renames: bool = False, repository_info: Optional[RepositoryInfo] = None, extra_args: List[str] = [], with_parent_diff: bool = True) SCMClientDiffResult[source]

Perform a diff using the given revisions.

Callers should make sure that the appropriate diff tool is installed by calling rbtools.diffs.tools.registry.get_diff_tool() and passing requires_diff_tool if it’s a list.

This is expected to be overridden by subclasses, which should:

  1. Set requires_diff_tool based on the client’s needs.

  2. Optionally use options for any client-specific diff functionality.

  3. Call get_diff_tool() early, if needed.

Subclasses that need to support special arguments should use options.

Changed in version 4.0:

  • All arguments except revisions must be specified as keyword arguments.

  • Subclasses should now use requires_diff_tool and get_diff_tool() instead of manually invoking diff tools.

Parameters:
  • revisions (dict) – A dictionary of revisions, as returned by parse_revision_spec().

  • include_files (list of str, optional) – A list of files to whitelist during the diff generation.

  • exclude_patterns (list of str, optional) – A list of shell-style glob patterns to blacklist during diff generation.

  • no_renames (bool, optional) – Whether to avoid rename detection.

  • repository_info (rbtools.clients.base.repository.RepositoryInfo, optional) – The repository info structure.

  • extra_args (list, unused) – Additional arguments to be passed to the diff generation.

  • with_parent_diff (bool, optional) – Whether or not to compute a parent diff.

Returns:

A dictionary containing keys documented in SCMClientDiffResult.

Return type:

dict

get_commit_history(revisions: SCMClientRevisionSpec) List[SCMClientCommitHistoryItem][source]

Return the commit history between the given revisions.

Derived classes must override this method if they support posting with history.

Parameters:

revisions (dict) – The parsed revision spec to use to generate the history.

Returns:

The history entries.

Return type:

list of dict

has_pending_changes() bool[source]

Return whether there are changes waiting to be committed.

Derived classes should override this method if they wish to support checking for pending changes.

Returns:

True if the working directory has been modified or if changes have been staged in the index.

Return type:

bool

apply_patch(patch_file: str, *, base_path: str, base_dir: str, p: Optional[str] = None, revert: bool = False) PatchResult[source]

Apply the patch and return a PatchResult indicating its success.

Parameters:
  • patch_file (str) – The name of the patch file to apply.

  • base_path (str) – The base path that the diff was generated in.

  • base_dir (str) – The path of the current working directory relative to the root of the repository.

  • p (str, optional) – The prefix level of the diff.

  • revert (bool, optional) – Whether the patch should be reverted rather than applied.

Returns:

The result of the patch operation.

Return type:

rbtools.clients.base.patch.PatchResult

create_commit(*, message: str, author: PatchAuthor, run_editor: bool, files: List[str] = [], all_files: bool = False) None[source]

Create a commit based on the provided message and author.

Derived classes should override this method if they wish to support committing changes to their repositories.

Parameters:
  • message (str) – The commit message to use.

  • author (rbtools.clients.base.patch.PatchAuthor) – The author of the commit.

  • run_editor (bool) – Whether to run the user’s editor on the commmit message before committing.

  • files (list of str, optional) – The list of filenames to commit.

  • all_files (bool, optional) – Whether to commit all changed files, ignoring the files argument.

Raises:
get_commit_message(revisions: SCMClientRevisionSpec) Optional[SCMClientCommitMessage][source]

Return the commit message from the commits in the given revisions.

This pulls out the first line from the commit messages of the given revisions. That is then used as the summary.

Parameters:

revisions (dict) – A dictionary as returned by parse_revision_spec().

Returns:

A dictionary containing keys found in SCMClientCommitMessage.

This may be None, if no commit message is found.

Return type:

dict

delete_branch(branch_name: str, *, merged_only: bool = True) None[source]

Delete the specified branch.

Parameters:
  • branch_name (str) – The name of the branch to delete.

  • merged_only (bool, optional) – Whether to limit branch deletion to only those branches which have been merged into the current HEAD.

merge(*, target: str, destination: str, message: str, author: PatchAuthor, squash: bool = False, run_editor: bool = False, close_branch: bool = True) None[source]

Merge the target branch with destination branch.

Parameters:
  • target (str) – The name of the branch to merge.

  • destination (str) – The name of the branch to merge into.

  • message (str) – The commit message to use.

  • author (rbtools.clients.base.patch.PatchAuthor) – The author of the commit.

  • squash (bool, optional) – Whether to squash the commits or do a plain merge.

  • run_editor (bool, optional) – Whether to run the user’s editor on the commmit message before committing.

  • close_branch (bool, optional) – Whether to close/delete the merged branch.

Raises:

rbtools.clients.errors.MergeError – An error occurred while merging the branch.

push_upstream(remote_branch: str) None[source]

Push the current branch to upstream.

Parameters:

remote_branch (str) – The name of the branch to push to.

Raises:

rbtools.client.errors.PushError – The branch was unable to be pushed.

get_raw_commit_message(revisions: SCMClientRevisionSpec) str[source]

Extract the commit messages on the commits in the given revisions.

Derived classes should override this method in order to allow callers to fetch commit messages. This is needed for description guessing.

If a derived class is unable to fetch the description, None should be returned.

Callers that need to differentiate the summary from the description should instead use get_commit_message().

Parameters:

revisions (dict) – A dictionary containing base and tip keys.

Returns:

The commit messages of all commits between (base, tip].

Return type:

str

get_current_branch() str[source]

Return the repository branch name of the current directory.

Derived classes should override this method if they are able to determine the current branch of the working directory.

Returns:

A string with the name of the current branch. If the branch is unable to be determined, returns None.

Return type:

str

supports_empty_files() bool[source]

Return whether the server supports added/deleted empty files.

Returns:

True if the Review Board server supports added or deleted empty files.

Return type:

bool

apply_patch_for_empty_files(patch: bytes, *, p_num: str, revert: bool = False) bool[source]

Return whether any empty files in the patch are applied.

Parameters:
  • patch (bytes) – The contents of the patch.

  • p_num (str) – The prefix level of the diff.

  • revert (bool, optional) – Whether the patch should be reverted rather than applied.

Returns:

True if there are empty files in the patch. False if there were no empty files, or if an error occurred while applying the patch.

Return type:

bool

amend_commit_description(message: str, *, revisions: Optional[SCMClientRevisionSpec] = None) None[source]

Update a commit message to the given string.

Parameters:
  • message (str) – The commit message to use when amending the commit.

  • revisions (dict, optional) – A dictionary of revisions, as returned by parse_revision_spec(). This provides compatibility with SCMs that allow modifications of multiple changesets at any given time, and will amend the change referenced by the tip key.

Raises:

rbtools.clients.errors.AmendError – The amend operation failed.