Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
ff57dc6
fix: prompt for password when username given but no password provided…
jacalata Jun 29, 2026
a9836b0
fix: --filename extension takes precedence over URL extension (#256)
jacalata Jun 30, 2026
652f0a3
fix: rotate log file using RotatingFileHandler (#211)
jacalata Jun 30, 2026
304b9eb
fix: default to https when no protocol given in server URL (#331)
jacalata Jun 30, 2026
ae9f929
typing: from static methods to class methods
jacalata Aug 14, 2025
ad78386
type fixes: session.py
jacalata Aug 14, 2025
c8901ae
typing: parser tests
jacalata Aug 14, 2025
daee090
Update test_session.py
jacalata Aug 14, 2025
4cb5e68
Update pyproject.toml
jacalata Aug 14, 2025
3c8f7c5
type fixes
jacalata Aug 14, 2025
366c39a
fix type errors in /tests
jacalata Sep 24, 2025
0600fab
Refactor version retrieval to use importlib.metadata
jacalata Feb 13, 2026
5d7247a
Update tabcmd/commands/datasources_and_workbooks/export_command.py
jacalata Apr 13, 2026
ac057f3
Update tabcmd/commands/user/add_users_command.py
jacalata Apr 13, 2026
b202848
fix typings
jacalata Apr 21, 2026
152cb11
fix: set root logger level explicitly; guard against duplicate handlers
jacalata Jun 30, 2026
c7b08ae
test: add error-path test for get_file_type_from_filename
jacalata Jun 30, 2026
8ab8048
fix: don't sign out existing session when only --username is given
jacalata Jun 30, 2026
316c23b
style: black formatting
jacalata Jun 30, 2026
52ff6b2
style: black formatting
jacalata Jun 30, 2026
7e24c46
style: black formatting
jacalata Jun 30, 2026
7b3d329
ci: add workflow to check i18n string keys on PRs
jacalata Jun 30, 2026
2b30522
ci: pin action versions to v6, note regex limitation
jacalata Jun 30, 2026
f0de017
fix: black formatting and mypy errors for check_untyped_defs
jacalata Jul 1, 2026
f278a62
ci: add workflow to check i18n string keys on PRs (#409)
jacalata Jul 1, 2026
001c045
fix: cast _ProjectItem stubs to TSC.ProjectItem in tests
jacalata Jul 1, 2026
6d0b0ac
fix: add rotating log file handler (#211) (#404)
jacalata Jul 1, 2026
096819c
fix: prompt for password when --username given without credentials (#…
jacalata Jul 1, 2026
02e9aba
fix: use explicit extension check in get_file_type_from_filename (#25…
jacalata Jul 1, 2026
d50c35f
fix: default to https when no scheme specified in server URL (#331) (…
jacalata Jul 1, 2026
1ec12f9
mypy: enable checking untyped code (#367)
jacalata Jul 1, 2026
e447579
chore: upgrade tableauserverclient to 0.41, add SVG format tests (#1772)
jacalata Jun 29, 2026
00c09e9
fix: set user_id in test so _validate_existing_signin passes
jacalata Jul 1, 2026
9686e99
chore: upgrade tableauserverclient to 0.41 (#408)
jacalata Jul 1, 2026
ec299d4
fix: show correct version in PyInstaller exe (W-22831646) (#410)
jacalata Jul 2, 2026
7248112
ci: automate release pipeline (draft release, PyPI trigger, e2e skip …
jacalata Jul 7, 2026
1a13fcf
backport: merge main back to development (#421)
jacalata Jul 8, 2026
3cdbba0
Move hardcoded strings to localized files (#368)
jacalata Jul 8, 2026
3f2fdbc
ci: bump actions/checkout to v7 in check-strings workflow (#426)
bcantoni Jul 15, 2026
f273f37
fix: point dependabot at development branch (#420)
jacalata Jul 20, 2026
708f3a7
fix: make python -m tabcmd work reliably (#375) (#411)
jacalata Jul 20, 2026
e0e1bb0
fix: route INFO logs to stdout so PowerShell doesn't raise NativeComm…
jacalata Jul 20, 2026
5d00587
fix: correct :size=W,H argument order in URL params (#349) (#414)
jacalata Jul 20, 2026
59f3864
fix: explicitly dispatch package.yml after tag push (#419)
jacalata Jul 20, 2026
97123eb
fix: preserve CSV role/auth in createusers, fix case-sensitive valida…
jacalata Jul 20, 2026
9bbc50c
chore: redirect e2e output files to test-output/, tighten .gitignore …
jacalata Jul 20, 2026
c0f6a66
ci: trigger PyPI smoke tests after publish workflow completes (#424)
jacalata Jul 20, 2026
742e507
fix: actionable error when --password-file or --token-file is missing…
jacalata Jul 20, 2026
6626930
ci: bump actions/setup-python to v7 (#428)
bcantoni Jul 20, 2026
8269bcf
security: add environment gate to production PyPI publish job (#439)
jacalata Jul 23, 2026
dfc2877
fix: fall back to English per-key when locale is missing a msgid
jacalata Jul 27, 2026
43e7c5e
fix: move setuptools_scm import out of top-level dodo.py
jacalata Jul 28, 2026
1329628
fix: unblock check-mo-freshness workflow
jacalata Jul 28, 2026
d94f91f
chore: regenerate .mo bundles from committed .properties sources
jacalata Jul 28, 2026
46b7410
ci: drop .po from check-mo-freshness (globally gitignored, dead check)
jacalata Jul 29, 2026
f399979
Backport #458 to development: fix publish crash with embedded db cred…
jacalata Sep 10, 2026
bf3a304
Regenerate .mo catalogs after #458 backport (#469)
jacalata Sep 16, 2026
61375b0
Require --db-server when publishing with embedded credentials
jacalata Sep 18, 2026
f6edc3b
i18n: add English fallback for publish.errors.db_server_required in a…
jacalata Sep 19, 2026
d77d648
deps: pin black and mypy to match TSC (black==26.5.1, mypy==2.3.0) (#…
jacalata Oct 14, 2026
6d33775
Fix #433: accept Classic `delete --workbook Name` syntax (#451)
jacalata Oct 14, 2026
cdef3c3
deps: pin urllib3>=2.6.0,<3 to match tableauserverclient (#453)
jacalata Oct 14, 2026
fae42df
Fix #437: add 10 editsite flags for tabcmd Classic parity (#452)
jacalata Oct 14, 2026
2e61b9e
Validate publish directory workbooks up front
Copilot Oct 14, 2026
86d4bd4
Format online_tests.py with black
Copilot Oct 14, 2026
6aca355
Require --db-server when publishing with embedded credentials (#473)
jacalata Oct 16, 2026
d0c7deb
Merge origin/development into jac/localization-fallback
jacalata Oct 16, 2026
78d161c
Merge main into development
jacalata Oct 26, 2026
f70958f
Require certifi>=2026.10.19 to pick up the eMudhra intermediate CA di…
jacalata Oct 27, 2026
687420b
Stop committing generated .mo files; build them with doit localize (#…
jacalata Oct 27, 2026
9cdbd2b
pkg: upgrade PyInstaller 5.13.1 -> 6.22.3, smoke-test packaged binari…
jacalata Oct 27, 2026
2087456
Bump tableauserverclient pin to 0.42 (#481)
jacalata Oct 27, 2026
efab7e6
fix: accept yes/no on --encrypt for Classic parity (#450)
jacalata Oct 27, 2026
9698768
Merge development into jac/merge-main-into-development
jacalata Nov 2, 2026
ef96c08
Merge main into development (#490)
jacalata Nov 2, 2026
33983d5
Fix #35: --nowait / --silent-progress on createsiteusers (#455)
jacalata Nov 2, 2026
68d84b1
i18n: escape double quotes in prop2po output so msgfmt keeps them (#486)
jacalata Nov 2, 2026
f49bbfb
fix: correct and standardize tabcmd 2 output messages to match tabcmd…
jacalata Nov 3, 2026
8718fa6
fix: preserve '=' inside --filter values (#442)
jacalata Nov 3, 2026
34ab4cb
feat: allow repeated --filter flags for exports (#443)
jacalata Nov 3, 2026
8165c30
Bump github/codeql-action from 4.39.1 to 4.39.3 (#495)
dependabot[bot] Nov 10, 2026
315dade
fix: Package-and-Upload workflow attaches binaries to UI-created rele…
jacalata Nov 10, 2026
693732f
Fix #434: map "Local" auth_setting to ServerDefault (#446)
jacalata Nov 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
# Raise pull requests for version updates to pip against the `develop` branch
target-branch: "develop"
- package-ecosystem: "pip"
directory: "/"
target-branch: "development"
schedule:
interval: "weekly"

- package-ecosystem: "github-actions"
directory: "/"
target-branch: "development"
schedule:
interval: "weekly"
4 changes: 3 additions & 1 deletion .github/workflows/check-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v7

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -32,6 +32,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build
pip install .[test]
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/check-strings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: '3.12'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4.39.1
uses: github/codeql-action/init@v4.39.3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -53,6 +53,6 @@ jobs:
# queries: security-extended,security-and-quality

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4.39.1
uses: github/codeql-action/analyze@v4.39.3
with:
category: "/language:${{matrix.language}}"
4 changes: 3 additions & 1 deletion .github/workflows/generate-metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: '3.12'

Expand All @@ -25,6 +25,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build
pip install .[test]
Expand Down
152 changes: 141 additions & 11 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,33 @@ name: Package-and-Upload
# https://anshumanfauzdar.medium.com/using-github-actions-to-bundle-python-application-into-a-single-package-and-automatic-release-834bd42e0670

on:
push:
tags:
- '*'
release:
types: [published]
# Manual repair path for a published release. The release tag is resolved from
# the release event, then inputs.release_tag, then github.ref_name when
# dispatched at a tag ref. Don't dispatch for a draft release: the upload step
# finds the release by tag, drafts can't be found that way, and the action then
# creates a second release for the same tag.
# There is deliberately no `push: tags` trigger: release-on-merge.yml pushes a
# tag on every merge to main, and a build should only run once a release is published.
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag to attach binaries to. Required when dispatching from a branch rather than a tag ref.'
required: false
type: string

concurrency:
group: package-${{ github.event.release.tag_name || inputs.release_tag || github.ref_name }}
cancel-in-progress: false

jobs:

buildexe:
name: Build executables and upload them to the existing release
name: Build executables
runs-on: ${{ matrix.os }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -63,7 +80,7 @@ jobs:
steps:
- uses: actions/checkout@v7

- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: 3.12

Expand All @@ -74,6 +91,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build
pip install .[package]
Expand All @@ -89,6 +108,32 @@ jobs:
if: matrix.TARGET == 'macos'
run: ./dist/${{ matrix.TARGET }}/${{ matrix.OUT_FILE_NAME }}/Contents/MacOS/${{ matrix.APP_BINARY_FILE_NAME }}

# -v checks the bundled version file. The login probe checks that requests/urllib3/certifi are bundled:
# a closed port must fail with a connection error, not an import error.
- name: Smoke test package for ${{matrix.TARGET}}
shell: bash
env:
TARGET: ${{ matrix.TARGET }}
OUT_FILE_NAME: ${{ matrix.OUT_FILE_NAME }}
APP_BINARY_FILE_NAME: ${{ matrix.APP_BINARY_FILE_NAME }}
run: |
case "$TARGET" in
macos) BIN="./dist/macos/$OUT_FILE_NAME/Contents/MacOS/$APP_BINARY_FILE_NAME" ;;
*) BIN="./dist/$TARGET/$OUT_FILE_NAME" ;;
esac
"$BIN" -v
if out=$("$BIN" login -s https://localhost:1 -u a -p b --no-certcheck 2>&1); then
echo "$out"
echo "login to a closed port unexpectedly succeeded"
exit 1
fi
echo "$out"
if echo "$out" | grep -Eq "ImportError|ModuleNotFoundError|Unhandled exception"; then
echo "packaged binary failed with an import error"
exit 1
fi
echo "$out" | grep -q "Max retries exceeded" || { echo "expected a connection error from requests"; exit 1; }

- name: Tar app bundle for Mac
if: matrix.TARGET == 'macos'
run: |
Expand All @@ -97,18 +142,103 @@ jobs:
tar -cvf ${{ matrix.UPLOAD_FILE_NAME }} ${{ matrix.OUT_FILE_NAME }}


# UPLOAD_FILE_NAME distinguishes the two macOS artifacts (x86 vs arm64);
# the shared artifact name `tabcmd-macos` would otherwise collide and each
# upload would clobber the other in the artifact store.
- name: Upload build artifact for ${{ matrix.TARGET }}
uses: actions/upload-artifact@v7
with:
name: tabcmd-${{ matrix.TARGET }}
name: ${{ matrix.UPLOAD_FILE_NAME }}
path: ./dist/${{ matrix.TARGET }}/${{ matrix.UPLOAD_FILE_NAME }}

- name: Upload binaries to release for ${{ matrix.TARGET }}
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
# Attach the built binaries to the target GitHub release. Split into its own
# job so we can gate it behind the `release` environment: a required-reviewer
# protection on that environment means publishing a release triggers a build,
# but only an approved reviewer can actually attach binaries to that release.
# The workflow pauses at this job until a reviewer clicks Approve.
#
# `needs: buildexe` waits for ALL matrix legs to succeed. If any leg fails
# this job is skipped (default behavior with no `if: always()`), so a partial
# release upload where e.g. macOS is missing is never possible.
upload_to_release:
name: Attach build artifacts to release
needs: buildexe
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
steps:
# download-artifact versions independently of upload-artifact; v7 reads the
# zipped artifacts that upload-artifact@v7 produces by default
- name: Download all build artifacts
uses: actions/download-artifact@v7
with:
path: artifacts/

# Resolve the release tag, in order of preference: the release event's
# tag_name, the workflow_dispatch release_tag input, then github.ref_name
# when the run was dispatched from a tag ref. A dispatch from a branch
# with no release_tag fails fast rather than treating the branch name as
# a tag, and an empty result never reaches the upload steps.
- name: Resolve release tag
id: tag
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
INPUT_TAG: ${{ inputs.release_tag }}
REF_NAME: ${{ github.ref_name }}
REF_TYPE: ${{ github.ref_type }}
EVENT_NAME: ${{ github.event_name }}
run: |
TAG="$RELEASE_TAG"
if [ -z "$TAG" ]; then
TAG="$INPUT_TAG"
fi
if [ -z "$TAG" ] && [ "$REF_TYPE" = "tag" ]; then
TAG="$REF_NAME"
fi
if [ -z "$TAG" ] && [ "$EVENT_NAME" = "workflow_dispatch" ]; then
echo "::error::workflow_dispatch from $REF_TYPE '$REF_NAME' has no release_tag input; pass -f release_tag=<tag> or dispatch with --ref <tag>"
exit 1
fi
if [ -z "$TAG" ]; then
echo "::error::No release tag resolvable (event=$EVENT_NAME, release.tag_name empty, release_tag input empty, ref_type=$REF_TYPE)"
exit 1
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Resolved release tag: $TAG"

- name: Upload tabcmd.exe (Windows) to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: tabcmd.exe
file: artifacts/tabcmd.exe/tabcmd.exe
tag: ${{ steps.tag.outputs.tag }}
overwrite: true

- name: Upload tabcmd (Ubuntu) to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: tabcmd
file: artifacts/tabcmd/tabcmd
tag: ${{ steps.tag.outputs.tag }}
overwrite: true

- name: Upload tabcmd-x86.app.tar (macOS x86) to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: tabcmd-x86.app.tar
file: artifacts/tabcmd-x86.app.tar/tabcmd-x86.app.tar
tag: ${{ steps.tag.outputs.tag }}
overwrite: true

- name: Upload tabcmd_arm64.app.tar (macOS ARM64) to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
asset_name: ${{ matrix.UPLOAD_FILE_NAME }}
file: ./dist/${{ matrix.TARGET }}/${{ matrix.UPLOAD_FILE_NAME }}
tag: ${{ github.ref_name }}
asset_name: tabcmd_arm64.app.tar
file: artifacts/tabcmd_arm64.app.tar/tabcmd_arm64.app.tar
tag: ${{ steps.tag.outputs.tag }}
overwrite: true
5 changes: 4 additions & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ jobs:
build-n-publish:
name: Build dist files for PyPi
runs-on: ubuntu-latest
environment: pypi
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: 3.12
- name: Build dist files
Expand All @@ -28,6 +29,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build

Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@

name: Pypi smoke tests

# maybe we want this triggered after the publish-pypi workflow?
on:
workflow_dispatch:
schedule:
- cron: 0 11 * * * # Every day at 11AM UTC (7AM EST)
workflow_run:
workflows: ["Publish to PyPi"]
types: [completed]

permissions:
contents: read

jobs:
build:
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
strategy:
fail-fast: false
matrix:
Expand All @@ -24,7 +27,7 @@ jobs:

steps:
- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: pip install Tabcmd
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-on-merge.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Draft release on merge to main

# Triggers when a PR is merged into main (push to main covers all merge strategies).
# Creates a draft GitHub release with auto-generated notes and pushes the version tag.
# The tag push triggers package.yml to build and attach binaries.
# When you publish the draft release, publish-pypi.yml uploads to PyPI automatically.
# Pushes the next patch version tag and creates a draft GitHub release with auto-generated notes.
# Nothing is built here. When you publish the draft release, package.yml builds and attaches
# the binaries and publish-pypi.yml uploads to PyPI.

on:
push:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/run-e2-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
- uses: actions/checkout@v7

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -91,6 +91,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build
pip install .[test]
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- uses: actions/checkout@v7

- name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -34,6 +34,8 @@ jobs:
python -m pip install --upgrade build
pip install .[versioning]
doit version
pip install .[localize]
doit localize
pip install .
python -m build
pip install .[test]
Expand Down
Loading
Loading