From 59b01fd87840404c81c2e7ab109d0f45286311ee Mon Sep 17 00:00:00 2001 From: Tomas Sebestik Date: Fri, 6 Sep 2024 08:18:54 +0200 Subject: [PATCH] ci(pre-commit): update pre-commit config to latest Espressif standard - ci(pre-commit): remove Hadolint hook, no Dockerfile in the project now - ci(dependabot): add dependabot configuration - ci(changelog): update commitizen for czespressif plugin, new changelog - ci(pre-commit): add config for yamlfix, fixes failed pre-commit ci - ci(codeowners): add CODEOWNERS file, dependabot, clean GH workflows - ci: clean pyproject.toml, Justfile, update ref action.yml --- .github/CODEOWNERS | 26 ++++ .github/dependabot.yml | 32 +++++ .github/workflows/dangerjs.yml | 24 ++-- .github/workflows/pre-commit.yml | 20 +++- .github/workflows/python-test.yml | 31 ++--- .pre-commit-config.yaml | 72 +++++++---- CHANGELOG.md | 29 +++-- CONTRIBUTING.md | 1 + Justfile | 27 +++++ pyproject.toml | 190 +++++++++++++----------------- sync_jira_actions/__init__.py | 1 + sync_jira_actions/sync_issue.py | 8 +- 12 files changed, 282 insertions(+), 179 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 Justfile diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..62ce7b9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,26 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# More details are here: https://help.github.com/articles/about-codeowners/ + +# The '*' pattern is global owners. + +# Order is important. The last matching pattern has the most precedence. +# The folders are ordered as follows: + +# In each subsection folders are ordered first by depth, then alphabetically. +# This should make it easy to add new rules without breaking existing ones. + +# TIP: syntax formatting in VS Code; extension "vscode-codeowners" + +#------------------------------------------------------------------------------------------------------------------------ + +# Global rule: +# * @espressif + +# Code owners for the entire repository +/.github @espressif/ci + + +.pre-commit-config.yaml @espressif/ci +CONTRIBUTING.md @espressif/ci diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..648cb5e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,32 @@ +--- +version: 2 + +updates: + - package-ecosystem: "pip" + versioning-strategy: increase-if-necessary + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + commit-message: + prefix: "ci(dependabot-pip): " + reviewers: ["espressif/ci"] + + - package-ecosystem: "npm" + versioning-strategy: increase-if-necessary + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + commit-message: + prefix: "ci(dependabot-npm): " + reviewers: ["espressif/ci"] + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + commit-message: + prefix: "ci(dependabot-actions): " + reviewers: ["espressif/ci"] diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml index 4d2b897..16ed88f 100644 --- a/.github/workflows/dangerjs.yml +++ b/.github/workflows/dangerjs.yml @@ -1,4 +1,6 @@ +--- name: DangerJS Pull Request linter + on: pull_request_target: types: [opened, edited, reopened, synchronize] @@ -8,17 +10,17 @@ permissions: contents: write jobs: - pull-request-style-linter: + dangerjs: runs-on: ubuntu-latest steps: - - name: Check out PR head - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} + - name: Check out PR head + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - - name: DangerJS pull request linter - uses: espressif/shared-github-dangerjs@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - instructions-contributions-file: 'CONTRIBUTING.md' + - name: DangerJS pull request linter + uses: espressif/shared-github-dangerjs@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + instructions-contributions-file: 'CONTRIBUTING.md' diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 6b2c3c0..e042453 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,16 +1,24 @@ +--- name: Check pre-commit on: pull_request: jobs: - check-pre-commit: + pre-commit: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 with: - fetch-depth: 0 - - uses: actions/setup-python@v5 - - uses: pre-commit/action@v3.0.1 + python-version: '3.9' + + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 env: - SKIP: pip-compile + SKIP: pip-compile,update-changelog diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index be57119..ce4d259 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -1,4 +1,5 @@ -name: Tests +--- +name: Tests codebase on: pull_request: @@ -6,20 +7,22 @@ on: jobs: pytest: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 - with: - python-version: 3.11 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest pytest-cov - pip install -r requirements.txt + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov + pip install -r requirements.txt - - name: Run pytest with coverage - run: | - python -m pytest + - name: Run pytest with coverage + run: |- + python -m pytest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c2e52ab..c2cc11e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,62 +1,82 @@ -# Run `pre-commit autoupdate` to update to the latest pre-commit hooks version. -# When changing the version of tools that are also installed as development dependencies (e.g., black, mypy, ruff), -# please ensure the same versions are pinned in this file as in `pyproject.toml`. --- minimum_pre_commit_version: 3.3.0 # Specifies the minimum version of pre-commit required for this configuration default_install_hook_types: [pre-commit, commit-msg] # Default hook types to install if not specified in individual hooks default_stages: [pre-commit] repos: + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace # Removes trailing whitespaces from lines - id: end-of-file-fixer # Ensures files end with a newline - id: check-executables-have-shebangs # Checks executables have a proper shebang + - id: check-shebang-scripts-are-executable # Checks that scripts with shebangs are executable. + - id: check-case-conflict # Check conflict on a case-insensitive filesystem (MacOS HFS+/Windows FAT). - id: mixed-line-ending # Detects mixed line endings (CRLF/LF) args: ['-f=lf'] # Forces files to use LF line endings - - id: double-quote-string-fixer # Converts single quotes to double quotes in strings - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.2.1 + rev: v0.6.4 hooks: - - id: ruff # Runs ruff linter (replaces flake8) + - id: ruff # Linter args: [--fix, --exit-non-zero-on-fix] - - - repo: https://github.com/asottile/reorder_python_imports - rev: v3.12.0 - hooks: - - id: reorder-python-imports # Reorders Python imports to a standard format (replaces isort) + - id: ruff-format # Formatter (replaces Black) - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.11.2 hooks: - id: mypy # Runs mypy for Python type checking - additional_dependencies: ['types-all'] + + - repo: https://github.com/pylint-dev/pylint + rev: v3.2.7 + hooks: + - id: pylint # Runs pylint on Python code - repo: https://github.com/espressif/conventional-precommit-linter - rev: v1.6.0 + rev: v1.10.0 hooks: - id: conventional-precommit-linter # Lints commit messages for conventional format stages: [commit-msg] - - repo: https://github.com/psf/black - rev: '24.1.1' + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 hooks: - - id: black # Formats Python code using black + - id: codespell # Code spell checker + args: ['--write-changes'] + additional_dependencies: [tomli] - - repo: https://github.com/pylint-dev/pylint - rev: v3.0.3 + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 hooks: - - id: pylint # Runs pylint on Python code + - id: mdformat + args: [--number] # Keep numbering for ordered lists + additional_dependencies: + - mdformat-gfm # Support for GitHub Flavored Markdown (GFM), including tables, task lists, strikethroughs, and autolinks. + - mdformat-ruff # Formats Python code blocks in Markdown files according to the `ruff` linter's style. + - mdformat-simple-breaks # Ensures that single line breaks in Markdown are converted to `
` t - - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 hooks: - - id: codespell # Code spell checker - args: ["--write-changes"] - additional_dependencies: [tomli] + - id: detect-secrets + args: + - --base64-limit=4 # Level of entropy for base64 type strings + - --hex-limit=3 # Level of entropy for hex strings + + - repo: https://github.com/lyz-code/yamlfix/ + rev: 1.17.0 + hooks: + - id: yamlfix + - repo: https://github.com/espressif/cz-plugin-espressif + rev: 'v1.0.1' + hooks: + - id: update-changelog # Local hooks - repo: local diff --git a/CHANGELOG.md b/CHANGELOG.md index aac32f4..06aedb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,20 +26,25 @@ ## v0.1.1 (2024-02-14) +### 📖 Documentation + +- add CONTRIBUTING guide, update README *(Tomas Sebestik - b82419e)* + +### 🔧 Code refactoring -- docs: add CONTRIBUTING guide, update README -- ci(project-structure): package and tools config by pyproject.toml -- - add commitizen support to pyproject.toml -- add Danger for GitHub -- add pre-commit hook for codespell -- add pre-commit hook prettier - formatting Markdown files -- add pre-commit workflow to CI -- refactor: refactor to Python 3.11, refactor Dockerfile (Bookworm, node20) -- - refactor(tests): add tests and GH workflow for pytest -- refactor: move source code to src directory +- refactor to Python 3.11, refactor Dockerfile (Bookworm, node20) *(Tomas Sebestik - c26938e)* + +--- ## v0.1.0 (2024-02-07) +### ✨ New features + +- **init**: original code from github-actions repo *(Tomas Sebestik - 36ac8e0)* + +--- + +**[Espressif Systems CO LTD. (2024)](https://www.espressif.com/)** -- feat(init): original code from github-actions repo -- Init +- [Commitizen tools plugin with Espressif code style](https://www.github.com/espressif/cz-plugin-espressif) +- [Espressif Coding Standards and Best Practices](https://www.github.com/espressif/standards) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c0ae237..7f7c20c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,6 +62,7 @@ We welcome contributions! To contribute to this repository, please read these in ``` - Install the project and development dependencies: + ```sh pip install -e '.[dev]' ``` diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..31bcf0d --- /dev/null +++ b/Justfile @@ -0,0 +1,27 @@ +set quiet := true + +[private] +default: + just --choose --unsorted + +clean: + rm -rf \ + dist \ + .pytest_cache \ + .mypy_cache \ + .coverage \ + .coverage.* \ + .ruff_cache \ + *.egg-info \ + : + +pidev: + pip install -e '.[dev]' + pip install --upgrade pip + +checkall: + pre-commit run --all-files + +rebase: + git fetch --all + git rebase -i origin/v1 diff --git a/pyproject.toml b/pyproject.toml index ecea440..fd750f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,75 +1,101 @@ -[build-system] - requires = ["setuptools-scm>=8.0", "setuptools>=60"] - [project] authors = [ - { name = "Tomas Sebestik (Espressif Systems)", email = "tomas.sebestik@espressif.com" }, + { name = "Tomas Sebestik", email = "tomas.sebestik@espressif.com" }, + { name = "Espressif Systems" }, + ] + classifiers = [ + "Intended Audience :: Developers", + "Natural Language :: English", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS :: MacOS X", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] - classifiers = ["Programming Language :: Python :: 3"] + dependencies = ["PyGithub==2.2.0", "jira==3.6.0"] description = "Espressif GitHub Actions for JIRA synchronization" dynamic = ["version"] + license = { text = "Apache 2.0" } name = "sync-jira-actions" readme = "README.md" requires-python = ">=3.11" - dependencies = ["PyGithub==2.2.0", "jira==3.6.0"] + [project.urls] + Changelog = "https://github.com/espressif/sync-jira-actions/tags/blob/master/CHANGELOG.md" + Homepage = "https://github.com/espressif/sync-jira-actions/tags" + Source = "https://github.com/espressif/sync-jira-actions/tags" + Tracker = "https://github.com/espressif/sync-jira-actions/tags/issues" [project.optional-dependencies] dev = [ - "commitizen", + "czespressif", "pip-tools~=7.3", "pre-commit>=3.3", "pytest", "pytest-cov", + "just-bin~=1.26.0", ] -[tool.setuptools_scm] - write_to = "sync_jira_actions/version.py" +[build-system] + build-backend = "setuptools.build_meta" + requires = ["setuptools>=64"] + +[tool.setuptools.packages.find] + exclude = ["node_modules", "tests"] + include = ["sync_jira_actions"] -[tool.black] - line-length = 120 # The maximum line length for Python code formatting - skip-string-normalization = true # Avoids converting single quotes to double quotes in strings (pre-commit hook enforces single quotes in Python code) +[tool.setuptools.dynamic] + version = { attr = "sync_jira_actions.__init__.__version__" } [tool.ruff] - line-length = 120 # Specifies the maximum line length for ruff checks - select = ['E', 'F', 'W'] # Types of issues ruff should check for - target-version = "py311" # Specifies the target Python version for ruff checks + exclude = ["tests/"] + line-length = 120 + lint.select = ["B", "E", "F", "I", "S", "W"] + target-version = "py311" + + [tool.ruff.format] + quote-style = "single" + + [tool.ruff.lint.isort] + force-single-line = true + lines-between-types = 1 [tool.mypy] - disallow_incomplete_defs = false # Disallows defining functions with incomplete type annotations - disallow_untyped_defs = false # Disallows defining functions without type annotations or with incomplete type annotations - exclude = '^venv/' # Paths to ignore during type checking - ignore_missing_imports = true # Suppress error messages about imports that cannot be resolved - python_version = "3.11" # Specifies the Python version used to parse and check the target program - warn_no_return = true # Shows errors for missing return statements on some execution paths - warn_return_any = true # Shows a warning when returning a value with type Any from a function declared with a non- Any return type + disallow_incomplete_defs = false + disallow_untyped_defs = false + exclude = '^venv/' + ignore_missing_imports = true + python_version = "3.11" + warn_no_return = true + warn_return_any = true [tool.pylint] [tool.pylint.MASTER] - ignore-paths = ["tests/.*"] # Paths to ignore during linting + ignore-paths = ["tests/.*"] [tool.pylint.'BASIC'] - variable-rgx = "[a-z_][a-z0-9_]{1,30}$" # Variable names must start with a lowercase letter or underscore, followed by any combination of lowercase letters, numbers, or underscores, with a total length of 2 to 30 characters. + variable-rgx = "[a-z_][a-z0-9_]{1,30}$" [tool.pylint.'MESSAGES CONTROL'] disable = [ - "duplicate-code", # R0801: Similar lines in %s files - "fixme", # W0511: Used when TODO/FIXME is encountered - "import-error", # E0401: Used when pylint has been unable to import a module - "import-outside-toplevel", # E0402: Imports should usually be on top of the module - "logging-fstring-interpolation", # W1202: Use % formatting in logging functions and pass the % parameters as arguments - "missing-class-docstring", # C0115: Missing class docstring - "missing-function-docstring", # C0116: Missing function or method docstring - "missing-module-docstring", # C0114: Missing module docstring - "no-name-in-module", # W0611: Used when a name cannot be found in a module - "too-few-public-methods", # R0903: Too few public methods of class - "too-many-branches", # R0912: Too many branches - "too-many-locals", # R0914: Too many local variables - "too-many-return-statements", # R0911: Too many return statements - "too-many-statements", # R0915: Too many statements - "ungrouped-imports", # C0412: Imports should be grouped by packages + "duplicate-code", + "fixme", + "import-error", + "import-outside-toplevel", + "logging-fstring-interpolation", + "missing-class-docstring", + "missing-function-docstring", + "missing-module-docstring", + "no-name-in-module", + "too-few-public-methods", + "too-many-branches", + "too-many-locals", + "too-many-return-statements", + "too-many-statements", + "ungrouped-imports", ] [tool.pylint.'FORMAT'] - max-line-length = 120 # Specifies the maximum line length for pylint checks - + max-line-length = 120 [tool.pytest.ini_options] addopts = "-s --log-cli-level DEBUG --cov=. --cov-report=term" @@ -81,69 +107,21 @@ [tool.coverage.run] omit = ["__*__.py", "tests/*"] -[tool.commitizen] - annotated_tag = true - bump_message = "change(bump-version): bump release version to v$new_version" - name = "cz_customize" - tag_format = "v$version" - update_changelog_on_bump = true - version_provider = "scm" - - [tool.commitizen.customize] - bump_map = { "change" = "MINOR", "feat" = "MINOR", "fix" = "PATCH", "refactor" = "PATCH", "remove" = "PATCH", "revert" = "PATCH" } - bump_pattern = "^(change|feat|fix|refactor|remove|revert)" - change_type_order = [ - "change", - "ci", - "docs", - "feat", - "fix", - "refactor", - "remove", - "revert", - ] - example = "change: this is a custom change type" - message_template = "{% if scope %}{{change_type}}({{scope}}): {{message}}{% else %}{{change_type}}: {{message}}{% endif %}{% if body %}\n\n{{body}}{% endif %}{% if is_breaking_change %}\n\nBREAKING CHANGE{% endif %}{% if footer %}\n\n{{footer}}{% endif %}" - schema = "(): " - schema_pattern = "^([a-z]+)(\\([\\w\\-\\.]+\\))?:\\s.*" - - [[tool.commitizen.customize.questions]] - choices = [ - { value = "change", name = "change: A change made to the codebase." }, - { value = "ci", name = "ci: Changes to our CI configuration files and scripts." }, - { value = "docs", name = "docs: Documentation only changes." }, - { value = "feat", name = "feat: A new feature." }, - { value = "fix", name = "fix: A bug fix." }, - { value = "refactor", name = "refactor: A code change that neither fixes a bug nor adds a feature." }, - { value = "remove", name = "remove: Removing code or files." }, - { value = "revert", name = "revert: Revert to a commit." }, - ] - message = "Select the TYPE of change you are committing" - name = "change_type" - type = "list" - - [[tool.commitizen.customize.questions]] - message = "What is the SCOPE of this change (press enter to skip)?" - name = "scope" - type = "input" +[tool.yamlfix] + comments_min_spaces_from_content = 1 + line_length = 200 + preserve_quotes = true + section_whitelines = 1 + sequence_style = "keep_style" + whitelines = 1 - [[tool.commitizen.customize.questions]] - message = "Describe the changes made (SUMMARY of commit message):" - name = "message" - type = "input" - - [[tool.commitizen.customize.questions]] - message = "Provide additional contextual information - commit message BODY: (press [enter] to skip)" - name = "body" - type = "input" - - [[tool.commitizen.customize.questions]] - default = false - message = "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer" - name = "is_breaking_change" - type = "confirm" - - [[tool.commitizen.customize.questions]] - message = "Footer. Information about Breaking Changes and reference issues that this commit closes: (press [enter] to skip)" - name = "footer" - type = "input" +[tool.commitizen] + annotated_tag = true + bump_message = 'change(bump): release $current_version → $new_version [skip-ci]' + changelog_merge_prerelease = true + name = "czespressif" + tag_format = "v$version" + update_changelog_on_bump = true + version = "0.1.1" + version_files = ["sync_jira_actions/__init__.py"] + version_provider = "commitizen" diff --git a/sync_jira_actions/__init__.py b/sync_jira_actions/__init__.py index e69de29..df9144c 100644 --- a/sync_jira_actions/__init__.py +++ b/sync_jira_actions/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1.1' diff --git a/sync_jira_actions/sync_issue.py b/sync_jira_actions/sync_issue.py index 28b327f..a55288a 100755 --- a/sync_jira_actions/sync_issue.py +++ b/sync_jira_actions/sync_issue.py @@ -359,7 +359,7 @@ def _update_github_with_jira_key(gh_issue, jira_issue): if retries == 0: raise print(f'GitHub edit failed: {error} ({retries} retries)') - time.sleep(random.randrange(1, 5)) + time.sleep(random.randrange(1, 5)) # noqa: S311 retries -= 1 @@ -416,12 +416,12 @@ def _get_jira_issue_type(jira, gh_issue): for gh_label in gh_labels: # Type: Feature Request label should match New Feature issue type in Jira if gh_label == 'Type: Feature Request': - print('GitHub label is \'Type: Feature Request\'. Mapping to New Feature Jira issue type') + print("GitHub label is 'Type: Feature Request'. Mapping to New Feature Jira issue type") return {'id': JIRA_NEW_FEATURE_TYPE_ID} # JIRA API needs JSON here # Some projects use Label with bug icon represented by ":bug:" in label name. # This if matches those to Bug Jira issue type if gh_label == 'Type: Bug :bug:': - print('GitHub label is \'Type: Bug :bug:\'. Mapping to Bug Jira issue type') + print("GitHub label is 'Type: Bug :bug:'. Mapping to Bug Jira issue type") return {'id': JIRA_BUG_TYPE_ID} # JIRA API needs JSON here for issue_type in issue_types: type_name = issue_type.name.lower() @@ -489,7 +489,7 @@ def _find_jira_issue(jira, gh_issue, make_new=False, retries=5): # minutes for an old issue (created before the sync was installed), or an issue where the created # event sync failed, to sync in. print(f'Waiting to see if issue is created by another Action... (retries={retries})') - time.sleep(random.randrange(30, 60)) + time.sleep(random.randrange(30, 60)) # noqa: S311 return _find_jira_issue(jira, gh_issue, True, retries - 1) print('Creating missing issue in JIRA')