vcspull import - vcspull.cli.import_cmd

vcspull import subcommand package.

Each supported service (GitHub, GitLab, Codeberg, Gitea, Forgejo, CodeCommit) is registered as a proper argparse subcommand so that vcspull import <service> --help shows only the flags relevant to that service.

vcspull.cli.import_cmd.create_import_subparser(parser)[source]

Wire per-service subparsers into the vcspull import parser.

Return type:

None

Parameters:

parser (argparse.ArgumentParser) – The import parser to attach service subcommands to.

Shared infrastructure for the vcspull import subcommand tree.

Provides parent argparse parsers (for flag composition via parents=[]) and the _run_import() function that all per-service handlers delegate to.

class vcspull.cli.import_cmd._common.Importer[source]

Bases: Protocol

Structural type for any remote service importer.

service_name: str
fetch_repos(options)[source]

Yield repositories matching options.

Return type:

Iterator[RemoteRepo]

Parameters:

options (ImportOptions)

__init__(*args, **kwargs)[source]
_abc_impl = <_abc._abc_data object>
_is_protocol = True
class vcspull.cli.import_cmd._common.ImportAction[source]

Bases: Enum

Action resolved for each repo candidate during vcspull import.

ADD = 'add'
SKIP_UNCHANGED = 'skip_unchanged'
SKIP_EXISTING = 'skip_existing'
UPDATE_URL = 'update_url'
SKIP_PINNED = 'skip_pinned'
PRUNE = 'prune'
vcspull.cli.import_cmd._common._classify_import_action(*, incoming_url, existing_entry, sync)[source]

Classify the import action for a single repository.

Return type:

ImportAction

Parameters:
  • incoming_url (str) – URL from the remote service (already formatted with git+ prefix).

  • existing_entry (Any) – Current config entry for this repo name, or None if not in config.

  • sync (bool) – Whether --sync was passed.

Examples

New repo is always added:

>>> _classify_import_action(
...     incoming_url="git+ssh://x", existing_entry=None, sync=False
... )
<ImportAction.ADD: 'add'>
>>> _classify_import_action(
...     incoming_url="git+ssh://x", existing_entry=None, sync=True
... )
<ImportAction.ADD: 'add'>

Same URL is always classified as unchanged — even when pinned or sync is set.

Note: _run_import may still stamp provenance metadata on unchanged entries when import_source is provided.

>>> _classify_import_action(
...     incoming_url="git+ssh://x",
...     existing_entry={"repo": "git+ssh://x"},
...     sync=True,
... )
<ImportAction.SKIP_UNCHANGED: 'skip_unchanged'>
>>> _classify_import_action(
...     incoming_url="git+ssh://x",
...     existing_entry={"repo": "git+ssh://x", "options": {"pin": True}},
...     sync=True,
... )
<ImportAction.SKIP_UNCHANGED: 'skip_unchanged'>

url key takes precedence over repo key (matches extract_repos semantics):

>>> _classify_import_action(
...     incoming_url="git+ssh://new",
...     existing_entry={"repo": "git+ssh://old", "url": "git+ssh://new"},
...     sync=False,
... )
<ImportAction.SKIP_UNCHANGED: 'skip_unchanged'>

Different URL without sync is skipped:

>>> _classify_import_action(
...     incoming_url="git+ssh://x",
...     existing_entry={"repo": "git+https://x"},
...     sync=False,
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>

Different URL with sync updates the URL (unless pinned):

>>> _classify_import_action(
...     incoming_url="git+ssh://x",
...     existing_entry={"repo": "git+https://x"},
...     sync=True,
... )
<ImportAction.UPDATE_URL: 'update_url'>

URL update is blocked by pin (only when URL differs):

>>> _classify_import_action(
...     incoming_url="git+ssh://x",
...     existing_entry={"repo": "git+https://x", "options": {"pin": True}},
...     sync=True,
... )
<ImportAction.SKIP_PINNED: 'skip_pinned'>

Non-dict, non-str entries fall back to empty URL (treated as different):

>>> _classify_import_action(
...     incoming_url="git+ssh://x", existing_entry=42, sync=False
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>
vcspull.cli.import_cmd._common._classify_prune_action(*, existing_entry, imported_from_tag)[source]

Classify whether an existing config entry should be pruned.

Return type:

ImportAction

Parameters:
  • existing_entry (dict | str | Any) – Current config entry for this repo name.

  • imported_from_tag (str) – The provenance tag to match against, e.g. "github:myorg".

Examples

String entries (no metadata) are never pruned:

>>> _classify_prune_action(
...     existing_entry="git+ssh://x", imported_from_tag="github:org"
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>

Entry with matching tag is pruned:

>>> _classify_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "metadata": {"imported_from": "github:org"},
...     },
...     imported_from_tag="github:org",
... )
<ImportAction.PRUNE: 'prune'>

Entry with different tag is not pruned:

>>> _classify_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "metadata": {"imported_from": "github:other"},
...     },
...     imported_from_tag="github:org",
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>

Pinned entry with matching tag is not pruned:

>>> _classify_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "options": {"pin": True},
...         "metadata": {"imported_from": "github:org"},
...     },
...     imported_from_tag="github:org",
... )
<ImportAction.SKIP_PINNED: 'skip_pinned'>

Entry without metadata is not pruned:

>>> _classify_prune_action(
...     existing_entry={"repo": "git+ssh://x"},
...     imported_from_tag="github:org",
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>
vcspull.cli.import_cmd._common._classify_untracked_prune_action(*, existing_entry)[source]

Classify whether an untracked config entry should be pruned.

“Untracked” means the entry has no import provenance from any source. This is the complement of _classify_prune_action(), which checks for a specific source tag.

Return type:

ImportAction

Parameters:

existing_entry (dict | str | Any) – Current config entry for this repo name.

Returns:

PRUNE for entries without provenance (untracked), SKIP_PINNED for pinned entries, SKIP_EXISTING for entries that have provenance from any source.

Return type:

ImportAction

Examples

String entries have no metadata — they are untracked:

>>> _classify_untracked_prune_action(existing_entry="git+ssh://x")
<ImportAction.PRUNE: 'prune'>

Dict entry without metadata is untracked:

>>> _classify_untracked_prune_action(
...     existing_entry={"repo": "git+ssh://x"},
... )
<ImportAction.PRUNE: 'prune'>

Dict entry with provenance from any source is tracked (kept):

>>> _classify_untracked_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "metadata": {"imported_from": "github:org"},
...     },
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>
>>> _classify_untracked_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "metadata": {"imported_from": "gitlab:other"},
...     },
... )
<ImportAction.SKIP_EXISTING: 'skip_existing'>

Pinned entry without provenance is protected:

>>> _classify_untracked_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "options": {"pin": True},
...     },
... )
<ImportAction.SKIP_PINNED: 'skip_pinned'>

Pinned entry with provenance is also protected:

>>> _classify_untracked_prune_action(
...     existing_entry={
...         "repo": "git+ssh://x",
...         "options": {"pin": True},
...         "metadata": {"imported_from": "github:org"},
...     },
... )
<ImportAction.SKIP_PINNED: 'skip_pinned'>
vcspull.cli.import_cmd._common._create_shared_parent()[source]

Create parent parser with workspace, filtering, and output flags.

Return type:

ArgumentParser

Returns:

Parent parser (add_help=False) carrying flags shared by all import service subcommands.

Return type:

argparse.ArgumentParser

vcspull.cli.import_cmd._common._create_token_parent()[source]

Create parent parser with the --token flag.

Return type:

ArgumentParser

Returns:

Parent parser carrying --token.

Return type:

argparse.ArgumentParser

vcspull.cli.import_cmd._common._create_mode_parent()[source]

Create parent parser with the -m/--mode flag.

Return type:

ArgumentParser

Returns:

Parent parser carrying -m/--mode.

Return type:

argparse.ArgumentParser

vcspull.cli.import_cmd._common._create_target_parent()[source]

Create parent parser with the required target positional.

Return type:

ArgumentParser

Returns:

Parent parser carrying the target positional argument.

Return type:

argparse.ArgumentParser

vcspull.cli.import_cmd._common._resolve_config_file(config_path_str)[source]

Resolve the config file path.

Return type:

Path

Parameters:

config_path_str (str | None) – Config file path from user, or None for default

Returns:

Resolved config file path

Return type:

pathlib.Path

vcspull.cli.import_cmd._common._run_import(importer, *, service_name, target, workspace, mode, language, topics, min_stars, include_archived, include_forks, limit, config_path_str, dry_run, yes, output_json, output_ndjson, color, use_https=False, flatten_groups=False, with_shared=False, skip_groups=None, sync=False, prune=False, prune_untracked=False, import_source=None)[source]

Run the import workflow for a single service.

This is the core fetch / preview / confirm / write logic shared by every per-service handler. The caller is responsible for constructing the importer instance; this function only orchestrates the import flow.

Return type:

int

Parameters:
  • importer (Importer) – Already-constructed importer instance (any object satisfying the Importer protocol)

  • service_name (str) – Canonical service name (e.g. "github", "gitlab", "codecommit")

  • target (str) – User, org, or search query

  • workspace (str) – Workspace root directory

  • mode (str) – Import mode (user, org, search)

  • language (str | None) – Language filter

  • topics (str | None) – Topics filter (comma-separated)

  • min_stars (int) – Minimum stars filter

  • include_archived (bool) – Include archived repositories

  • include_forks (bool) – Include forked repositories

  • limit (int) – Maximum repositories to fetch

  • config_path_str (str | None) – Config file path

  • dry_run (bool) – Preview without writing

  • yes (bool) – Skip confirmation

  • output_json (bool) – Output as JSON

  • output_ndjson (bool) – Output as NDJSON

  • color (str) – Color mode

  • use_https (bool) – Use HTTPS clone URLs instead of SSH (default: False, i.e., SSH)

  • flatten_groups (bool) – For GitLab org imports, flatten subgroup paths into base workspace

  • with_shared (bool) – Include projects shared into a group from other namespaces (GitLab only)

  • skip_groups (list[str] | None) – Exclude repos whose owner path contains any of these group name segments

  • sync (bool) – Sync existing config entries whose URL has changed (default: False). Entries with options.pin.import or options.allow_overwrite: false are exempt.

  • prune (bool) – Remove config entries tagged by a previous import that are no longer on the remote (default: False). Does not update URLs for existing entries; use sync for that.

  • import_source (str | None) – Provenance tag for imported repos, e.g. "github:myorg". When provided, repos are tagged with metadata.imported_from and stale tagged entries are pruned when sync is True.

  • prune_untracked (bool)

Returns:

0 on success, 1 on error

Return type:

int