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.
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.
pip install svncliFor interactive browser login (optional):
pip install "svncli[interactive]"
playwright install chromiumgit clone https://github.com/pupca/svncli.git
cd svncli
pip install -e ".[dev]"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.comAll methods save the session to ~/.svncli/cookies.json — you only need to log in once per server. After that, all commands just work.
svncli ls https://your-server.example.com:MyProject/trunk
svncli ls -r https://your-server.example.com:MyProject/trunk # recursive# 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# 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/srcCopy 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/srcThis 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.
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 TrueRemote 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
| 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 |
--no-verify-ssl Disable SSL certificate verification
--timeout SECONDS HTTP request timeout (default: 60)
-v, --verbose Verbose output
--version Show version
-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)
Each server has its own saved session. svncli resolves cookies per server in this order:
--cookieflag- Saved cookies from
~/.svncli/cookies.json(from a previoussvncli login) - Auto-extraction from browser cookie store (Chrome, Firefox, Edge, Safari, etc.)
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 WindowsSupported browsers: chrome, firefox, edge, brave, opera, chromium, vivaldi, safari, librewolf, arc.
For environments where automatic cookie extraction doesn't work (e.g., remote servers, locked-down browsers):
svncli login -i https://your-server.comThis 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.
If neither automatic nor interactive login works, you can extract cookies manually from your browser:
- Open your Polarion server in Chrome/Firefox
- Log in normally
- Open Developer Tools (F12 or Cmd+Option+I)
- Go to the Network tab
- Navigate to any page on the Polarion server (e.g. refresh the page)
- Click on any request to the server
- In the Headers section, find the
Cookierequest header - 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.comAfter 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
-bor--cookieflag in the copied command.
svncli tracks sync state in manifest files stored in ~/.svncli/manifests/. On each sync:
- First sync — compares by file size; uploads/downloads differences
- 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.
For servers with self-signed or corporate CA certificates:
svncli --no-verify-ssl ls MyProjectgit 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