Skip to content

Commit

Permalink
packaging update (#279)
Browse files Browse the repository at this point in the history
* skip .po and .properties files
* pin pyinstaller to 5.13

Co-authored-by: Andy Young <[email protected]>
  • Loading branch information
jacalata and anyoung-tableau authored May 9, 2024
1 parent 01fb8f3 commit 19aabf5
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 110 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@ workon
test.junit.xml

# exceptions
!tests/assets/detailed_users.csv
!tests/assets/detailed_users.csv
est
73 changes: 15 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]`
Expand Down
139 changes: 95 additions & 44 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

## 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?
Expand All @@ -65,43 +64,95 @@ 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.
3. in map_of_parsers.py, add an entry for your new parser, like "dreams": DreamParser.dream_parser
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 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)
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
10 changes: 4 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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']
extend-exclude = '^/bin/*'
[tool.mypy]
disable_error_code = [
Expand All @@ -29,17 +29,15 @@ dynamic = ["version"]
description="A command line client for working with Tableau Server."
authors = [{name="Tableau", email="[email protected]"}]
license = {file = "LICENSE"}
readme = "README.md"
readme = "res/README.md"
requires-python = ">=3.7" # 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",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
"Programming Language :: Python :: 3.11"
]
dependencies = [
'argparse',
Expand Down Expand Up @@ -68,7 +66,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]
Expand Down
5 changes: 5 additions & 0 deletions res/README.md
Original file line number Diff line number Diff line change
@@ -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/
7 changes: 6 additions & 1 deletion tabcmd-windows.spec
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -22,6 +26,7 @@ a = Analysis(
cipher=block_cipher,
noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
Expand Down

0 comments on commit 19aabf5

Please sign in to comment.