Skip to content

pupca/svncli

Repository files navigation

Polarion SVN CLI (svncli)

CI Python 3.10+ License: MIT

CLI tool for syncing files with Polarion's SVN repository when direct SVN access is not available — such as on PolarionX or other hosted environments.

Supports macOS, Linux, and Windows.

Why?

Some Polarion deployments don't expose direct SVN access. You can browse and manage individual files through the web UI, but there's no built-in way to recursively upload folders, sync changes, or automate file management. svncli fills that gap.

Installation

pip install svncli

For interactive browser login (optional):

pip install "svncli[interactive]"
playwright install chromium

From source

git clone https://github.com/pupca/svncli.git
cd svncli
pip install -e ".[dev]"

Quick start

1. Authenticate

Pick one of these methods:

# Auto-extract cookies from Chrome (requires being logged in via browser)
svncli login https://your-server.example.com

# Interactive login — opens a browser window (works with SSO/MFA)
svncli login -i https://your-server.example.com

# Manual cookie — paste from browser DevTools
svncli login --cookie "JSESSIONID=ABC123; X-CSRF-Token=DEF456" https://your-server.example.com

All methods save the session to ~/.svncli/cookies.json — you only need to log in once per server. After that, all commands just work.

2. Browse

svncli ls https://your-server.example.com:MyProject/trunk
svncli ls -r https://your-server.example.com:MyProject/trunk   # recursive

3. Copy files

# Upload
svncli cp ./report.pdf https://your-server.example.com:MyProject/trunk/docs/report.pdf

# Download
svncli cp https://your-server.example.com:MyProject/trunk/docs/report.pdf ./report.pdf

# Copy a whole folder
svncli cp -r ./local-folder https://your-server.example.com:MyProject/trunk/folder

4. Sync

# Push local changes to remote
svncli sync ./src https://your-server.example.com:MyProject/trunk/src

# Pull remote changes to local
svncli sync https://your-server.example.com:MyProject/trunk/src ./src

# Preview what would change
svncli sync -n ./src https://your-server.example.com:MyProject/trunk/src

# Delete remote files not present locally
svncli sync --delete --force ./src https://your-server.example.com:MyProject/trunk/src

5. Cross-server operations

Copy or sync files directly between two Polarion servers — no manual download/upload needed:

# Copy a folder from one server to another
svncli cp -r https://server1.com:Project/src https://server2.com:Project/src

# Sync between servers (only transfers changed files)
svncli sync https://server1.com:Project/src https://server2.com:Project/src

# Preview cross-server sync
svncli sync -n https://server1.com:Project/src https://server2.com:Project/src

This works by downloading from the source server to a temp directory, then uploading to the destination. Each server authenticates independently — run svncli login for each one.

Python API

svncli can be used as a Python library:

from svncli import PolarionSVNClient

client = PolarionSVNClient(verify_ssl=False)

# Authenticate (saved to ~/.svncli/cookies.json)
client.login("https://server.com")                            # auto-extract from Chrome
client.login("https://server.com", browser="edge")            # specific browser
client.login("https://server.com", cookie="JSESSIONID=...")   # manual cookie
client.login("https://server.com", interactive=True)           # opens browser window

# List files
items = client.ls("https://server.com:Project/trunk")
for item in items:
    print(f"{item.name}  {item.size} bytes  r{item.revision}")

# Copy a single file
client.cp("./report.pdf", "https://server.com:Project/docs/report.pdf")   # upload
client.cp("https://server.com:Project/docs/report.pdf", "./report.pdf")   # download

# Copy a directory recursively
actions = client.cp_r("./src", "https://server.com:Project/trunk/src")

# Sync with options
actions = client.sync("./src", "https://server.com:Project/trunk/src",
    delete=True,                     # remove remote files not in local
    exclude=["*.log", ".git/*"],     # exclude patterns
    dry_run=True,                    # preview only, don't execute
)

# Inspect what happened
from svncli import SyncOp
uploaded = [a for a in actions if a.op == SyncOp.UPLOAD]
skipped = [a for a in actions if a.op == SyncOp.SKIP]

# Cross-server sync
client.login("https://other-server.com")
client.sync("https://server.com:Project/src", "https://other-server.com:Project/src")

# Create / delete
client.mkdir("https://server.com:Project/new-folder")   # returns True
client.rm("https://server.com:Project/old-file.txt")     # returns True

Path format

Remote paths include the server URL followed by : and the repository path:

https://server.example.com:RepoName/folder/path

Local paths start with /, ./, or ~/:

./local-folder
/absolute/path
~/home-relative

Commands

Command Description
svncli ls <remote> List remote directory (-r for recursive)
svncli cp <src> <dst> Copy files (local↔remote or remote↔remote with -r)
svncli sync <src> <dst> Sync files between local and remote
svncli rm <remote> Delete a remote file or folder
svncli mb <remote> Create a remote directory
svncli login <server> Authenticate and save session cookies
svncli logout [server] Remove saved session cookies

Global options

--no-verify-ssl    Disable SSL certificate verification
--timeout SECONDS  HTTP request timeout (default: 60)
-v, --verbose      Verbose output
--version          Show version

Sync options

-n, --dry-run      Show what would change without doing it
--delete           Remove destination files not present in source
--force            Skip confirmation prompt for deletions
--exclude PATTERN  Exclude files matching glob pattern (repeatable)

Authentication

Each server has its own saved session. svncli resolves cookies per server in this order:

  1. --cookie flag
  2. Saved cookies from ~/.svncli/cookies.json (from a previous svncli login)
  3. Auto-extraction from browser cookie store (Chrome, Firefox, Edge, Safari, etc.)

Automatic cookie extraction

By default, svncli reads cookies from your Chrome cookie store. This requires that you've already logged into Polarion in Chrome. To use a different browser:

svncli login --browser firefox https://your-server.com
svncli login --browser edge https://your-server.com    # common on Windows

Supported browsers: chrome, firefox, edge, brave, opera, chromium, vivaldi, safari, librewolf, arc.

Interactive login

For environments where automatic cookie extraction doesn't work (e.g., remote servers, locked-down browsers):

svncli login -i https://your-server.com

This opens a Chromium window. Log in normally (including SSO/MFA), then close the window. Cookies are saved automatically.

Requires the interactive extra: pip install "svncli[interactive]" and playwright install chromium.

Manual cookie extraction

If neither automatic nor interactive login works, you can extract cookies manually from your browser:

  1. Open your Polarion server in Chrome/Firefox
  2. Log in normally
  3. Open Developer Tools (F12 or Cmd+Option+I)
  4. Go to the Network tab
  5. Navigate to any page on the Polarion server (e.g. refresh the page)
  6. Click on any request to the server
  7. In the Headers section, find the Cookie request header
  8. Copy the entire cookie value string (e.g. JSESSIONID=ABC123; X-CSRF-Token=DEF456; ...)

Then save it with svncli login:

svncli login --cookie "JSESSIONID=ABC123; X-CSRF-Token=DEF456" https://your-server.com

After this, all commands to that server will use the saved session automatically.

Tip: In Chrome, you can also right-click a request in the Network tab → Copy → Copy as cURL, then extract the cookie value from the -b or --cookie flag in the copied command.

How sync works

svncli tracks sync state in manifest files stored in ~/.svncli/manifests/. On each sync:

  1. First sync — compares by file size; uploads/downloads differences
  2. Subsequent syncs — uses SVN revision numbers + local file SHA-256 hashes:
    • Local file unchanged + remote revision unchanged → skip (fast, no hashing needed)
    • Local file changed → upload
    • Remote revision changed, local unchanged → skip (remote is newer)
    • New local file → upload
    • New remote file → download (in download direction)

The manifest enables efficient incremental syncs without downloading remote files to compare.

Corporate environments

For servers with self-signed or corporate CA certificates:

svncli --no-verify-ssl ls MyProject

Development

git clone https://github.com/pupca/svncli.git
cd svncli
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run unit tests (no server needed)
pytest tests/test_sync.py tests/test_client.py tests/test_models.py tests/test_util.py -v

# Run full suite including E2E (requires access to two Polarion servers)
export SVNCLI_SERVER_A="https://your-server.example.com"
export SVNCLI_ROOT_A="ProjectRoot"
export SVNCLI_SERVER_B="https://your-other-server.example.com"
export SVNCLI_ROOT_B="OtherProjectRoot"
pytest tests/ -v --cov=svncli --cov-report=html

# Run E2E with one server only (cross-server tests will be skipped)
export SVNCLI_SERVER_A="https://your-server.example.com"
export SVNCLI_ROOT_A="ProjectRoot"
pytest tests/ -v

License

MIT

About

CLI tool for syncing files with Polarion's SVN repository

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages