From 46f65d5d6d6bf6b705c13b9cd5152a50f364dea1 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Wed, 21 Feb 2024 21:46:46 -0800 Subject: [PATCH 1/8] skip .po and .properties files --- .gitignore | 3 ++- tabcmd-windows.spec | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 90521b3b..adb4842c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,5 @@ workon test.junit.xml # exceptions -!tests/assets/detailed_users.csv \ No newline at end of file +!tests/assets/detailed_users.csv +est diff --git a/tabcmd-windows.spec b/tabcmd-windows.spec index 25acf08c..e02b0bd3 100644 --- a/tabcmd-windows.spec +++ b/tabcmd-windows.spec @@ -2,7 +2,11 @@ from PyInstaller.utils.hooks import collect_data_files datas = [] -datas += collect_data_files('tabcmd.locales') +datas += collect_data_files( + 'tabcmd.locales', + include_py_files=False, + includes=["./**/tabcmd.mo"]) + print(datas) block_cipher = None @@ -22,6 +26,7 @@ a = Analysis( cipher=block_cipher, noarchive=False, ) + pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( From 597ba982fbb9e8e72902f350a067f0825f1eba25 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Thu, 22 Feb 2024 13:09:55 -0800 Subject: [PATCH 2/8] pin pyinstaller to 5.13 --- pyproject.toml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c9aa9d18..3123eb14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = ["tabcmd"] tabcmd = ["tabcmd.locales/**/*.mo"] [tool.black] line-length = 120 -target-version = ['py37', 'py38', 'py39', 'py310', 'py311'] +target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] extend-exclude = '^/bin/*' [tool.mypy] disable_error_code = [ @@ -29,12 +29,11 @@ dynamic = ["version"] description="A command line client for working with Tableau Server." authors = [{name="Tableau", email="github@tableau.com"}] license = {file = "LICENSE"} -readme = "README.md" -requires-python = ">=3.7" # https://devguide.python.org/versions/ +readme = "res/README.md" +requires-python = ">=3.8" # https://devguide.python.org/versions/ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -68,7 +67,7 @@ test = [ "pytest-runner", "requests-mock>=1.0,<2.0"] localize = ["doit", "ftfy"] -package = ["pyinstaller>=5.1", "doit"] +package = ["pyinstaller==5.13", "doit"] [project.urls] repository = "https://github.com/tableau/tabcmd" [project.scripts] From 0d987ed605fa507397d68e4e94c7b587ff9d9136 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Thu, 22 Feb 2024 13:10:17 -0800 Subject: [PATCH 3/8] update docs to separate user/dev docs --- README.md | 73 ++++++------------------- contributing.md | 139 +++++++++++++++++++++++++++++++++--------------- res/README.md | 5 ++ 3 files changed, 115 insertions(+), 102 deletions(-) create mode 100644 res/README.md diff --git a/README.md b/README.md index 810f817c..3390dffa 100644 --- a/README.md +++ b/README.md @@ -5,76 +5,33 @@ [![Python tests](https://github.com/tableau/tabcmd/actions/workflows/run-tests.yml/badge.svg)](https://github.com/tableau/tabcmd/actions/workflows/run-tests.yml) [![Pypi smoke tests](https://github.com/tableau/tabcmd/actions/workflows/python-app.yml/badge.svg)](https://github.com/tableau/tabcmd/actions/workflows/python-app.yml) -An open source, cross platform command-line utility which you can use to automate site administration tasks on your Tableau Server site. +An open source, cross platform command-line utility which you can use to automate activity on Tableau Cloud or Tableau Server. -## Download exe (or rpm/deb) -* To download the latest release as an executable see https://github.com/tableau/tabcmd/releases +## Download the app +* To download the latest release ready to use see https://github.com/tableau/tabcmd/releases * There is no need to install: open a command line in the same folder as the exe and run -```shell -tabcmd [command_name] [--flags] -``` -e.g -* `tabcmd login --username [username] --password [password] --server [server_name] --site [site_name]` -* `tabcmd createproject --name [project_name]` -* `tabcmd help` -###or -## Install on the command line -(Note: this requires Python 3.7+. Generally we will actively support versions of Python that are still in security support). +> [!TIP] +> You can also download the current latest release directly on the command line: +> ```shell +> pip install tabcmd +> ``` -```shell -pip install tabcmd -``` - -Or install the current work-in-progress version from Git\ -*Only do this if you know you want the development version, no guarantee that we won't break APIs during development* -```shell -pip install git+https://github.com/tableau/tabcmd.git@development -``` - -If you go this route, but want to switch back to the non-development version, you need to run the following command before installing the stable version: +### Run tabcmd +These commands can be run from the folder that you downloaded tabcmd. If you add this folder to your PATH, they can be run from any folder. ```shell -pip uninstall tabcmd +tabcmd [command_name] [--flags] ``` +e.g +* `tabcmd login --username [username] --password [password] --server [server_name] --site [site_name]` +* `tabcmd createproject --name [project_name]` +* `tabcmd help` -### Run tabcmd - -To run tabcmd from your local copy, from a console window in the same directory as the file tabcmd.py: - -1. Clone the repo -2. Run `pip install .` - -- build -> python setup.py build - -- run tests -> pytest -- run tests against a live server -> python -m tabcmd login {your server info here} -> pytest -q tests\e2e\online_tests.py -r pfE -- with coverage calculation (https://coverage.readthedocs.io/en/6.3.2) -> coverage run -m pytest && coverage report -m - -- autoformat your code with black (https://pypi.org/project/black/) -> black --line-length 120 tabcmd tests [--check] - -- type check with mypy -> mypy tabcmd tests - -- packaging is done with pyinstaller. You can only build an executable for the platform you build on. -- To package a release, we first bump the version with `doit version` and build as 2.x.0 before packaging -> pyinstaller tabcmd\tabcmd.py --clean --noconfirm - -produces dist/tabcmd.exe -To run tabcmd during development, from a console window in the same directory as the file tabcmd.py: - -> dist/tabcmd/tabcmd.exe --help -* `python -m tabcmd.py [command_name] [--flags]` * Examples: * `tabcmd.py login --username [username] --password [password] --server [server_name] --site [site_name]` * `tabcmd.py createproject --name [project_name]` diff --git a/contributing.md b/contributing.md index 417cd22c..9a083351 100644 --- a/contributing.md +++ b/contributing.md @@ -13,40 +13,39 @@ * [Packaging](#packaging) -These instructions are for people who want to download the code and edit it directly. If you are interested in tabcmd but not the code, see [here](Readme.md). -####To work with tabcmd, you need to have **Python 3.7+** installed. +## Install Tabcmd +> [!NOTE] +> These instructions are for people who want to write code in or using tabcmd. If > you are interested in tabcmd but not the code, see [here](Readme.md). +####To work with tabcmd, you need to have **Python 3.8+** installed. To propose changes, you must have a Github account. -## Contributing +### To make changes to tabcmd code -Code contributions and improvements by the community are welcomed! +Fork the tabcmd repo and create a branch off the **development** branch, not the default branch (named main) [(See Github Docs)](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) -See the LICENSE file for current open-source licensing and use information. -Before we can accept pull requests from contributors, we require a signed [Contributor License Agreement (CLA)](http://tableau.github.io/contributing.html). - +### As a library that you can use in another application: -## Development +To install the current release: +```shell +pip install tabcmd +``` -### Dev scripts -To work on the tabcmd code, use these scripts. -_(note that running mypy and black is required for code being submitted to the repo)_ +Or install the current work-in-progress version from Git\ +*Only do this if you know you want the development version, no guarantee that we won't break APIs during development* -- build -> pip install build -> python -m build -- run tests -> pytest -- run tests against a live server -> python -m tabcmd login {your server info here} -> pytest -q tests\e2e\online_tests.py -r pfE -- autoformat your code with black (https://pypi.org/project/black/) -> black . -- check types -> mypy tabcmd tests -- do test coverage calculation (https://coverage.readthedocs.io/en/6.3.2) -> bin/coverage.sh +```shell +pip install git+https://github.com/tableau/tabcmd.git@development +``` +> [!TIP] +> If you want to switch back to the non-development version, you need to run the following command before installing the stable version: +> +>```shell +>pip uninstall tabcmd +>``` + +## Software design ### Why Python? @@ -65,7 +64,7 @@ The core design principles for this app are 3. the 'commands' module contains the logic required to translate the tabcmd CLI interface into calls to tsc. This is completely dissociated from the parsers, and could theoretically be called from a completely different interface. 4. The 'execution' module is the core logic. TabcmdController gets an argparse parser, then attaches all the defined parsers to it and associates one command with each parser. -### To add a new command +#### To add a new command 0. choose the single word that will be used as your command. Let's call this one `dream` 1. add parsers/dream_parser.py, and use methods from parent_parser to define the arguments 2. add commands/dreams/dream_command.py. It must have a method run_command.py(args) and the args object must contain all information needed from the user. @@ -73,35 +72,87 @@ The core design principles for this app are 4. in map_of_commands.py, add an entry for your new command, like "dream": ("dream", DreamCommand, "Think about picnics")," 5. add tests! +## Contributing + +Code contributions and improvements by the community are welcomed! + +See the LICENSE file for current open-source licensing and use information. + +Before we can accept pull requests from contributors, we require a signed [Contributor License Agreement (CLA)](http://tableau.github.io/contributing.html). + + +## Developing +To work on the tabcmd code, use these scripts. +_(note that running mypy and black with no errors is required before code will be merged into the repo)_ + +- build and run +> pip install build +> python setup.py build +> python -m tabcmd.py [command_name] [--flags] + +- run tests +> pytest + +- run tests against a live server +> python -m tabcmd login {your server info here} +> pytest -q tests\e2e\online_tests.py -r pfE + +- autoformat your code with black (https://pypi.org/project/black/) +> black . + +- check types +> mypy tabcmd tests + +- do test coverage calculation (https://coverage.readthedocs.io/en/6.3.2) +> bin/coverage.sh + + +### Packaging +- build an executable package with [pyinstaller](https://github.com/pyinstaller/pyinstaller). +> [!NOTE] +> You can only build an executable for the platform you are running pyinstaller on. The spec for each platform is stored in tabcmd-*platform*.spec and the exact build commands for each platform can be checked in [our packaging script](.github/workflows//package.yml). + +e.g for Windows +> pyinstaller tabcmd-windows.spec --clean --noconfirm --distpath ./dist/windows + +produces dist/tabcmd.exe +To run the newly created executable, from a console window in the same directory as the file tabcmd.py: + +> dist/tabcmd/tabcmd.exe --help + + + ### Localization Strings are stored in /tabcmd/locales/[language]/*.properties by id and referred to in code as > string = _("string.id") -For runtime execution these files must be converted to .mo via .po +For runtime execution these files must be converted from .properties -> .po -> .mo files. These .mo files will be bundled in the the package by pyinstaller. The entire conversion action is done by a .doit script: > doit mo +### Versioning -## Releases -To trigger publishing to pypi tag a commit on main with 'pypi'. -When pypi-release is done, begin the app smoke test action. +Versioning is done with setuptools_scm and based on git tags. The version number will be x.y.dev0.dirty except for commits with a new version tag. + This is pulled from the git state, and to get a clean version like "v2.1.0", you must be on a commit with the tag "v2.1.0" (Creating a Github release also creates a tag on the selected branch.) +The version reflected in the executable (tabcmd -v) is stored in a metadata file created by a .doit script: +> doit version -### Versioning -Versioning is done with setuptools_scm and based on git tags. -It will be a x.y.dev0 pre-release version except for commits with a new version tag. e.g -> git tag v2.0.4 && git push --tags +## Release process -A new tag is created with the name of each release on github. +1. Create a new Github project release manually: https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases + - include a useful list of changes since the last release + - include a clear list of remaining non-server-admin functional gaps -### Packaging -Before packaging, we produce a current metadata file to include in the bundle -> doit version +1. This will trigger our github packaging action to run on 3 different OSs. + - write an updated metadata file with the correct version number. + - build the python wheel + - run pyinstaller to create executables + - save the executable as an artifact on that job. -Packaging is done with pyinstaller, which will build an executable for the platform it runs on. -A github action runs on Mac, Windows and Linux to generate each executable. +1. Find the artifacts created by this job and manually copy them to the new release. (Beware! of what the file type is, github does somethign weird with zipping it if you download with curl etc. TODO: automate workflow with a github action) + +1. To trigger publishing to pypi run the manual workflow on main with 'pypi'. (TODO: automate trigger) + +1. When the packages are available on pypi, you can run the 'Pypi smoke test action'. This action will also be run every 24 hours to validate doing pip install. (TODO: automate the after-release trigger) -> pyinstaller tabcmd-windows.spec .... - -Packaging produces executables in the dist folder. To run: -> dist/tabcmd/tabcmd.exe --help diff --git a/res/README.md b/res/README.md new file mode 100644 index 00000000..0cb368a1 --- /dev/null +++ b/res/README.md @@ -0,0 +1,5 @@ + +This program is an executable command-line utility which you can use to automate activity on Tableau Cloud or Tableau Server. + +For instructions on how to use it, launch the app on a command line with 'tabcmd -h'. +For updates, bug reports and help, visit https://tableau.github.io/tabcmd/ From bc3b62a17759fe4def3cf3959375722da8adb2d4 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 23 Feb 2024 21:46:35 -0800 Subject: [PATCH 4/8] Update pyproject.toml have to pass the existing gate for 3.7 in order to delete it --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3123eb14..b60cbada 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = ["tabcmd"] tabcmd = ["tabcmd.locales/**/*.mo"] [tool.black] line-length = 120 -target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] +target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312'] extend-exclude = '^/bin/*' [tool.mypy] disable_error_code = [ From 0a2c6c9d3b93b3a1d18c51355665d2e08d76494f Mon Sep 17 00:00:00 2001 From: Jac Date: Wed, 28 Feb 2024 11:50:52 -0800 Subject: [PATCH 5/8] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b60cbada..1b2fbe7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ description="A command line client for working with Tableau Server." authors = [{name="Tableau", email="github@tableau.com"}] license = {file = "LICENSE"} readme = "res/README.md" -requires-python = ">=3.8" # https://devguide.python.org/versions/ +requires-python = ">=3.7" # https://devguide.python.org/versions/ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", From 11677035198db7313f42d166c3afe2b12ddd3981 Mon Sep 17 00:00:00 2001 From: Jac Date: Mon, 6 May 2024 13:12:52 -0700 Subject: [PATCH 6/8] remove 3.7, 3.12 --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1b2fbe7c..f5efb03c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = ["tabcmd"] tabcmd = ["tabcmd.locales/**/*.mo"] [tool.black] line-length = 120 -target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312'] +target-version = ['py38', 'py39', 'py310', 'py311'] extend-exclude = '^/bin/*' [tool.mypy] disable_error_code = [ @@ -37,8 +37,7 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.11" ] dependencies = [ 'argparse', From 2d83197bc1228059265dcae071cff46f15d61ea4 Mon Sep 17 00:00:00 2001 From: Jac Date: Wed, 8 May 2024 14:36:23 -0700 Subject: [PATCH 7/8] Update contributing.md --- contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing.md b/contributing.md index 9a083351..d17f0178 100644 --- a/contributing.md +++ b/contributing.md @@ -15,7 +15,7 @@ ## Install Tabcmd > [!NOTE] -> These instructions are for people who want to write code in or using tabcmd. If > you are interested in tabcmd but not the code, see [here](Readme.md). +> These instructions are for people who want to work with the python code behind tabcmd. If you are interested in tabcmd but not the code, see [here](Readme.md). ####To work with tabcmd, you need to have **Python 3.8+** installed. To propose changes, you must have a Github account. From 85bbfcf11b49d8dc4e64c1ae5dde9320ad3cc42b Mon Sep 17 00:00:00 2001 From: Jac Date: Wed, 8 May 2024 14:36:50 -0700 Subject: [PATCH 8/8] Update contributing.md Co-authored-by: Andy Young <90729701+anyoung-tableau@users.noreply.github.com> --- contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing.md b/contributing.md index d17f0178..d8662e5a 100644 --- a/contributing.md +++ b/contributing.md @@ -149,7 +149,7 @@ The version reflected in the executable (tabcmd -v) is stored in a metadata file - run pyinstaller to create executables - save the executable as an artifact on that job. -1. Find the artifacts created by this job and manually copy them to the new release. (Beware! of what the file type is, github does somethign weird with zipping it if you download with curl etc. TODO: automate workflow with a github action) +1. Find the artifacts created by this job and manually copy them to the new release. (Beware! of what the file type is, github does something weird with zipping it if you download with curl etc. TODO: automate workflow with a github action) 1. To trigger publishing to pypi run the manual workflow on main with 'pypi'. (TODO: automate trigger)