diff --git a/.config/dictionary.txt b/.config/dictionary.txt index bf52b4c93..306621c18 100644 --- a/.config/dictionary.txt +++ b/.config/dictionary.txt @@ -1 +1,2 @@ +CAs assertIn diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..838a2518f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @pycontribs/jira +/.github/ @ssbarnea diff --git a/.github/workflows/jira_ci.yml b/.github/workflows/jira_ci.yml index a793b12d7..dac7bc563 100644 --- a/.github/workflows/jira_ci.yml +++ b/.github/workflows/jira_ci.yml @@ -1,17 +1,16 @@ name: ci +# runs only after tox workflow finished successfully on: - # Trigger the workflow on push or pull request, - # but only for the main branch - push: - branches: - - main - pull_request: - branches: - - main + workflow_run: + workflows: [tox] + branches: [main] + types: + - completed jobs: server: + if: ${{ github.event.workflow_run.conclusion == 'success' }} uses: pycontribs/jira/.github/workflows/jira_server_ci.yml@main cloud: diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml new file mode 100644 index 000000000..f6c953481 --- /dev/null +++ b/.github/workflows/tox.yml @@ -0,0 +1,179 @@ +--- +name: tox +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +env: + FORCE_COLOR: 1 # tox, pytest + PY_COLORS: 1 + +jobs: + prepare: + name: prepare + runs-on: ubuntu-24.04 + outputs: + matrix: ${{ steps.generate_matrix.outputs.matrix }} + steps: + - name: Determine matrix + id: generate_matrix + uses: coactions/dynamic-matrix@v3 + with: + min_python: "3.9" + max_python: "3.12" + default_python: "3.9" + other_names: | + lint + docs + pkg + # ^ arm64 runner is using py311 for matching python version used in AAP 2.5 + platforms: linux,macos,linux-arm64:ubuntu-24.04-arm64-2core + skip_explode: "1" + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os || 'ubuntu-24.04' }} + needs: + - prepare + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.prepare.outputs.matrix) }} + steps: + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed by setuptools-scm + submodules: true + + - name: Set pre-commit cache + uses: actions/cache@v4 + if: ${{ contains(matrix.name, 'lint') }} + with: + path: | + ~/.cache/pre-commit + key: pre-commit-${{ matrix.name }}-${{ hashFiles('.pre-commit-config.yaml') }} + + - name: Set up Python ${{ matrix.python_version || '3.10' }} + uses: actions/setup-python@v5 + with: + cache: pip + python-version: ${{ matrix.python_version || '3.10' }} + cache-dependency-path: "*requirements*.txt" + + - name: Install tox + run: | + python3 -m pip install --upgrade pip wheel tox + + - run: ${{ matrix.command }} + + - run: ${{ matrix.command2 }} + if: ${{ matrix.command2 }} + + - run: ${{ matrix.command3 }} + if: ${{ matrix.command3 }} + + - run: ${{ matrix.command4 }} + if: ${{ matrix.command4 }} + + - run: ${{ matrix.command5 }} + if: ${{ matrix.command5 }} + + - name: Archive logs + uses: actions/upload-artifact@v4 + with: + name: logs-${{ matrix.name }}.zip + if-no-files-found: error + path: | + .tox/**/log/ + .tox/**/coverage.xml + + - name: Report failure if git reports dirty status + run: | + if [[ -n $(git status -s) ]]; then + # shellcheck disable=SC2016 + echo -n '::error file=git-status::' + printf '### Failed as git reported modified and/or untracked files\n```\n%s\n```\n' "$(git status -s)" | tee -a "$GITHUB_STEP_SUMMARY" + exit 99 + fi + # https://github.com/actions/toolkit/issues/193 + check: + if: always() + environment: check + permissions: + id-token: write + checks: read + + needs: + - build + + runs-on: ubuntu-24.04 + + steps: + # checkout needed for codecov action which needs codecov.yml file + - uses: actions/checkout@v4 + + - name: Set up Python # likely needed for coverage + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - run: pip3 install 'coverage>=7.5.1' + + - name: Merge logs into a single archive + uses: actions/upload-artifact/merge@v4 + with: + name: logs.zip + pattern: logs-*.zip + # artifacts like py312.zip and py312-macos do have overlapping files + separate-directories: true + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: logs.zip + path: . + + - name: Check for expected number of coverage reports + run: .github/check-coverage.sh + + # Single uploads inside check job for codecov to allow use to retry + # it when it fails without running tests again. Fails often enough! + - name: Upload junit xml reports + # PRs from forks might not have access to the secret + if: env.CODECOV_TOKEN + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN || env.CODECOV_TOKEN }} + uses: codecov/test-results-action@v1 + with: + name: ${{ matrix.name }} + files: "*/tests/output/junit/*.xml" + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload coverage data + uses: codecov/codecov-action@v4 + with: + name: ${{ matrix.name }} + # verbose: true # optional (default = false) + fail_ci_if_error: true + use_oidc: true # cspell:ignore oidc + files: "*/tests/output/reports/coverage.xml" + + # - name: Check codecov.io status + # if: github.event_name == 'pull_request' + # uses: coactions/codecov-status@main + + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} + + - name: Delete Merged Artifacts + uses: actions/upload-artifact/merge@v4 + with: + delete-merged: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 96be8bad6..0ff461314 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,8 @@ repos: types: [text] args: [] require_serial: false - additional_dependencies: [] + additional_dependencies: + - tomli; python_version<'3.11' - repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.6.2" hooks: diff --git a/README.rst b/README.rst index 413227c52..24499a673 100644 --- a/README.rst +++ b/README.rst @@ -11,11 +11,6 @@ Jira Python Library .. image:: https://img.shields.io/github/issues/pycontribs/jira.svg :target: https://github.com/pycontribs/jira/issues -.. image:: https://img.shields.io/badge/irc-%23pycontribs-blue - :target: irc:///#pycontribs - ------------- - .. image:: https://readthedocs.org/projects/jira/badge/?version=main :target: https://jira.readthedocs.io/ diff --git a/docs/conf.py b/docs/conf.py index 6ba493e84..c04c59b96 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -81,8 +81,7 @@ # The encoding of source files. # source_encoding = 'utf-8-sig' -# The master toctree document. -master_doc = "index" +root_doc = "index" # General information about the project. project = py_pkg.__name__ diff --git a/jira/client.py b/jira/client.py index aefae7cd1..980dfa230 100644 --- a/jira/client.py +++ b/jira/client.py @@ -3279,7 +3279,7 @@ def create_temp_project_avatar( This method returns a dict of properties that can be used to crop a subarea of a larger image for use. This dict should be saved and passed to :py:meth:`confirm_project_avatar` to finish the avatar creation process. - If you want to cut out the middleman and confirm the avatar with Jira's default cropping, + If you want to confirm the avatar with Jira's default cropping, pass the 'auto_confirm' argument with a truthy value and :py:meth:`confirm_project_avatar` will be called for you before this method returns. Args: @@ -3825,7 +3825,7 @@ def create_temp_user_avatar( This method returns a dict of properties that can be used to crop a subarea of a larger image for use. This dict should be saved and passed to :py:meth:`confirm_user_avatar` to finish the avatar creation process. - If you want to cut out the middleman and confirm the avatar with Jira's default cropping, pass the ``auto_confirm`` argument with a truthy value and + If you want to confirm the avatar with Jira's default cropping, pass the ``auto_confirm`` argument with a truthy value and :py:meth:`confirm_user_avatar` will be called for you before this method returns. Args: @@ -4234,7 +4234,7 @@ def _add_client_cert_to_session(self): If configured through the constructor. - https://docs.python-requests.org/en/master/user/advanced/#client-side-certificates + https://docs.python-requests.org/en/latest/user/advanced/#client-side-certificates - str: a single file (containing the private key and the certificate) - Tuple[str,str] a tuple of both files’ paths """ @@ -4246,7 +4246,7 @@ def _add_ssl_cert_verif_strategy_to_session(self): If configured through the constructor. - https://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification + https://docs.python-requests.org/en/latest/user/advanced/#ssl-cert-verification - str: Path to a `CA_BUNDLE` file or directory with certificates of trusted CAs. - bool: True/False """ diff --git a/pyproject.toml b/pyproject.toml index 8dc146aad..3de8c41dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,14 +93,31 @@ test = [ jirashell = "jira.jirashell:main" [tool.codespell] +check-filenames = true +check-hidden = true +quiet-level = 0 +write-changes = true +enable-colors = true skip = [ + "./.eggs", + "./.git", + "./.mypy_cache", + "./.tox", "./build", "./docs/build", "./node_modules", + "./pip-wheel-metadata", + "./tests/icon.png", + ".DS_Store", + ".ruff_cache", "AUTHORS", - "ChangeLog" + "ChangeLog", + "__pycache__", + "coverage.xml", + "dist", ] -ignore-words = ".config/dictionary.txt" +builtin = ["clear", "rare", "usage", "names", "code"] +ignore-words = [".config/dictionary.txt"] [tool.files] packages = """ diff --git a/tox.ini b/tox.ini index b398da265..8df5886e0 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,9 @@ requires = # tox-extra # tox-pyenv envlist = + lint + pkg + docs py311 py310 py39 @@ -99,7 +102,7 @@ commands = 'import pathlib; '\ 'docs_dir = pathlib.Path(r"{toxworkdir}") / "docs_out"; index_file = docs_dir / "index.html"; print(f"\nDocumentation available under `file://\{index_file\}`\n\nTo serve docs, use `python3 -m http.server --directory \{docs_dir\} 0`\n")' -[testenv:packaging] +[testenv:pkg] basepython = python3 description = Build package, verify metadata, install package and assert behavior when ansible is missing.