From 0cb6d2052c989f58c0c53f7c7d14bbd8df9e97e9 Mon Sep 17 00:00:00 2001 From: Noah Canadea Date: Thu, 30 Nov 2023 09:06:17 +0100 Subject: [PATCH] merge upstream (#28) * Refac/github_actions (#1) * feat(dev_requirements): Add pytest * refac(workspace_settings): Specify python interpreter path * refac(cicd): Combine actions in composition action and add unit tests. * fix(cicd): Remove custom arg from pytest. * fix(cicd): Add missing requirements for pytest * feat(tasks): Add task to install all dependencies. * feat(pytest_typehint): Add extension for pytest hints. * feat(tests): Add initial test. * ruff format * fix(pytest): Set pythonpath * fix(cicd): Pass python version to sub actions with input. * fix(cicd): Add input for sub actions * fix(cicd): Read python version from project file instead of env. * fix(cicd): python version var assignment * Feat/migrate git logic to python (#5) * feat(action): Add configuration provider * feat(vscode): Change auto save to onFocusChange since ruff does not work with afterDelay. * feat(vscode): Add test task * refac(tests): Remove __main__.py tests * feat(vscode): Exclude __pycache__ folders in workspace * refac(ActionConfig): Remove default value for registry_domain * feat(git): Add git helper * refac(action): Pass configuration over env. instead of cli args. * refac(action): Add git handling and use new configuration provider. * refac(action_integration_test): Provider github token in env. instead of input. * fix(action): Remove git logic and rename env vars * feat(ActionConfig): Log substring of secrets * fix(ConfigProvider): Make flag registry_secrets as secret. * refac(action): Change github_token back to input variable. * fix(action): Add exception handling if target branch does not exist * fix(config): Fix conversion from env_string to bool. * refac(cli): Move cli resources to __main__ * feat(action): Add input to set relative working dir. * feat(git): Set git root to new repo_root value. * doc(README): Update documentation of the github action. * Feat/refac_core (#10) * refac(hcledit): Move bin in subdirectory * refac(terraform_utils): Move in own directory. * refac(terraform_utils): Move to own directory * feat(vscode): Add some project settings. * feat(pip): Add py-markdown-table as requirement. * refac(terraform_utils): Add init file. * feat(providers): Add Providers. * feat(provider_handler): Add provider_handler and builder. * refac(models): Update versioned resources models. * feat(composition): Remove composition. * feat(models): Add statistics model. * feat(cli): Switch to provider implementation. * refac(builder): Change secret input from file path to dict. * refac(action): Switch to provider implementation. * ruff auto-fix * feat(vscode): Add task to auto-fix with ruff. * doc(README): Update doc. * fix(provider): Fix get markdown table * feat(Statistics): Add function to get markdown table. * feat(action): Add report to pr body. * fix(upgrade_resources): Add catch to handle unsuccesfull upgrades * ruff format * fix(terraform_provider): remove exception handling. * refac(exception): Remove base exception. * fix(cicd): Change error text. * fix(hcledit_cli): Check if binary exists. * fix(hcledit): Make binary executable. * fix(hcledit_cli): REmove exist check. * Revert "fix(hcledit_cli): REmove exist check." This reverts commit c4a29a27a4dd52d6660cba8419330ec9fdf88997. * fix(setup): Change package_data path. * fix(Statistics): Fix markdown table. * fix(Statistics): Change markdown input to list. * feat(vscode): Disable justmycode in launch.json * doc(README): Add supported platforms. * fix(pr_body): Add missing newline after provider table. * fix(pr_body): Remove second newline. * fix(pr_body): Format tables. * fix(pr_body): Add quotes. * refac(markdown_table): Switch to new library for markdown tables. * fix(pip): Fix pytablewriter version * fix(terraform_provider): Set table_name * feat(action): Implement handling of existing PRs * fix(action): Save upgradable resources instead of all. * fix(cicd): Disable checks on merge event. * refac(action): Rename registry_secrets to terraform_registry_secrets * Fix/action_file_references (#23) * feat(action): Implement correct handling of repo root and action files path * fix(tests): Change inputs in config tests. * refac(rich): Change text in progress bar. * fix(action): Change working directory * dic(README): Update documentation and add pr image. * doc(README): Change infrapatch Name to Upper-Case. * Feat/add_tests (#27) * feat(tests): Add tests for models * ruff auto-fix * test(terraform_resource): Add to_dict() test. * doc(checkout): Add note and update action example regarding fetch-depth. * feat(action): Add log message when updating pr. * fix(provider_cache): Fix provider cache not working. * fix(markdown_tables): Skip table generate for providers without changes. * fix(pr_update): Fix handling of existing prs * fix(action): Fix searching existing pr. * fix(action): Filter pr in python instead of search over github api. * feat(action): Update pr even when no upgrades where performed. * fix(provider_handler): Switch reference of object. * fix(provider_handler): Fix resource update. * fix(provider_handler): Fix resource replace in cache. * fix(provider_handler): REmove indent. * fix(hcl_handler): Skip modules without version attribute. * fix(action_integration_test): Fix repo name to source repo. (#37) * Revert "fix(action_integration_test): Fix repo name to source repo. (#37)" This reverts commit 67adea48feca8db20c4cf3ccc1b79414944ffb33. * fix(action_integration_test): Switch update test to secrets.github_token, so that it can be replaced with a pat. * feat(action_integration_test): Add condition to use token from secrets if available. * fix(action_integration_test): Fix token variable assignment. * Revert "fix(action_integration_test): Fix token variable assignment." This reverts commit d488e16dc046449a373d3ebbdc43b07802c187ba. * Revert "feat(action_integration_test): Add condition to use token from secrets if available." This reverts commit e99cc378879ffc3d84e6cbedbb2a3d8dd238bffb. * Revert "fix(action_integration_test): Switch update test to secrets.github_token, so that it can be replaced with a pat." This reverts commit 0ea227cac940af3d5609fe412faa14dbe7125db2. --- .devcontainer/devcontainer.json | 3 +- .github/workflows/action_integration_test.yml | 118 +++++----- .github/workflows/check_format_and_lint.yml | 28 ++- ...tion-test.yml => cli_integration_test.yml} | 157 ++++++------- .github/workflows/composition.yml | 35 +++ .github/workflows/unit_tests.yml | 52 +++++ .vscode/launch.json | 6 +- .vscode/settings.json | 98 ++++---- .vscode/tasks.json | 36 +++ README.md | 175 ++++++++++----- action.yml | 75 +++---- asset/infrapatch_help.png | Bin 107972 -> 26442 bytes asset/infrapatch_pr.png | Bin 0 -> 114880 bytes infrapatch/action/__main__.py | 211 +++++++++++------- infrapatch/action/config.py | 65 ++++++ infrapatch/action/tests/test_config.py | 102 +++++++++ infrapatch/cli/__main__.py | 86 ++++++- infrapatch/cli/cli.py | 67 ------ infrapatch/core/composition.py | 165 -------------- infrapatch/core/credentials_helper.py | 2 +- infrapatch/core/models/statistics.py | 57 +++++ .../models/tests/test_versioned_resource.py | 70 ++++++ .../test_versioned_terraform_resource.py | 82 +++++++ infrapatch/core/models/versioned_resource.py | 108 +++++++++ .../models/versioned_terraform_resources.py | 107 +-------- infrapatch/core/provider_handler.py | 159 +++++++++++++ infrapatch/core/provider_handler_builder.py | 58 +++++ infrapatch/core/providers/__init__.py | 0 .../core/providers/base_provider_interface.py | 27 +++ .../core/providers/terraform/__init__.py | 0 .../terraform/base_terraform_provider.py | 90 ++++++++ .../terraform/terraform_module_provider.py | 9 + .../terraform/terraform_provider_provider.py | 9 + infrapatch/core/utils/git.py | 38 ++++ infrapatch/core/utils/terraform/__init__.py | 0 .../{ => utils/terraform}/bin/hcledit_darwin | Bin .../{ => utils/terraform}/bin/hcledit_linux | Bin .../terraform}/bin/hcledit_windows.exe | Bin .../utils/{ => terraform}/hcl_edit_cli.py | 22 +- .../core/utils/{ => terraform}/hcl_handler.py | 74 ++++-- .../utils/{ => terraform}/registry_handler.py | 14 +- pyproject.toml | 7 +- python_version.txt | 1 + requirements-dev.txt | 5 +- requirements.txt | 3 +- setup.py | 4 +- 46 files changed, 1670 insertions(+), 755 deletions(-) rename .github/workflows/{cli-integration-test.yml => cli_integration_test.yml} (77%) create mode 100644 .github/workflows/composition.yml create mode 100644 .github/workflows/unit_tests.yml create mode 100644 asset/infrapatch_pr.png create mode 100644 infrapatch/action/config.py create mode 100644 infrapatch/action/tests/test_config.py delete mode 100644 infrapatch/cli/cli.py delete mode 100644 infrapatch/core/composition.py create mode 100644 infrapatch/core/models/statistics.py create mode 100644 infrapatch/core/models/tests/test_versioned_resource.py create mode 100644 infrapatch/core/models/tests/test_versioned_terraform_resource.py create mode 100644 infrapatch/core/models/versioned_resource.py create mode 100644 infrapatch/core/provider_handler.py create mode 100644 infrapatch/core/provider_handler_builder.py create mode 100644 infrapatch/core/providers/__init__.py create mode 100644 infrapatch/core/providers/base_provider_interface.py create mode 100644 infrapatch/core/providers/terraform/__init__.py create mode 100644 infrapatch/core/providers/terraform/base_terraform_provider.py create mode 100644 infrapatch/core/providers/terraform/terraform_module_provider.py create mode 100644 infrapatch/core/providers/terraform/terraform_provider_provider.py create mode 100644 infrapatch/core/utils/git.py create mode 100644 infrapatch/core/utils/terraform/__init__.py rename infrapatch/core/{ => utils/terraform}/bin/hcledit_darwin (100%) rename infrapatch/core/{ => utils/terraform}/bin/hcledit_linux (100%) rename infrapatch/core/{ => utils/terraform}/bin/hcledit_windows.exe (100%) mode change 100755 => 100644 rename infrapatch/core/utils/{ => terraform}/hcl_edit_cli.py (73%) rename infrapatch/core/utils/{ => terraform}/hcl_handler.py (58%) rename infrapatch/core/utils/{ => terraform}/registry_handler.py (93%) create mode 100644 python_version.txt diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ae1ccb3..dc79b90 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -32,7 +32,8 @@ "evendead.help-me-add", "charliermarsh.ruff", "streetsidesoftware.code-spell-checker", - "njqdev.vscode-python-typehint" + "njqdev.vscode-python-typehint", + "Cameron.vscode-pytest" ] } } diff --git a/.github/workflows/action_integration_test.yml b/.github/workflows/action_integration_test.yml index 8228a1e..83c5ea8 100644 --- a/.github/workflows/action_integration_test.yml +++ b/.github/workflows/action_integration_test.yml @@ -1,62 +1,56 @@ -name: "GitHub Action integration test" - -permissions: - contents: write - pull-requests: write - -on: - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - integration-test: - env: - report_json_file: InfraPatch_Statistics.json - - name: "Run GitHub Action integration test" - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Run in report only mode - uses: ./ - with: - report_only: true - - - name: Run in update mode - id: update - uses: ./ - with: - report_only: false - target_branch_name: "feat/infrapatch_test_${{ github.run_number }}" - - - name: Check update result - shell: pwsh - run: | - $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json - if ( -not $report.total_resources -gt 0 ) { - throw "Failed to get resources" - } - if ( -not ( $report.resources_patched -gt 3 ) ) { - throw "No resources should be patched" - } - if ( $report.errors -gt 0 ) { - throw "Errors have been detected" - } - - - name: Delete created branch$ - if: always() - uses: dawidd6/action-delete-branch@v3 - with: - github_token: ${{github.token}} - branches: ${{ steps.update.outputs.target_branch }} - soft_fail: true - - - - - - +name: "GitHub Action integration test" + +on: + workflow_call: + +jobs: + integration-test: + env: + report_json_file: InfraPatch_Statistics.json + + name: "Run GitHub Action integration test" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run in report only mode + uses: ./ + with: + report_only: true + + - name: Run in update mode + id: update + uses: ./ + with: + report_only: false + target_branch_name: "feat/infrapatch_test_${{ github.run_number }}" + + - name: Check update result + shell: pwsh + run: | + $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json + if ( -not $report.total_resources -gt 0 ) { + throw "Failed to get resources" + } + if ( -not ( $report.resources_patched -gt 3 ) ) { + throw "No resources should be patched" + } + if ( $report.errors -gt 0 ) { + throw "Errors have been detected" + } + + - name: Delete created branch$ + if: always() + uses: dawidd6/action-delete-branch@v3 + with: + branches: ${{ steps.update.outputs.target_branch }} + soft_fail: true + env: + GITHUB_TOKEN: ${{github.token}} + + + + + + diff --git a/.github/workflows/check_format_and_lint.yml b/.github/workflows/check_format_and_lint.yml index 10ae4a8..6753ea9 100644 --- a/.github/workflows/check_format_and_lint.yml +++ b/.github/workflows/check_format_and_lint.yml @@ -1,24 +1,27 @@ +name: "Check Format and Lint Code" + on: - pull_request: - types: - - opened - - synchronize - - reopened - - closed - branches: - - main + workflow_call: jobs: check_code: + name: "Check Format and Lint Code" runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 + + - name: Get Python Version + id: get_python_verion + run: | + python_version=$(cat python_version.txt) + echo "Using Python version $python_version" + echo "::set-output name=python_version::$(echo $python_version)" - name: Install Python uses: actions/setup-python@v2 with: - python-version: 3.11 + python-version: ${{ steps.get_python_verion.outputs.python_version }} - name: Install Dependencies run: | @@ -31,4 +34,9 @@ jobs: - name: Check code with ruff run: ruff check . - \ No newline at end of file + + + + + + diff --git a/.github/workflows/cli-integration-test.yml b/.github/workflows/cli_integration_test.yml similarity index 77% rename from .github/workflows/cli-integration-test.yml rename to .github/workflows/cli_integration_test.yml index 610f9a7..6752f28 100644 --- a/.github/workflows/cli-integration-test.yml +++ b/.github/workflows/cli_integration_test.yml @@ -1,78 +1,79 @@ -name: CLI Integration test - -on: - pull_request: - types: - - opened - - synchronize - - reopened - - closed - branches: - - main - -jobs: - test: - # only run if not closed or closed with merge - if: ${{ github.event.pull_request.merged == true || github.event.pull_request.state != 'closed' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - report_json_file: InfraPatch_Statistics.json - - strategy: - matrix: - os: - - macos-latest - - ubuntu-latest - # - windows-latest Windows does currently not work because of pygohcl - runs-on: ${{ matrix.os }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Python - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - - name: Install InfraPatch CLI - run: | - python -m pip install . - shell: bash - - - name: Run InfraPatch report - shell: bash - run: infrapatch --debug report --dump-json-statistics - - - name: Check report result - shell: pwsh - run: | - $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json - if ( -not $report.total_resources -gt 0 ) { - throw "Failed to get resources" - } - if ( $report.resources_patched -ne 0 ) { - throw "No resources should be patched" - } - if ( $report.errors -gt 0 ) { - throw "Errors have been detected" - } - - - name: Run InfraPatch update - shell: bash - run: infrapatch --debug update --dump-json-statistics --confirm - - - name: Check update result - shell: pwsh - run: | - $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json - if ( -not $report.total_resources -gt 0 ) { - throw "Failed to get resources" - } - if ( -not ( $report.resources_patched -gt 3 ) ) { - throw "No resources should be patched" - } - if ( $report.errors -gt 0 ) { - throw "Errors have been detected" - } - - +name: CLI Integration test + +on: + workflow_call: + +jobs: + cli_integration_test: + name: CLI Integration test + # only run if not closed or closed with merge + if: ${{ github.event.pull_request.merged == true || github.event.pull_request.state != 'closed' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + report_json_file: InfraPatch_Statistics.json + + strategy: + matrix: + os: + - macos-latest + - ubuntu-latest + # - windows-latest Windows does currently not work because of pygohcl + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get Python Version + id: get_python_verion + run: | + python_version=$(cat python_version.txt) + echo "Using Python version $python_version" + echo "::set-output name=python_version::$(echo $python_version)" + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: ${{ steps.get_python_verion.outputs.python_version }} + + - name: Install InfraPatch CLI + run: | + python -m pip install . + shell: bash + + - name: Run InfraPatch report + shell: bash + run: infrapatch --debug report --dump-json-statistics + + - name: Check report result + shell: pwsh + run: | + $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json + if ( -not $report.total_resources -gt 0 ) { + throw "Failed to get resources" + } + if ( $report.resources_patched -ne 0 ) { + throw "No resources should be patched" + } + if ( $report.errors -gt 0 ) { + throw "Errors have been detected" + } + + - name: Run InfraPatch update + shell: bash + run: infrapatch --debug update --dump-json-statistics --confirm + + - name: Check update result + shell: pwsh + run: | + $report = Get-Content $env:report_json_file -Raw | ConvertFrom-Json + if ( -not $report.total_resources -gt 0 ) { + throw "Failed to get resources" + } + if ( -not ( $report.resources_patched -gt 3 ) ) { + throw "At least 3 resources should be patched" + } + if ( $report.errors -gt 0 ) { + throw "Errors have been detected" + } + + diff --git a/.github/workflows/composition.yml b/.github/workflows/composition.yml new file mode 100644 index 0000000..85e11d0 --- /dev/null +++ b/.github/workflows/composition.yml @@ -0,0 +1,35 @@ +name: InfraPatch Checks + +permissions: + contents: write + pull-requests: write + +on: + pull_request: + types: + - opened + - synchronize + - reopened + branches: + - main + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + check_code: + uses: ./.github/workflows/check_format_and_lint.yml + + unit_tests: + needs: check_code + uses: ./.github/workflows/unit_tests.yml + + cli_integration_test: + needs: unit_tests + uses: ./.github/workflows/cli_integration_test.yml + + github_action_integration_test: + needs: unit_tests + uses: ./.github/workflows/action_integration_test.yml + diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml new file mode 100644 index 0000000..3807e5b --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,52 @@ +name: "Run Python Unit Tests" + + +on: + workflow_call: + +jobs: + integration-test: + name: "Run Unit Tests" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get Python Version + id: get_python_verion + run: | + python_version=$(cat python_version.txt) + echo "Using Python version $python_version" + echo "::set-output name=python_version::$(echo $python_version)" + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: ${{ steps.get_python_verion.outputs.python_version }} + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r requirements-dev.txt + + - name: Set timezone + uses: szenius/set-timezone@v1.2 + with: + timezoneLinux: 'Europe/Berlin' + + - name: Run pytest + uses: pavelzw/pytest-action@v2 + with: + verbose: true + emoji: true + job-summary: true + click-to-expand: true + report-title: 'InfraPatch Unit-Tests Report' + + + + + + + diff --git a/.vscode/launch.json b/.vscode/launch.json index b5472e0..7db06a0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "--debug", "report" ], - "justMyCode": true + "justMyCode": false }, { "name": "InfraPatch CLI: Update", @@ -21,7 +21,7 @@ "--debug", "update" ], - "justMyCode": true + "justMyCode": false }, { "name": "InfraPatch CLI: custom", @@ -29,7 +29,7 @@ "request": "launch", "module": "infrapatch.cli", "args": "${input:custom_args}", - "justMyCode": true + "justMyCode": false } ], "inputs": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index be312f9..549a43a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,43 +1,57 @@ -{ - "terminal.integrated.env.osx": { - "PYTHONPATH": "${workspaceFolder}", - }, - "terminal.integrated.env.linux": { - "PYTHONPATH": "${workspaceFolder}", - }, - "terminal.integrated.env.windows": { - "PYTHONPATH": "${workspaceFolder}", - }, - "[python]": { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll": true, - "source.organizeImports": true - }, - "editor.defaultFormatter": "charliermarsh.ruff" - }, - "files.autoSave": "afterDelay", - "python.analysis.inlayHints.functionReturnTypes": true, - "python.analysis.inlayHints.pytestParameters": true, - "python.analysis.inlayHints.variableTypes": true, - "python.languageServer": "Default", - "editor.defaultFormatter": "charliermarsh.ruff", - "python.missingPackage.severity": "Error", - "python.terminal.activateEnvInCurrentTerminal": true, - "cSpell.words": [ - "infrapatch" - ], - "editor.formatOnPaste": true, - "editor.formatOnSave": true, - "python.analysis.autoImportCompletions": true, - "python.analysis.fixAll": [ - "source.unusedImports", - "source.convertImportFormat" - ], - "python.analysis.typeCheckingMode": "basic", - "python.analysis.diagnosticMode": "workspace", - "editor.guides.indentation": false, - "editor.guides.bracketPairs": true, - "editor.guides.highlightActiveBracketPair": true, - "editor.guides.bracketPairsHorizontal": false, +{ + "terminal.integrated.env.osx": { + "PYTHONPATH": "${workspaceFolder}", + }, + "terminal.integrated.env.linux": { + "PYTHONPATH": "${workspaceFolder}", + }, + "terminal.integrated.env.windows": { + "PYTHONPATH": "${workspaceFolder}", + }, + "[python]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": true, + "source.organizeImports": true + }, + "editor.defaultFormatter": "charliermarsh.ruff" + }, + "files.autoSave": "onFocusChange", + "python.analysis.inlayHints.functionReturnTypes": true, + "python.analysis.inlayHints.pytestParameters": true, + "python.analysis.inlayHints.variableTypes": true, + "python.languageServer": "Default", + "editor.defaultFormatter": "charliermarsh.ruff", + "python.missingPackage.severity": "Error", + "python.terminal.activateEnvInCurrentTerminal": true, + "cSpell.words": [ + "infrapatch" + ], + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "python.analysis.autoImportCompletions": true, + "python.analysis.fixAll": [ + "source.unusedImports", + "source.convertImportFormat" + ], + "python.analysis.extraPaths": [], + "python.analysis.typeCheckingMode": "basic", + "python.analysis.diagnosticMode": "workspace", + "editor.guides.indentation": false, + "editor.guides.bracketPairs": true, + "editor.guides.highlightActiveBracketPair": true, + "editor.guides.bracketPairsHorizontal": false, + "python.defaultInterpreterPath": "/usr/local/bin/python", + "python.testing.pytestArgs": [ + "." + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "files.exclude": { + "**/__pycache__": true + }, + "python.analysis.autoSearchPaths": false, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a0992ef..d1ed7f4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -26,6 +26,42 @@ "reveal": "always" }, "problemMatcher": [] + }, + { + "label": "ruff auto-fix", + "type": "shell", + "command": "ruff", + "args": [ + "check", + ".", + "--fix" + ], + "presentation": { + "reveal": "always" + }, + "problemMatcher": [] + }, + { + "label": "pip install all dependencies", + "type": "shell", + "command": "pip3 install -r requirements.txt && pip3 install -r requirements-dev.txt", + "presentation": { + "reveal": "always" + }, + "problemMatcher": [] + }, + { + "label": "run tests (pytest)", + "type": "shell", + "command": "pytest", + "presentation": { + "reveal": "always" + }, + "problemMatcher": [], + "group": { + "kind": "test", + "isDefault": true + } } ] } \ No newline at end of file diff --git a/README.md b/README.md index 114b385..db64743 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,125 @@ -# infrapatch +# InfraPatch CLI Tool and GitHub Action to patch your Terraform Code -Infrapatch is a CLI tool and GitHub Action to patch the Provider and Module dependencies in your Terraform Code. +InfraPatch is a CLI tool and GitHub Action to patch the Provider and Module dependencies in your Terraform Code. The CLI works by scanning your .tf files for versioned providers and modules and then updating the version to the latest available version. +- [InfraPatch](#infrapatch) + - [GitHub Action](#github-action) + - [Example PR](#example-pr) + - [Providers](#providers) + - [Report only Mode](#report-only-mode) + - [Authentication](#authentication) + - [Working Directory](#working-directory) + - [CLI](#cli) + - [Supported Platforms](#supported-platforms) + - [Installation](#installation) + - [Usage](#usage) + - [Authentication](#authentication-1) + - [.terraformrc file:](#terraformrc-file) + - [infrapatch\_credentials.json file:](#infrapatch_credentialsjson-file) + + +## GitHub Action + +This repository contains a Github Action. +The Action can for example be run on a schedule to automatically update your code and open a PR with the changes to the head branch. + +The following example workflow runs once a day: + +```yaml +name: "InfraPatch" + +permissions: + contents: write + pull-requests: write + +on: + schedule: + - cron: '0 23 * * *' + workflow_dispatch: + +jobs: + infrapatch: + name: "Check Terraform Code for Updates" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run in update mode + uses: Noahnc/infrapatch@main + with: + report_only: false + +``` + +> **_NOTE:_** It's important to set the `fetch-depth: 0` in the Checkout step, otherwise rebases performed by InfraPatch will not work correctly. + +### Example PR + +InfraPatch will create a new branch with the changes and open a PR to the branch for which the Action was triggered. +The PR body contains a list for every enabled provider with the current and newest version. + +![InfraPatch Pull Request](asset/infrapatch_pr.png) + +### Providers + +InfraPatch supports individual providers to detect and patch versions. Currently, the following providers are available: +| Name | Description | +| ------------------- | -------------------------------------- | +| terraform_modules | Provider to patch Terraform Modules. | +| terraform_providers | Provider to patch Terraform Providers. | + +Per default, all providers are enabled. You can only enable specific providers by specifying the provider names as comma separated list in the input `enabled_providers`: + + ```yaml + - name: Run in update mode + uses: Noahnc/infrapatch@main + with: + enabled_providers: terraform_modules,terraform_providers + ``` + +### Report only Mode + +By default, the Action will create a Branch with all the changes and opens a PR to Branch for which the Action was triggered. +When setting the input `report_only` to `true`, the Action will only report available updates in the Action output. + +### Authentication + +If you use private registries in your Terraform project, you can specify credentials for the Action with the Input `terraform_registry_secrets`: + +```yaml + - name: Run in update mode + uses: Noahnc/infrapatch@main + with: + terraform_registry_secrets: | + spacelift.io=${{ secrets.SPACELIFT_API_TOKEN }} + = +``` + +Each secret must be specified in a new line with the following format: `=` + +### Working Directory + +By default, the Action will run in the root directory of the repository. If you want to only scan a subdirectory, you can specify a subdirectory with the `working_directory_relative` input: + +```yaml + - name: Run in update mode + uses: Noahnc/infrapatch@main + with: + working_directory: "path/to/terraform/code" +``` + + ## CLI -The follwoing chapter describes the CLI usage. +InfraPatch is also available as CLI to run locally. See the [Installation](#installation) section for more information on how to install the CLI. + +### Supported Platforms + +Currently, the CLI supports only MacOS and Linux, since the terraform parser used has no version available for Windows. ### Installation @@ -23,7 +137,7 @@ After the installation, InfraPatch can be run with the following command: ```bash infrapatch --help ``` -![infrapatch_help.png](asset%2Finfrapatch_help.png) +![infrapatch_help](asset/infrapatch_help.png) ### Usage @@ -68,56 +182,3 @@ You can also specify the path to the credentials file with the `--credentials-fi infrapatch --credentials-file-path "path/to/credentials/file" update ``` -### GitHub Action - -This repository also contains a GitHub Action. -The Action can for example be run on a schedule to automatically update your terraform code and open a PR with the changes. - -The following example workflow runs once a day: - -```yaml -name: "InfraPatch" - -permissions: - contents: write - pull-requests: write - -on: - schedule: - - cron: '0 23 * * *' - workflow_dispatch: - -jobs: - infrapatch: - name: "Check Terraform Code for Updates" - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Run in update mode - uses: Noahnc/infrapatch@main - with: - report_only: false -``` - -#### Report only Mode - -By default, the Action will create a Branch with all the changes and opens a PR to Branch for which the Action was triggered. -When setting the input `report_only` to `true`, the Action will only report available updates in the Action output. - -#### Authentication - -If you use private registries in your Terraform project, you can specify credentials for the Action with the Input `registry_secrets`: - -```yaml - - name: Run in update mode - uses: Noahnc/infrapatch@main - with: - report_only: false - registry_secrets: | - spacelift.io=${{ secrets.SPACELIFT_API_TOKEN }} - = -``` - -Each secret must be specified in a new line with the following format: `=` diff --git a/action.yml b/action.yml index f43adb2..232454b 100644 --- a/action.yml +++ b/action.yml @@ -22,21 +22,24 @@ inputs: description: "Git email to use for commits. Defaults to bot@infrapatch.ch" required: false default: "bot@infrapatch.ch" - github_token: - description: "GitHub access token. Defaults to github.token." - default: ${{ github.token }} report_only: description: "Only report new versions. Do not update files. Defaults to false" default: "false" required: true - registry_secrets: - description: "Registry secrets to use for private registries" + enabled_providers: + description: "Comma separated list of provider names to enable. Defaults to terraform_modules,terraform_providers" + default: "terraform_modules,terraform_providers" + required: true + terraform_registry_secrets: + description: "Registry secrets to use for private terraform registries. Needs to be a newline separated list of secrets in the format :. Defaults to empty" required: false default: "" - working_directory: - description: "Working directory to run the command in. Defaults to the root of the repository" + working_directory_relative: + description: "Working directory to run the action in. Defaults to the root of the repository" required: false - default: ${{ github.workspace }} + github_token: + description: "GitHub access token. Defaults to github.token." + default: ${{ github.token }} outputs: target_branch: description: "Name of the branch where changes will be pushed to" @@ -68,60 +71,40 @@ runs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + working-directory: ${{ github.action_path }} shell: bash - - name: Create target branch - id: create_branch - if: ${{ inputs.report_only == 'false' }} - uses: peterjgrainger/action-create-branch@v2.2.0 - env: - GITHUB_TOKEN: ${{ inputs.github_token }} - with: - branch: "refs/heads/${{ inputs.target_branch_name }}" - - name: Configure git if: ${{ inputs.report_only }} == 'false' }} - working-directory: ${{ inputs.working_directory }} shell: bash run: | git config --global user.name "${{ inputs.git_user }}" git config --global user.email "${{ inputs.git_email }}" - - name: Switch to target branch - if: ${{ inputs.report_only == 'false' }} - working-directory: ${{ inputs.working_directory }} - shell: bash - run: | - git fetch origin - git checkout -b "${{ steps.branch.outputs.target }}" "${{ steps.branch.outputs.target_origin }}" - - - name: Rebase target branch - if: ${{ steps.create_branch.outputs.created == 'false' }} - working-directory: ${{ inputs.working_directory }} - shell: bash - run: | - echo "Rebasing ${{ steps.branch.outputs.target }} on ${{ steps.branch.outputs.head_origin }}" - git rebase -Xtheirs ${{ steps.branch.outputs.head_origin }} - - name: Run InfraPatch Action + shell: bash + working-directory: ${{ github.action_path }} run: | module="infrapatch.action" arguments=() if [ "${{ runner.debug }}" == "1" ]; then arguments+=("--debug") fi - if [ "${{ inputs.report_only }}" == "true" ]; then - arguments+=("--report-only") - fi - if [ "${{ inputs.registry_secrets }}" != "" ]; then - arguments+=("--registry-secrets-string" "\"${{ inputs.registry_secrets }}\"") - fi - arguments+=("--github-token" "${{ inputs.github_token }}") - arguments+=("--head-branch" "${{ steps.branch.outputs.head }}") - arguments+=("--target-branch" "${{ steps.branch.outputs.target }}") - arguments+=("--repository-name" "${{ inputs.repository_name }}") - arguments+=("--working-directory" "${{ inputs.working_directory }}") - arguments+=("--default-registry-domain" "${{ inputs.default_registry_domain }}") python -m "$module" "${arguments[@]}" + env: + # Config from inputs + GITHUB_TOKEN: ${{ inputs.github_token }} + DEFAULT_REGISTRY_DOMAIN: ${{ inputs.DEFAULT_REGISTRY_DOMAIN }} + REPOSITORY_NAME: ${{ inputs.repository_name }} + REPORT_ONLY: ${{ inputs.report_only }} + TERRAFORM_REGISTRY_SECRET_STRING: ${{ inputs.terraform_registry_secrets }} + WORKING_DIRECTORY_RELATIVE: ${{ inputs.working_directory_relative }} + ENABLED_PROVIDERS: ${{ inputs.enabled_providers }} + + REPOSITORY_ROOT: ${{ github.workspace }} + + # Calculated config from other steps + HEAD_BRANCH: ${{ steps.branch.outputs.head }} + TARGET_BRANCH: ${{ steps.branch.outputs.target }} diff --git a/asset/infrapatch_help.png b/asset/infrapatch_help.png index ef7f5b0977533f9f9c61a1a403dfc93593cf2df1..1df2e5ab3571ebcbd8dca46e1b5868239520bf57 100644 GIT binary patch literal 26442 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 Z2DgG{#yr=|{#JuhlvS0fkTU!5-v9^XT08&% literal 107972 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
YjP*@E)cy4~?W-k|Cy_#5 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 RbQk!id(H6IB5j+;{{y40U*7-# diff --git a/asset/infrapatch_pr.png b/asset/infrapatch_pr.png new file mode 100644 index 0000000000000000000000000000000000000000..aa493367a6fb0657e7da8598438cb047acebb984 GIT binary patch literal 114880 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 ?n&>z5)Hk9(gZ=XIJ4L^9>Bs?O8r$^vDM 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 literal 0 HcmV?d00001 diff --git a/infrapatch/action/__main__.py b/infrapatch/action/__main__.py index 27f0bd6..6c512ef 100644 --- a/infrapatch/action/__main__.py +++ b/infrapatch/action/__main__.py @@ -1,109 +1,150 @@ import logging as log -import subprocess -from pathlib import Path +from typing import Union import click -from github import Auth, Github +from github import Auth, Github, GithubException from github.PullRequest import PullRequest +from github.Repository import Repository -from infrapatch.core.composition import build_main_handler +from infrapatch.action.config import ActionConfigProvider from infrapatch.core.log_helper import catch_exception, setup_logging -from infrapatch.core.models.versioned_terraform_resources import get_upgradable_resources +from infrapatch.core.provider_handler import ProviderHandler +from infrapatch.core.provider_handler_builder import ProviderHandlerBuilder +from infrapatch.core.utils.git import Git @click.group(invoke_without_command=True) @click.option("--debug", is_flag=True) -@click.option("--default-registry-domain") -@click.option("--registry-secrets-string", default=None) -@click.option("--github-token") -@click.option("--target-branch") -@click.option("--head-branch") -@click.option("--repository-name") -@click.option("--report-only", is_flag=True) -@click.option("--working-directory") @catch_exception(handle=Exception) -def main( - debug: bool, - default_registry_domain: str, - registry_secrets_string: str, - github_token: str, - target_branch: str, - head_branch: str, - repository_name: str, - report_only: bool, - working_directory: Path, -): +def main(debug: bool): setup_logging(debug) - log.debug( - f"Running infrapatch with the following parameters: " - f"default_registry_domain={default_registry_domain}, " - f"registry_secrets_string={registry_secrets_string}, " - f"github_token={github_token}, " - f"report_only={report_only}, " - f"working_directory={working_directory}" - ) - credentials = {} - working_directory = Path(working_directory) - if registry_secrets_string is not None: - credentials = get_credentials_from_string(registry_secrets_string) - main_handler = build_main_handler(default_registry_domain=default_registry_domain, credentials_dict=credentials) - resources = main_handler.get_all_terraform_resources(working_directory) - - if report_only: - main_handler.print_resource_table(resources) + + config = ActionConfigProvider() + + git = Git(config.repository_root) + github = Github(auth=Auth.Token(config.github_token)) + github_repo = github.get_repo(config.repository_name) + github_head_branch = github_repo.get_branch(config.head_branch) + + if len(config.enabled_providers) == 0: + raise Exception("No providers enabled. Please enable at least one provider.") + + builder = ProviderHandlerBuilder(config.working_directory) + builder.with_git_integration(config.repository_root) + if "terraform_modules" in config.enabled_providers or "terraform_providers" in config.enabled_providers: + builder.add_terraform_registry_configuration(config.default_registry_domain, config.terraform_registry_secrets) + if "terraform_modules" in config.enabled_providers: + builder.with_terraform_module_provider() + if "terraform_providers" in config.enabled_providers: + builder.with_terraform_provider_provider() + + provider_handler = builder.build() + + git.fetch_origin() + + try: + github_target_branch = github_repo.get_branch(config.target_branch) + except GithubException: + github_target_branch = None + + upgradable_resources_head_branch = None + pr = None + if github_target_branch is not None and config.report_only is False: + pr = get_pr(github_repo, head=config.target_branch, base=config.head_branch) + if pr is not None: + upgradable_resources_head_branch = provider_handler.get_upgradable_resources() + log.info(f"Branch {config.target_branch} already exists. Checking out...") + git.checkout_branch(config.target_branch, f"origin/{config.target_branch}") + + log.info(f"Rebasing branch {config.target_branch} onto origin/{config.head_branch}") + git.run_git_command(["rebase", "-Xtheirs", f"origin/{config.head_branch}"]) + git.push(["-f", "-u", "origin", config.target_branch]) + + provider_handler.print_resource_table(only_upgradable=True, disable_cache=True) + + if config.report_only: log.info("Report only mode is enabled. No changes will be applied.") return - upgradable_resources = get_upgradable_resources(resources) - if len(upgradable_resources) == 0: - log.info("No upgradable resources found.") + if provider_handler.check_if_upgrades_available() is False: + log.info("No resources with pending upgrade found.") + if pr is not None and upgradable_resources_head_branch is not None: + log.info("Updating PR Body...") + provider_handler.set_resources_patched_based_on_existing_resources(upgradable_resources_head_branch) + update_pr_body(pr, provider_handler) return - main_handler.update_resources(upgradable_resources, True, working_directory, True) - main_handler.dump_statistics(upgradable_resources, save_as_json_file=True) + if github_target_branch is None: + log.info(f"Branch {config.target_branch} does not exist. Creating and checking out...") + github_repo.create_git_ref(ref=f"refs/heads/{config.target_branch}", sha=github_head_branch.commit.sha) + git.checkout_branch(config.target_branch, f"origin/{config.head_branch}") - push_changes(target_branch, working_directory) + provider_handler.upgrade_resources() + if upgradable_resources_head_branch is not None: + log.info("Updating status of resources from previous branch...") + provider_handler.set_resources_patched_based_on_existing_resources(upgradable_resources_head_branch) - create_pr(github_token, head_branch, repository_name, target_branch) + provider_handler.print_statistics_table() + provider_handler.dump_statistics() + git.push(["-f", "-u", "origin", config.target_branch]) -def push_changes(target_branch, working_directory): - command = ["git", "push", "-f", "-u", "origin", target_branch] - log.debug(f"Executing command: {' '.join(command)}") - try: - result = subprocess.run(command, capture_output=True, text=True, cwd=working_directory.absolute().as_posix()) - except Exception as e: - raise Exception(f"Error pushing to remote: {e}") - if result.returncode != 0: - log.error(f"Stdout: {result.stdout}") - raise Exception(f"Error pushing to remote: {result.stderr}") - - -def create_pr(github_token, head_branch, repository_name, target_branch) -> PullRequest: - token = Auth.Token(github_token) - github = Github(auth=token) - repo = github.get_repo(repository_name) - pull = repo.get_pulls(state="open", sort="created", base=head_branch, head=target_branch) - if pull.totalCount != 0: - log.info(f"Pull request found from '{target_branch}' to '{head_branch}'") - return pull[0] - log.info(f"No pull request found from '{target_branch}' to '{head_branch}'. Creating a new one.") - return repo.create_pull(title="InfraPatch Module and Provider Update", body="InfraPatch Module and Provider Update", base=head_branch, head=target_branch) - - -def get_credentials_from_string(credentials_string: str) -> dict: - credentials = {} - if credentials_string == "": - return credentials - for line in credentials_string.splitlines(): - try: - name, token = line.split("=", 1) - except ValueError as e: - log.debug(f"Secrets line '{line}' could not be split into name and token.") - raise Exception(f"Error processing secrets: '{e}'") - # add the name and token to the credentials dict - credentials[name] = token - return credentials + if pr is not None: + update_pr_body(pr, provider_handler) + return + create_pr(github_repo, config.head_branch, config.target_branch, provider_handler) + + +def update_pr_body(pr, provider_handler): + if pr is not None: + log.info("Updating existing pull request with new body.") + body = get_pr_body(provider_handler) + log.debug(f"Pull request body:\n{body}") + pr.edit(body=body) + return + + +def get_pr_body(provider_handler: ProviderHandler) -> str: + body = "" + markdown_tables = provider_handler.get_markdown_table_for_changed_resources() + for table in markdown_tables: + body += table.dumps() + body += "\n" + + body += provider_handler._get_statistics().get_markdown_table().dumps() + body += "\n" + return body + + +def get_pr(repo: Repository, base: str, head: str) -> Union[PullRequest, None]: + base_ref = base + head_ref = head + if base_ref.startswith("origin/"): + base_ref = base_ref[len("origin/") :] + if head_ref.startswith("origin/"): + head_ref = head_ref[len("origin/") :] + pulls = repo.get_pulls(state="open", sort="created", direction="desc") + + if pulls.totalCount == 0: + log.debug("No pull request found") + return None + + pr = [pr for pr in pulls if pr.base.ref == base_ref and pr.head.ref == head_ref] + if len(pr) == 0: + log.debug(f"No pull request found from '{head}' to '{base}'.") + return None + elif len(pr) == 1: + log.debug(f"Pull request found from '{head}' to '{base}'.") + return pr[0] + if len(pr) > 1: + raise Exception(f"Multiple pull requests found from '{head}' to '{base}'.") + + +def create_pr(repo: Repository, head_branch: str, target_branch: str, provider_handler: ProviderHandler) -> PullRequest: + body = get_pr_body(provider_handler) + log.info(f"Creating new pull request from '{target_branch}' to '{head_branch}'.") + log.debug(f"Pull request body:\n{body}") + return repo.create_pull(title="InfraPatch Module and Provider Update", body=body, base=head_branch, head=target_branch) if __name__ == "__main__": diff --git a/infrapatch/action/config.py b/infrapatch/action/config.py new file mode 100644 index 0000000..b522372 --- /dev/null +++ b/infrapatch/action/config.py @@ -0,0 +1,65 @@ +import logging as log +import os +from pathlib import Path +from typing import Any + + +class MissingConfigException(Exception): + pass + + +class ActionConfigProvider: + github_token: str + head_branch: str + target_branch: str + repository_name: str + default_registry_domain: str + working_directory: Path + enabled_providers: list[str] + repository_root: Path + report_only: bool + terraform_registry_secrets: dict[str, str] + + def __init__(self) -> None: + self.github_token = _get_value_from_env("GITHUB_TOKEN", secret=True) + self.head_branch = _get_value_from_env("HEAD_BRANCH") + self.target_branch = _get_value_from_env("TARGET_BRANCH") + self.repository_name = _get_value_from_env("REPOSITORY_NAME") + self.repository_root = Path(_get_value_from_env("REPOSITORY_ROOT")) + self.enabled_providers = _get_value_from_env("ENABLED_PROVIDERS", default="").split(",") + self.working_directory = self.repository_root.joinpath(_get_value_from_env("WORKING_DIRECTORY_RELATIVE", default="")) + self.default_registry_domain = _get_value_from_env("DEFAULT_REGISTRY_DOMAIN") + self.terraform_registry_secrets = _get_credentials_from_string(_get_value_from_env("TERRAFORM_REGISTRY_SECRET_STRING", secret=True, default="")) + self.report_only = _from_env_to_bool(_get_value_from_env("REPORT_ONLY", default="False").lower()) + + +def _get_value_from_env(key: str, secret: bool = False, default: Any = None) -> Any: + if key in os.environ: + log_value = os.environ[key] + if secret: + log_value = f"{log_value[:3]}***" + log.debug(f"Found the following value for {key}: {log_value}") + return os.environ[key] + if default is not None: + log.debug(f"Using default value for {key}: {default}") + return default + raise MissingConfigException(f"Missing configuration for key: {key}") + + +def _get_credentials_from_string(credentials_string: str) -> dict[str, str]: + credentials = {} + if credentials_string == "": + return credentials + for line in credentials_string.splitlines(): + try: + name, token = line.split("=", 1) + except ValueError as e: + log.debug(f"Secrets line '{line}' could not be split into name and token.") + raise Exception(f"Error processing secrets: '{e}'") + # add the name and token to the credentials dict + credentials[name] = token + return credentials + + +def _from_env_to_bool(value: str) -> bool: + return value.lower() in ["true", "1", "yes", "y", "t"] diff --git a/infrapatch/action/tests/test_config.py b/infrapatch/action/tests/test_config.py new file mode 100644 index 0000000..ba8d1e6 --- /dev/null +++ b/infrapatch/action/tests/test_config.py @@ -0,0 +1,102 @@ +import os +from pathlib import Path + +import pytest + +from infrapatch.action.config import ActionConfigProvider, MissingConfigException, _from_env_to_bool, _get_credentials_from_string, _get_value_from_env + + +def test_get_credentials_from_string(): + # Test case 1: Empty credentials string + credentials_string = "" + expected_result = {} + assert _get_credentials_from_string(credentials_string) == expected_result + + # Test case 2: Single line credentials string + credentials_string = "username=abc123" + expected_result = {"username": "abc123"} + assert _get_credentials_from_string(credentials_string) == expected_result + + # Test case 3: Multiple line credentials string + credentials_string = "username=abc123\npassword=xyz789\ntoken=123456" + expected_result = {"username": "abc123", "password": "xyz789", "token": "123456"} + assert _get_credentials_from_string(credentials_string) == expected_result + + # Test case 4: Invalid credentials string + credentials_string = "username=abc123\npassword" + try: + _get_credentials_from_string(credentials_string) + except Exception as e: + assert str(e) == "Error processing secrets: 'not enough values to unpack (expected 2, got 1)'" + + +def test_get_value_from_env(): + # Test case 1: Value exists in os.environ + os.environ["TEST_VALUE"] = "abc123" + assert _get_value_from_env("TEST_VALUE") == "abc123" + + # Test case 2: Value does not exist in os.environ + os.environ.clear() + try: + _get_value_from_env("TEST_VALUE") + except MissingConfigException as e: + assert str(e) == "Missing configuration for key: TEST_VALUE" + + # Test case 3: Value does not exist in os.environ, but default is provided + assert _get_value_from_env("TEST_VALUE", default="abc123") == "abc123" + + +@pytest.mark.parametrize("working_directory_relative_path", ["/working/directory", ""], ids=lambda d: f"x={d}") +def test_action_config_init(working_directory_relative_path): + # Test case 1: All values exist in os.environ + os.environ["GITHUB_TOKEN"] = "abc123" + os.environ["HEAD_BRANCH"] = "main" + os.environ["TARGET_BRANCH"] = "develop" + os.environ["REPOSITORY_NAME"] = "my-repo" + os.environ["REPOSITORY_ROOT"] = "/repository/root" + os.environ["WORKING_DIRECTORY_RELATIVE"] = working_directory_relative_path + os.environ["DEFAULT_REGISTRY_DOMAIN"] = "registry.example.com" + os.environ["TERRAFORM_REGISTRY_SECRET_STRING"] = "test_registry.ch=abc123" + os.environ["REPORT_ONLY"] = "False" + + config = ActionConfigProvider() + + assert config.github_token == "abc123" + assert config.head_branch == "main" + assert config.target_branch == "develop" + assert config.repository_name == "my-repo" + assert config.working_directory == config.repository_root.joinpath(working_directory_relative_path) + assert config.repository_root == Path("/repository/root") + assert config.default_registry_domain == "registry.example.com" + assert config.terraform_registry_secrets == {"test_registry.ch": "abc123"} + assert config.report_only is False + + # Test case 2: Missing values in os.environ + os.environ.clear() + try: + config = ActionConfigProvider() + except MissingConfigException as e: + assert str(e).__contains__("Missing configuration for key") + + +def test_env_to_bool(): + # Test case 1: True values + assert _from_env_to_bool("true") is True + assert _from_env_to_bool("1") is True + assert _from_env_to_bool("yes") is True + assert _from_env_to_bool("y") is True + assert _from_env_to_bool("t") is True + + # Test case 2: False values + assert _from_env_to_bool("false") is False + assert _from_env_to_bool("0") is False + assert _from_env_to_bool("no") is False + assert _from_env_to_bool("n") is False + assert _from_env_to_bool("f") is False + + # Test case 3: Case-insensitive + assert _from_env_to_bool("True") is True + assert _from_env_to_bool("FALSE") is False + assert _from_env_to_bool("YeS") is True + assert _from_env_to_bool("N") is False + assert _from_env_to_bool("T") is True diff --git a/infrapatch/cli/__main__.py b/infrapatch/cli/__main__.py index 5be3a36..2962812 100644 --- a/infrapatch/cli/__main__.py +++ b/infrapatch/cli/__main__.py @@ -1,8 +1,88 @@ -from infrapatch.cli import cli +from pathlib import Path +from typing import Union +import click -def main(): - cli.main() +from infrapatch.cli.__init__ import __version__ +from infrapatch.core.credentials_helper import get_registry_credentials +from infrapatch.core.log_helper import catch_exception, setup_logging +from infrapatch.core.provider_handler import ProviderHandler +from infrapatch.core.provider_handler_builder import ProviderHandlerBuilder +from infrapatch.core.utils.terraform.hcl_edit_cli import HclEditCli +from infrapatch.core.utils.terraform.hcl_handler import HclHandler + +provider_handler: Union[ProviderHandler, None] = None + + +@click.group(invoke_without_command=True) +@click.option("--debug", is_flag=True, help="Enable debug logging.") +@click.option("--version", is_flag=True, help="Prints the version of the tool.") +@click.option("--working-directory-path", default=None, help="Working directory to run. Defaults to the current working directory") +@click.option("--credentials-file-path", default=None, help="Path to a file containing credentials for private registries.") +@click.option("--default-registry-domain", default="registry.terraform.io", help="Default registry domain for resources without a specified domain.") +@catch_exception(handle=Exception) +def main(debug: bool, version: bool, working_directory_path: str, credentials_file_path: str, default_registry_domain: str): + if version: + print(f"You are running infrapatch version: {__version__}") + exit(0) + setup_logging(debug) + + global provider_handler + credentials_file = None + working_directory = Path.cwd() + + if working_directory_path is not None: + working_directory = Path(working_directory_path) + if not working_directory.exists() or not working_directory.is_dir(): + raise Exception(f"Project root '{working_directory.absolute().as_posix()}' does not exist.") + + if credentials_file_path is not None: + credentials_file = Path(credentials_file_path) + if not credentials_file.exists() or not credentials_file.is_file(): + raise Exception(f"Credentials file '{credentials_file}' does not exist.") + credentials = get_registry_credentials(HclHandler(HclEditCli()), credentials_file) + provider_builder = ProviderHandlerBuilder(working_directory) + provider_builder.add_terraform_registry_configuration(default_registry_domain, credentials) + provider_builder.with_terraform_module_provider() + provider_builder.with_terraform_provider_provider() + provider_handler = provider_builder.build() + + +# noinspection PyUnresolvedReferences +@main.command() +@click.option("--only-upgradable", is_flag=True, help="Only show providers and modules that can be upgraded.") +@click.option("--dump-json-statistics", is_flag=True, help="Creates a json file containing statistics about the found resources and there update status as json file in the cwd.") +@catch_exception(handle=Exception) +def report(only_upgradable: bool, dump_json_statistics: bool): + """Finds all modules and providers in the project_root and prints the newest version.""" + if provider_handler is None: + raise Exception("provider_handler not initialized.") + provider_handler.print_resource_table(only_upgradable) + provider_handler.print_statistics_table() + if dump_json_statistics: + provider_handler.dump_statistics() + + +@main.command() +@click.option("--confirm", is_flag=True, help="Apply changes without confirmation.") +@click.option("--dump-json-statistics", is_flag=True, help="Creates a json file containing statistics about the updated resources in the cwd.") +@catch_exception(handle=Exception) +def update(confirm: bool, dump_json_statistics: bool): + """Finds all modules and providers in the project_root and updates them to the newest version.""" + global provider_handler + if provider_handler is None: + raise Exception("main_handler not initialized.") + + provider_handler.print_resource_table(only_upgradable=True) + if not confirm: + if not click.confirm("Do you want to apply the changes?"): + print("Aborting...") + return + + provider_handler.upgrade_resources() + provider_handler.print_statistics_table() + if dump_json_statistics: + provider_handler.dump_statistics() if __name__ == "__main__": diff --git a/infrapatch/cli/cli.py b/infrapatch/cli/cli.py deleted file mode 100644 index 0d632b4..0000000 --- a/infrapatch/cli/cli.py +++ /dev/null @@ -1,67 +0,0 @@ -from pathlib import Path -from typing import Union - -import click - -from infrapatch.cli.__init__ import __version__ -from infrapatch.core.composition import MainHandler, build_main_handler -from infrapatch.core.log_helper import catch_exception, setup_logging - -main_handler: Union[MainHandler, None] = None - - -@click.group(invoke_without_command=True) -@click.option("--debug", is_flag=True, help="Enable debug logging.") -@click.option("--version", is_flag=True, help="Prints the version of the tool.") -@click.option("--credentials-file-path", default=None, help="Path to a file containing credentials for private registries.") -@click.option("--default_registry_domain", default="registry.terraform.io", help="Default registry domain for resources without a specified domain.") -@catch_exception(handle=Exception) -def main(debug: bool, version: bool, credentials_file_path: str, default_registry_domain: str): - if version: - print(f"You are running infrapatch version: {__version__}") - exit(0) - setup_logging(debug) - global main_handler - credentials_file = None - if credentials_file_path is not None: - credentials_file = Path(credentials_file_path) - main_handler = build_main_handler(default_registry_domain, credentials_file) - - -# noinspection PyUnresolvedReferences -@main.command() -@click.option("--project-root-path", default=None, help="Root directory of the project. If not specified, the current working directory is used.") -@click.option("--only-upgradable", is_flag=True, help="Only show providers and modules that can be upgraded.") -@click.option("--dump-json-statistics", is_flag=True, help="Creates a json file containing statistics about the found resources and there update status as json file in the cwd.") -@catch_exception(handle=Exception) -def report(project_root_path: str, only_upgradable: bool, dump_json_statistics: bool): - """Finds all modules and providers in the project_root and prints the newest version.""" - if project_root_path is None: - project_root = Path.cwd() - else: - project_root = Path(project_root_path) - global main_handler - if main_handler is None: - raise Exception("main_handler not initialized.") - resources = main_handler.get_all_terraform_resources(project_root) - main_handler.print_resource_table(resources, only_upgradable) - main_handler.dump_statistics(resources, dump_json_statistics) - - -@main.command() -@click.option("--project-root-path", default=None, help="Root directory of the project. If not specified, the current working directory is used.") -@click.option("--confirm", is_flag=True, help="Apply changes without confirmation.") -@click.option("--dump-json-statistics", is_flag=True, help="Creates a json file containing statistics about the updated resources in the cwd.") -@catch_exception(handle=Exception) -def update(project_root_path: str, confirm: bool, dump_json_statistics: bool): - """Finds all modules and providers in the project_root and updates them to the newest version.""" - if project_root_path is None: - project_root = Path.cwd() - else: - project_root = Path(project_root_path) - global main_handler - if main_handler is None: - raise Exception("main_handler not initialized.") - resources = main_handler.get_all_terraform_resources(project_root) - main_handler.update_resources(resources, confirm, Path(project_root)) - main_handler.dump_statistics(resources, dump_json_statistics) diff --git a/infrapatch/core/composition.py b/infrapatch/core/composition.py deleted file mode 100644 index 9bd410f..0000000 --- a/infrapatch/core/composition.py +++ /dev/null @@ -1,165 +0,0 @@ -import json -import logging as log -from pathlib import Path -from typing import Sequence, Union - -import click -from git import Repo -from rich import progress -from rich.console import Console -from rich.table import Table - -import infrapatch.core.constants as cs -from infrapatch.core.credentials_helper import get_registry_credentials -from infrapatch.core.models.versioned_terraform_resources import ( - VersionedTerraformResource, - TerraformModule, - TerraformProvider, - get_upgradable_resources, - ResourceStatus, - from_terraform_resources_to_dict_list, -) -from infrapatch.core.utils.hcl_edit_cli import HclEditCliException, HclEditCli -from infrapatch.core.utils.hcl_handler import HclHandler -from infrapatch.core.utils.registry_handler import RegistryHandler - - -def build_main_handler(default_registry_domain: str, credentials_file: Union[Path, None] = None, credentials_dict: Union[dict, None] = None): - hcl_edit_cli = HclEditCli() - hcl_handler = HclHandler(hcl_edit_cli) - if credentials_dict is None: - credentials_dict = get_registry_credentials(hcl_handler, credentials_file) - registry_handler = RegistryHandler(default_registry_domain, credentials_dict) - return MainHandler(hcl_handler, registry_handler, Console(width=cs.CLI_WIDTH)) - - -class MainHandler: - def __init__(self, hcl_handler: HclHandler, registry_handler: RegistryHandler, console: Console): - self.hcl_handler = hcl_handler - self.registry_handler = registry_handler - self._console = console - - def get_all_terraform_resources(self, project_root: Path) -> Sequence[VersionedTerraformResource]: - log.info(f"Searching for .tf files in {project_root.absolute().as_posix()} ...") - terraform_files = self.hcl_handler.get_all_terraform_files(project_root) - if len(terraform_files) == 0: - return [] - resources = [] - for terraform_file in progress.track(terraform_files, description="Parsing .tf files..."): - resources.extend(self.hcl_handler.get_terraform_resources_from_file(terraform_file)) - for resource in progress.track(resources, description="Getting newest resource versions..."): - resource.newest_version = self.registry_handler.get_newest_version(resource) - return resources - - def print_resource_table(self, resources: Sequence[VersionedTerraformResource], only_upgradable: bool = False): - if len(resources) == 0: - print("No resources found.") - return - provider_resources = [resource for resource in resources if isinstance(resource, TerraformProvider)] - module_resources = [resource for resource in resources if isinstance(resource, TerraformModule)] - - if only_upgradable: - upgradeable_provider_resources = [resource for resource in provider_resources if not resource.installed_version_equal_or_newer_than_new_version()] - upgradeable_module_resources = [resource for resource in module_resources if not resource.installed_version_equal_or_newer_than_new_version()] - if len(upgradeable_module_resources) == 0 and len(upgradeable_provider_resources) == 0: - print("All resources are up to date.") - return - if len(upgradeable_module_resources) > 0: - self._compose_resource_table(upgradeable_module_resources, "Upgradeable Modules") - else: - print("No upgradeable modules found.") - if len(upgradeable_provider_resources) > 0: - self._compose_resource_table(upgradeable_provider_resources, "Upgradeable Providers") - else: - print("No upgradeable providers found.") - return - if len(module_resources) > 0: - sorted_module_resources = sorted(module_resources, key=lambda resource: resource.installed_version_equal_or_newer_than_new_version()) - self._compose_resource_table(sorted_module_resources, "Modules") - else: - print("No modules found.") - if len(provider_resources) > 0: - sorted_provider_resources = sorted(provider_resources, key=lambda resource: resource.installed_version_equal_or_newer_than_new_version()) - self._compose_resource_table(sorted_provider_resources, "Providers") - else: - print("No providers found.") - - # noinspection PyUnboundLocalVariable - def update_resources( - self, resources: Sequence[VersionedTerraformResource], confirm: bool, working_dir: Path, commit_changes: bool = False - ) -> Sequence[VersionedTerraformResource]: - upgradable_resources = get_upgradable_resources(resources) - if len(upgradable_resources) == 0: - log.info("All resources are up to date, nothing to do.") - return [] - repo: Union[Repo, None] = None - if commit_changes: - repo = Repo(path=working_dir.absolute().as_posix()) - if repo.bare: - raise Exception("Working directory is not a git repository.") - log.info(f"Committing changes to git branch '{repo.active_branch.name}'.") - self.print_resource_table(resources, True) - if not confirm: - if not click.confirm("Do you want to apply the changes?"): - print("Aborting...") - return [] - for resource in progress.track(upgradable_resources, description="Updating resource versions..."): - try: - self.hcl_handler.bump_resource_version(resource) - except HclEditCliException as e: - log.error(f"Could not update resource '{resource.name}': {e}") - resource.set_patch_error() - continue - if commit_changes: - if repo is None: - raise Exception("repo is None.") - repo.index.add([resource.source_file.absolute().as_posix()]) - repo.index.commit(f"Bump {resource.resource_name} '{resource.name}' from version '{resource.current_version}' to '{resource.newest_version}'.") - resource.set_patched() - return upgradable_resources - - def _compose_resource_table(self, resources: Sequence[VersionedTerraformResource], title: str): - table = Table(show_header=True, title=title, expand=True) - table.add_column("Name", overflow="fold") - table.add_column("Source", overflow="fold") - table.add_column("Current") - table.add_column("Newest") - table.add_column("Upgradeable") - for resource in resources: - table.add_row(resource.name, resource.source, resource.current_version, resource.newest_version, str(not resource.installed_version_equal_or_newer_than_new_version())) - self._console.print(table) - - def dump_statistics(self, resources, save_as_json_file: bool = False): - providers = [resource for resource in resources if isinstance(resource, TerraformProvider)] - modules = [resource for resource in resources if isinstance(resource, TerraformModule)] - statistics = {} - statistics["errors"] = len([resource for resource in resources if resource.status == ResourceStatus.PATCH_ERROR]) - statistics["resources_patched"] = len([resource for resource in resources if resource.status == ResourceStatus.PATCHED]) - statistics["resources_pending_update"] = len([resource for resource in resources if resource.check_if_up_to_date() is False]) - statistics["total_resources"] = len(resources) - statistics["modules_count"] = len(modules) - statistics["providers_count"] = len(providers) - statistics["modules"] = from_terraform_resources_to_dict_list(modules) - statistics["providers"] = from_terraform_resources_to_dict_list(providers) - if save_as_json_file: - file = Path(f"{cs.APP_NAME}_Statistics.json") - if file.exists(): - file.unlink() - with open(file, "w") as f: - f.write(json.dumps(statistics)) - table = Table(show_header=True, title="Statistics", expand=True) - table.add_column("Total Resources") - table.add_column("Resources Pending Update") - table.add_column("Resources Patched") - table.add_column("Errors") - table.add_column("Modules") - table.add_column("Providers") - table.add_row( - str(statistics["total_resources"]), - str(statistics["resources_pending_update"]), - str(statistics["resources_patched"]), - str(statistics["errors"]), - str(statistics["modules_count"]), - str(statistics["providers_count"]), - ) - self._console.print(table) diff --git a/infrapatch/core/credentials_helper.py b/infrapatch/core/credentials_helper.py index d55364d..cb574b0 100644 --- a/infrapatch/core/credentials_helper.py +++ b/infrapatch/core/credentials_helper.py @@ -4,7 +4,7 @@ import infrapatch.core.constants as cs from pathlib import Path -from infrapatch.core.utils.hcl_handler import HclHandler +from infrapatch.core.utils.terraform.hcl_handler import HclHandler def get_registry_credentials(hcl_handler: HclHandler, credentials_file: Union[Path, None] = None) -> dict[str, str]: diff --git a/infrapatch/core/models/statistics.py b/infrapatch/core/models/statistics.py new file mode 100644 index 0000000..a4f76bd --- /dev/null +++ b/infrapatch/core/models/statistics.py @@ -0,0 +1,57 @@ +from dataclasses import dataclass +import dataclasses +from typing import Any, Sequence +from pytablewriter import MarkdownTableWriter +from rich.table import Table +from infrapatch.core.models.versioned_resource import VersionedResource + + +@dataclass +class BaseStatistics: + errors: int + resources_patched: int + resources_pending_update: int + total_resources: int + + def to_dict(self) -> dict[str, Any]: + return dataclasses.asdict(self) + + +@dataclass +class ProviderStatistics(BaseStatistics): + resources: Sequence[VersionedResource] + + +@dataclass +class Statistics(BaseStatistics): + providers: dict[str, ProviderStatistics] + + def get_rich_table(self) -> Table: + table = Table(show_header=True, title="Statistics", expand=True) + table.add_column("Errors") + table.add_column("Patched") + table.add_column("Pending Update") + table.add_column("Total") + table.add_column("Enabled Providers") + table.add_row( + str(self.errors), + str(self.resources_patched), + str(self.resources_pending_update), + str(self.total_resources), + str(len(self.providers)), + ) + return table + + def get_markdown_table(self) -> MarkdownTableWriter: + dict_element = { + "Errors": self.errors, + "Patched": self.resources_patched, + "Pending Update": self.resources_pending_update, + "Total": self.total_resources, + "Enabled Providers": len(self.providers), + } + return MarkdownTableWriter( + table_name="Statistics", + headers=list(dict_element.keys()), + value_matrix=[list(dict_element.values())], + ) diff --git a/infrapatch/core/models/tests/test_versioned_resource.py b/infrapatch/core/models/tests/test_versioned_resource.py new file mode 100644 index 0000000..d6f3d77 --- /dev/null +++ b/infrapatch/core/models/tests/test_versioned_resource.py @@ -0,0 +1,70 @@ +from pathlib import Path + +from infrapatch.core.models.versioned_resource import ResourceStatus, VersionedResource + + +def test_version_management(): + # Create new resource with newer version + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="test_file.py") + resource.newest_version = "2.0.0" + + assert resource.status == ResourceStatus.UNPATCHED + assert resource.installed_version_equal_or_newer_than_new_version() is False + + resource.set_patched() + assert resource.status == ResourceStatus.PATCHED + + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="test_file.py") + resource.newest_version = "1.0.0" + + assert resource.status == ResourceStatus.UNPATCHED + assert resource.installed_version_equal_or_newer_than_new_version() is True + + +def test_tile_constraint(): + resource = VersionedResource(name="test_resource", current_version="~>1.0.0", _source_file="test_file.py") + resource.newest_version = "~>1.0.1" + assert resource.has_tile_constraint() is True + assert resource.installed_version_equal_or_newer_than_new_version() is True + + resource.newest_version = "~>1.1.0" + assert resource.installed_version_equal_or_newer_than_new_version() is False + + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="test_file.py") + assert resource.has_tile_constraint() is False + + resource = VersionedResource(name="test_resource", current_version="~>1.0.0", _source_file="test_file.py") + resource.newest_version = "1.1.0" + assert resource.newest_version == "~>1.1.0" + + +def test_patch_error(): + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="test_file.py") + resource.set_patch_error() + assert resource.status == ResourceStatus.PATCH_ERROR + + +def test_path(): + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="/var/testdir/test_file.py") + assert resource.source_file == Path("/var/testdir/test_file.py") + + +def test_find(): + findably_resource = VersionedResource(name="test_resource3", current_version="1.0.0", _source_file="test_file3.py") + unfindably_resource = VersionedResource(name="test_resource6", current_version="1.0.0", _source_file="test_file8.py") + resources = [ + VersionedResource(name="test_resource1", current_version="1.0.0", _source_file="test_file1.py"), + VersionedResource(name="test_resource2", current_version="1.0.0", _source_file="test_file2.py"), + VersionedResource(name="test_resource3", current_version="1.0.0", _source_file="test_file3.py"), + VersionedResource(name="test_resource4", current_version="1.0.0", _source_file="test_file4.py"), + VersionedResource(name="test_resource5", current_version="1.0.0", _source_file="test_file5.py"), + ] + assert len(findably_resource.find(resources)) == 1 + assert findably_resource.find(resources) == [resources[2]] + assert len(unfindably_resource.find(resources)) == 0 + + +def test_versioned_resource_to_dict(): + resource = VersionedResource(name="test_resource", current_version="1.0.0", _source_file="test_file.py") + expected_dict = {"name": "test_resource", "current_version": "1.0.0", "_source_file": "test_file.py", "_newest_version": None, "_status": ResourceStatus.UNPATCHED} + assert resource.to_dict() == expected_dict diff --git a/infrapatch/core/models/tests/test_versioned_terraform_resource.py b/infrapatch/core/models/tests/test_versioned_terraform_resource.py new file mode 100644 index 0000000..a4b568b --- /dev/null +++ b/infrapatch/core/models/tests/test_versioned_terraform_resource.py @@ -0,0 +1,82 @@ +import pytest + +from infrapatch.core.models.versioned_terraform_resources import TerraformModule, TerraformProvider + + +def test_attributes(): + # test with default registry + module = TerraformModule(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="test/test_module/test_provider") + provider = TerraformProvider(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="test_provider/test_provider") + + assert module.source == "test/test_module/test_provider" + assert module.base_domain is None + assert module.identifier == "test/test_module/test_provider" + + assert provider.source == "test_provider/test_provider" + assert provider.base_domain is None + assert provider.identifier == "test_provider/test_provider" + + # test with custom registry + module = TerraformModule(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="testregistry.ch/test/test_module/test_provider") + provider = TerraformProvider(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="testregistry.ch/test_provider/test_provider") + + assert module.source == "testregistry.ch/test/test_module/test_provider" + assert module.base_domain == "testregistry.ch" + assert module.identifier == "test/test_module/test_provider" + + assert provider.source == "testregistry.ch/test_provider/test_provider" + assert provider.base_domain == "testregistry.ch" + assert provider.identifier == "test_provider/test_provider" + + # test invalid sources + with pytest.raises(Exception): + TerraformModule(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="test/test_module/test_provider/test") + TerraformModule(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="/test_module") + + with pytest.raises(Exception): + TerraformProvider(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="/test_module") + TerraformProvider(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="kfdsjflksdj/kldfsjflsdkj/dkljflsk/test_module") + + +def test_find(): + findably_resource = TerraformModule(name="test_resource3", current_version="1.0.0", _source_file="test_file3.py", _source="test/test_module3/test_provider") + unfindably_resource = TerraformModule(name="test_resource6", current_version="1.0.0", _source_file="test_file8.py", _source="test/test_module3/test_provider") + resources = [ + TerraformModule(name="test_resource1", current_version="1.0.0", _source_file="test_file1.py", _source="test/test_module1/test_provider"), + TerraformModule(name="test_resource2", current_version="1.0.0", _source_file="test_file2.py", _source="test/test_module2/test_provider"), + TerraformModule(name="test_resource3", current_version="1.0.0", _source_file="test_file3.py", _source="test/test_module3/test_provider"), + TerraformModule(name="test_resource4", current_version="1.0.0", _source_file="test_file4.py", _source="test/test_module4/test_provider"), + TerraformModule(name="test_resource5", current_version="1.0.0", _source_file="test_file5.py", _source="test/test_module5/test_provider"), + ] + assert len(findably_resource.find(resources)) == 1 + assert findably_resource.find(resources) == [resources[2]] + assert len(unfindably_resource.find(resources)) == 0 + + +def test_to_dict(): + module = TerraformModule(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="test/test_module/test_provider") + provider = TerraformProvider(name="test_resource", current_version="1.0.0", _source_file="test_file.py", _source="test_provider/test_provider") + + module_dict = module.to_dict() + provider_dict = provider.to_dict() + + assert module_dict == { + "name": "test_resource", + "current_version": "1.0.0", + "_newest_version": None, + "_status": "unpatched", + "_source_file": "test_file.py", + "_source": "test/test_module/test_provider", + "_base_domain": None, + "_identifier": "test/test_module/test_provider", + } + assert provider_dict == { + "name": "test_resource", + "current_version": "1.0.0", + "_newest_version": None, + "_status": "unpatched", + "_source_file": "test_file.py", + "_source": "test_provider/test_provider", + "_base_domain": None, + "_identifier": "test_provider/test_provider", + } diff --git a/infrapatch/core/models/versioned_resource.py b/infrapatch/core/models/versioned_resource.py new file mode 100644 index 0000000..0147f6d --- /dev/null +++ b/infrapatch/core/models/versioned_resource.py @@ -0,0 +1,108 @@ +import dataclasses +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Optional, Union + +import semantic_version + + +class ResourceStatus: + UNPATCHED = "unpatched" + PATCHED = "patched" + PATCH_ERROR = "patch_error" + + +@dataclass +class VersionedResource: + name: str + current_version: str + _source_file: str + _newest_version: Union[str, None] = None + _status: str = ResourceStatus.UNPATCHED + + @property + def source_file(self) -> Path: + return Path(self._source_file) + + @property + def status(self) -> str: + return self._status + + @property + def resource_name(self): + raise NotImplementedError() + + @property + def newest_version(self) -> Optional[str]: + return self._newest_version + + @property + def newest_version_base(self): + if self.has_tile_constraint(): + if self.newest_version is None: + raise Exception(f"Newest version of resource '{self.name}' is not set.") + return self.newest_version.strip("~>") + return self.newest_version + + @newest_version.setter + def newest_version(self, version: str): + if self.has_tile_constraint(): + self._newest_version = f"~>{version}" + return + self._newest_version = version + + def set_patched(self): + self._status = ResourceStatus.PATCHED + + def has_tile_constraint(self) -> bool: + result = re.match(r"^~>[0-9]+\.[0-9]+\.[0-9]+$", self.current_version) + if result is None: + return False + return True + + def set_patch_error(self): + self._status = ResourceStatus.PATCH_ERROR + + def find(self, resources): + result = [resource for resource in resources if resource.name == self.name and resource._source_file == self._source_file] + return result + + def installed_version_equal_or_newer_than_new_version(self): + if self.newest_version is None: + raise Exception(f"Newest version of resource '{self.name}' is not set.") + + newest = semantic_version.Version(self.newest_version_base) + + # check if the current version has the following format: "1.2.3" + if re.match(r"^[0-9]+\.[0-9]+\.[0-9]+$", self.current_version): + current = semantic_version.Version(self.current_version) + if current >= newest: + return True + return False + + # chech if the current version has the following format: "~>3.76.0" + if self.has_tile_constraint(): + current = semantic_version.Version(self.current_version.strip("~>")) + if current.major > newest.major: # type: ignore + return True + if current.minor >= newest.minor: # type: ignore + return True + return False + + current_constraint = semantic_version.NpmSpec(self.current_version) + if newest in current_constraint: + return True + return False + + def check_if_up_to_date(self): + if self.status == ResourceStatus.PATCH_ERROR: + return False + if self.status == ResourceStatus.PATCHED: + return True + if self.installed_version_equal_or_newer_than_new_version(): + return True + return False + + def to_dict(self) -> dict[str, Any]: + return dataclasses.asdict(self) diff --git a/infrapatch/core/models/versioned_terraform_resources.py b/infrapatch/core/models/versioned_terraform_resources.py index 5c68d09..1882db0 100644 --- a/infrapatch/core/models/versioned_terraform_resources.py +++ b/infrapatch/core/models/versioned_terraform_resources.py @@ -1,24 +1,13 @@ import logging as log import re -import semantic_version from dataclasses import dataclass -from pathlib import Path -from typing import Optional, Sequence, Union +from typing import Optional, Union - -class ResourceStatus: - UNPATCHED = "unpatched" - PATCHED = "patched" - PATCH_ERROR = "patch_error" +from infrapatch.core.models.versioned_resource import VersionedResource @dataclass -class VersionedTerraformResource: - name: str - current_version: str - source_file: Path - _newest_version: Union[str, None] = None - _status: str = ResourceStatus.UNPATCHED +class VersionedTerraformResource(VersionedResource): _base_domain: Union[str, None] = None _identifier: Union[str, None] = None _source: Union[str, None] = None @@ -27,10 +16,6 @@ class VersionedTerraformResource: def source(self) -> Union[str, None]: return self._source - @property - def status(self) -> str: - return self._status - @property def base_domain(self) -> Optional[str]: return self._base_domain @@ -43,81 +28,9 @@ def resource_name(self): def identifier(self) -> Union[str, None]: return self._identifier - @property - def newest_version(self) -> Optional[str]: - return self._newest_version - - @property - def newest_version_base(self): - if self.has_tile_constraint(): - if self.newest_version is None: - raise Exception(f"Newest version of resource '{self.name}' is not set.") - return self.newest_version.strip("~>") - return self.newest_version - - @newest_version.setter - def newest_version(self, version: str): - if self.has_tile_constraint(): - self._newest_version = f"~>{version}" - return - self._newest_version = version - - def set_patched(self): - self._status = ResourceStatus.PATCHED - - def has_tile_constraint(self): - return re.match(r"^~>[0-9]+\.[0-9]+\.[0-9]+$", self.current_version) - - def set_patch_error(self): - self._status = ResourceStatus.PATCH_ERROR - - def installed_version_equal_or_newer_than_new_version(self): - if self.newest_version is None: - raise Exception(f"Newest version of resource '{self.name}' is not set.") - - newest = semantic_version.Version(self.newest_version_base) - - # check if the current version has the following format: "1.2.3" - if re.match(r"^[0-9]+\.[0-9]+\.[0-9]+$", self.current_version): - current = semantic_version.Version(self.current_version) - if current >= newest: - return True - return False - - # chech if the current version has the following format: "~>3.76.0" - if self.has_tile_constraint(): - current = semantic_version.Version(self.current_version.strip("~>")) - if current.major > newest.major: # type: ignore - return True - if current.minor >= newest.minor: # type: ignore - return True - return False - - current_constraint = semantic_version.NpmSpec(self.current_version) - if newest in current_constraint: - return True - return False - - def check_if_up_to_date(self): - if self.status == ResourceStatus.PATCH_ERROR: - return False - if self.status == ResourceStatus.PATCHED: - return True - if self.installed_version_equal_or_newer_than_new_version(): - return True - return False - - def __to_dict__(self): - return { - "name": self.name, - "current_version": self.current_version, - "source_file": self.source_file.absolute().as_posix(), - "newest_version": self.newest_version, - "status": self.status, - "base_domain": self.base_domain, - "identifier": self.identifier, - "source": self.source, - } + def find(self, resources): + filtered_resources = super().find(resources) + return [resource for resource in filtered_resources if resource._source == self._source] @dataclass @@ -180,11 +93,3 @@ def source(self, source: str) -> None: self._identifier = source_lower_case else: raise Exception(f"Source '{source_lower_case}' is not a valid terraform resource source.") - - -def get_upgradable_resources(resources: Sequence[VersionedTerraformResource]) -> Sequence[VersionedTerraformResource]: - return [resource for resource in resources if not resource.check_if_up_to_date()] - - -def from_terraform_resources_to_dict_list(terraform_resources: Sequence[VersionedTerraformResource]) -> Sequence[dict]: - return [terraform_resource.__to_dict__() for terraform_resource in terraform_resources] diff --git a/infrapatch/core/provider_handler.py b/infrapatch/core/provider_handler.py new file mode 100644 index 0000000..dcaea56 --- /dev/null +++ b/infrapatch/core/provider_handler.py @@ -0,0 +1,159 @@ +import json +import logging as log +from pathlib import Path +from typing import Sequence, Union + +from git import Repo +from pytablewriter import MarkdownTableWriter +from rich import progress +from rich.console import Console + +from infrapatch.core.models.statistics import ProviderStatistics, Statistics +from infrapatch.core.models.versioned_resource import ResourceStatus, VersionedResource +from infrapatch.core.providers.base_provider_interface import BaseProviderInterface + + +class ProviderHandler: + def __init__(self, providers: Sequence[BaseProviderInterface], console: Console, statistics_file: Path, repo: Union[Repo, None] = None) -> None: + self.providers: dict[str, BaseProviderInterface] = {} + for provider in providers: + self.providers[provider.get_provider_name()] = provider + + self._resource_cache: dict[str, Sequence[VersionedResource]] = {} + self.console = console + self.statistics_file = statistics_file + self.repo = repo + + def get_resources(self, disable_cache: bool = False) -> dict[str, Sequence[VersionedResource]]: + for provider_name, provider in self.providers.items(): + if provider_name not in self._resource_cache: + log.debug(f"Fetching resources for provider {provider.get_provider_name()} since cache is empty.") + self._resource_cache[provider.get_provider_name()] = provider.get_resources() + continue + elif disable_cache: + log.debug(f"Fetching resources for provider {provider.get_provider_name()} since cache is disabled.") + self._resource_cache[provider.get_provider_name()] = provider.get_resources() + continue + else: + log.debug(f"Using cached resources for provider {provider.get_provider_name()}.") + return self._resource_cache + + def get_upgradable_resources(self, disable_cache: bool = False) -> dict[str, Sequence[VersionedResource]]: + upgradable_resources: dict[str, Sequence[VersionedResource]] = {} + resources = self.get_resources(disable_cache) + for provider_name, provider in self.providers.items(): + upgradable_resources[provider.get_provider_name()] = [resource for resource in resources[provider.get_provider_name()] if not resource.check_if_up_to_date()] + return upgradable_resources + + def check_if_upgrades_available(self, disable_cache: bool = False) -> bool: + upgradable_resources = self.get_upgradable_resources(disable_cache) + for provider_name, provider in self.providers.items(): + if len(upgradable_resources[provider.get_provider_name()]) > 0: + return True + return False + + def upgrade_resources(self) -> bool: + if self._resource_cache is None: + raise Exception("No resources found. Run get_resources() first.") + if not self.check_if_upgrades_available(): + log.info("No upgrades available.") + return False + upgradable_resources = self.get_upgradable_resources() + for provider_name, resources in upgradable_resources.items(): + for resource in progress.track(resources, description=f"Upgrading resources for Provider {self.providers[provider_name].get_provider_display_name()}..."): + try: + resource = self.providers[provider_name].patch_resource(resource) + except Exception as e: + log.error(f"Error patching resource '{resource.name}': {e}") + resource.set_patch_error() + continue + resource.set_patched() + if self.repo is not None: + log.debug(f"Commiting file: {resource.source_file.absolute().as_posix()} .") + self.repo.index.add(resource.source_file.absolute().as_posix()) + self.repo.index.commit(f"Bump {resource.resource_name} '{resource.name}' from version '{resource.current_version}' to '{resource.newest_version}'.") + + return True + + def print_resource_table(self, only_upgradable: bool, disable_cache: bool = False): + provider_resources = self.get_resources(disable_cache) + if len([resource for provider in provider_resources for resource in provider_resources[provider]]) == 0: + self.console.print("No resources found.") + return + if only_upgradable: + provider_resources = self.get_upgradable_resources(disable_cache) + if not self.check_if_upgrades_available(disable_cache): + self.console.print("No upgradable resources found.") + return + + tables = [] + for provider_name, provider in self.providers.items(): + resources = provider_resources[provider_name] + if len(resources) > 0: + tables.append(provider.get_rich_table(resources)) + for table in tables: + self.console.print(table) + + def _get_statistics(self, disable_cache: bool = False) -> Statistics: + resources = self.get_resources(disable_cache) + provider_statistics: dict[str, ProviderStatistics] = {} + + for provider_name, provider in self.providers.items(): + provider_resources = resources[provider.get_provider_name()] + provider_statistics[provider_name] = ProviderStatistics( + errors=len([resource for resource in provider_resources if resource.status == ResourceStatus.PATCH_ERROR]), + resources_patched=len([resource for resource in provider_resources if resource.status == ResourceStatus.PATCHED]), + resources_pending_update=len([resource for resource in provider_resources if resource.check_if_up_to_date() is False]), + total_resources=len(provider_resources), + resources=provider_resources, + ) + return Statistics( + errors=sum([provider_statistics[provider].errors for provider in provider_statistics]), + resources_patched=sum([provider_statistics[provider].resources_patched for provider in provider_statistics]), + resources_pending_update=sum([provider_statistics[provider].resources_pending_update for provider in provider_statistics]), + total_resources=sum([provider_statistics[provider].total_resources for provider in provider_statistics]), + providers=provider_statistics, + ) + + def dump_statistics(self, disable_cache: bool = False): + if self.statistics_file.exists(): + log.debug(f"Deleting existing statistics file {self.statistics_file.absolute().as_posix()}.") + self.statistics_file.unlink() + log.debug(f"Writing statistics to {self.statistics_file.absolute().as_posix()}.") + statistics_dict = self._get_statistics(disable_cache).to_dict() + with open(self.statistics_file, "w") as f: + f.write(json.dumps(statistics_dict)) + + def print_statistics_table(self, disable_cache: bool = False): + table = self._get_statistics(disable_cache).get_rich_table() + self.console.print(table) + + def get_markdown_table_for_changed_resources(self) -> list[MarkdownTableWriter]: + if self._resource_cache is None: + raise Exception("No resources found. Run get_resources() first.") + + markdown_tables = [] + for provider_name, provider in self.providers.items(): + changed_resources = [ + resource for resource in self._resource_cache[provider_name] if resource.status == ResourceStatus.PATCHED or resource.status == ResourceStatus.PATCH_ERROR + ] + if len(changed_resources) == 0: + log.debug(f"No changed resources found for provider {provider_name}. Skipping.") + continue + markdown_tables.append(provider.get_markdown_table(changed_resources)) + return markdown_tables + + def set_resources_patched_based_on_existing_resources(self, original_resources: dict[str, Sequence[VersionedResource]]) -> None: + for provider_name, provider in self.providers.items(): + original_resources_provider = original_resources[provider_name] + for i, resource in enumerate(self._resource_cache[provider_name]): + found_resources = resource.find(original_resources_provider) + if len(found_resources) == 0: + log.debug(f"Resource '{resource.name}' not found in original resources. Skipping update.") + continue + if len(found_resources) > 1: + raise Exception(f"Found multiple resources with the same name: {resource.name}") + log.debug(f"Updating resource '{resource.name}' from provider {provider_name} with original resource.") + found_resource = found_resources[0] + found_resource.set_patched() + self._resource_cache[provider_name][i] = found_resource # type: ignore diff --git a/infrapatch/core/provider_handler_builder.py b/infrapatch/core/provider_handler_builder.py new file mode 100644 index 0000000..1bf76d4 --- /dev/null +++ b/infrapatch/core/provider_handler_builder.py @@ -0,0 +1,58 @@ +import logging as log +from pathlib import Path +from typing import Self +from infrapatch.core.providers.terraform.terraform_provider_provider import TerraformProviderProvider + +from infrapatch.core.providers.terraform.terraform_module_provider import TerraformModuleProvider +from git import Repo +from rich.console import Console + +import infrapatch.core.constants as const +import infrapatch.core.constants as cs +from infrapatch.core.provider_handler import ProviderHandler +from infrapatch.core.utils.terraform.hcl_edit_cli import HclEditCli +from infrapatch.core.utils.terraform.hcl_handler import HclHandler +from infrapatch.core.utils.terraform.registry_handler import RegistryHandler + + +class ProviderHandlerBuilder: + def __init__(self, working_directory: Path) -> None: + self.providers = [] + self.working_directory = working_directory + self.registry_handler = None + self.git_repo = None + pass + + def add_terraform_registry_configuration(self, default_registry_domain: str, credentials: dict[str, str]) -> Self: + log.debug(f"Using {default_registry_domain} as default registry domain for Terraform.") + log.debug(f"Found {len(credentials)} credentials for Terraform registries.") + self.registry_handler = RegistryHandler(default_registry_domain, credentials) + return self + + def with_terraform_module_provider(self) -> Self: + if self.registry_handler is None: + raise Exception("No registry configuration added to ProviderHandlerBuilder.") + log.debug("Adding TerraformModuleProvider to ProviderHandlerBuilder.") + tf_module_provider = TerraformModuleProvider(HclEditCli(), self.registry_handler, HclHandler(HclEditCli()), self.working_directory) + self.providers.append(tf_module_provider) + return self + + def with_terraform_provider_provider(self) -> Self: + if self.registry_handler is None: + raise Exception("No registry configuration added to ProviderHandlerBuilder.") + log.debug("Adding TerraformModuleProvider to ProviderHandlerBuilder.") + tf_module_provider = TerraformProviderProvider(HclEditCli(), self.registry_handler, HclHandler(HclEditCli()), self.working_directory) + self.providers.append(tf_module_provider) + return self + + def with_git_integration(self, git_working_directory: Path) -> Self: + log.debug("Enabling Git integration.") + self.git_integration = True + self.git_repo = Repo(git_working_directory) + return self + + def build(self) -> ProviderHandler: + if len(self.providers) == 0: + raise Exception("No providers added to ProviderHandlerBuilder.") + statistics_file = self.working_directory.joinpath(f"{cs.APP_NAME}_Statistics.json") + return ProviderHandler(providers=self.providers, console=Console(width=const.CLI_WIDTH), statistics_file=statistics_file, repo=self.git_repo) diff --git a/infrapatch/core/providers/__init__.py b/infrapatch/core/providers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrapatch/core/providers/base_provider_interface.py b/infrapatch/core/providers/base_provider_interface.py new file mode 100644 index 0000000..24e8335 --- /dev/null +++ b/infrapatch/core/providers/base_provider_interface.py @@ -0,0 +1,27 @@ +from typing import Protocol, Sequence +from pytablewriter import MarkdownTableWriter +from rich.table import Table +from infrapatch.core.models.versioned_resource import VersionedResource + + +class BaseProviderInterface(Protocol): + def get_provider_name(self) -> str: + ... + + def get_provider_display_name(self) -> str: + ... + + def get_resources(self) -> Sequence[VersionedResource]: + ... + + def patch_resource(self, resource: VersionedResource) -> VersionedResource: + ... + + def get_rich_table(self, resources: Sequence[VersionedResource]) -> Table: + ... + + def get_markdown_table(self, resources: Sequence[VersionedResource]) -> MarkdownTableWriter: + ... + + def get_resources_as_dict_list(self, resources: Sequence[VersionedResource]): + ... diff --git a/infrapatch/core/providers/terraform/__init__.py b/infrapatch/core/providers/terraform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrapatch/core/providers/terraform/base_terraform_provider.py b/infrapatch/core/providers/terraform/base_terraform_provider.py new file mode 100644 index 0000000..b0776f7 --- /dev/null +++ b/infrapatch/core/providers/terraform/base_terraform_provider.py @@ -0,0 +1,90 @@ +from pathlib import Path +from typing import Any, Sequence + +from abc import abstractmethod +from pytablewriter import MarkdownTableWriter + +from rich import progress +from rich.table import Table +from infrapatch.core.models.versioned_resource import VersionedResource +from infrapatch.core.models.versioned_terraform_resources import VersionedTerraformResource +from infrapatch.core.providers.base_provider_interface import BaseProviderInterface +from infrapatch.core.utils.terraform.hcl_edit_cli import HclEditCliInterface +from infrapatch.core.utils.terraform.hcl_handler import HclHandlerInterface +from infrapatch.core.utils.terraform.registry_handler import RegistryHandlerInterface +import logging as log + + +class TerraformProvider(BaseProviderInterface): + def __init__(self, hcledit: HclEditCliInterface, registry_handler: RegistryHandlerInterface, hcl_handler: HclHandlerInterface, project_root: Path) -> None: + self.hcledit = hcledit + self.registry_handler = registry_handler + self.hcl_handler = hcl_handler + self.project_root = project_root + + @abstractmethod + def get_provider_name(self) -> str: + raise NotImplementedError + + @abstractmethod + def get_provider_display_name(self) -> str: + raise NotImplementedError + + def get_resources(self) -> Sequence[VersionedResource]: + log.info(f"Searching for .tf files in {self.project_root.absolute().as_posix()} ...") + terraform_files = self.hcl_handler.get_all_terraform_files(self.project_root) + if len(terraform_files) == 0: + return [] + + resources = [] + for terraform_file in progress.track(terraform_files, description=f"Parsing .tf files for {self.get_provider_display_name()}..."): + if self.get_provider_name() == "terraform_modules": + resources.extend(self.hcl_handler.get_terraform_resources_from_file(terraform_file, get_modules=True, get_providers=False)) + + elif self.get_provider_name() == "terraform_providers": + resources.extend(self.hcl_handler.get_terraform_resources_from_file(terraform_file, get_modules=False, get_providers=True)) + + else: + raise Exception(f"Provider name '{self.get_provider_name()}' is not implemented.") + + for resource in progress.track(resources, description=f"Getting newest resource versions for Provider {self.get_provider_display_name()}..."): + resource.newest_version = self.registry_handler.get_newest_version(resource) + return resources + + def patch_resource(self, resource: VersionedTerraformResource) -> VersionedTerraformResource: + if resource.check_if_up_to_date() is True: + log.debug(f"Resource '{resource.name}' is already up to date.") + return resource + self.hcl_handler.bump_resource_version(resource) + return resource + + def get_rich_table(self, resources: Sequence[VersionedTerraformResource]) -> Table: + table = Table(show_header=True, title=self.get_provider_display_name(), expand=True) + table.add_column("Name", overflow="fold") + table.add_column("Source", overflow="fold") + table.add_column("Current") + table.add_column("Newest") + table.add_column("Upgradeable") + for resource in resources: + table.add_row(resource.name, resource.source, resource.current_version, resource.newest_version, str(not resource.installed_version_equal_or_newer_than_new_version())) + return table + + def get_markdown_table(self, resources: Sequence[VersionedTerraformResource]) -> MarkdownTableWriter: + dict_list = [] + for resource in resources: + dict_element = { + "Name": resource.name, + "Source": resource.source, + "Current": resource.current_version, + "Newest": resource.newest_version, + "Upgradeable": str(not resource.installed_version_equal_or_newer_than_new_version()), + } + dict_list.append(dict_element) + return MarkdownTableWriter( + table_name=self.get_provider_display_name(), + headers=list(dict_list[0].keys()), + value_matrix=[list(dict_element.values()) for dict_element in dict_list], + ) + + def get_resources_as_dict_list(self, resources: Sequence[VersionedTerraformResource]) -> list[dict[str, Any]]: + return [resource.to_dict() for resource in resources] diff --git a/infrapatch/core/providers/terraform/terraform_module_provider.py b/infrapatch/core/providers/terraform/terraform_module_provider.py new file mode 100644 index 0000000..50e3e9c --- /dev/null +++ b/infrapatch/core/providers/terraform/terraform_module_provider.py @@ -0,0 +1,9 @@ +from infrapatch.core.providers.terraform.base_terraform_provider import TerraformProvider + + +class TerraformModuleProvider(TerraformProvider): + def get_provider_name(self) -> str: + return "terraform_modules" + + def get_provider_display_name(self) -> str: + return "Terraform Modules" diff --git a/infrapatch/core/providers/terraform/terraform_provider_provider.py b/infrapatch/core/providers/terraform/terraform_provider_provider.py new file mode 100644 index 0000000..736bfd0 --- /dev/null +++ b/infrapatch/core/providers/terraform/terraform_provider_provider.py @@ -0,0 +1,9 @@ +from infrapatch.core.providers.terraform.base_terraform_provider import TerraformProvider + + +class TerraformProviderProvider(TerraformProvider): + def get_provider_name(self) -> str: + return "terraform_providers" + + def get_provider_display_name(self) -> str: + return "Terraform Providers" diff --git a/infrapatch/core/utils/git.py b/infrapatch/core/utils/git.py new file mode 100644 index 0000000..75d69ae --- /dev/null +++ b/infrapatch/core/utils/git.py @@ -0,0 +1,38 @@ +from pathlib import Path +import subprocess +from typing import Union +import logging as log + + +class GitException(Exception): + pass + + +class Git: + _repo_path: Path + + def __init__(self, repo_path: Path): + self._repo_path = repo_path + + def run_git_command(self, command: list[str]) -> tuple[str, Union[str, None]]: + command = ["git", *command] + command_string = " ".join(command) + log.debug(f"Executing git command: {command_string}") + try: + result = subprocess.run(command, capture_output=True, text=True, cwd=self._repo_path.absolute().as_posix()) + except Exception as e: + raise GitException(f"Error executing git command {command_string} with error: {e}") + if result.returncode != 0: + raise GitException(f"Git command {command_string} exited with non-zero exit code {result.returncode}: {result.stderr}") + return result.stdout, result.stderr + + def fetch_origin(self): + log.debug("Fetching origin") + self.run_git_command(["fetch", "origin"]) + + def checkout_branch(self, target: str, origin: str): + log.debug(f"Checking out branch {target} from {origin}") + self.run_git_command(["checkout", "-b", target, origin]) + + def push(self, additional_arguments: list[str] = []): + self.run_git_command(["push", *additional_arguments]) diff --git a/infrapatch/core/utils/terraform/__init__.py b/infrapatch/core/utils/terraform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrapatch/core/bin/hcledit_darwin b/infrapatch/core/utils/terraform/bin/hcledit_darwin similarity index 100% rename from infrapatch/core/bin/hcledit_darwin rename to infrapatch/core/utils/terraform/bin/hcledit_darwin diff --git a/infrapatch/core/bin/hcledit_linux b/infrapatch/core/utils/terraform/bin/hcledit_linux similarity index 100% rename from infrapatch/core/bin/hcledit_linux rename to infrapatch/core/utils/terraform/bin/hcledit_linux diff --git a/infrapatch/core/bin/hcledit_windows.exe b/infrapatch/core/utils/terraform/bin/hcledit_windows.exe old mode 100755 new mode 100644 similarity index 100% rename from infrapatch/core/bin/hcledit_windows.exe rename to infrapatch/core/utils/terraform/bin/hcledit_windows.exe diff --git a/infrapatch/core/utils/hcl_edit_cli.py b/infrapatch/core/utils/terraform/hcl_edit_cli.py similarity index 73% rename from infrapatch/core/utils/hcl_edit_cli.py rename to infrapatch/core/utils/terraform/hcl_edit_cli.py index dd74163..017bd8d 100644 --- a/infrapatch/core/utils/hcl_edit_cli.py +++ b/infrapatch/core/utils/terraform/hcl_edit_cli.py @@ -2,20 +2,30 @@ import platform import subprocess from pathlib import Path -from typing import Optional, Union +from typing import Optional, Protocol, Union -class HclEditCliException(BaseException): +class HclEditCliException(Exception): pass -class HclEditCli: +class HclEditCliInterface(Protocol): + def update_hcl_value(self, resource: str, file: Path, value: str): + ... + + def get_hcl_value(self, resource: str, file: Path) -> str: + ... + + +class HclEditCli(HclEditCliInterface): def __init__(self): - pass + self._binary_path = self._get_binary_path() + if not self._binary_path.exists() and not self._binary_path.is_file(): + raise Exception(f"Binary '{self._binary_path.absolute().as_posix()}' does not exist.") def _get_binary_path(self) -> Path: current_folder = Path(__file__).parent - binary_folder = current_folder.parent.joinpath("bin") + binary_folder = current_folder.joinpath("bin") if platform.system() == "Windows": return binary_folder.joinpath("hcledit_windows.exe") elif platform.system() == "Linux": @@ -35,7 +45,7 @@ def get_hcl_value(self, resource: str, file: Path) -> str: return result def _run_hcl_edit_command(self, action: str, resource: str, file: Path, value: Union[str, None] = None) -> Optional[str]: - command = [self._get_binary_path().absolute().as_posix(), action, resource] + command = [self._binary_path.absolute().as_posix(), action, resource] if value is not None: command.append(value) command.append(file.absolute().as_posix()) diff --git a/infrapatch/core/utils/hcl_handler.py b/infrapatch/core/utils/terraform/hcl_handler.py similarity index 58% rename from infrapatch/core/utils/hcl_handler.py rename to infrapatch/core/utils/terraform/hcl_handler.py index 5ee7c82..88efb9f 100644 --- a/infrapatch/core/utils/hcl_handler.py +++ b/infrapatch/core/utils/terraform/hcl_handler.py @@ -2,19 +2,33 @@ import logging as log import platform from pathlib import Path -from typing import Sequence +from typing import Protocol, Sequence import pygohcl from infrapatch.core.models.versioned_terraform_resources import TerraformModule, TerraformProvider, VersionedTerraformResource -from infrapatch.core.utils.hcl_edit_cli import HclEditCli +from infrapatch.core.utils.terraform.hcl_edit_cli import HclEditCli -class HclParserException(BaseException): +class HclParserException(Exception): pass -class HclHandler: +class HclHandlerInterface(Protocol): + def bump_resource_version(self, resource: VersionedTerraformResource): + ... + + def get_terraform_resources_from_file(self, tf_file: Path, get_modules: bool = True, get_providers: bool = True) -> Sequence[VersionedTerraformResource]: + ... + + def get_all_terraform_files(self, root: Path) -> Sequence[Path]: + ... + + def get_credentials_form_user_rc_file(self) -> dict[str, str]: + ... + + +class HclHandler(HclHandlerInterface): def __init__(self, hcl_edit_cli: HclEditCli): self.hcl_edit_cli = hcl_edit_cli pass @@ -38,33 +52,55 @@ def bump_resource_version(self, resource: VersionedTerraformResource): self.hcl_edit_cli.update_hcl_value(resource_name, resource.source_file, resource.newest_version) - def get_terraform_resources_from_file(self, tf_file: Path) -> Sequence[VersionedTerraformResource]: + def get_terraform_resources_from_file(self, tf_file: Path, get_modules: bool = True, get_providers: bool = True) -> Sequence[VersionedTerraformResource]: + if get_modules is False and get_providers is False: + raise Exception("At least one of the parameters 'modules' and 'providers' must be True.") + if not tf_file.exists(): raise Exception(f"File '{tf_file}' does not exist.") + if not tf_file.is_file(): raise Exception(f"Path '{tf_file}' is not a file.") + with open(tf_file.absolute(), "r") as file: try: terraform_file_dict = pygohcl.loads(file.read()) except Exception as e: raise HclParserException(f"Could not parse file '{tf_file}': {e}") found_resources = [] - if "terraform" in terraform_file_dict: - if "required_providers" in terraform_file_dict["terraform"]: - providers = terraform_file_dict["terraform"]["required_providers"] - for provider_name, provider_config in providers.items(): - found_resources.append( - TerraformProvider(name=provider_name, _source=provider_config["source"], current_version=provider_config["version"], source_file=tf_file) - ) - if "module" in terraform_file_dict: - modules = terraform_file_dict["module"] - for module_name, value in modules.items(): - if "source" not in value: - log.debug(f"Skipping module '{module_name}' because it has no source attribute.") - continue - found_resources.append(TerraformModule(name=module_name, _source=value["source"], current_version=value["version"], source_file=tf_file)) + if get_modules: + found_resources.extend(self._get_terraform_modules_from_dict(terraform_file_dict, tf_file)) + if get_providers: + found_resources.extend(self._get_terraform_providers_from_dict(terraform_file_dict, tf_file)) return found_resources + def _get_terraform_providers_from_dict(self, terraform_file_dict: dict, tf_file: Path) -> Sequence[TerraformProvider]: + found_resources = [] + if "terraform" in terraform_file_dict: + if "required_providers" in terraform_file_dict["terraform"]: + providers = terraform_file_dict["terraform"]["required_providers"] + for provider_name, provider_config in providers.items(): + found_resources.append( + TerraformProvider( + name=provider_name, _source=provider_config["source"], current_version=provider_config["version"], _source_file=tf_file.absolute().as_posix() + ) + ) + return found_resources + + def _get_terraform_modules_from_dict(self, terraform_file_dict: dict, tf_file: Path) -> Sequence[TerraformProvider]: + found_resources = [] + if "module" in terraform_file_dict: + modules = terraform_file_dict["module"] + for module_name, value in modules.items(): + if "source" not in value: + log.debug(f"Skipping module '{module_name}' because it has no source attribute.") + continue + if "version" not in value: + log.debug(f"Skipping module '{module_name}' because it has no version attribute.") + continue + found_resources.append(TerraformModule(name=module_name, _source=value["source"], current_version=value["version"], _source_file=tf_file.absolute().as_posix())) + return found_resources + def get_all_terraform_files(self, root: Path) -> Sequence[Path]: if not root.is_dir(): raise Exception(f"Path '{root}' is not a directory.") diff --git a/infrapatch/core/utils/registry_handler.py b/infrapatch/core/utils/terraform/registry_handler.py similarity index 93% rename from infrapatch/core/utils/registry_handler.py rename to infrapatch/core/utils/terraform/registry_handler.py index f9de4db..7b41f2d 100644 --- a/infrapatch/core/utils/registry_handler.py +++ b/infrapatch/core/utils/terraform/registry_handler.py @@ -1,25 +1,31 @@ import json import logging as log from distutils.version import StrictVersion +from typing import Protocol from urllib import request from urllib.parse import urlparse from infrapatch.core.models.versioned_terraform_resources import VersionedTerraformResource, TerraformModule, TerraformProvider -class RegistryNotFoundException(BaseException): +class RegistryNotFoundException(Exception): pass -class RegistryMetadataException(BaseException): +class RegistryMetadataException(Exception): pass -class ResourceNotFoundException(BaseException): +class ResourceNotFoundException(Exception): pass -class RegistryHandler: +class RegistryHandlerInterface(Protocol): + def get_newest_version(self, resource: VersionedTerraformResource): + ... + + +class RegistryHandler(RegistryHandlerInterface): def __init__(self, default_registry_domain: str, credentials: dict): self.default_registry_domain = default_registry_domain self.cached_registry_metadata = {} diff --git a/pyproject.toml b/pyproject.toml index 68c10f4..5b7e0c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,4 +4,9 @@ line-length = 180 [tool.ruff.lint] select = ["E4", "E7", "E9", "F"] -ignore = [] \ No newline at end of file +ignore = [] + +[tool.pytest.ini_options] +pythonpath = [ + "." +] \ No newline at end of file diff --git a/python_version.txt b/python_version.txt new file mode 100644 index 0000000..902b2c9 --- /dev/null +++ b/python_version.txt @@ -0,0 +1 @@ +3.11 \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt index ede3eb4..e2d8d82 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1 +1,4 @@ -ruff \ No newline at end of file +ruff +pytest +pytest-md +pytest-emoji \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d629124..16c9359 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ GitPython~=3.1.40 setuptools~=65.5.1 pygit2~=1.13.1 semantic-version~=2.10.0 -PyGithub~=2.1.1 \ No newline at end of file +PyGithub~=2.1.1 +pytablewriter~=1.2.0 \ No newline at end of file diff --git a/setup.py b/setup.py index c446b03..381caeb 100644 --- a/setup.py +++ b/setup.py @@ -6,8 +6,8 @@ description="CLI Tool to patch Terraform Providers and Modules.", version=__version__, packages=find_packages(where=".", include=["infrapatch*"], exclude=["action*"]), - package_data={"infrapatch": ["core/bin/*"]}, - install_requires=["click~=8.1.7", "rich~=13.6.0", "pygohcl~=1.0.7", "GitPython~=3.1.40", "setuptools~=65.5.1", "semantic_version~=2.10.0"], + package_data={"infrapatch": ["core/utils/terraform/bin/*"]}, + install_requires=["click~=8.1.7", "rich~=13.6.0", "pygohcl~=1.0.7", "GitPython~=3.1.40", "setuptools~=65.5.1", "semantic_version~=2.10.0", "pytablewriter~=1.2.0"], python_requires=">=3.11", entry_points=""" [console_scripts]