diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml index 4d2b897..9b174b3 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] @@ -11,14 +13,14 @@ jobs: pull-request-style-linter: 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..1d238bc 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,3 +1,4 @@ +--- name: Check pre-commit on: diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index be57119..990e08c 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -1,3 +1,4 @@ +--- name: Tests on: @@ -7,19 +8,19 @@ jobs: pytest: runs-on: ubuntu-latest 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..8ca1b5c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,62 +1,88 @@ -# 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/AleksaC/hadolint-py + rev: v2.12.1b3 hooks: - - id: codespell # Code spell checker - args: ["--write-changes"] - additional_dependencies: [tomli] + - id: hadolint + args: + - --ignore=DL3008 # No version pin in apk add (Alpine) + - --ignore=DL3013 # No version pin in pip install + - --ignore=DL3018 # No version pin in apt-get (Debian) + - --ignore=DL3025 # Allow any registry in FROM + - --ignore=DL3059 # Multiple consecutive `RUN` instructions + + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - 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 # Local hooks - repo: local diff --git a/CHANGELOG.md b/CHANGELOG.md index de19d91..384ef65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ ## v0.1.1 (2024-02-14) - - docs: add CONTRIBUTING guide, update README - ci(project-structure): package and tools config by pyproject.toml - - add commitizen support to pyproject.toml @@ -14,6 +13,5 @@ ## v0.1.0 (2024-02-07) - - feat(init): original code from github-actions repo - Init 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/action.yml b/action.yml index 109385e..df16488 100644 --- a/action.yml +++ b/action.yml @@ -1,14 +1,45 @@ -name: "GitHub to JIRA Issue Sync" +--- +name: Sync GitHub Issues to JIRA description: "Performs simple one way syncing of GitHub issues into JIRA." + branding: icon: "fast-forward" color: "green" + inputs: cron_job: description: > Whether the action is run as a cron job. Set true to trigger syncing of new PRs. required: false + runs: - using: "docker" - image: "Dockerfile" + using: "composite" + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install Python dependencies + run: | + python -m venv venv + source venv/bin/activate + pip install --upgrade pip + pip install -r requirements.txt + shell: bash + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install markdown2confluence + run: npm install -g @shogobg/markdown2confluence@0.1.6 + shell: bash + + - name: Run sync_to_jira.py + run: | + source venv/bin/activate + python sync_jira_actions/sync_to_jira.py + shell: bash diff --git a/pyproject.toml b/pyproject.toml index ecea440..37e8986 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,32 +15,37 @@ dependencies = ["PyGithub==2.2.0", "jira==3.6.0"] [project.optional-dependencies] - dev = [ - "commitizen", - "pip-tools~=7.3", - "pre-commit>=3.3", - "pytest", - "pytest-cov", - ] + dev = ["commitizen", "pip-tools~=7.3", "pre-commit>=3.3", "pytest", "pytest-cov"] [tool.setuptools_scm] write_to = "sync_jira_actions/version.py" -[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.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/"] # Exclude specific paths + line-length = 120 # Specifies the maximum line length for ruff checks + lint.select = [ + "B", # Bugbear: Enforces additional linting rules aimed at catching common bugs and design issues. + "E", # pycodestyle Error: Enforces PEP 8 error checks related to formatting and code style. + "F", # Pyflakes: Detects common errors like unused imports, undefined variables, and more. + "I", # Isort: Ensures that imports are sorted and grouped correctly. + "S", # Security: Includes security-related linting rules from the Bandit plugin. + "W", # pycodestyle Warning: Enforces PEP 8 warnings, such as trailing whitespace or missing newlines. + ] # Selects specific linting rules from various sources + target-version = "py311" # Specifies the target Python version for ruff checks + + [tool.ruff.format] # See formatter config options at https://docs.astral.sh/ruff/formatter + quote-style = "single" + + [tool.ruff.lint.isort] + force-single-line = true # Forces all imports to be placed on individual lines, improving readability and reducing merge conflicts. + lines-between-types = 1 # Ensures there is one blank line between different types of imports (e.g., standard library, third-party, local imports). [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 + 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 @@ -70,7 +75,6 @@ [tool.pylint.'FORMAT'] max-line-length = 120 # Specifies the maximum line length for pylint checks - [tool.pytest.ini_options] addopts = "-s --log-cli-level DEBUG --cov=. --cov-report=term" python_classes = ["Test*"] @@ -90,22 +94,13 @@ 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.*" + 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 = [ @@ -147,3 +142,11 @@ message = "Footer. Information about Breaking Changes and reference issues that this commit closes: (press [enter] to skip)" name = "footer" type = "input" + +[tool.yamlfix] + comments_min_spaces_from_content = 1 # Minimum number of spaces between comments and content + line_length = 200 # Maximum line length before wrapping + preserve_quotes = true # Preserve quotes around string values if they are present + section_whitelines = 1 # Number of blank lines before and after sections + sequence_style = "keep_style" # Determines how sequences (lists) are formatted: 'flow_style', 'block_style', or 'keep_style' + whitelines = 1 # Number of blank lines between elements, useful for separating items diff --git a/sync_jira_actions/sync_issue.py b/sync_jira_actions/sync_issue.py index 83d8b1d..312029c 100755 --- a/sync_jira_actions/sync_issue.py +++ b/sync_jira_actions/sync_issue.py @@ -224,7 +224,7 @@ def _markdown2wiki(markdown): mdf.write('\n') try: - subprocess.check_call(['markdown2confluence', md_path, conf_path]) + subprocess.check_call(['markdown2confluence', md_path, conf_path]) # noqa: S603, S607 with open(conf_path, 'r', encoding='utf-8') as file: result = file.read() if len(result) > 16384: # limit any single body of text to 16KB (JIRA API limits total text to 32KB) @@ -355,7 +355,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 @@ -412,12 +412,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() @@ -484,7 +484,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')