From 37ceb72ef2027f02c077d7afff57926b087cd872 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 13:31:46 +0100 Subject: [PATCH 01/78] Upgrade GitHub actions --- .github/workflows/ci-build.yml | 2 +- .../workflows/release_droid_prepare_original_checksum.yml | 4 ++-- .../release_droid_upload_github_release_assets.yml | 2 -- .github/workflows/test_linux_build_on_windows.yml | 4 ++-- .github/workflows/test_on_windows.yml | 2 +- .../.github/workflows/ci-build-db-version-matrix.yml | 2 +- .../templates/.github/workflows/ci-build-native-build.yml | 6 +++--- .../main/resources/templates/.github/workflows/ci-build.yml | 2 +- .../workflows/release_droid_prepare_original_checksum.yml | 2 +- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index d3f05222..46992224 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -32,7 +32,7 @@ jobs: - name: Install Go tools run: go install github.com/google/go-licenses@v1.6.0 - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/.github/workflows/release_droid_prepare_original_checksum.yml b/.github/workflows/release_droid_prepare_original_checksum.yml index 28948834..a0515fd0 100644 --- a/.github/workflows/release_droid_prepare_original_checksum.yml +++ b/.github/workflows/release_droid_prepare_original_checksum.yml @@ -24,7 +24,7 @@ jobs: with: go-version: "1.21" - name: Cache Go modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cache/go-build @@ -39,7 +39,7 @@ jobs: - name: Prepare checksum run: find target -maxdepth 1 -name *.jar -exec sha256sum "{}" + > original_checksum - name: Upload checksum to the artifactory - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: original_checksum retention-days: 5 diff --git a/.github/workflows/release_droid_upload_github_release_assets.yml b/.github/workflows/release_droid_upload_github_release_assets.yml index b66a0d61..d0fb6c89 100644 --- a/.github/workflows/release_droid_upload_github_release_assets.yml +++ b/.github/workflows/release_droid_upload_github_release_assets.yml @@ -39,8 +39,6 @@ jobs: with: upload_url: ${{ github.event.inputs.upload_url }} asset_path: project-keeper-cli/target/*.sha256 - - name: Zip error-code-reports - run: zip -v error_code_report.zip */target/error_code_report.json - name: Upload error-code-report uses: shogo82148/actions-upload-release-asset@v1 with: diff --git a/.github/workflows/test_linux_build_on_windows.yml b/.github/workflows/test_linux_build_on_windows.yml index 8e623d8a..4cd88797 100644 --- a/.github/workflows/test_linux_build_on_windows.yml +++ b/.github/workflows/test_linux_build_on_windows.yml @@ -30,7 +30,7 @@ jobs: with: go-version: "1.21" - name: Cache Go modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cache/go-build @@ -57,7 +57,7 @@ jobs: cp $(find project-keeper-maven-plugin/target/ -regextype sed -regex ".*/project-keeper-maven-plugin-[0-9]\+\.[0-9]\+\.[0-9]\+\(-SNAPSHOT\)\?\.jar") artifact/project-keeper-maven-plugin.jar cp project-keeper-maven-plugin/.flattened-pom.xml artifact/project-keeper-maven-plugin.pom - name: Upload jar artifact - uses: actions/upload-artifact@master + uses: actions/upload-artifact@v4 with: name: project-keeper-jar path: artifact diff --git a/.github/workflows/test_on_windows.yml b/.github/workflows/test_on_windows.yml index 039afbd0..bc951b62 100644 --- a/.github/workflows/test_on_windows.yml +++ b/.github/workflows/test_on_windows.yml @@ -30,7 +30,7 @@ jobs: with: go-version: "1.21" - name: Cache Go modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cache/go-build diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml index 5e98d32b..afcf41ed 100644 --- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml +++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml @@ -38,7 +38,7 @@ jobs: 17 cache: "maven" - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml index 97a79a69..9d4f1d70 100644 --- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml +++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml @@ -35,7 +35,7 @@ jobs: - name: Enable testcontainer reuse run: echo 'testcontainers.reuse.enable=true' > "$HOME/.testcontainers.properties" - name: Cache local Maven repository - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -44,7 +44,7 @@ jobs: - name: Run tests and build with Maven run: mvn --batch-mode --update-snapshots clean verify --file pom.xml -DtrimStackTrace=false - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar @@ -60,7 +60,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - name: Upload binary - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: executable-${{ matrix.os }} path: target/${{ github.event.repository.name }} diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml index 7b4c1792..cfc33587 100644 --- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml +++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml @@ -32,7 +32,7 @@ jobs: 17 cache: "maven" - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/project-keeper/src/main/resources/templates/.github/workflows/release_droid_prepare_original_checksum.yml b/project-keeper/src/main/resources/templates/.github/workflows/release_droid_prepare_original_checksum.yml index 2c72984b..ea8812b6 100644 --- a/project-keeper/src/main/resources/templates/.github/workflows/release_droid_prepare_original_checksum.yml +++ b/project-keeper/src/main/resources/templates/.github/workflows/release_droid_prepare_original_checksum.yml @@ -32,7 +32,7 @@ jobs: - name: Prepare checksum run: find target -maxdepth 1 -name *.jar -exec sha256sum "{}" + > original_checksum - name: Upload checksum to the artifactory - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: original_checksum retention-days: 5 From 156dc87879812285a027c32e899dce03451d512a Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 13:33:13 +0100 Subject: [PATCH 02/78] Remove unnecessary dependency override --- parent-pom/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index dfb2c276..2d7bab17 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -213,13 +213,6 @@ 1.4.8 test - - - junit - junit - 4.13.2 - test - From 99a3d022c00c317724f0785b3809d6fe1bc927c8 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 13:34:01 +0100 Subject: [PATCH 03/78] Increment version --- doc/changes/changelog.md | 1 + doc/changes/changes_4.0.0.md | 53 ++++++++++++++++++++++++++++++++++++ parent-pom/pom.xml | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 doc/changes/changes_4.0.0.md diff --git a/doc/changes/changelog.md b/doc/changes/changelog.md index 672beb8a..ddff9ab8 100644 --- a/doc/changes/changelog.md +++ b/doc/changes/changelog.md @@ -1,5 +1,6 @@ # Changes +* [4.0.0](changes_4.0.0.md) * [3.0.1](changes_3.0.1.md) * [3.0.0](changes_3.0.0.md) * [2.9.17](changes_2.9.17.md) diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md new file mode 100644 index 00000000..27e8d412 --- /dev/null +++ b/doc/changes/changes_4.0.0.md @@ -0,0 +1,53 @@ +# Project Keeper 4.0.0, released 2024-??-?? + +Code name: Automatic Security Updates + +## Summary + +## Features + +* #515: Added automatic dependency upgrade + +## Dependency Updates + +### Project Keeper Core + +#### Compile Dependency Updates + +* Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` + +#### Runtime Dependency Updates + +* Updated `com.exasol:project-keeper-java-project-crawler:3.0.1` to `4.0.0` + +#### Test Dependency Updates + +* Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` + +### Project Keeper Command Line Interface + +#### Compile Dependency Updates + +* Updated `com.exasol:project-keeper-core:3.0.1` to `4.0.0` + +#### Test Dependency Updates + +* Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` + +### Project Keeper Maven Plugin + +#### Compile Dependency Updates + +* Updated `com.exasol:project-keeper-core:3.0.1` to `4.0.0` + +### Project Keeper Java Project Crawler + +#### Compile Dependency Updates + +* Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` + +### Project Keeper Shared Test Setup + +#### Compile Dependency Updates + +* Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index 2d7bab17..31e2b8f9 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -28,7 +28,7 @@ - 3.0.1 + 4.0.0 3.9.6 3.6.3 5.10.1 From cfcb14404d71b1c550b677d19f35525eb7046698 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 17:16:57 +0100 Subject: [PATCH 04/78] #515: Requirements & design --- doc/design.md | 156 +++++++++++++++++++++++++++++++++++++ doc/system_requirements.md | 73 +++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/doc/design.md b/doc/design.md index 18820f97..511f1408 100644 --- a/doc/design.md +++ b/doc/design.md @@ -442,3 +442,159 @@ Covers: * [`req~npm-changed-dependency~1`](system_requirements.md#get-changed-dependency) Needs: impl, utest, itest + +## Automatic Dependency Update Process + +This consists of the following steps: +1. Trigger the dependency update process +2. Update dependencies +3. Create a pull request + +#### Triggering the Dependency Update Process +`dsn~trigger-dependency-updates~1` + +PK generates the `dependencies_check.yml` GitHub workflow so that it launches the `dependencies_update.yml` workflow when it detects new vulnerabilities. + +Rationale: + +`dependencies_check.yml` already uses the [security-issues](https://exasol.github.io/python-toolbox/github_actions/security_issues.html) tool from the [python-toolbox](https://github.com/exasol/python-toolbox) to create issues for new vulnerabilities. Re-implementing this in PK is not necessary. + +Covers +* [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) + +Needs: impl, utest, itest + +#### Update Dependencies Mode +`dsn~update-dependencies-mode~1` + +PK provides an `update-dependencies` mode in addition to `fix` and `verify`. This mode performs the following steps: + +1. Increment version of the project +2. Update dependencies to their latest version +3. Create changelog containing information about the fixed vulnerabilities (if available) + +Rationale: + +* We implement this in PK because + * PK already contains code for working with versions and changelog, so we can reuse this code + * The `update-dependencies` mode is also useful for running locally on the developer's machine when working on a non-security related task +* We don't implement git/GitHub operations in PK because + * This would couple PK to GitHub + * This would be surprising when running it locally + * This would require credentials for accessing the GitHub API + +Covers +* [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) +* [`req~auto-create-changelog~1`](system_requirements.md#automatically-create-change-log-entry) + +Needs: dsn + +##### Incrementing the Version +`dsn~increment-version~1` + +PK increments the patch version. PK does not modify the version if the current version was not yet released (i.e. there is not release in the latest changelog file). + +Rationale: + +Leaving the version unchanged when it was not yet released avoids surprises when running this locally. + +Covers +* [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) + +Needs: impl, utest, itest + +##### Upgrade Dependencies +`dsn~upgrade-dependencies~1` + +PK upgrades dependencies using the [versions-maven-plugin](https://www.mojohaus.org/versions/versions-maven-plugin/index.html): + +```sh +mvn versions:use-latest-releases && mvn versions:update-properties +``` + +Rationale: + +* This avoids re-inventing the wheel. +* The plugin supports excluding dependencies from the upgrade that could cause problems using the [``](https://www.mojohaus.org/versions/versions-maven-plugin/use-latest-releases-mojo.html#excludes) configuration. + +Covers +* [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) + +Needs: impl, utest, itest + +##### Generate Changelog + +PK generates the changelog for the fixed vulnerabilities if the required information is available. The changelog contains the following information: +* Issues that fix the vulnerabilities +* CVE-number, description and severity of each vulnerability +* The vulnerable dependency, its version and scope + +Rationale: +* The `dependencies_check.yml` workflow detects vulnerabilities and creates issues. It will output information about the created issues and the vulnerabilities. This information is passed to `dependencies_update.yml` as a parameter and forwarded to PK's `update-dependencies` mode. +* Vulnerability information must be optional in order to allow running the process locally. + +Covers +* [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) + +Needs: impl, utest, itest + +#### Generate `dependencies_update.yml` workflow +`dsn~dependencies_update-workflow~1` + +PK generates the `dependencies_update.yml` GitHub workflow. + +Covers +* [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) +* [`req~auto-create-changelog~1`](system_requirements.md#automatically-create-change-log-entry) +* [`req~auto-create-pr~1`](system_requirements.md#automatically-create-a-pull-request) + +Needs: dsn + +##### `dependencies_update.yml` Workflow Receives Vulnerability Info +`dsn~dependencies_update-vulnerability-info~1` + +PK generates the `dependencies_update.yml` workflow so that it receives information about vulnerabilities and issues as optional parameter. + +Needs: impl, utest, itest + +Covers +* [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) + +##### `dependencies_update.yml` Workflow Starts PK `update-dependencies` Mode +`dsn~dependencies_update-starts-pk-update~1` + +PK generates the `dependencies_update.yml` workflow so that it starts PK's [`update-dependencies` mode](#update-dependencies-mode), passing information about vulnerabilities. + +Rationale: + +PK needs the vulnerability info for generating the changelog. + +Needs: impl, utest, itest + +Covers +* [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) + +##### `dependencies_update.yml` Workflow Creates a Pull Request +`dsn~dependencies_update-creates-pull-request~1` + +PK generates the `dependencies_update.yml` workflow so that it creates a Pull Request in GitHub. This requires the following steps: +1. Create a new local branch using a random name +2. Commit local changes using a commit message that contains the issue number +3. Push the branch +4. Create a new pull request with `Closes` comments for each issue number +5. Send a Slack notification + * If the workflow fails: send a warning containing the workflow run + * If the workflow succeeded: send a success message containing the pull request link + +Rationale: + +We implement this in a workflow and not in PK because +* Git/GitHub operations should not be done locally to avoid surprises +* GitHub action automatically have credentials for pushing and creating a pull request + +Note: Implementing this in a workflow makes it hard to do integration tests. We accept that there are no integration tests for running the workflow. + +Needs: impl, utest, itest + +Covers: +* [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) diff --git a/doc/system_requirements.md b/doc/system_requirements.md index f2ee7638..4b9955b3 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -311,3 +311,76 @@ Covers: * `feat~npm-project-support~1` Needs: dsn + +### Automatic Dependency Update Process +`feat~automatic-dependency-update-process~1` + +PK supports the automatic dependency process. This speeds up fixing vulnerabilities in third party dependencies and creating releases. + +Rationale: + +We have 130+ projects in the integration team that often require dependency updates due to security issues that are found in the dependencies or transitive dependencies. Most of the time the update is a combination of pulling the latest source, updating the dependencies, updating the change log, running the tests locally, on success pushing the branch, running CI and creating a release. + +* Auto-update dependencies +* Automatically create change log entry +* Automatically run local tests +* Automatically push branch +* Automatically run CI +* Release + +Needs: req + +#### Auto-update dependencies +`req~auto-update-dependencies~1` + +PK automatically updates dependencies when a new vulnerability is found. + +Covers: +* `feat~automatic-dependency-update-process~1` + +Needs: dsn + +#### Automatically create change log entry +`req~auto-create-changelog~1` + +PK automatically generates the change log for fixed vulnerabilities. + +Rationale: + +The change log for fixed vulnerabilities always has the same structure and can be easily automated to avoid manual work. + +Covers: +* `feat~automatic-dependency-update-process~1` + +Needs: dsn + +#### Automatically Create a Pull Request +`req~auto-create-pr~1` + +PK creates a new Pull Request after upgrading dependencies. + +Rationale: + +A pull requests allows to +* automatically run tests using the upgraded dependencies to verify if the upgrade caused any problems +* review and approve changes +* manually modify files in case of problems + +Covers: +* `feat~automatic-dependency-update-process~1` + +Needs: dsn + +#### Release +`req~auto-release~1` + +PK automatically builds a new release whenever the `main` branch is updated. + +Rationale: + +This reduces manual work, it's not necessary any more to manually run release-droid. + +Covers: +* `feat~automatic-dependency-update-process~1` + +Needs: dsn From 180eb1ff27db1395756a4f2733886ede3e08325d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 17:48:43 +0100 Subject: [PATCH 05/78] Upgrade dependencies --- doc/changes/changes_4.0.0.md | 66 +++++++++++++++++++ maven-project-crawler/pk_generated_parent.pom | 10 +-- maven-project-crawler/pom.xml | 4 +- parent-pom/pom.xml | 18 ++++- pom.xml | 9 ++- project-keeper-cli/pk_generated_parent.pom | 10 +-- .../.settings/org.eclipse.jdt.core.prefs | 2 +- .../pk_generated_parent.pom | 10 +-- project-keeper-maven-plugin/pom.xml | 4 +- project-keeper/pk_generated_parent.pom | 10 +-- .../error-code-crawler-maven-plugin.xml | 2 +- .../maven_templates/flatten-maven-plugin.xml | 2 +- .../maven_templates/maven-compiler-plugin.xml | 2 +- .../maven_templates/maven-failsafe-plugin.xml | 2 +- .../maven_templates/maven-surefire-plugin.xml | 2 +- shared-model-classes/pk_generated_parent.pom | 8 +-- shared-test-setup/pk_generated_parent.pom | 8 +-- 17 files changed, 129 insertions(+), 40 deletions(-) diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md index 27e8d412..7e6892a8 100644 --- a/doc/changes/changes_4.0.0.md +++ b/doc/changes/changes_4.0.0.md @@ -10,6 +10,20 @@ Code name: Automatic Security Updates ## Dependency Updates +### Project Keeper Shared Model Classes + +#### Test Dependency Updates + +* Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` +* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` + +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` + ### Project Keeper Core #### Compile Dependency Updates @@ -23,6 +37,16 @@ Code name: Automatic Security Updates #### Test Dependency Updates * Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` +* Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` +* Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0` + +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-failsafe-plugin:3.2.3` to `3.2.5` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` ### Project Keeper Command Line Interface @@ -34,20 +58,62 @@ Code name: Automatic Security Updates * Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-failsafe-plugin:3.2.3` to `3.2.5` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` + ### Project Keeper Maven Plugin #### Compile Dependency Updates * Updated `com.exasol:project-keeper-core:3.0.1` to `4.0.0` +#### Test Dependency Updates + +* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` + +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-failsafe-plugin:3.2.3` to `3.2.5` +* Updated `org.apache.maven.plugins:maven-plugin-plugin:3.10.2` to `3.11.0` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` + ### Project Keeper Java Project Crawler #### Compile Dependency Updates * Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` +#### Test Dependency Updates + +* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` +* Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0` + +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-failsafe-plugin:3.2.3` to `3.2.5` +* Updated `org.apache.maven.plugins:maven-plugin-plugin:3.10.2` to `3.11.0` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` + ### Project Keeper Shared Test Setup #### Compile Dependency Updates * Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` + +#### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.1` to `2.0.0` +* Updated `org.apache.maven.plugins:maven-compiler-plugin:3.11.0` to `3.12.1` +* Updated `org.apache.maven.plugins:maven-surefire-plugin:3.2.3` to `3.2.5` +* Updated `org.codehaus.mojo:flatten-maven-plugin:1.5.0` to `1.6.0` diff --git a/maven-project-crawler/pk_generated_parent.pom b/maven-project-crawler/pk_generated_parent.pom index d3c92cc6..b9745cc7 100644 --- a/maven-project-crawler/pk_generated_parent.pom +++ b/maven-project-crawler/pk_generated_parent.pom @@ -88,7 +88,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -126,7 +126,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -165,7 +165,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -325,7 +325,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.3 + 3.2.5 -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} @@ -394,7 +394,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/maven-project-crawler/pom.xml b/maven-project-crawler/pom.xml index f173d06d..a031ef89 100644 --- a/maven-project-crawler/pom.xml +++ b/maven-project-crawler/pom.xml @@ -99,7 +99,9 @@ org.apache.maven.plugins maven-plugin-plugin - 3.10.2 + + pk-crawl + org.basepom.maven diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index 31e2b8f9..db5a528b 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -33,7 +33,7 @@ 3.6.3 5.10.1 2.9.1 - 5.8.0 + 5.10.0 UTF-8 UTF-8 11 @@ -89,7 +89,7 @@ org.apache.maven.plugin-tools maven-plugin-annotations - 3.10.2 + 3.11.0 provided @@ -111,6 +111,7 @@ org.eclipse.jgit org.eclipse.jgit + 6.7.0.202309050840-r @@ -204,7 +205,7 @@ nl.jqno.equalsverifier equalsverifier - 3.15.4 + 3.15.6 test @@ -215,4 +216,15 @@ + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.11.0 + + + + diff --git a/pom.xml b/pom.xml index 579e33f8..f574dd7a 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,13 @@ + + + false + html + ALL + true + org.apache.maven.plugins @@ -61,7 +68,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/project-keeper-cli/pk_generated_parent.pom b/project-keeper-cli/pk_generated_parent.pom index ea59acae..2f2022b7 100644 --- a/project-keeper-cli/pk_generated_parent.pom +++ b/project-keeper-cli/pk_generated_parent.pom @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -118,7 +118,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -157,7 +157,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -347,7 +347,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.3 + 3.2.5 -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} @@ -408,7 +408,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs b/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs index e55eb05b..364a360f 100644 --- a/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs +++ b/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs @@ -111,7 +111,7 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.processAnnotations=enabled org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false diff --git a/project-keeper-maven-plugin/pk_generated_parent.pom b/project-keeper-maven-plugin/pk_generated_parent.pom index 2789bdc5..7b91571e 100644 --- a/project-keeper-maven-plugin/pk_generated_parent.pom +++ b/project-keeper-maven-plugin/pk_generated_parent.pom @@ -88,7 +88,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -126,7 +126,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -165,7 +165,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -325,7 +325,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.3 + 3.2.5 -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} @@ -394,7 +394,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/project-keeper-maven-plugin/pom.xml b/project-keeper-maven-plugin/pom.xml index 8d16a459..06af4b13 100644 --- a/project-keeper-maven-plugin/pom.xml +++ b/project-keeper-maven-plugin/pom.xml @@ -91,7 +91,9 @@ org.apache.maven.plugins maven-plugin-plugin - 3.10.2 + + project-keeper + org.apache.maven.plugins diff --git a/project-keeper/pk_generated_parent.pom b/project-keeper/pk_generated_parent.pom index 9f59f2bb..44c2a879 100644 --- a/project-keeper/pk_generated_parent.pom +++ b/project-keeper/pk_generated_parent.pom @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -118,7 +118,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -157,7 +157,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -297,7 +297,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.3 + 3.2.5 -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} @@ -358,7 +358,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/project-keeper/src/main/resources/maven_templates/error-code-crawler-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/error-code-crawler-maven-plugin.xml index 09dccd46..564dafb3 100644 --- a/project-keeper/src/main/resources/maven_templates/error-code-crawler-maven-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/error-code-crawler-maven-plugin.xml @@ -1,7 +1,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/project-keeper/src/main/resources/maven_templates/flatten-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/flatten-maven-plugin.xml index a085da45..289e1055 100644 --- a/project-keeper/src/main/resources/maven_templates/flatten-maven-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/flatten-maven-plugin.xml @@ -1,7 +1,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss diff --git a/project-keeper/src/main/resources/maven_templates/maven-compiler-plugin.xml b/project-keeper/src/main/resources/maven_templates/maven-compiler-plugin.xml index d85791f3..39407441 100644 --- a/project-keeper/src/main/resources/maven_templates/maven-compiler-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/maven-compiler-plugin.xml @@ -1,7 +1,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} diff --git a/project-keeper/src/main/resources/maven_templates/maven-failsafe-plugin.xml b/project-keeper/src/main/resources/maven_templates/maven-failsafe-plugin.xml index 2976a31d..71ed162d 100644 --- a/project-keeper/src/main/resources/maven_templates/maven-failsafe-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/maven-failsafe-plugin.xml @@ -1,7 +1,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.2.3 + 3.2.5 -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} diff --git a/project-keeper/src/main/resources/maven_templates/maven-surefire-plugin.xml b/project-keeper/src/main/resources/maven_templates/maven-surefire-plugin.xml index 7a2a23ac..4845da1c 100644 --- a/project-keeper/src/main/resources/maven_templates/maven-surefire-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/maven-surefire-plugin.xml @@ -1,7 +1,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 diff --git a/shared-model-classes/pk_generated_parent.pom b/shared-model-classes/pk_generated_parent.pom index 0b397bd0..e5e3dba0 100644 --- a/shared-model-classes/pk_generated_parent.pom +++ b/shared-model-classes/pk_generated_parent.pom @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -118,7 +118,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -157,7 +157,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -338,7 +338,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify diff --git a/shared-test-setup/pk_generated_parent.pom b/shared-test-setup/pk_generated_parent.pom index c1109e2e..91f61d03 100644 --- a/shared-test-setup/pk_generated_parent.pom +++ b/shared-test-setup/pk_generated_parent.pom @@ -69,7 +69,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${java.version} ${java.version} @@ -107,7 +107,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.5.0 + 1.6.0 true oss @@ -146,7 +146,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 @@ -241,7 +241,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.1 + 2.0.0 verify From cd7fd116ff01e6311c29562bbc060935c9d02aae Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 25 Jan 2024 17:53:30 +0100 Subject: [PATCH 06/78] Fix eclipse config file --- .gitattributes | 2 ++ .../.settings/org.eclipse.jdt.core.prefs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 21854292..fba7f06d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,5 @@ pk_generated_parent.pom linguist-generated=true dependencies.md linguist-generated=true doc/changes/changelog.md linguist-generated=true + +.settings/org.eclipse.jdt.core.prefs linguist-generated=true diff --git a/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs b/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs index 364a360f..e55eb05b 100644 --- a/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs +++ b/project-keeper-maven-plugin/.settings/org.eclipse.jdt.core.prefs @@ -111,7 +111,7 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.processAnnotations=enabled +org.eclipse.jdt.core.compiler.processAnnotations=disabled org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=17 org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false From 8a55880adc3f93d9d95b375e51214abe6e053409 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 07:37:24 +0100 Subject: [PATCH 07/78] Mark other eclipse config file as generated --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index fba7f06d..50d4ab57 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,4 @@ dependencies.md linguist-generated=true doc/changes/changelog.md linguist-generated=true .settings/org.eclipse.jdt.core.prefs linguist-generated=true +.settings/org.eclipse.jdt.ui.prefs linguist-generated=true From 3d891e3e07f34580ada2304614acd82f9037f8c3 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 07:43:14 +0100 Subject: [PATCH 08/78] Fix tracing --- doc/design.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/design.md b/doc/design.md index 511f1408..058bd911 100644 --- a/doc/design.md +++ b/doc/design.md @@ -459,7 +459,7 @@ Rationale: `dependencies_check.yml` already uses the [security-issues](https://exasol.github.io/python-toolbox/github_actions/security_issues.html) tool from the [python-toolbox](https://github.com/exasol/python-toolbox) to create issues for new vulnerabilities. Re-implementing this in PK is not necessary. -Covers +Covers: * [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) Needs: impl, utest, itest @@ -483,7 +483,7 @@ Rationale: * This would be surprising when running it locally * This would require credentials for accessing the GitHub API -Covers +Covers: * [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) * [`req~auto-create-changelog~1`](system_requirements.md#automatically-create-change-log-entry) @@ -498,7 +498,7 @@ Rationale: Leaving the version unchanged when it was not yet released avoids surprises when running this locally. -Covers +Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) Needs: impl, utest, itest @@ -517,7 +517,7 @@ Rationale: * This avoids re-inventing the wheel. * The plugin supports excluding dependencies from the upgrade that could cause problems using the [``](https://www.mojohaus.org/versions/versions-maven-plugin/use-latest-releases-mojo.html#excludes) configuration. -Covers +Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) Needs: impl, utest, itest @@ -533,7 +533,7 @@ Rationale: * The `dependencies_check.yml` workflow detects vulnerabilities and creates issues. It will output information about the created issues and the vulnerabilities. This information is passed to `dependencies_update.yml` as a parameter and forwarded to PK's `update-dependencies` mode. * Vulnerability information must be optional in order to allow running the process locally. -Covers +Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) Needs: impl, utest, itest @@ -543,7 +543,7 @@ Needs: impl, utest, itest PK generates the `dependencies_update.yml` GitHub workflow. -Covers +Covers: * [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) * [`req~auto-create-changelog~1`](system_requirements.md#automatically-create-change-log-entry) * [`req~auto-create-pr~1`](system_requirements.md#automatically-create-a-pull-request) @@ -557,7 +557,7 @@ PK generates the `dependencies_update.yml` workflow so that it receives informat Needs: impl, utest, itest -Covers +Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) ##### `dependencies_update.yml` Workflow Starts PK `update-dependencies` Mode @@ -571,7 +571,7 @@ PK needs the vulnerability info for generating the changelog. Needs: impl, utest, itest -Covers +Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) ##### `dependencies_update.yml` Workflow Creates a Pull Request From c6afdf992aabb2caf0d10ade96b95ecad836945c Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 09:55:25 +0100 Subject: [PATCH 09/78] #515 Add design --- doc/design.md | 170 ++++++++++++++++++++++++++++++++++++- doc/system_requirements.md | 2 +- 2 files changed, 170 insertions(+), 2 deletions(-) diff --git a/doc/design.md b/doc/design.md index 058bd911..5fbc416d 100644 --- a/doc/design.md +++ b/doc/design.md @@ -582,7 +582,7 @@ PK generates the `dependencies_update.yml` workflow so that it creates a Pull Re 2. Commit local changes using a commit message that contains the issue number 3. Push the branch 4. Create a new pull request with `Closes` comments for each issue number -5. Send a Slack notification +5. If the Slack notification URL is available as secret: send a Slack notification * If the workflow fails: send a warning containing the workflow run * If the workflow succeeded: send a success message containing the pull request link @@ -591,6 +591,10 @@ Rationale: We implement this in a workflow and not in PK because * Git/GitHub operations should not be done locally to avoid surprises * GitHub action automatically have credentials for pushing and creating a pull request +* The Slack notification URL might not be available as secret to all repositories, so this step must be optional +* Sending notifications to developers to + * investigate a failed update process + * review and merge a new pull request Note: Implementing this in a workflow makes it hard to do integration tests. We accept that there are no integration tests for running the workflow. @@ -598,3 +602,167 @@ Needs: impl, utest, itest Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) + +#### Generate `release.yml` workflow +`dsn~release-workflow~1` + +PK generates the `release.yml` GitHub workflow for Maven projects. This workflow runs the build including tests, integration tests, releases to Maven Central and on GitHub. + +Rationale: +* The release process is limited to Maven projects. Support for other projects may be added later. +* The previous build process using release-droid used separate steps for testing and releasing. This allowed re-starting a release (e.g. to Maven Central) in case of failures, without having to start potentially long running tests (~40 minutes). + * The new process always runs the complete process, it's not possible to skip tests. + * We accept this disadvantage of potential slow release times for now because the release process to Maven Central is usually stable nowadays. + +Covers: +* [`req~auto-release~1`](system_requirements.md#automatic-release) + +Needs: dsn + +##### `release.yml` Workflow Triggers +`dsn~release-workflow-triggers~1` + +PK generates the `release.yml` workflow so that it is triggered by the following events: +* manual triggering (`workflow_dispatch`) +* push to `main` branch (`push: branches: - main`) + +Rationale: +* Manually triggering simplifies debugging in case of problems +* Hard-coding the `main` branch for the `push` trigger is OK because we assume that all repositories use the same development workflow + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +##### `release.yml` Workflow Release Verification +`dsn~release-workflow-run-verify-release~1` + +PK generates the `release.yml` workflow so that it runs PK in `verify-release` mode, see [`dsn~verify-release-mode~1`](#verify-release-mode). + +Rationale: +This ensures that all preconditions for the release are met (e.g. current release date). In the previous process this was checked by release-droid. + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +##### `release.yml` Workflow Runs Build +`dsn~release-workflow-run-build~1` + +PK generates the `release.yml` workflow so that it runs the build including tests, integration tests and verifications (`mvn verify`). + +Rationale: +* Supporting other build tools is not necessary for now because building and testing of other components (e.g. JavaScript extensions using `npm`) can be included into the Maven build process using the `exec-maven-plugin` plugin. + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +##### `release.yml` Workflow Deploys to Maven Central +`dsn~release-workflow-deploy-maven-central~1` + +If at least one source in `.project-keeper.yml` uses the `maven_central` module, PK generates the `release.yml` workflow so that it runs deploys the project to Maven Central (`mvn deploy`). + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +##### `release.yml` Workflow Creates GitHub Release +`dsn~release-workflow-create-github-release~1` + +PK generates the `release.yml` workflow so that it creates a new GitHub release for the new version. + +Rationale: +* In the old release process this was implemented in release-droid (`GitHubReleaseMaker.createReleaseModel()`). +* The GitHub workflow has permissions to use the GitHub API. + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +##### `release.yml` Workflow Creates Tags for Golang Modules +`dsn~release-workflow-create-golang-tags~1` + +PK generates the `release.yml` workflow so that it creates the correct tags for Golang modules. + +Rationale: +* In the old release process this was implemented in release-droid (`Revision.getTags()`). + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: impl, utest, itest + +#### `verify-release` Mode +`dsn~verify-release-mode~1` + +PK provides an `verify-release` mode in addition to `fix`, `verify` and `update-dependencies`. + +If any of the checks fails, PK fails with an exit code > 0 to signal a build failure. + +Covers: +* [`dsn~release-workflow~1`](#generate-releaseyml-workflow) + +Needs: dsn + +##### `verify-release` Mode Runs PK Verify +`dsn~verify-release-mode-verify~1` + +PK's `verify-release` mode runs the same validations as the `verify` mode. + +Rationale: +This simplifies usage because it's not necessary to start PK twice. + +Covers: +* [`dsn~verify-release-mode~1`](#verify-release-mode) + +Needs: impl, utest, itest + +##### `verify-release` Mode Checks Release Date +`dsn~verify-release-mode-verify-release-date~1` + +PK's `verify-release` mode verifies that the release date in the current version's changelog is the current date. + +Rationale: +* The release date must be up-to-date. In the previous release process this was checked by release-droid. +* This allows opting out of releasing: + * The `release.yml` workflow runs for every push to the `main` branch. This is not always intended if developers want to wait with the release and add more changes in other pull requests. + * Setting the release date to `2024-??-??` will let the `verify-release` mode fail which will stop the release build. +* Possible future improvement: + * To avoid creating a PR just for updating the release date we could add an optional parameter to the `release.yml` workflow that updates the release date and commits this change directly to `main`. + +Covers: +* [`dsn~verify-release-mode~1`](#verify-release-mode) + +Needs: impl, utest, itest + +##### `verify-release` Mode Checks All Issues are Closed +`dsn~verify-release-mode-verify-issues-closed~1` + +PK's `verify-release` mode verifies that all GitHub issues mentioned in the current version's changelog are closed. + +Rationale: +* In the previous release process this was checked by release-droid. + +Covers: +* [`dsn~verify-release-mode~1`](#verify-release-mode) + +Needs: impl, utest, itest + +##### `verify-release` Mode Checks Version Increment +`dsn~verify-release-mode-verify-version-increment~1` + +PK's `verify-release` mode verifies that current version was incremented correctly based on the previous version. + +Rationale: +* In the previous release process this was checked by release-droid in `CommonRepositoryValidator.validateSuccessor()` + +Covers: +* [`dsn~verify-release-mode~1`](#verify-release-mode) + +Needs: impl, utest, itest diff --git a/doc/system_requirements.md b/doc/system_requirements.md index 4b9955b3..a72f3699 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -371,7 +371,7 @@ Covers: Needs: dsn -#### Release +#### Automatic Release `req~auto-release~1` PK automatically builds a new release whenever the `main` branch is updated. From 221b0835598c9717b2328847fdfaf85b7eb221ee Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 12:29:04 +0100 Subject: [PATCH 10/78] Add diagrams --- doc/dependencies_update_process.plantuml | 25 ++++++++++++++++ doc/design.md | 21 ++++++++++++-- doc/release_process.plantuml | 37 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 doc/dependencies_update_process.plantuml create mode 100644 doc/release_process.plantuml diff --git a/doc/dependencies_update_process.plantuml b/doc/dependencies_update_process.plantuml new file mode 100644 index 00000000..6df2ea74 --- /dev/null +++ b/doc/dependencies_update_process.plantuml @@ -0,0 +1,25 @@ +@startuml Automatic Dependency Update Process + +start +:**dependencies_check.yml** workflow +(triggered daily); +note right + Pass information about created + issues & vulnerabilities to + **dependencies_update.yml** +end note +if(vulnerable dependencies found?) then (yes) + group **dependencies_update.yml** workflow + group PK **update-dependencies** + :Increment project version; + :Update dependencies; + :Generate changelog; + end group + :Create pull request; + :Send notification; + end group +else (no) + stop +endif +stop +@enduml diff --git a/doc/design.md b/doc/design.md index 5fbc416d..b9885b35 100644 --- a/doc/design.md +++ b/doc/design.md @@ -489,10 +489,10 @@ Covers: Needs: dsn -##### Incrementing the Version +##### Incrementing the Project Version `dsn~increment-version~1` -PK increments the patch version. PK does not modify the version if the current version was not yet released (i.e. there is not release in the latest changelog file). +PK increments the project's patch version. PK does not modify the version if the current version was not yet released (i.e. there is not release in the latest changelog file). Rationale: @@ -766,3 +766,20 @@ Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) Needs: impl, utest, itest + +##### `verify-release` Mode Sets GitHub Action Output Parameters +`dsn~verify-release-mode-output-parameters~1` + +PK's `verify-release` mode outputs the following information as [GitHub Output Parameters](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter): +* Project version +* Code name from changelog +* Remaining content of changelog + +Rationale: +* The `release.yml` workflow needs this information for creating the GitHub release. +* Steps in a GitHub workflow can read the output parameters of other steps. + +Covers: +* [`dsn~verify-release-mode~1`](#verify-release-mode) + +Needs: impl, utest, itest diff --git a/doc/release_process.plantuml b/doc/release_process.plantuml new file mode 100644 index 00000000..1d7377c4 --- /dev/null +++ b/doc/release_process.plantuml @@ -0,0 +1,37 @@ +@startuml Automatic Release Process + +start +note right + Triggered manually or + on pushes to main branch. +end note +group **release.yml** workflow + :Run PK **verify-release** as Maven plugin; + group PK **verify-release** + if(Check release date\n(allow skipping the release)) then (current date) + :Run PK **verify**; + :Run additional release checks; + :Write changelog content to file; + note right + Required for creating + the GitHub release + end note + else (not current date) + stop + endif + end group + :Run build and tests; + :Send notification; + if(Maven Central deployment required) then (required) + :Run **mvn deploy**; + endif + :Calculate checksums for release artifacts; + :Create GitHub release & + attach artifacts.; + note right + Reads changelog + content from file + end note +end group +stop +@enduml From 22606f2c426adda7a36756bd483ca1c9e0e38b05 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 13:11:49 +0100 Subject: [PATCH 11/78] Fix typos --- doc/changes/changes_2.9.3.md | 4 ++-- doc/system_requirements.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/changes/changes_2.9.3.md b/doc/changes/changes_2.9.3.md index 5f53487c..66e45b28 100644 --- a/doc/changes/changes_2.9.3.md +++ b/doc/changes/changes_2.9.3.md @@ -4,9 +4,9 @@ Code name: Fix GitHub verify workflow ## Summary -This release fixes fetching dependencies for NPM modules. Dependencies where only fetched for the first NPM module, not for the others. The release also fixes the syntax of the GitHub verify workflow file and increases the timeout for Maven Central deployments. +This release fixes fetching dependencies for NPM modules. Dependencies were only fetched for the first NPM module, not for the others. The release also fixes the syntax of the GitHub verify workflow file and increases the timeout for Maven Central deployments. -PK's template for github workflow `ci-build-next-java.yml` now uses Maven profile `-P skipNativeImage` for projects using PK module [native_image](../developers_guide/preparing_a_project_for_native_image_builds.md). +PK's template for github workflow `ci-build-next-java.yml` now uses Maven profile `-P skipNativeImage` for projects using PK module [native_image](../user_guide/preparing_a_project_for_native_image_builds.md). ## Features diff --git a/doc/system_requirements.md b/doc/system_requirements.md index a72f3699..eba3e1c6 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -266,7 +266,7 @@ Needs: dsn `req~golang-changed-dependency~1` -PK can retrieve changed Golang dependencies that where added, updated or removed since the last release. +PK can retrieve changed Golang dependencies that were added, updated or removed since the last release. Covers: @@ -305,7 +305,7 @@ Needs: dsn #### Get Changed Dependency `req~npm-changed-dependency~1` -PK can retrieve changed NPM dependencies that where added, updated or removed since the last release. +PK can retrieve changed NPM dependencies that were added, updated or removed since the last release. Covers: * `feat~npm-project-support~1` From 8123673af7deb91737df753caa67166e041a85f5 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 13:16:59 +0100 Subject: [PATCH 12/78] Add diagrams to design document --- doc/design.md | 4 ++++ doc/{ => images}/dependencies_update_process.plantuml | 2 +- doc/images/dependencies_update_process.svg | 1 + doc/{ => images}/release_process.plantuml | 2 +- doc/images/release_process.svg | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) rename doc/{ => images}/dependencies_update_process.plantuml (91%) create mode 100644 doc/images/dependencies_update_process.svg rename doc/{ => images}/release_process.plantuml (95%) create mode 100644 doc/images/release_process.svg diff --git a/doc/design.md b/doc/design.md index b9885b35..a7b341c7 100644 --- a/doc/design.md +++ b/doc/design.md @@ -450,6 +450,8 @@ This consists of the following steps: 2. Update dependencies 3. Create a pull request +![Activity Diagram for the dependencies update process](images/dependencies_update_process.svg) + #### Triggering the Dependency Update Process `dsn~trigger-dependency-updates~1` @@ -614,6 +616,8 @@ Rationale: * The new process always runs the complete process, it's not possible to skip tests. * We accept this disadvantage of potential slow release times for now because the release process to Maven Central is usually stable nowadays. +![Activity diagram of the release process](images/release_process.svg) + Covers: * [`req~auto-release~1`](system_requirements.md#automatic-release) diff --git a/doc/dependencies_update_process.plantuml b/doc/images/dependencies_update_process.plantuml similarity index 91% rename from doc/dependencies_update_process.plantuml rename to doc/images/dependencies_update_process.plantuml index 6df2ea74..e59c6978 100644 --- a/doc/dependencies_update_process.plantuml +++ b/doc/images/dependencies_update_process.plantuml @@ -1,4 +1,4 @@ -@startuml Automatic Dependency Update Process +@startuml dependencies_update_process start :**dependencies_check.yml** workflow diff --git a/doc/images/dependencies_update_process.svg b/doc/images/dependencies_update_process.svg new file mode 100644 index 00000000..0808ba5e --- /dev/null +++ b/doc/images/dependencies_update_process.svg @@ -0,0 +1 @@ +Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowPKupdate-dependenciesIncrement project versionUpdate dependenciesGenerate changelogCreate pull requestSend notificationyesvulnerable dependencies found?no \ No newline at end of file diff --git a/doc/release_process.plantuml b/doc/images/release_process.plantuml similarity index 95% rename from doc/release_process.plantuml rename to doc/images/release_process.plantuml index 1d7377c4..dbdea85a 100644 --- a/doc/release_process.plantuml +++ b/doc/images/release_process.plantuml @@ -1,4 +1,4 @@ -@startuml Automatic Release Process +@startuml release_process start note right diff --git a/doc/images/release_process.svg b/doc/images/release_process.svg new file mode 100644 index 00000000..394a7407 --- /dev/null +++ b/doc/images/release_process.svg @@ -0,0 +1 @@ +Triggered manually oron pushes to main branch.release.ymlworkflowRun PKverify-releaseas Maven pluginPKverify-releaseRun PKverifyRun additional release checksRequired for creatingthe GitHub releaseWrite changelog content to filecurrent dateCheck release date(allow skipping the release)not current dateRun build and testsSend notificationRunmvn deployrequiredMaven Central deployment requiredCalculate checksums for release artifactsReads changelogcontent from fileCreate GitHub release &attach artifacts. \ No newline at end of file From 8a7c408cf8b5a7dfa5c86af8f42bda7e2f638c0d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 26 Jan 2024 13:28:49 +0100 Subject: [PATCH 13/78] Update diagrams --- .../dependencies_update_process.plantuml | 23 +++++++++++++--- doc/images/dependencies_update_process.svg | 2 +- doc/images/release_process.plantuml | 26 ++++++++++++++----- doc/images/release_process.svg | 2 +- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/doc/images/dependencies_update_process.plantuml b/doc/images/dependencies_update_process.plantuml index e59c6978..dd8b0ef1 100644 --- a/doc/images/dependencies_update_process.plantuml +++ b/doc/images/dependencies_update_process.plantuml @@ -10,13 +10,30 @@ note right end note if(vulnerable dependencies found?) then (yes) group **dependencies_update.yml** workflow - group PK **update-dependencies** - :Increment project version; + note right + GitHub Workflow + generated by PK + end note + :Run PK **update-dependencies** as Maven plugin; + group PK **update-dependencies** + note right + Implement + in PK + end note + if(latest version already released?) + :Increment project version; + endif :Update dependencies; :Generate changelog; + :Run PK fix; end group :Create pull request; - :Send notification; + note right + Needs information about + issues & vulnerabilities + end note + :Send Slack notification + for success and failure; end group else (no) stop diff --git a/doc/images/dependencies_update_process.svg b/doc/images/dependencies_update_process.svg index 0808ba5e..166d9dcb 100644 --- a/doc/images/dependencies_update_process.svg +++ b/doc/images/dependencies_update_process.svg @@ -1 +1 @@ -Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowPKupdate-dependenciesIncrement project versionUpdate dependenciesGenerate changelogCreate pull requestSend notificationyesvulnerable dependencies found?no \ No newline at end of file +Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowGitHub Workflowgenerated by PKRun PKupdate-dependenciesas Maven pluginPKupdate-dependenciesImplementin PKIncrement project versionlatest version already released?Update dependenciesGenerate changelogRun PK fixNeeds information aboutissues & vulnerabilitiesCreate pull requestSend Slack notificationfor success and failureyesvulnerable dependencies found?no \ No newline at end of file diff --git a/doc/images/release_process.plantuml b/doc/images/release_process.plantuml index dbdea85a..6f54aa41 100644 --- a/doc/images/release_process.plantuml +++ b/doc/images/release_process.plantuml @@ -6,9 +6,17 @@ note right on pushes to main branch. end note group **release.yml** workflow + note right + Generated + by PK + end note :Run PK **verify-release** as Maven plugin; group PK **verify-release** - if(Check release date\n(allow skipping the release)) then (current date) + note right + Implemented + in PK + end note + if(Release date up-to-date?\n(allow skipping the release)) then (up-to-date) :Run PK **verify**; :Run additional release checks; :Write changelog content to file; @@ -16,22 +24,28 @@ group **release.yml** workflow Required for creating the GitHub release end note - else (not current date) + else (invalid/outdated) + :Fail build; stop endif end group - :Run build and tests; - :Send notification; + :Run **mvn verify**; if(Maven Central deployment required) then (required) :Run **mvn deploy**; endif :Calculate checksums for release artifacts; - :Create GitHub release & - attach artifacts.; + :Create GitHub release; note right Reads changelog content from file end note + :Attach release artifacts and + checksums to GitHub release; + note right + Customizable + end note + :Send Slack notification + for success & failure; end group stop @enduml diff --git a/doc/images/release_process.svg b/doc/images/release_process.svg index 394a7407..850f6913 100644 --- a/doc/images/release_process.svg +++ b/doc/images/release_process.svg @@ -1 +1 @@ -Triggered manually oron pushes to main branch.release.ymlworkflowRun PKverify-releaseas Maven pluginPKverify-releaseRun PKverifyRun additional release checksRequired for creatingthe GitHub releaseWrite changelog content to filecurrent dateCheck release date(allow skipping the release)not current dateRun build and testsSend notificationRunmvn deployrequiredMaven Central deployment requiredCalculate checksums for release artifactsReads changelogcontent from fileCreate GitHub release &attach artifacts. \ No newline at end of file +Triggered manually oron pushes to main branch.release.ymlworkflowGeneratedby PKRun PKverify-releaseas Maven pluginPKverify-releaseImplementedin PKRelease date up-to-date?(allow skipping the release)up-to-dateinvalid/outdatedRun PKverifyRun additional release checksRequired for creatingthe GitHub releaseWrite changelog content to fileFail buildRunmvn verifyRunmvn deployrequiredMaven Central deployment requiredCalculate checksums for release artifactsReads changelogcontent from fileCreate GitHub releaseCustomizableAttach release artifacts andchecksums to GitHub releaseSend Slack notificationfor success & failure \ No newline at end of file From 3a7b47c0cf840cc8a8a735d3d9c79758f9d18beb Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 09:26:14 +0100 Subject: [PATCH 14/78] Add requirements for customizing workflows --- doc/design.md | 10 +++++++- doc/system_requirements.md | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/doc/design.md b/doc/design.md index a7b341c7..8dd125b5 100644 --- a/doc/design.md +++ b/doc/design.md @@ -612,9 +612,17 @@ PK generates the `release.yml` GitHub workflow for Maven projects. This workflow Rationale: * The release process is limited to Maven projects. Support for other projects may be added later. -* The previous build process using release-droid used separate steps for testing and releasing. This allowed re-starting a release (e.g. to Maven Central) in case of failures, without having to start potentially long running tests (~40 minutes). +* The previous build process with release-droid used separate steps for testing and releasing. This allowed re-starting a release (e.g. to Maven Central) in case of failures, without having to start potentially long running tests (~40 minutes). * The new process always runs the complete process, it's not possible to skip tests. * We accept this disadvantage of potential slow release times for now because the release process to Maven Central is usually stable nowadays. +* We implement the workflow purely with a single generated GitHub actions. An alternative would be to implement parts of the build logic (e.g. checksum of build artifacts) as workflow steps implemented in JavaScript. + * Advantages: + * All generated code is one file, no need to use multiple files or reference other workflows + * Simple, standalone implementation + * Disadvantage: + * Long generated workflow file + * Not easily testable, one option would be [nektos/act](https://github.com/nektos/act) + * We accept the disadvantages for now. However the architecture allows changing this in the future. ![Activity diagram of the release process](images/release_process.svg) diff --git a/doc/system_requirements.md b/doc/system_requirements.md index eba3e1c6..a3027a8f 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -336,7 +336,7 @@ Needs: req PK automatically updates dependencies when a new vulnerability is found. Covers: -* `feat~automatic-dependency-update-process~1` +* [`feat~automatic-dependency-update-process~1`](#automatic-dependency-update-process) Needs: dsn @@ -350,7 +350,7 @@ Rationale: The change log for fixed vulnerabilities always has the same structure and can be easily automated to avoid manual work. Covers: -* `feat~automatic-dependency-update-process~1` +* [`feat~automatic-dependency-update-process~1`](#automatic-dependency-update-process) Needs: dsn @@ -367,7 +367,7 @@ A pull requests allows to * manually modify files in case of problems Covers: -* `feat~automatic-dependency-update-process~1` +* [`feat~automatic-dependency-update-process~1`](#automatic-dependency-update-process) Needs: dsn @@ -381,6 +381,48 @@ Rationale: This reduces manual work, it's not necessary any more to manually run release-droid. Covers: -* `feat~automatic-dependency-update-process~1` +* [`feat~automatic-dependency-update-process~1`](#automatic-dependency-update-process) Needs: dsn + +### Customizable Workflows +`feat~customize-workflows~0` + +PK allows customizing the `ci-build.yml` and `release.yml` workflows with project-specific build steps. + +Rationale: +Some projects use customized workflows and exclude them from PK generation. Allowing to customize workflows will simplify maintenance of GH workflows. + +Needs: req + +#### Customize Release Artifacts +`req~customize-release-artifacts~0` + +PK allows customizing the list of files that are attached to new GitHub releases in the `release.yml` workflow. + +Rationale: +Some projects need to release custom files like executable `.jar` files or `.js` extensions. + +Needs: dsn + +Covers: +* [`feat~customize-workflows~0`](#customizable-workflows) + +#### Customize Build Process +`req~customize-release-artifacts~0` + +PK allows adding pre and post steps during the build process as well as customize the actual build step. + +Rationale: +Some projects need to +* install additional tools like Go, Node +* prepare files (e.g. `test_config.properties`) with configuration and credentials +* prepare test infrastructure with `terraform init && terraform apply` +* pass additional environment variables (e.g. AWS credentials) to the build step +* attach files to the workflow (e.g. `classes.lst` for the S3 virtual schema) +* run cleanup steps like `terraform destroy` + +Needs: dsn + +Covers: +* [`feat~customize-workflows~0`](#customizable-workflows) From 78de9571cf1edbc965266f96915708022dab92e6 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 11:08:37 +0100 Subject: [PATCH 15/78] Implement review findings for diagrams --- .gitattributes | 1 + doc/developer_guide/developer_guide.md | 14 +++++++++++++- .../dependencies_update_process.plantuml | 19 +++++++++++++++---- doc/images/dependencies_update_process.svg | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/.gitattributes b/.gitattributes index 50d4ab57..83cfcd69 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,3 +7,4 @@ doc/changes/changelog.md linguist-generated=true .settings/org.eclipse.jdt.core.prefs linguist-generated=true .settings/org.eclipse.jdt.ui.prefs linguist-generated=true +doc/images/.svg linguist-generated=true diff --git a/doc/developer_guide/developer_guide.md b/doc/developer_guide/developer_guide.md index 7b76989f..37c670f9 100644 --- a/doc/developer_guide/developer_guide.md +++ b/doc/developer_guide/developer_guide.md @@ -6,13 +6,25 @@ You need the following dependencies for running the tests: * Java Development Kit 11 * Maven 3.6.3 or later -* Go 1.16 or later for testing Go support, see [installation guide](https://go.dev/doc/install) +* Go 1.20 or later for testing Go support, see [installation guide](https://go.dev/doc/install) ### go-licenses [go-licenses](https://github.com/google/go-licenses/) is required for extracting Go module license information. Since version 2.7.0 PK will automatically install `go-licenses` if required. +## Requirements and Design + +Design documents are located at +* [system_requirements.md](../system_requirements.md) +* [design.md](../design.md) + +After modifying the `.plantuml` files in `doc/images/` please generate the `.svg` diagrams by running the following command and commit them to Git: + +```sh +./scripts/build_diagrams.sh +``` + ## Building When building a new release of PK then Maven might display the following error: diff --git a/doc/images/dependencies_update_process.plantuml b/doc/images/dependencies_update_process.plantuml index dd8b0ef1..5de174ae 100644 --- a/doc/images/dependencies_update_process.plantuml +++ b/doc/images/dependencies_update_process.plantuml @@ -8,7 +8,7 @@ note right issues & vulnerabilities to **dependencies_update.yml** end note -if(vulnerable dependencies found?) then (yes) +if(Vulnerable dependencies found?) then (yes) group **dependencies_update.yml** workflow note right GitHub Workflow @@ -20,14 +20,25 @@ if(vulnerable dependencies found?) then (yes) Implement in PK end note - if(latest version already released?) + if(Latest version already released?) then (yes) :Increment project version; + else (no) endif :Update dependencies; - :Generate changelog; :Run PK fix; + note right + Add dependency changes to + changelog, Update list of + dependencies, ... + end note + :Update changlog: add fixed vulnerabilites; + if(pom.xml contains artifact-reference-checker-maven-plugin) then (yes) + :Run artifact-reference-checker-maven-plugin:fix; + else (no) + endif end group - :Create pull request; + :Create branch, commit, push & + create pull request; note right Needs information about issues & vulnerabilities diff --git a/doc/images/dependencies_update_process.svg b/doc/images/dependencies_update_process.svg index 166d9dcb..8fe162b6 100644 --- a/doc/images/dependencies_update_process.svg +++ b/doc/images/dependencies_update_process.svg @@ -1 +1 @@ -Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowGitHub Workflowgenerated by PKRun PKupdate-dependenciesas Maven pluginPKupdate-dependenciesImplementin PKIncrement project versionlatest version already released?Update dependenciesGenerate changelogRun PK fixNeeds information aboutissues & vulnerabilitiesCreate pull requestSend Slack notificationfor success and failureyesvulnerable dependencies found?no \ No newline at end of file +Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowGitHub Workflowgenerated by PKRun PKupdate-dependenciesas Maven pluginPKupdate-dependenciesImplementin PKIncrement project versionyesLatest version already released?noUpdate dependenciesAdd dependency changes tochangelog, Update list ofdependencies, ...Run PK fixUpdate changlog: add fixed vulnerabilitesRun artifact-reference-checker-maven-plugin:fixyespom.xml contains artifact-reference-checker-maven-pluginnoNeeds information aboutissues & vulnerabilitiesCreate branch, commit, push &create pull requestSend Slack notificationfor success and failureyesVulnerable dependencies found?no \ No newline at end of file From 8a8dbfa51a8dc162d4191e783cef4509f9e375e5 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 11:25:16 +0100 Subject: [PATCH 16/78] Customize release artifacts --- doc/design.md | 60 ++++++++++++++++++++++++++++++++++++++ doc/system_requirements.md | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/doc/design.md b/doc/design.md index 8dd125b5..9d02c483 100644 --- a/doc/design.md +++ b/doc/design.md @@ -345,6 +345,66 @@ Covers: Needs: impl, utest, itest +### Customize Release Artifacts +`dsn~customize-release-artifacts~0` + +PK allows customizing the list of files that are attached to new GitHub releases in the `release.yml` workflow. + +Needs: dsn +Covers: +* [`req~customize-release-artifacts~0`](system_requirements.md#customize-release-artifacts) + +#### Archive Configured JAR Artifact +`dsn~customize-release-artifacts-jar~0` +Status: draft + +PK adds the JAR name configured in the `maven-assembly-plugin` to the list of release artifacts. + +Rationale: +* This avoids duplicating configuration already present in `pom.xml`. +* This requires evaluating placeholders, e.g. `document-files-virtual-schema-dist-${vs-common-document-files.version}-s3-${project.version}`. + +Covers: +* [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) + +Needs: impl, utest, itest + +#### Common List of Release Artifacts +`dsn~customize-release-artifacts-hard-coded~0` +Status: draft + +PK adds the following files to a hard coded list of release artifacts: +* `target/error_code_report.json` + +Rationale: +* These files are created by all projects. +* Hard coding this list in PK avoids duplication in the `.project-keeper.yml` + +Covers: +* [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) + +Needs: impl, utest, itest + +#### Custom Release Artifacts +`dsn~customize-release-artifacts-custom~0` + +PK adds a list of configured files to the list of release artifacts. + +Rationale: +This allows adding project-specific release artifacts like `.js` extensions. + +Covers: +* [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) + +Needs: impl, utest, itest + +### Customize Build Process +`dsn~customize-build-process~0` + +Covers: + +* [`req~customize-build-process~0`](system_requirements.md#customize-build-process) + ## Golang Support ### Get Project Version diff --git a/doc/system_requirements.md b/doc/system_requirements.md index a3027a8f..18ceaef6 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -409,7 +409,7 @@ Covers: * [`feat~customize-workflows~0`](#customizable-workflows) #### Customize Build Process -`req~customize-release-artifacts~0` +`req~customize-build-process~0` PK allows adding pre and post steps during the build process as well as customize the actual build step. From 71e4b2d1bcf94bdf28297e4032ef5f57d75925c4 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 11:31:05 +0100 Subject: [PATCH 17/78] Disable tracing into sources for unimplemented requirements --- doc/design.md | 44 +++++++++++++++++++++----------------------- pom.xml | 3 +-- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/doc/design.md b/doc/design.md index 9d02c483..731d85fc 100644 --- a/doc/design.md +++ b/doc/design.md @@ -356,7 +356,6 @@ Covers: #### Archive Configured JAR Artifact `dsn~customize-release-artifacts-jar~0` -Status: draft PK adds the JAR name configured in the `maven-assembly-plugin` to the list of release artifacts. @@ -367,11 +366,10 @@ Rationale: Covers: * [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) -Needs: impl, utest, itest +-Needs: impl, utest, itest #### Common List of Release Artifacts `dsn~customize-release-artifacts-hard-coded~0` -Status: draft PK adds the following files to a hard coded list of release artifacts: * `target/error_code_report.json` @@ -383,7 +381,7 @@ Rationale: Covers: * [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) -Needs: impl, utest, itest +-Needs: impl, utest, itest #### Custom Release Artifacts `dsn~customize-release-artifacts-custom~0` @@ -396,7 +394,7 @@ This allows adding project-specific release artifacts like `.js` extensions. Covers: * [`dsn~customize-release-artifacts~0`](#customize-release-artifacts) -Needs: impl, utest, itest +-Needs: impl, utest, itest ### Customize Build Process `dsn~customize-build-process~0` @@ -524,7 +522,7 @@ Rationale: Covers: * [`req~auto-update-dependencies~1`](system_requirements.md#auto-update-dependencies) -Needs: impl, utest, itest +-Needs: impl, utest, itest #### Update Dependencies Mode `dsn~update-dependencies-mode~1` @@ -563,7 +561,7 @@ Leaving the version unchanged when it was not yet released avoids surprises when Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### Upgrade Dependencies `dsn~upgrade-dependencies~1` @@ -582,7 +580,7 @@ Rationale: Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### Generate Changelog @@ -598,7 +596,7 @@ Rationale: Covers: * [`dsn~update-dependencies-mode~1`](#update-dependencies-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest #### Generate `dependencies_update.yml` workflow `dsn~dependencies_update-workflow~1` @@ -617,7 +615,7 @@ Needs: dsn PK generates the `dependencies_update.yml` workflow so that it receives information about vulnerabilities and issues as optional parameter. -Needs: impl, utest, itest +-Needs: impl, utest, itest Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) @@ -631,7 +629,7 @@ Rationale: PK needs the vulnerability info for generating the changelog. -Needs: impl, utest, itest +-Needs: impl, utest, itest Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) @@ -660,7 +658,7 @@ We implement this in a workflow and not in PK because Note: Implementing this in a workflow makes it hard to do integration tests. We accept that there are no integration tests for running the workflow. -Needs: impl, utest, itest +-Needs: impl, utest, itest Covers: * [`dsn~dependencies_update-workflow~1`](#generate-dependencies_updateyml-workflow) @@ -705,7 +703,7 @@ Rationale: Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `release.yml` Workflow Release Verification `dsn~release-workflow-run-verify-release~1` @@ -718,7 +716,7 @@ This ensures that all preconditions for the release are met (e.g. current releas Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `release.yml` Workflow Runs Build `dsn~release-workflow-run-build~1` @@ -731,7 +729,7 @@ Rationale: Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `release.yml` Workflow Deploys to Maven Central `dsn~release-workflow-deploy-maven-central~1` @@ -741,7 +739,7 @@ If at least one source in `.project-keeper.yml` uses the `maven_central` module, Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `release.yml` Workflow Creates GitHub Release `dsn~release-workflow-create-github-release~1` @@ -755,7 +753,7 @@ Rationale: Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `release.yml` Workflow Creates Tags for Golang Modules `dsn~release-workflow-create-golang-tags~1` @@ -768,7 +766,7 @@ Rationale: Covers: * [`dsn~release-workflow~1`](#generate-releaseyml-workflow) -Needs: impl, utest, itest +-Needs: impl, utest, itest #### `verify-release` Mode `dsn~verify-release-mode~1` @@ -793,7 +791,7 @@ This simplifies usage because it's not necessary to start PK twice. Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `verify-release` Mode Checks Release Date `dsn~verify-release-mode-verify-release-date~1` @@ -811,7 +809,7 @@ Rationale: Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `verify-release` Mode Checks All Issues are Closed `dsn~verify-release-mode-verify-issues-closed~1` @@ -824,7 +822,7 @@ Rationale: Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `verify-release` Mode Checks Version Increment `dsn~verify-release-mode-verify-version-increment~1` @@ -837,7 +835,7 @@ Rationale: Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest ##### `verify-release` Mode Sets GitHub Action Output Parameters `dsn~verify-release-mode-output-parameters~1` @@ -854,4 +852,4 @@ Rationale: Covers: * [`dsn~verify-release-mode~1`](#verify-release-mode) -Needs: impl, utest, itest +-Needs: impl, utest, itest diff --git a/pom.xml b/pom.xml index f574dd7a..a2d83f9e 100644 --- a/pom.xml +++ b/pom.xml @@ -50,8 +50,7 @@ - - false + true html ALL true From 6029d61e7fbfab16163345a55a14aad8625327e2 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 14:10:07 +0100 Subject: [PATCH 18/78] Fail on compiler warnings --- dependencies.md | 20 +++++++++---------- project-keeper-cli/pom.xml | 11 ++++++++++ project-keeper-maven-plugin/pom.xml | 11 ++++++++++ project-keeper/pom.xml | 11 ++++++++++ shared-model-classes/pom.xml | 15 ++++++++++++++ .../MavenProjectCrawlResult.java | 2 ++ shared-test-setup/pom.xml | 15 ++++++++++++++ 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/dependencies.md b/dependencies.md index fcd2d32f..c623cd8e 100644 --- a/dependencies.md +++ b/dependencies.md @@ -90,6 +90,7 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | @@ -102,11 +103,10 @@ | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | ## Project Keeper Command Line Interface @@ -148,14 +148,14 @@ | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [Artifact reference checker and unifier][59] | [MIT License][60] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -192,14 +192,14 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Maven Plugin Plugin][65] | [Apache-2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | | [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | | [Maven Surefire Plugin][30] | [Apache-2.0][16] | | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | @@ -207,7 +207,7 @@ | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | | [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -261,7 +261,7 @@ | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | | [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -350,8 +350,8 @@ [53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE [54]: https://github.com/exasol/maven-plugin-integration-testing/ [55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE -[56]: https://maven.apache.org/surefire/maven-failsafe-plugin/ -[57]: https://maven.apache.org/plugins/maven-jar-plugin/ +[56]: https://maven.apache.org/plugins/maven-jar-plugin/ +[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/ [58]: https://maven.apache.org/plugins/maven-assembly-plugin/ [59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ [60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE diff --git a/project-keeper-cli/pom.xml b/project-keeper-cli/pom.xml index 084c8570..6138d643 100644 --- a/project-keeper-cli/pom.xml +++ b/project-keeper-cli/pom.xml @@ -59,6 +59,17 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + org.apache.maven.plugins maven-assembly-plugin diff --git a/project-keeper-maven-plugin/pom.xml b/project-keeper-maven-plugin/pom.xml index 06af4b13..6674bff6 100644 --- a/project-keeper-maven-plugin/pom.xml +++ b/project-keeper-maven-plugin/pom.xml @@ -95,6 +95,17 @@ project-keeper + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + org.apache.maven.plugins maven-jar-plugin diff --git a/project-keeper/pom.xml b/project-keeper/pom.xml index 31e652b2..a0464df5 100644 --- a/project-keeper/pom.xml +++ b/project-keeper/pom.xml @@ -119,6 +119,17 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + diff --git a/shared-model-classes/pom.xml b/shared-model-classes/pom.xml index 6ec90efd..d949cf6c 100644 --- a/shared-model-classes/pom.xml +++ b/shared-model-classes/pom.xml @@ -75,4 +75,19 @@ test + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + + + diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java index 254fa507..65fea867 100644 --- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java +++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java @@ -37,6 +37,7 @@ public MavenProjectCrawlResult(final Map crawledPro * @param json serialized JSON * @return deserialized {@link DependencyChangeReport}. */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public static MavenProjectCrawlResult fromJson(final String json) { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.fromJson(json, MavenProjectCrawlResult.class); @@ -51,6 +52,7 @@ public static MavenProjectCrawlResult fromJson(final String json) { * * @return JSON string */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public String toJson() { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.toJson(this); diff --git a/shared-test-setup/pom.xml b/shared-test-setup/pom.xml index 9b492f1f..e63ce69e 100644 --- a/shared-test-setup/pom.xml +++ b/shared-test-setup/pom.xml @@ -34,4 +34,19 @@ maven-model + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + + + From 92f79435b29a2f4b55cc6a28ce0eab642c9452d8 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Mon, 29 Jan 2024 18:16:46 +0100 Subject: [PATCH 19/78] #515: Increment version --- .../cli/ProjectKeeperLauncher.java | 23 ++- .../plugin/ProjectKeeperFixMojo.java | 2 +- .../ProjectKeeperUpdateDependenciesMojo.java | 25 +++ .../plugin/ProjectKeeperVerifyMojo.java | 2 +- .../plugin/ProjectKeeperMojoIT.java | 55 +++++- project-keeper/error_code_config.yml | 2 +- .../exasol/projectkeeper/ProjectKeeper.java | 25 +++ .../dependencyupdate/DependencyUpdater.java | 65 +++++++ .../ProjectVersionIncrementor.java | 111 ++++++++++++ .../validators/changesfile/ChangesFile.java | 158 +++++++++++++++--- .../validators/changesfile/ChangesFileIO.java | 56 +++++-- .../changesfile/ChangesFileSection.java | 4 +- .../changesfile/ChangesFileValidator.java | 10 +- .../changesfile/DependencySectionFixer.java | 4 +- .../changesfile/ChangesFileIOTest.java | 45 ++++- .../changesfile/ChangesFileSectionTest.java | 13 ++ .../changesfile/ChangesFileTest.java | 58 +++++++ .../DependencySectionFixerTest.java | 15 +- .../shared/repository/GitRepositoryTest.java | 6 +- 19 files changed, 616 insertions(+), 63 deletions(-) create mode 100644 project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperUpdateDependenciesMojo.java create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java diff --git a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java index 8e18b028..8e4c344a 100644 --- a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java +++ b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java @@ -19,6 +19,7 @@ public class ProjectKeeperLauncher { private static final Logger LOGGER = Logger.getLogger(ProjectKeeperLauncher.class.getName()); private static final String GOAL_VERIFY = "verify"; private static final String GOAL_FIX = "fix"; + private static final String GOAL_UPGRADE_DEPENDENCIES = "update-dependencies"; private final Path currentWorkingDir; @@ -60,7 +61,21 @@ void start(final String[] args) { private void runProjectKeeper(final String goal) { final ProjectKeeper projectKeeper = createProjectKeeper(); - final boolean success = goal.equals(GOAL_FIX) ? projectKeeper.fix() : projectKeeper.verify(); + final boolean success; + switch (goal) { + case GOAL_FIX: + success = projectKeeper.fix(); + break; + case GOAL_VERIFY: + success = projectKeeper.verify(); + break; + case GOAL_UPGRADE_DEPENDENCIES: + success = projectKeeper.updateDependencies(); + break; + default: + success = false; + break; + } if (!success) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CLI-1").message("Failed to run project keeper {{goal}}", goal) @@ -73,10 +88,12 @@ private ProjectKeeper createProjectKeeper() { } private void verifyCommandLineArguments(final String[] args) { - if ((args == null) || (args.length != 1) || !(GOAL_FIX.equals(args[0]) || GOAL_VERIFY.equals(args[0]))) { + if ((args == null) || (args.length != 1) || !(GOAL_FIX.equals(args[0]) || GOAL_VERIFY.equals(args[0]) + || GOAL_UPGRADE_DEPENDENCIES.equals(args[0]))) { throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CLI-2") .message("Got no or invalid command line argument {{arguments}}.", Arrays.toString(args)) - .mitigation("Please only specify arguments '" + GOAL_VERIFY + "' or '" + GOAL_FIX + "'.") + .mitigation("Please only specify arguments '" + GOAL_VERIFY + "', '" + GOAL_FIX + "' or '" + + GOAL_UPGRADE_DEPENDENCIES + "'.") .toString()); } } diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java index 38fddf9a..5f310cea 100644 --- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java +++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java @@ -6,7 +6,7 @@ import com.exasol.projectkeeper.ProjectKeeper; /** - * Entry point for the fix goal. + * Entry point for the {@code fix} goal. *

* Run using {@code mvn project-keeper:fix} *

diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperUpdateDependenciesMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperUpdateDependenciesMojo.java new file mode 100644 index 00000000..aac03317 --- /dev/null +++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperUpdateDependenciesMojo.java @@ -0,0 +1,25 @@ +package com.exasol.projectkeeper.plugin; + +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; + +import com.exasol.projectkeeper.ProjectKeeper; + +/** + * Entry point for the {@code update-dependencies} goal. + *

+ * Run using {@code mvn project-keeper:update-dependencies} + *

+ */ +@Mojo(name = "update-dependencies") +public class ProjectKeeperUpdateDependenciesMojo extends AbstractProjectKeeperMojo { + + @Override + protected void runProjectKeeper(final ProjectKeeper projectKeeper) throws MojoFailureException { + final boolean success = projectKeeper.updateDependencies(); + if (!success) { + throw new MojoFailureException( + "project-keeper:update-dependencies failed. See log messages above for details"); + } + } +} diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java index 2524c634..e28c1875 100644 --- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java +++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java @@ -7,7 +7,7 @@ import com.exasol.projectkeeper.ProjectKeeper; /** - * Entry point for the verify goal. + * Entry point for the {code verify} goal. *

* Run using {@code mvn project-keeper:verify} *

diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index 713edc4d..ea786067 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -2,17 +2,22 @@ import static com.exasol.projectkeeper.plugin.TestEnvBuilder.CURRENT_VERSION; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.*; import static org.hamcrest.io.FileMatchers.anExistingFile; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.time.LocalDate; +import java.util.List; import org.apache.maven.it.VerificationException; import org.apache.maven.it.Verifier; +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.junit.jupiter.api.*; @@ -72,8 +77,52 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException { anExistingFile()); } + @Test + void testUpgradeDependencies() throws VerificationException, IOException { + final PrintStream out = System.out; + Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // + "sources:\n" + // + " - type: maven\n" + // + " path: pom.xml\n"); + final Verifier verifier = getVerifier(); + verifier.executeGoal("project-keeper:fix"); + assertThat("original version", readPom().getVersion(), equalTo("0.1.0")); + + updateReleaseDate("0.1.0", "2023-01-01"); + verifier.verify(true); + + verifier.executeGoal("project-keeper:update-dependencies"); + verifier.verify(true); + + final List lines = verifier.loadFile(verifier.getBasedir(), verifier.getLogFileName(), false); + out.println("Got " + lines.size() + " lines:"); + lines.forEach(out::println); + assertThat("incremented version", readPom().getVersion(), equalTo("0.1.1")); + } + + private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) { + final Path changelogPath = projectDir.resolve("doc/changes/changes_" + changeLogVersion + ".md"); + try { + final String content = Files.readString(changelogPath); + final String updatedContent = content.replace(LocalDate.now().getYear() + "-??-??", newReleaseDate); + assertThat(updatedContent, not(equalTo(content))); + Files.writeString(changelogPath, updatedContent); + } catch (final IOException exception) { + throw new UncheckedIOException("Error updating release date in " + changelogPath, exception); + } + } + + private Model readPom() { + final Path path = projectDir.resolve("pom.xml"); + try { + return new MavenXpp3Reader().read(Files.newBufferedReader(path)); + } catch (IOException | XmlPullParserException exception) { + throw new IllegalStateException("failed to parse " + path + ": " + exception.getMessage(), exception); + } + } + @ParameterizedTest - @ValueSource(strings = { "verify", "fix" }) + @ValueSource(strings = { "verify", "fix", "update-dependencies" }) void testSkip(final String phase) throws IOException, VerificationException { Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // "sources:\n" + // diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml index e550c0e8..55570222 100644 --- a/project-keeper/error_code_config.yml +++ b/project-keeper/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CORE: packages: - com.exasol.projectkeeper - highest-index: 170 + highest-index: 174 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index 46a9de64..6ffdd407 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -13,6 +13,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.ValidationPhase.Provision; import com.exasol.projectkeeper.config.ProjectKeeperConfigReader; +import com.exasol.projectkeeper.dependencyupdate.DependencyUpdater; import com.exasol.projectkeeper.shared.config.*; import com.exasol.projectkeeper.sources.AnalyzedSource; import com.exasol.projectkeeper.sources.SourceAnalyzer; @@ -280,4 +281,28 @@ private interface PhaseResultHandler { */ boolean handlePhaseResult(final List findings); } + + /** + * Verify the project and return validation provisions. + * + * @return Validation provisions if the validation succeeded + * @throws IllegalStateException if validation fails + */ + private Provision getValidationProvision() { + Provision provision = null; + for (final Function phaseSupplier : getValidationPhases()) { + final ValidationPhase phase = phaseSupplier.apply(provision); + provision = phase.provision(); + final List findings = runValidation(phase.validators()); + if (!handleVerifyFindings(findings)) { + throw new IllegalStateException(ExaError.messageBuilder("").message("").toString()); + } + } + return provision; + } + + public boolean updateDependencies() { + final Provision provision = getValidationProvision(); + return DependencyUpdater.create(logger, projectDir, provision.projectVersion()).updateDependencies(); + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java new file mode 100644 index 00000000..24335807 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -0,0 +1,65 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import java.nio.file.Path; + +import com.exasol.projectkeeper.Logger; + +/** + * This class runs the dependency update process. + */ +public class DependencyUpdater { + + private final Logger logger; + private final ProjectVersionIncrementor projectVersionIncrementor; + + DependencyUpdater(final Logger logger, final ProjectVersionIncrementor projectVersionIncrementor) { + this.logger = logger; + this.projectVersionIncrementor = projectVersionIncrementor; + + } + + public static DependencyUpdater create(final Logger logger, final Path projectDir, + final String currentProjectVersion) { + return new DependencyUpdater(logger, new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion)); + } + + /** + * Runs the dependency update process. This includes the following steps: + *
    + *
  1. Increment project patch version if necessary
  2. + *
  3. Update all dependencies to their latest versions
  4. + *
  5. Run project-keeper fix
  6. + *
  7. If available: add information about fixed vulnerabilities to changelog
  8. + *
+ * + * @return {@code true} if the process succeeded. + */ + public boolean updateDependencies() { + incrementProjectVersion(); + updateDependencyVersions(); + runProjectKeeperFix(); + updateChangelog(); + return true; + } + + private void incrementProjectVersion() { + if (projectVersionIncrementor.isCurrentVersionReleased()) { + logger.info("Current version was already released: increment version"); + projectVersionIncrementor.incrementProjectVersion(); + } else { + logger.info("Current version was not yet released: no need to increment"); + } + } + + private void updateDependencyVersions() { + // TODO Auto-generated method stub + } + + private void runProjectKeeperFix() { + // TODO Auto-generated method stub + } + + private void updateChangelog() { + // TODO Auto-generated method stub + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java new file mode 100644 index 00000000..2ba32e24 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -0,0 +1,111 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.*; +import java.util.Objects; +import java.util.Optional; + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import com.exasol.errorreporting.ExaError; +import com.exasol.projectkeeper.Logger; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; +import com.vdurmont.semver4j.Semver; + +class ProjectVersionIncrementor { + private static final ZoneId UTC_ZONE = ZoneId.of("UTC"); + private final String currentProjectVersion; + private final ChangesFileIO changesFileIO; + private final Clock clock; + private final Path projectDir; + private final Logger logger; + + ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion) { + this(logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC()); + } + + ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion, + final ChangesFileIO changesFileIO, final Clock clock) { + this.logger = logger; + this.projectDir = projectDir; + this.changesFileIO = changesFileIO; + this.clock = clock; + this.currentProjectVersion = Objects.requireNonNull(currentProjectVersion, "currentProjectVersion"); + } + + /** + * Check if the current version was released, i.e. has a changelog release date in the past or today. + * + * @return {@code true} if the current version was released (i.e. has a release date) or not (i.e. has no release + * date or a future date) + */ + boolean isCurrentVersionReleased() { + final Path changesFilePath = projectDir.resolve(ChangesFile.getPathForVersion(currentProjectVersion)); + final ChangesFile changesFile = changesFileIO.read(changesFilePath); + final Optional releaseDate = changesFile.getParsedReleaseDate(); + if (releaseDate.isEmpty()) { + logger.info("Found invalid date '" + changesFile.getReleaseDate() + "' in changelog " + changesFilePath + + ": version " + currentProjectVersion + " was not yet released"); + return false; + } + final boolean released = releaseDate.get().isBefore(today()); + if (released) { + logger.info("Version " + currentProjectVersion + " was released on " + changesFile.getReleaseDate() + + " according to " + changesFilePath); + } + return released; + } + + private LocalDate today() { + return LocalDate.ofInstant(clock.instant(), UTC_ZONE); + } + + void incrementProjectVersion() { + final Path path = getPomPath(); + final Model pom = readPom(path); + if (!this.currentProjectVersion.equals(pom.getVersion())) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message( + "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}", + pom.getVersion(), path, currentProjectVersion).toString()); + } + final String nextVersion = getIncrementedVersion(currentProjectVersion); + System.out.println("#### Incremeing to " + nextVersion); + logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + path); + pom.setVersion(nextVersion); + writePom(path, pom); + } + + static String getIncrementedVersion(final String version) { + final Semver current = new Semver(version); + return current.nextPatch().toString(); + } + + private Model readPom(final Path path) { + try { + return new MavenXpp3Reader().read(Files.newBufferedReader(path)); + } catch (IOException | XmlPullParserException exception) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172") + .message("Failed to read pom {{pom file path}}", path).toString(), exception); + } + } + + private void writePom(final Path path, final Model pom) { + try { + new MavenXpp3Writer().write(Files.newOutputStream(getPomPath()), pom); + } catch (final IOException exception) { + throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173") + .message("Failed to write pom {{pom file path}}", path).toString(), exception); + } + } + + private Path getPomPath() { + return projectDir.resolve("pom.xml"); + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 38e3c4fd..85e229b9 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -1,6 +1,8 @@ package com.exasol.projectkeeper.validators.changesfile; import java.nio.file.Path; +import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -13,27 +15,37 @@ /** * This class represents a doc/changes/changes_x.x.x.md file. */ -public class ChangesFile { +public final class ChangesFile { /** Headline of the dependency updates section. */ public static final String DEPENDENCY_UPDATES_HEADING = "## Dependency Updates"; + private final String projectName; + private final Semver projectVersion; + private final String releaseDate; private final List headerSectionLines; private final List sections; + private ChangesFile(final Builder builder) { + this.projectName = Objects.requireNonNull(builder.projectName, "projectName"); + this.projectVersion = Objects.requireNonNull(builder.projectVersion, "projectVersion"); + this.releaseDate = Objects.requireNonNull(builder.releaseDate, "releaseDate"); + this.headerSectionLines = List.copyOf(Objects.requireNonNull(builder.header, "header")); + this.sections = List.copyOf(Objects.requireNonNull(builder.sections, "sections")); + } + /** - * Create a new instance of {@link ChangesFile}. - * - * @param headerLines lines of the changes file until the first level section - * @param sections sections of the changes file + * Get the relative path of the changes file for the given version. + * + * @param projectVersion project version + * @return relative path of the changes file, e.g. {@code doc/changes/changes_1.2.3.md} */ - public ChangesFile(final List headerLines, final List sections) { - this.headerSectionLines = headerLines; - this.sections = sections; + public static Path getPathForVersion(final String projectVersion) { + return Path.of("doc", "changes", new Filename(projectVersion).filename()); } /** - * Filename of a changes file, e.g. "changes_1.2.3.md". + * Filename of a changes file, e.g. {@code changes_1.2.3.md}. */ - public static class Filename implements Comparable { + public static final class Filename implements Comparable { /** Regular expression to identify valid names of changes files and to extract version number. **/ public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md"); @@ -111,6 +123,58 @@ public static Builder builder() { return new Builder(); } + /** + * Get a builder configured with the this ChangesFile. This is useful for creating a copy and modify some parts of + * this object. + * + * @return a preconfigured builder + */ + public Builder toBuilder() { + return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString()) + .releaseDate(this.releaseDate).setHeader(this.headerSectionLines).sections(this.sections); + } + + /** + * Get the project name for the first header line, e.g. {@code Project Keeper}. + * + * @return project name + */ + public String getProjectName() { + return projectName; + } + + /** + * Get the project version for the first header line, e.g. {@code 1.2.3}. + * + * @return project version + */ + public Semver getProjectVersion() { + return projectVersion; + } + + /** + * Get the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}. + * + * @return release date + */ + public String getReleaseDate() { + return releaseDate; + } + + /** + * Get the parsed release date for the first header line. If the date is not valid (e.g. {@code 2024-??-??}), this + * will return an empty {@link Optional}. + * + * @return release date + */ + public Optional getParsedReleaseDate() { + try { + return Optional.of(LocalDate.parse(this.getReleaseDate())); + } catch (final DateTimeParseException exception) { + return Optional.empty(); + } + } + /** * Get the header of the changes section. *

@@ -142,21 +206,26 @@ public List getSections() { } @Override - public boolean equals(final Object other) { - if (this == other) { + public boolean equals(final Object obj) { + if (this == obj) { return true; } - if ((other == null) || (getClass() != other.getClass())) { + if (obj == null) { return false; } - final ChangesFile that = (ChangesFile) other; - return Objects.equals(this.headerSectionLines, that.headerSectionLines) - && Objects.equals(this.sections, that.sections); + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFile other = (ChangesFile) obj; + return Objects.equals(projectName, other.projectName) && Objects.equals(projectVersion, other.projectVersion) + && Objects.equals(releaseDate, other.releaseDate) + && Objects.equals(headerSectionLines, other.headerSectionLines) + && Objects.equals(sections, other.sections); } @Override public int hashCode() { - return Objects.hash(this.headerSectionLines, this.sections); + return Objects.hash(projectName, projectVersion, releaseDate, headerSectionLines, sections); } @Override @@ -169,13 +238,49 @@ public String toString() { * Builder for {@link ChangesFile}. */ public static class Builder { - private final List sections = new ArrayList<>(); + private String projectName; + private Semver projectVersion; + private String releaseDate; + private List sections = new ArrayList<>(); private List header = Collections.emptyList(); private Builder() { // private constructor to hide public default } + /** + * Set the project name for the first header line, e.g. {@code Project Keeper}. + * + * @param projectName project name + * @return self for fluent programming + */ + public Builder projectName(final String projectName) { + this.projectName = projectName; + return this; + } + + /** + * Set the project version for the first header line, e.g. {@code 1.2.3}. + * + * @param projectVersion project version + * @return self for fluent programming + */ + public Builder projectVersion(final String projectVersion) { + this.projectVersion = new Semver(projectVersion); + return this; + } + + /** + * Set the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}. + * + * @param releaseDate release date + * @return self for fluent programming + */ + public Builder releaseDate(final String releaseDate) { + this.releaseDate = releaseDate; + return this; + } + /** * Set the header of the changes file. * @@ -198,13 +303,28 @@ public Builder addSection(final List lines) { return this; } + /** + * Set all sections of the changes file. + * + * @param lines list of sections + * @return self for fluent programming + */ + public Builder sections(final List sections) { + this.sections = List.copyOf(sections); + return this; + } + /** * Build the {@link ChangesFile}. * * @return built {@link ChangesFile} */ public ChangesFile build() { - return new ChangesFile(this.header, this.sections); + return new ChangesFile(this); } } + + public static String getDependencyUpdatesHeading() { + return DEPENDENCY_UPDATES_HEADING; + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 3853c6f2..245a3b69 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -4,14 +4,21 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; import com.exasol.errorreporting.ExaError; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; /** * This class reads and writes a {@link ChangesFile} from disk. */ public class ChangesFileIO { + private static final String PROJECT_NAME_PATTERN = "[\\w\\s-]+"; + private static final String VERSION_PATTERN = "\\d+\\.\\d+\\.\\d+"; + private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}"; + private static final Pattern FIRST_LINE_PATTERN = Pattern + .compile("^# (" + PROJECT_NAME_PATTERN + ") (" + VERSION_PATTERN + "), released (" + DATE_PATTERN + ")$"); private static final Pattern SECTION_HEADING_PATTERN = Pattern.compile("\\s*##\\s.*"); private static final String LINE_SEPARATOR = System.lineSeparator(); @@ -23,19 +30,7 @@ public class ChangesFileIO { */ public ChangesFile read(final Path file) { try (final var fileReader = new BufferedReader(new FileReader(file.toFile()))) { - String sectionHeader = null; - String line; - final var builder = ChangesFile.builder(); - final List lineBuffer = new ArrayList<>(); - while ((line = fileReader.readLine()) != null) { - if (SECTION_HEADING_PATTERN.matcher(line).matches()) { - makeSection(sectionHeader, builder, lineBuffer); - sectionHeader = line; - } - lineBuffer.add(line); - } - makeSection(sectionHeader, builder, lineBuffer); - return builder.build(); + return read(file, fileReader); } catch (final IOException exception) { throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-39") .message("Failed to read changes file {{file}}.").parameter("file", file.toString()).toString(), @@ -43,6 +38,41 @@ public ChangesFile read(final Path file) { } } + ChangesFile read(final Path file, final BufferedReader fileReader) throws IOException { + String sectionHeader = null; + String line; + int lineCount = 0; + final var builder = ChangesFile.builder(); + final List lineBuffer = new ArrayList<>(); + while ((line = fileReader.readLine()) != null) { + if (lineCount == 0) { + parseFirstLine(file, line, builder); + } + if (SECTION_HEADING_PATTERN.matcher(line).matches()) { + makeSection(sectionHeader, builder, lineBuffer); + sectionHeader = line; + } + lineBuffer.add(line); + lineCount++; + } + makeSection(sectionHeader, builder, lineBuffer); + return builder.build(); + } + + private void parseFirstLine(final Path filePath, final String line, final Builder builder) { + final Matcher matcher = FIRST_LINE_PATTERN.matcher(line); + if (!matcher.matches()) { + throw new IllegalStateException(ExaError.messageBuilder("PK-CORE-171") + .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, line) + .mitigation("Update first line so that it matches regex {{expected regular expression}}", + FIRST_LINE_PATTERN) + .toString()); + } + builder.projectName(matcher.group(1)) // + .projectVersion(matcher.group(2)) // + .releaseDate(matcher.group(3)); + } + private void makeSection(final String sectionHeader, final ChangesFile.Builder builder, final List lineBuffer) { if (!lineBuffer.isEmpty()) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java index b5109bf9..26a27080 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java @@ -11,7 +11,7 @@ * Each level two heading (##) starts a new section. *

*/ -public class ChangesFileSection { +public final class ChangesFileSection { private final List content; /** @@ -24,7 +24,7 @@ public ChangesFileSection(final List content) { throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-36") .message("changes file sections must not be empty.").ticketMitigation().toString()); } - this.content = content; + this.content = List.copyOf(content); } /** diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java index 30a8bb5b..47ee1961 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java @@ -31,7 +31,7 @@ public class ChangesFileValidator extends AbstractFileValidator { */ public ChangesFileValidator(final String projectVersion, final String projectName, final Path projectDirectory, final List sources) { - super(projectDirectory, Path.of("doc", "changes", new ChangesFile.Filename(projectVersion).filename())); + super(projectDirectory, ChangesFile.getPathForVersion(projectVersion)); this.projectVersion = projectVersion; this.projectName = projectName; this.sources = sources; @@ -72,9 +72,11 @@ private ChangesFile fixSections(final ChangesFile changesFile) { } private ChangesFile getTemplate() { - final var changesFile = ChangesFile.builder() - .setHeader(List.of("# " + this.projectName + " " + this.projectVersion + ", released " - + LocalDateTime.now().getYear() + "-??-??", "", "Code name:", "")) // + final String releaseDate = LocalDateTime.now().getYear() + "-??-??"; + final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion) + .releaseDate(releaseDate) + .setHeader(List.of("# " + this.projectName + " " + this.projectVersion + ", released " + releaseDate, + "", "Code name:", "")) // .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) // .build(); return fixSections(changesFile); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java index 01a08241..60f4ddf9 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java @@ -12,7 +12,7 @@ /** * This class fixes the dependency section of a {@link ChangesFile}. */ -//[impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] +// [impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] class DependencySectionFixer { private final List sources; @@ -41,7 +41,7 @@ public ChangesFile fix(final ChangesFile changesFile) { if (!renderedReport.isEmpty()) { sections.add(new ChangesFileSection(renderedReport)); } - return new ChangesFile(List.copyOf(changesFile.getHeaderSectionLines()), sections); + return changesFile.toBuilder().sections(sections).build(); } private NamedDependencyChangeReport getDependencyChangesOfSource(final AnalyzedSource source) { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 191984a6..ad02e0d7 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -1,12 +1,12 @@ package com.exasol.projectkeeper.validators.changesfile; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.nio.file.*; +import java.time.LocalDate; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -31,8 +31,9 @@ void testParsing() throws IOException { @Test void testWriting() throws IOException { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("# MyChanges")) - .addSection(List.of("## My Subsection")).build(); + final ChangesFile changesFile = ChangesFile.builder().projectName("project").projectVersion("1.2.3") + .releaseDate("2023-??-??").setHeader(List.of("# MyChanges")).addSection(List.of("## My Subsection")) + .build(); final Path testFile = this.tempDir.resolve("myFile.md"); new ChangesFileIO().write(changesFile, testFile); assertThat(Files.readString(testFile), @@ -49,6 +50,36 @@ void testReadAndWrite() throws IOException { assertThat(Files.readString(testFile), equalTo(Files.readString(changesFilePath))); } + @Test + void testReadInvalidFirstLineFails() { + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> read("# invalid first line")); + assertThat(exception.getMessage(), startsWith( + "PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex")); + } + + @Test + void testReadFirstLineWithDummyReleaseDate() throws IOException { + final ChangesFile changesFile = read("# Project Name 1.2.3, released 2024-??-??"); + assertThat(changesFile.getProjectName(), equalTo("Project Name")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); + assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??")); + assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false)); + } + + @Test + void testReadFirstLineWithValidReleaseDate() throws IOException { + final ChangesFile changesFile = read("# Project Name 1.2.3, released 2024-01-29"); + assertThat(changesFile.getProjectName(), equalTo("Project Name")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); + assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29")); + assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("2024-01-29"))); + } + + ChangesFile read(final String content) throws IOException { + return new ChangesFileIO().read(Path.of("dummy-file"), new BufferedReader(new StringReader(content))); + } + private Path loadExampleFileToTempDir() throws IOException { final Path changesFile = this.tempDir.resolve("changed_0.1.0.md"); try (final InputStream exampleFileStream = getClass().getClassLoader() @@ -57,4 +88,4 @@ private Path loadExampleFileToTempDir() throws IOException { } return changesFile; } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java new file mode 100644 index 00000000..929afba6 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java @@ -0,0 +1,13 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileSectionTest { + + @Test + void equalsContract() { + EqualsVerifier.forClass(ChangesFileSection.class).verify(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java new file mode 100644 index 00000000..da862e8e --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java @@ -0,0 +1,58 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileTest { + + @Test + void equalsContract() { + EqualsVerifier.forClass(ChangesFile.class).verify(); + } + + @Test + void equalsContractFilename() { + EqualsVerifier.forClass(Filename.class).verify(); + } + + @Test + void getPathForVersion() { + assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md"))); + } + + @Test + void toBuilderCreatesCopy() { + final ChangesFile changesFile = builder().build(); + final ChangesFile copy = changesFile.toBuilder().build(); + assertThat(copy, equalTo(changesFile)); + assertThat(changesFile.equals(copy), is(true)); + } + + private Builder builder() { + return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??") + .addSection(List.of("section 1")).setHeader(List.of("header 1")); + } + + @Test + void getParsedReleaseDateValid() { + assertThat(builder().releaseDate("2024-01-29").build().getParsedReleaseDate().get(), + equalTo(LocalDate.of(2024, 1, 29))); + } + + @Test + void getParsedReleaseDateInvalid() { + assertThat(builder().releaseDate("invalid").build().getParsedReleaseDate().isPresent(), is(false)); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java index 90ca108e..f9391bba 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java @@ -13,9 +13,10 @@ import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; import com.exasol.projectkeeper.shared.dependencychanges.NewDependency; import com.exasol.projectkeeper.sources.AnalyzedMavenSource; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; @Tag("integration") -//[utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] +// [utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] class DependencySectionFixerTest { private static AnalyzedMavenSource source; @@ -32,16 +33,20 @@ static void beforeAll() { @Test void testSectionIsAdded() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")).build(); + final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")).build(); final List sections = new DependencySectionFixer(List.of(source)).fix(changesFile) .getSections(); assertThat(sections.size(), equalTo(1)); assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); } + private Builder changesFileBuilder() { + return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate"); + } + @Test void testSectionIsUpdated() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")) + final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")) .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); final List sections = fixedChangesFile.getSections(); @@ -52,9 +57,9 @@ void testSectionIsUpdated() { @Test void testHeaderIsPreserved() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")) + final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")) .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); assertThat(changesFile.getHeaderSectionLines(), equalTo(fixedChangesFile.getHeaderSectionLines())); } -} \ No newline at end of file +} diff --git a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java index 7fd42a8d..bbd19c83 100644 --- a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java +++ b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java @@ -7,7 +7,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -176,6 +177,7 @@ void testGetRepoName() throws GitAPIException, IOException, URISyntaxException { } @Test + @SuppressWarnings("try") // auto-closeable resource git is never referenced in body of corresponding try statement void testFindLatestReleaseCommitNoCommit() throws IllegalStateException, GitAPIException, IOException { try (final Git git = gitInit()) { this.repository = openRepo(this.tempDir); @@ -267,4 +269,4 @@ private GitRepository openRepo(final Path path) { private Git gitInit() throws GitAPIException { return Git.init().setDirectory(this.tempDir.toFile()).call(); } -} \ No newline at end of file +} From cb8b9428c0995c86dbfc10574b6b5bb6536a966e Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:00:33 +0100 Subject: [PATCH 20/78] Fix logging in Maven Mojo test --- .../plugin/ProjectKeeperMojoIT.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index ea786067..0b3b530b 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -1,17 +1,20 @@ package com.exasol.projectkeeper.plugin; import static com.exasol.projectkeeper.plugin.TestEnvBuilder.CURRENT_VERSION; +import static java.util.stream.Collectors.joining; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.hamcrest.io.FileMatchers.anExistingFile; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.*; +import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDate; import java.util.List; +import java.util.logging.Logger; import org.apache.maven.it.VerificationException; import org.apache.maven.it.Verifier; @@ -29,8 +32,11 @@ class ProjectKeeperMojoIT { private static MavenIntegrationTestEnvironment mavenIntegrationTestEnvironment; + private static final Logger LOG = Logger.getLogger(ProjectKeeperMojoIT.class.getName()); + @TempDir protected Path projectDir; + private Verifier verifier; @BeforeAll static void beforeAll() { @@ -38,9 +44,19 @@ static void beforeAll() { } @BeforeEach - void beforeEach() throws IOException, GitAPIException { + void beforeEach(final TestInfo test) throws IOException, GitAPIException { Git.init().setDirectory(this.projectDir.toFile()).call().close(); new MvnProjectWithProjectKeeperPluginWriter(CURRENT_VERSION).writeAsPomToProject(this.projectDir); + LOG.info(() -> "Running test " + test.getDisplayName() + "..."); + verifier = mavenIntegrationTestEnvironment.getVerifier(this.projectDir); + } + + @AfterEach + void logMavenOutput(final TestInfo test) throws VerificationException { + verifier.resetStreams(); + final List lines = verifier.loadFile(verifier.getBasedir(), verifier.getLogFileName(), false); + LOG.info(() -> "Maven log output for test " + test.getDisplayName() + ": " + lines.size() + " lines\n" + + lines.stream().collect(joining("\n"))); } @Test @@ -51,7 +67,6 @@ void testVerify() throws IOException { "sources:\n" + // " - type: maven\n" + // " path: pom.xml\n"); - final Verifier verifier = getVerifier(); final VerificationException exception = assertThrows(VerificationException.class, () -> verifier.executeGoal("project-keeper:verify")); final String output = exception.getMessage(); @@ -70,7 +85,6 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException { " modules:\n" + // " - integration_tests\n" + // " - udf_coverage\n"); - final Verifier verifier = getVerifier(); verifier.executeGoal("project-keeper:fix"); verifier.executeGoal("package"); assertThat(this.projectDir.resolve(Path.of("target", "jacoco-agent", "org.jacoco.agent-runtime.jar")).toFile(), @@ -79,12 +93,10 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException { @Test void testUpgradeDependencies() throws VerificationException, IOException { - final PrintStream out = System.out; Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // "sources:\n" + // " - type: maven\n" + // " path: pom.xml\n"); - final Verifier verifier = getVerifier(); verifier.executeGoal("project-keeper:fix"); assertThat("original version", readPom().getVersion(), equalTo("0.1.0")); @@ -94,9 +106,6 @@ void testUpgradeDependencies() throws VerificationException, IOException { verifier.executeGoal("project-keeper:update-dependencies"); verifier.verify(true); - final List lines = verifier.loadFile(verifier.getBasedir(), verifier.getLogFileName(), false); - out.println("Got " + lines.size() + " lines:"); - lines.forEach(out::println); assertThat("incremented version", readPom().getVersion(), equalTo("0.1.1")); } @@ -128,13 +137,8 @@ void testSkip(final String phase) throws IOException, VerificationException { "sources:\n" + // " - type: maven\n" + // " path: pom.xml\n"); - final Verifier verifier = getVerifier(); verifier.setSystemProperty("project-keeper.skip", "true"); verifier.executeGoal("project-keeper:" + phase); verifier.verifyTextInLog("Skipping project-keeper."); } - - protected Verifier getVerifier() { - return mavenIntegrationTestEnvironment.getVerifier(this.projectDir); - } } From 30590fc1afe0f88027ddba90f230674c6ac2fe51 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:04:51 +0100 Subject: [PATCH 21/78] Fix javadoc --- .../projectkeeper/validators/changesfile/ChangesFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 85e229b9..2c4889c4 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -306,7 +306,7 @@ public Builder addSection(final List lines) { /** * Set all sections of the changes file. * - * @param lines list of sections + * @param sections list of sections * @return self for fluent programming */ public Builder sections(final List sections) { From d75ade4bdaaa763aec6ba78ec1390bd275ba8907 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:22:36 +0100 Subject: [PATCH 22/78] Fix error code crawler --- project-keeper/error_code_config.yml | 2 +- .../main/java/com/exasol/projectkeeper/ProjectKeeper.java | 8 +++++++- .../validators/changesfile/ChangesFileIO.java | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml index 55570222..5d506759 100644 --- a/project-keeper/error_code_config.yml +++ b/project-keeper/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CORE: packages: - com.exasol.projectkeeper - highest-index: 174 + highest-index: 176 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index 6ffdd407..fc9669e4 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -295,9 +295,15 @@ private Provision getValidationProvision() { provision = phase.provision(); final List findings = runValidation(phase.validators()); if (!handleVerifyFindings(findings)) { - throw new IllegalStateException(ExaError.messageBuilder("").message("").toString()); + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-175") + .message("Validation failed, see log messages for details.") + .mitigation("Fix findings and try again.").toString()); } } + if (provision == null) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-176") + .message("Validation did not return required provision.").ticketMitigation().toString()); + } return provision; } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 245a3b69..39daca08 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -62,7 +62,7 @@ ChangesFile read(final Path file, final BufferedReader fileReader) throws IOExce private void parseFirstLine(final Path filePath, final String line, final Builder builder) { final Matcher matcher = FIRST_LINE_PATTERN.matcher(line); if (!matcher.matches()) { - throw new IllegalStateException(ExaError.messageBuilder("PK-CORE-171") + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171") .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, line) .mitigation("Update first line so that it matches regex {{expected regular expression}}", FIRST_LINE_PATTERN) From 094c12059ab9aa2d9fc4ccea656ee40f01b700a5 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:27:33 +0100 Subject: [PATCH 23/78] Add missing javadoc comments --- .../main/java/com/exasol/projectkeeper/ProjectKeeper.java | 5 +++++ .../projectkeeper/dependencyupdate/DependencyUpdater.java | 8 ++++++++ .../projectkeeper/validators/changesfile/ChangesFile.java | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index fc9669e4..a43e0553 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -307,6 +307,11 @@ private Provision getValidationProvision() { return provision; } + /** + * Update dependencies in the project. + * + * @return {@code true} if the update was successful. + */ public boolean updateDependencies() { final Provision provision = getValidationProvision(); return DependencyUpdater.create(logger, projectDir, provision.projectVersion()).updateDependencies(); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 24335807..aa48869c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -18,6 +18,14 @@ public class DependencyUpdater { } + /** + * Create a new instance. + * + * @param logger the logger to which we should write log messages + * @param projectDir the project directory + * @param currentProjectVersion the project's current version + * @return a new dependency updater + */ public static DependencyUpdater create(final Logger logger, final Path projectDir, final String currentProjectVersion) { return new DependencyUpdater(logger, new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion)); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 2c4889c4..41ecaa29 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -324,6 +324,11 @@ public ChangesFile build() { } } + /** + * Get the heading for the dependency updates section. + * + * @return heading + */ public static String getDependencyUpdatesHeading() { return DEPENDENCY_UPDATES_HEADING; } From 8a997e9442d5aa11dbc368e280ba0e8fa4e66aed Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:33:20 +0100 Subject: [PATCH 24/78] Adapt unit test to new error message --- .../projectkeeper/validators/changesfile/ChangesFileIOTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index ad02e0d7..8faa532c 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -55,7 +55,7 @@ void testReadInvalidFirstLineFails() { final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> read("# invalid first line")); assertThat(exception.getMessage(), startsWith( - "PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex")); + "E-PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex")); } @Test From b45c1d253c459c96ffea144d358b0e5bc5b8c6f9 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:41:51 +0100 Subject: [PATCH 25/78] Fix integration tests --- .vscode/settings.json | 3 ++- .../com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4f1536d8..e5310098 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,8 @@ "java.sources.organizeImports.staticStarThreshold": 3, "java.test.config": { "vmArgs": [ - "-Djava.util.logging.config.file=src/test/resources/logging.properties" + "-Djava.util.logging.config.file=src/test/resources/logging.properties", + "-Dcom.exasol.projectkeeper.ownVersion=4.0.0" ] }, "sonarlint.connectedMode.project": { diff --git a/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java b/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java index 1c9d30b5..fff77a4a 100644 --- a/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java +++ b/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java @@ -42,7 +42,7 @@ static Stream invalidArguments() { @MethodSource("invalidArguments") void failsForWrongArguments(final String... args) throws IOException, InterruptedException { assertProcessFails(args, "E-PK-CLI-2: Got no or invalid command line argument '" + Arrays.toString(args) - + "'. Please only specify arguments 'verify' or 'fix'."); + + "'. Please only specify arguments 'verify', 'fix' or 'update-dependencies'."); } @Test @@ -50,7 +50,7 @@ void runMainMethodWithNullArgumentFails() throws IOException, InterruptedExcepti final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> ProjectKeeperLauncher.main(null)); assertThat(exception.getMessage(), equalTo( - "E-PK-CLI-2: Got no or invalid command line argument 'null'. Please only specify arguments 'verify' or 'fix'.")); + "E-PK-CLI-2: Got no or invalid command line argument 'null'. Please only specify arguments 'verify', 'fix' or 'update-dependencies'.")); } @Test From b214f0b4a242054328cca04a7c3842a22ce9cae0 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 09:47:38 +0100 Subject: [PATCH 26/78] Add test for updating dependencies via CLI --- .../exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java b/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java index fff77a4a..941ba7fd 100644 --- a/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java +++ b/project-keeper-cli/src/test/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncherIT.java @@ -68,6 +68,13 @@ void fixingJavaProjectSucceeds() throws InterruptedException, IOException { assertProcessSucceeds("verify"); } + @Test + void updateDependenciesJavaProjectSucceeds() throws InterruptedException, IOException { + prepareMavenProject(); + assertProcessSucceeds("fix"); + assertProcessSucceeds("update-dependencies"); + } + @Test void fixingGolangProjectSucceeds() throws InterruptedException, IOException { prepareGolangProject(); From 27fd6fd07c6900c976d090d7e4cf23b02612e680 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:03:12 +0100 Subject: [PATCH 27/78] Configure versions plugin --- maven-project-crawler/pk_generated_parent.pom | 9 +++++++++ project-keeper-cli/pk_generated_parent.pom | 9 +++++++++ project-keeper-cli/pom.xml | 2 +- project-keeper-maven-plugin/pk_generated_parent.pom | 9 +++++++++ project-keeper-maven-plugin/pom.xml | 2 +- project-keeper/pk_generated_parent.pom | 9 +++++++++ project-keeper/pom.xml | 2 +- .../resources/maven_templates/versions-maven-plugin.xml | 9 +++++++++ shared-model-classes/pk_generated_parent.pom | 9 +++++++++ shared-model-classes/pom.xml | 2 +- shared-test-setup/pk_generated_parent.pom | 9 +++++++++ shared-test-setup/pom.xml | 2 +- 12 files changed, 68 insertions(+), 5 deletions(-) diff --git a/maven-project-crawler/pk_generated_parent.pom b/maven-project-crawler/pk_generated_parent.pom index b9745cc7..2b3666f4 100644 --- a/maven-project-crawler/pk_generated_parent.pom +++ b/maven-project-crawler/pk_generated_parent.pom @@ -189,6 +189,15 @@
file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/project-keeper-cli/pk_generated_parent.pom b/project-keeper-cli/pk_generated_parent.pom index 2f2022b7..ba30b7ba 100644 --- a/project-keeper-cli/pk_generated_parent.pom +++ b/project-keeper-cli/pk_generated_parent.pom @@ -181,6 +181,15 @@
file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/project-keeper-cli/pom.xml b/project-keeper-cli/pom.xml index 6138d643..bb11e9b5 100644 --- a/project-keeper-cli/pom.xml +++ b/project-keeper-cli/pom.xml @@ -69,7 +69,7 @@ -Werror
-
+
org.apache.maven.plugins maven-assembly-plugin diff --git a/project-keeper-maven-plugin/pk_generated_parent.pom b/project-keeper-maven-plugin/pk_generated_parent.pom index 7b91571e..8183b84e 100644 --- a/project-keeper-maven-plugin/pk_generated_parent.pom +++ b/project-keeper-maven-plugin/pk_generated_parent.pom @@ -189,6 +189,15 @@
file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/project-keeper-maven-plugin/pom.xml b/project-keeper-maven-plugin/pom.xml index 6674bff6..f5a387f5 100644 --- a/project-keeper-maven-plugin/pom.xml +++ b/project-keeper-maven-plugin/pom.xml @@ -105,7 +105,7 @@ -Werror
-
+
org.apache.maven.plugins maven-jar-plugin diff --git a/project-keeper/pk_generated_parent.pom b/project-keeper/pk_generated_parent.pom index 44c2a879..06bead2f 100644 --- a/project-keeper/pk_generated_parent.pom +++ b/project-keeper/pk_generated_parent.pom @@ -181,6 +181,15 @@
file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/project-keeper/pom.xml b/project-keeper/pom.xml index a0464df5..08f81c72 100644 --- a/project-keeper/pom.xml +++ b/project-keeper/pom.xml @@ -129,7 +129,7 @@ -Werror
-
+
diff --git a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml index a16896b7..12245b95 100644 --- a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml @@ -14,5 +14,14 @@
file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/shared-model-classes/pk_generated_parent.pom b/shared-model-classes/pk_generated_parent.pom index e5e3dba0..ca085d17 100644 --- a/shared-model-classes/pk_generated_parent.pom +++ b/shared-model-classes/pk_generated_parent.pom @@ -181,6 +181,15 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/shared-model-classes/pom.xml b/shared-model-classes/pom.xml index d949cf6c..d9133db8 100644 --- a/shared-model-classes/pom.xml +++ b/shared-model-classes/pom.xml @@ -87,7 +87,7 @@ -Werror
-
+
diff --git a/shared-test-setup/pk_generated_parent.pom b/shared-test-setup/pk_generated_parent.pom index 91f61d03..1f787939 100644 --- a/shared-test-setup/pk_generated_parent.pom +++ b/shared-test-setup/pk_generated_parent.pom @@ -170,6 +170,15 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false
diff --git a/shared-test-setup/pom.xml b/shared-test-setup/pom.xml index e63ce69e..f5d81b06 100644 --- a/shared-test-setup/pom.xml +++ b/shared-test-setup/pom.xml @@ -46,7 +46,7 @@ -Werror
-
+ From 9d197444387e52514e02bb3a94fc22bfde4f4d65 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:07:00 +0100 Subject: [PATCH 28/78] Allow updating dependencies in parent pom --- parent-pom/pom.xml | 33 +++++++++++++++++++++++++++++++-- pom.xml | 1 + 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index db5a528b..09951eef 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -5,7 +5,7 @@ project-keeper-parent-pom pom ${revision} - Project Keeper parent pom + Project Keeper Parent POM This tool checks and unifies a project's structure according to the Exasol integration team's repository standards. @@ -112,7 +112,7 @@ org.eclipse.jgit org.eclipse.jgit - 6.7.0.202309050840-r + 6.8.0.202311291450-r net.steppschuh.markdowngenerator @@ -226,5 +226,34 @@ + + + org.codehaus.mojo + versions-maven-plugin + 2.16.2 + + + display-updates + package + + display-plugin-updates + display-dependency-updates + + + + + file:///${project.basedir}/../project-keeper/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + + + diff --git a/pom.xml b/pom.xml index a2d83f9e..def9b3ba 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ shared-test-setup maven-project-crawler project-keeper-maven-plugin + parent-pom Project Keeper Root Project From 82fc68b4e45ca8a3ea1ec751674cf6288f9d48c4 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:13:10 +0100 Subject: [PATCH 29/78] Exclude slf4j from upgrading --- dependencies.md | 477 ++++++++++++++++++----------------- doc/changes/changes_4.0.0.md | 5 + parent-pom/pom.xml | 4 + 3 files changed, 248 insertions(+), 238 deletions(-) diff --git a/dependencies.md b/dependencies.md index c623cd8e..b38bad1e 100644 --- a/dependencies.md +++ b/dependencies.md @@ -11,42 +11,42 @@ | [JSON-B API][3] | [Eclipse Public License 2.0][1]; [GNU General Public License, version 2 with the GNU Classpath Exception][2] | | [Yasson][4] | [Eclipse Public License v. 2.0][5]; [Eclipse Distribution License v. 1.0][6] | | [error-reporting-java][7] | [MIT License][8] | -| [JGit - Core][9] | Eclipse Distribution License (New BSD License) | +| [JGit - Core][9] | [BSD-3-Clause][10] | ### Test Dependencies | Dependency | License | | ------------------------------------------ | --------------------------------- | -| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | -| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | -| [Hamcrest][12] | [BSD License 3][13] | -| [JUnit5 System Extensions][14] | [Eclipse Public License v2.0][5] | -| [EqualsVerifier \| release normal jar][15] | [Apache License, Version 2.0][16] | -| [to-string-verifier][17] | [MIT License][18] | -| [mockito-core][19] | [MIT][20] | -| [SLF4J JDK14 Binding][21] | [MIT License][18] | +| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | +| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | +| [Hamcrest][13] | [BSD License 3][14] | +| [JUnit5 System Extensions][15] | [Eclipse Public License v2.0][5] | +| [EqualsVerifier \| release normal jar][16] | [Apache License, Version 2.0][17] | +| [to-string-verifier][18] | [MIT License][19] | +| [mockito-core][20] | [MIT][21] | +| [SLF4J JDK14 Binding][22] | [MIT License][19] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | -| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | -| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | -| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | -| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | +| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | +| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | +| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | +| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | ## Project Keeper Core @@ -54,59 +54,59 @@ | Dependency | License | | ----------------------------------------- | ---------------------------------------------- | -| [Project Keeper shared model classes][45] | [The MIT License][46] | -| [org.xmlunit:xmlunit-core][47] | [The Apache Software License, Version 2.0][29] | +| [Project Keeper shared model classes][46] | [The MIT License][47] | +| [org.xmlunit:xmlunit-core][48] | [The Apache Software License, Version 2.0][30] | | [error-reporting-java][7] | [MIT License][8] | -| [Markdown Generator][48] | [The Apache Software License, Version 2.0][29] | -| [semver4j][49] | [The MIT License][18] | -| [SnakeYAML][50] | [Apache License, Version 2.0][29] | -| [Maven Model][51] | [Apache-2.0][16] | +| [Markdown Generator][49] | [The Apache Software License, Version 2.0][30] | +| [semver4j][50] | [The MIT License][19] | +| [SnakeYAML][51] | [Apache License, Version 2.0][30] | +| [Maven Model][52] | [Apache-2.0][17] | ### Test Dependencies | Dependency | License | | ------------------------------------------ | ---------------------------------------------- | -| [Project Keeper shared test setup][45] | [The MIT License][46] | -| [Maven Project Version Getter][52] | [MIT License][53] | -| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | -| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | -| [Hamcrest][12] | [BSD License 3][13] | -| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | -| [mockito-junit-jupiter][19] | [MIT][20] | -| [Maven Plugin Integration Testing][54] | [MIT License][55] | -| [EqualsVerifier \| release normal jar][15] | [Apache License, Version 2.0][16] | -| [to-string-verifier][17] | [MIT License][18] | -| [SLF4J JDK14 Binding][21] | [MIT License][18] | +| [Project Keeper shared test setup][46] | [The MIT License][47] | +| [Maven Project Version Getter][53] | [MIT License][54] | +| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | +| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | +| [Hamcrest][13] | [BSD License 3][14] | +| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | +| [mockito-junit-jupiter][20] | [MIT][21] | +| [Maven Plugin Integration Testing][55] | [MIT License][56] | +| [EqualsVerifier \| release normal jar][16] | [Apache License, Version 2.0][17] | +| [to-string-verifier][18] | [MIT License][19] | +| [SLF4J JDK14 Binding][22] | [MIT License][19] | ### Runtime Dependencies | Dependency | License | | ----------------------------------------- | --------------------- | -| [Project Keeper Java project crawler][45] | [The MIT License][46] | +| [Project Keeper Java project crawler][46] | [The MIT License][47] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | -| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | -| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | -| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | -| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | +| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | +| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | +| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | +| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | ## Project Keeper Command Line Interface @@ -114,51 +114,51 @@ | Dependency | License | | ------------------------- | --------------------- | -| [Project Keeper Core][45] | [The MIT License][46] | +| [Project Keeper Core][46] | [The MIT License][47] | | [error-reporting-java][7] | [MIT License][8] | -| [Maven Model][51] | [Apache-2.0][16] | +| [Maven Model][52] | [Apache-2.0][17] | ### Test Dependencies | Dependency | License | | -------------------------------------- | --------------------------------- | -| [Project Keeper shared test setup][45] | [The MIT License][46] | -| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | -| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | -| [Hamcrest][12] | [BSD License 3][13] | -| [Maven Project Version Getter][52] | [MIT License][53] | +| [Project Keeper shared test setup][46] | [The MIT License][47] | +| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | +| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | +| [Hamcrest][13] | [BSD License 3][14] | +| [Maven Project Version Getter][53] | [MIT License][54] | ### Runtime Dependencies | Dependency | License | | ------------------------- | ----------------- | -| [SLF4J JDK14 Binding][21] | [MIT License][18] | +| [SLF4J JDK14 Binding][22] | [MIT License][19] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | -| [Artifact reference checker and unifier][59] | [MIT License][60] | -| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | -| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | -| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | -| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | -| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [Apache Maven Assembly Plugin][59] | [Apache-2.0][17] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | +| [Artifact reference checker and unifier][60] | [MIT License][61] | +| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | +| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | +| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | +| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | +| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | ## Project Keeper Maven Plugin @@ -166,105 +166,105 @@ | Dependency | License | | ----------------------------------------- | --------------------- | -| [Project Keeper Core][45] | [The MIT License][46] | -| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | -| [Maven Plugin API][62] | [Apache-2.0][16] | -| [Maven Core][63] | [Apache-2.0][16] | +| [Project Keeper Core][46] | [The MIT License][47] | +| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][17] | +| [Maven Plugin API][63] | [Apache-2.0][17] | +| [Maven Core][64] | [Apache-2.0][17] | | [error-reporting-java][7] | [MIT License][8] | ### Test Dependencies | Dependency | License | | -------------------------------------- | ---------------------------------------------- | -| [Maven Project Version Getter][52] | [MIT License][53] | -| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | -| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | -| [Hamcrest][12] | [BSD License 3][13] | -| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | -| [mockito-core][19] | [MIT][20] | -| [Maven Plugin Integration Testing][54] | [MIT License][55] | -| [SLF4J JDK14 Binding][21] | [MIT License][18] | -| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | +| [Maven Project Version Getter][53] | [MIT License][54] | +| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | +| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | +| [Hamcrest][13] | [BSD License 3][14] | +| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | +| [mockito-core][20] | [MIT][21] | +| [Maven Plugin Integration Testing][55] | [MIT License][56] | +| [SLF4J JDK14 Binding][22] | [MIT License][19] | +| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][42] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | -| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | -| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | -| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | -| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Maven Plugin Plugin][66] | [Apache-2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | +| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | +| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | +| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | +| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | +| [Apache Maven Dependency Plugin][67] | [Apache-2.0][17] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | ## Project Keeper Java Project Crawler ### Compile Dependencies -| Dependency | License | -| ----------------------------------------- | ---------------------------------------------- | -| [Project Keeper shared model classes][45] | [The MIT License][46] | -| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | -| [Maven Plugin API][62] | [Apache-2.0][16] | -| [error-reporting-java][7] | [MIT License][8] | -| [JGit - Core][9] | Eclipse Distribution License (New BSD License) | -| [semver4j][49] | [The MIT License][18] | -| [Maven Core][63] | [Apache-2.0][16] | +| Dependency | License | +| ----------------------------------------- | --------------------- | +| [Project Keeper shared model classes][46] | [The MIT License][47] | +| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][17] | +| [Maven Plugin API][63] | [Apache-2.0][17] | +| [error-reporting-java][7] | [MIT License][8] | +| [JGit - Core][9] | [BSD-3-Clause][10] | +| [semver4j][50] | [The MIT License][19] | +| [Maven Core][64] | [Apache-2.0][17] | ### Test Dependencies | Dependency | License | | -------------------------------------- | ---------------------------------------------- | -| [Maven Project Version Getter][52] | [MIT License][53] | -| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | -| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | -| [Hamcrest][12] | [BSD License 3][13] | -| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | -| [SLF4J JDK14 Binding][21] | [MIT License][18] | -| [mockito-core][19] | [MIT][20] | -| [mockito-junit-jupiter][19] | [MIT][20] | -| [Maven Plugin Integration Testing][54] | [MIT License][55] | -| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | +| [Maven Project Version Getter][53] | [MIT License][54] | +| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | +| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | +| [Hamcrest][13] | [BSD License 3][14] | +| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | +| [SLF4J JDK14 Binding][22] | [MIT License][19] | +| [mockito-core][20] | [MIT][21] | +| [mockito-junit-jupiter][20] | [MIT][21] | +| [Maven Plugin Integration Testing][55] | [MIT License][56] | +| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][42] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | -| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | -| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | -| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | -| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [Maven Plugin Plugin][66] | [Apache-2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | +| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | +| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | +| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | +| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | +| [Apache Maven Dependency Plugin][67] | [Apache-2.0][17] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | ## Project Keeper Shared Test Setup @@ -272,27 +272,27 @@ | Dependency | License | | ----------------------------------------- | --------------------------------- | -| [Project Keeper shared model classes][45] | [The MIT License][46] | -| [SnakeYAML][50] | [Apache License, Version 2.0][29] | -| [Hamcrest][12] | [BSD License 3][13] | -| [Maven Model][51] | [Apache-2.0][16] | +| [Project Keeper shared model classes][46] | [The MIT License][47] | +| [SnakeYAML][51] | [Apache License, Version 2.0][30] | +| [Hamcrest][13] | [BSD License 3][14] | +| [Maven Model][52] | [Apache-2.0][17] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | -| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | -| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | -| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | -| [Maven Surefire Plugin][30] | [Apache-2.0][16] | -| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | -| [error-code-crawler-maven-plugin][42] | [MIT License][43] | -| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | +| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | +| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | +| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | +| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | +| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | +| [Maven Surefire Plugin][31] | [Apache-2.0][17] | +| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | +| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | +| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | +| [error-code-crawler-maven-plugin][43] | [MIT License][44] | +| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | [0]: https://github.com/eclipse-ee4j/jsonp [1]: https://projects.eclipse.org/license/epl-2.0 @@ -304,60 +304,61 @@ [7]: https://github.com/exasol/error-reporting-java/ [8]: https://github.com/exasol/error-reporting-java/blob/main/LICENSE [9]: https://www.eclipse.org/jgit/ -[10]: https://junit.org/junit5/ -[11]: https://www.eclipse.org/legal/epl-v20.html -[12]: http://hamcrest.org/JavaHamcrest/ -[13]: http://opensource.org/licenses/BSD-3-Clause -[14]: https://github.com/itsallcode/junit5-system-extensions -[15]: https://www.jqno.nl/equalsverifier -[16]: https://www.apache.org/licenses/LICENSE-2.0.txt -[17]: https://github.com/jparams/to-string-verifier -[18]: http://www.opensource.org/licenses/mit-license.php -[19]: https://github.com/mockito/mockito -[20]: https://opensource.org/licenses/MIT -[21]: http://www.slf4j.org -[22]: http://sonarsource.github.io/sonar-scanner-maven/ -[23]: http://www.gnu.org/licenses/lgpl.txt -[24]: https://maven.apache.org/plugins/maven-toolchains-plugin/ -[25]: https://maven.apache.org/plugins/maven-compiler-plugin/ -[26]: https://maven.apache.org/enforcer/maven-enforcer-plugin/ -[27]: https://www.mojohaus.org/flatten-maven-plugin/ -[28]: https://sonatype.github.io/ossindex-maven/maven-plugin/ -[29]: http://www.apache.org/licenses/LICENSE-2.0.txt -[30]: https://maven.apache.org/surefire/maven-surefire-plugin/ -[31]: https://www.mojohaus.org/versions/versions-maven-plugin/ -[32]: https://basepom.github.io/duplicate-finder-maven-plugin -[33]: http://www.apache.org/licenses/LICENSE-2.0.html -[34]: https://maven.apache.org/plugins/maven-deploy-plugin/ -[35]: https://maven.apache.org/plugins/maven-gpg-plugin/ -[36]: https://maven.apache.org/plugins/maven-source-plugin/ -[37]: https://maven.apache.org/plugins/maven-javadoc-plugin/ -[38]: http://www.sonatype.com/public-parent/nexus-maven-plugins/nexus-staging/nexus-staging-maven-plugin/ -[39]: http://www.eclipse.org/legal/epl-v10.html -[40]: https://www.jacoco.org/jacoco/trunk/doc/maven.html -[41]: https://www.eclipse.org/legal/epl-2.0/ -[42]: https://github.com/exasol/error-code-crawler-maven-plugin/ -[43]: https://github.com/exasol/error-code-crawler-maven-plugin/blob/main/LICENSE -[44]: http://zlika.github.io/reproducible-build-maven-plugin -[45]: https://github.com/exasol/project-keeper/ -[46]: https://github.com/exasol/project-keeper/blob/main/LICENSE -[47]: https://www.xmlunit.org/ -[48]: https://github.com/Steppschuh/Java-Markdown-Generator -[49]: https://github.com/vdurmont/semver4j -[50]: https://bitbucket.org/snakeyaml/snakeyaml -[51]: https://maven.apache.org/ref/3.9.6/maven-model/ -[52]: https://github.com/exasol/maven-project-version-getter/ -[53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE -[54]: https://github.com/exasol/maven-plugin-integration-testing/ -[55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE -[56]: https://maven.apache.org/plugins/maven-jar-plugin/ -[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/ -[58]: https://maven.apache.org/plugins/maven-assembly-plugin/ -[59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ -[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE -[61]: https://maven.apache.org/plugin-tools/maven-plugin-annotations -[62]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ -[63]: https://maven.apache.org/ref/3.9.6/maven-core/ -[64]: https://www.eclemma.org/jacoco/index.html -[65]: https://maven.apache.org/plugin-tools/maven-plugin-plugin -[66]: https://maven.apache.org/plugins/maven-dependency-plugin/ +[10]: https://www.eclipse.org/org/documents/edl-v10.php +[11]: https://junit.org/junit5/ +[12]: https://www.eclipse.org/legal/epl-v20.html +[13]: http://hamcrest.org/JavaHamcrest/ +[14]: http://opensource.org/licenses/BSD-3-Clause +[15]: https://github.com/itsallcode/junit5-system-extensions +[16]: https://www.jqno.nl/equalsverifier +[17]: https://www.apache.org/licenses/LICENSE-2.0.txt +[18]: https://github.com/jparams/to-string-verifier +[19]: http://www.opensource.org/licenses/mit-license.php +[20]: https://github.com/mockito/mockito +[21]: https://opensource.org/licenses/MIT +[22]: http://www.slf4j.org +[23]: http://sonarsource.github.io/sonar-scanner-maven/ +[24]: http://www.gnu.org/licenses/lgpl.txt +[25]: https://maven.apache.org/plugins/maven-toolchains-plugin/ +[26]: https://maven.apache.org/plugins/maven-compiler-plugin/ +[27]: https://maven.apache.org/enforcer/maven-enforcer-plugin/ +[28]: https://www.mojohaus.org/flatten-maven-plugin/ +[29]: https://sonatype.github.io/ossindex-maven/maven-plugin/ +[30]: http://www.apache.org/licenses/LICENSE-2.0.txt +[31]: https://maven.apache.org/surefire/maven-surefire-plugin/ +[32]: https://www.mojohaus.org/versions/versions-maven-plugin/ +[33]: https://basepom.github.io/duplicate-finder-maven-plugin +[34]: http://www.apache.org/licenses/LICENSE-2.0.html +[35]: https://maven.apache.org/plugins/maven-deploy-plugin/ +[36]: https://maven.apache.org/plugins/maven-gpg-plugin/ +[37]: https://maven.apache.org/plugins/maven-source-plugin/ +[38]: https://maven.apache.org/plugins/maven-javadoc-plugin/ +[39]: http://www.sonatype.com/public-parent/nexus-maven-plugins/nexus-staging/nexus-staging-maven-plugin/ +[40]: http://www.eclipse.org/legal/epl-v10.html +[41]: https://www.jacoco.org/jacoco/trunk/doc/maven.html +[42]: https://www.eclipse.org/legal/epl-2.0/ +[43]: https://github.com/exasol/error-code-crawler-maven-plugin/ +[44]: https://github.com/exasol/error-code-crawler-maven-plugin/blob/main/LICENSE +[45]: http://zlika.github.io/reproducible-build-maven-plugin +[46]: https://github.com/exasol/project-keeper/ +[47]: https://github.com/exasol/project-keeper/blob/main/LICENSE +[48]: https://www.xmlunit.org/ +[49]: https://github.com/Steppschuh/Java-Markdown-Generator +[50]: https://github.com/vdurmont/semver4j +[51]: https://bitbucket.org/snakeyaml/snakeyaml +[52]: https://maven.apache.org/ref/3.9.6/maven-model/ +[53]: https://github.com/exasol/maven-project-version-getter/ +[54]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE +[55]: https://github.com/exasol/maven-plugin-integration-testing/ +[56]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE +[57]: https://maven.apache.org/plugins/maven-jar-plugin/ +[58]: https://maven.apache.org/surefire/maven-failsafe-plugin/ +[59]: https://maven.apache.org/plugins/maven-assembly-plugin/ +[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ +[61]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE +[62]: https://maven.apache.org/plugin-tools/maven-plugin-annotations +[63]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ +[64]: https://maven.apache.org/ref/3.9.6/maven-core/ +[65]: https://www.eclemma.org/jacoco/index.html +[66]: https://maven.apache.org/plugin-tools/maven-plugin-plugin +[67]: https://maven.apache.org/plugins/maven-dependency-plugin/ diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md index 7e6892a8..6978dfeb 100644 --- a/doc/changes/changes_4.0.0.md +++ b/doc/changes/changes_4.0.0.md @@ -12,6 +12,10 @@ Code name: Automatic Security Updates ### Project Keeper Shared Model Classes +#### Compile Dependency Updates + +* Updated `org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r` to `6.8.0.202311291450-r` + #### Test Dependency Updates * Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` @@ -90,6 +94,7 @@ Code name: Automatic Security Updates #### Compile Dependency Updates * Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` +* Updated `org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r` to `6.8.0.202311291450-r` #### Test Dependency Updates diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index 09951eef..3044a23c 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -252,6 +252,10 @@ true true false + + + org.slf4j:slf4j-jdk14:jar:*:* + From 5a5746394b0db396bb2c29dc1cf1f4a33677d71d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:22:34 +0100 Subject: [PATCH 30/78] Add user guide entries --- doc/user_guide/user_guide.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/user_guide/user_guide.md b/doc/user_guide/user_guide.md index ff4cb0d6..8f339c72 100644 --- a/doc/user_guide/user_guide.md +++ b/doc/user_guide/user_guide.md @@ -268,6 +268,12 @@ In addition this plugin can also fix the project structure. For that use: mvn project-keeper:fix ``` +Run the following commands to update dependencies: + +```sh +mvn project-keeper:update-dependencies +``` + For multi-module projects these commands may fail with the following error: ``` @@ -279,6 +285,7 @@ In this case add command line option `--projects .`: ```sh mvn project-keeper:verify --projects . mvn project-keeper:fix --projects . +mvn project-keeper:update-dependencies --projects . ``` You can skip the execution of project-keeper by adding `-Dproject-keeper.skip=true` to your maven command. @@ -301,6 +308,13 @@ cd path/to/project java -jar path/to/project-keeper-cli-2.7.1.jar fix ``` +Run the following commands to update dependencies: + +```sh +cd path/to/project +java -jar path/to/project-keeper-cli-2.7.1.jar update-dependencies +``` + ### Project Version PK needs to know about the overall version of the project. For example for validating it in the changes file. For single source projects, PK simply takes the version from the project. For other projects you can: From 40c174e4743966613a8f31ff7864d143058a72b7 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:22:42 +0100 Subject: [PATCH 31/78] Remove debug code --- .../dependencyupdate/ProjectVersionIncrementor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index 2ba32e24..7a07464a 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -76,7 +76,6 @@ void incrementProjectVersion() { pom.getVersion(), path, currentProjectVersion).toString()); } final String nextVersion = getIncrementedVersion(currentProjectVersion); - System.out.println("#### Incremeing to " + nextVersion); logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + path); pom.setVersion(nextVersion); writePom(path, pom); From 48803630d27806e0be6a047379329194487a8740 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 10:26:41 +0100 Subject: [PATCH 32/78] Simplify test --- .../plugin/ProjectKeeperMojoIT.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index 0b3b530b..87aa7a7b 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -63,10 +63,9 @@ void logMavenOutput(final TestInfo test) throws VerificationException { // [itest->dsn~mvn-verify-goal~1] void testVerify() throws IOException { Files.writeString(this.projectDir.resolve("LICENSE"), "My License\n"); - Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // - "sources:\n" + // - " - type: maven\n" + // - " path: pom.xml\n"); + writeProjectKeeperConfig("sources:\n" + // + " - type: maven\n" + // + " path: pom.xml\n"); final VerificationException exception = assertThrows(VerificationException.class, () -> verifier.executeGoal("project-keeper:verify")); final String output = exception.getMessage(); @@ -78,13 +77,12 @@ void testVerify() throws IOException { @Test void testJacocoAgentIsExtracted() throws VerificationException, IOException { - Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // - "sources:\n" + // - " - type: maven\n" + // - " path: pom.xml\n" + // - " modules:\n" + // - " - integration_tests\n" + // - " - udf_coverage\n"); + writeProjectKeeperConfig("sources:\n" + // + " - type: maven\n" + // + " path: pom.xml\n" + // + " modules:\n" + // + " - integration_tests\n" + // + " - udf_coverage\n"); verifier.executeGoal("project-keeper:fix"); verifier.executeGoal("package"); assertThat(this.projectDir.resolve(Path.of("target", "jacoco-agent", "org.jacoco.agent-runtime.jar")).toFile(), @@ -93,10 +91,9 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException { @Test void testUpgradeDependencies() throws VerificationException, IOException { - Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // - "sources:\n" + // - " - type: maven\n" + // - " path: pom.xml\n"); + writeProjectKeeperConfig("sources:\n" + // + " - type: maven\n" + // + " path: pom.xml\n"); verifier.executeGoal("project-keeper:fix"); assertThat("original version", readPom().getVersion(), equalTo("0.1.0")); @@ -133,12 +130,15 @@ private Model readPom() { @ParameterizedTest @ValueSource(strings = { "verify", "fix", "update-dependencies" }) void testSkip(final String phase) throws IOException, VerificationException { - Files.writeString(this.projectDir.resolve(".project-keeper.yml"), // - "sources:\n" + // - " - type: maven\n" + // - " path: pom.xml\n"); + writeProjectKeeperConfig("sources:\n" + // + " - type: maven\n" + // + " path: pom.xml\n"); verifier.setSystemProperty("project-keeper.skip", "true"); verifier.executeGoal("project-keeper:" + phase); verifier.verifyTextInLog("Skipping project-keeper."); } + + private void writeProjectKeeperConfig(final String content) throws IOException { + Files.writeString(this.projectDir.resolve(".project-keeper.yml"), content); + } } From 45201b67a56b2cdd71853ec2f224a3fa41117226 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 12:09:57 +0100 Subject: [PATCH 33/78] Extract Maven process builder --- .../JavaProjectCrawlerRunner.java | 43 ++++++----- .../analyze/generic/MavenProcessBuilder.java | 72 +++++++++++++++++++ 2 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java index 3c4449ee..e8aa3ecd 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java @@ -5,16 +5,17 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.time.Duration; -import java.util.*; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.OsCheck.OSType; import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder; +import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; import com.exasol.projectkeeper.stream.AsyncStreamReader; import com.exasol.projectkeeper.stream.CollectingConsumer; @@ -53,22 +54,9 @@ private String runCrawlerPlugin(final Path... pomFiles) { final String projectList = Arrays.stream(pomFiles).map(pomFile -> pomFile.toAbsolutePath().toString() // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540 .replace(FileSystems.getDefault().getSeparator(), "/")).collect(Collectors.joining(";")); + final List commandParts = buildMavenCommand(projectList); + LOGGER.fine(() -> "Executing command " + commandParts); try { - final List commandParts = new ArrayList<>(List.of(getMavenExecutable(), "--batch-mode", - "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", - "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", - "-DprojectsToCrawl=" + projectList, - /* - * We need to disable the model cache here since it caches the parent poms with {revision} as - * version and then runs into trouble since the cache is different when reading the old pom (for - * comparing dependencies). - */ - "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")); - if (this.mvnRepositoryOverride != null) { - commandParts.add("-Dmaven.repo.local=" + this.mvnRepositoryOverride); - } - - LOGGER.fine(() -> "Executing command " + commandParts); final Process proc = new ProcessBuilder(commandParts).redirectErrorStream(true).start(); final CollectingConsumer outputStreamConsumer = new AsyncStreamReader() @@ -100,13 +88,22 @@ private String runCrawlerPlugin(final Path... pomFiles) { } } - private String getMavenExecutable() { - final OSType osType = new OsCheck().getOperatingSystemType(); - if (osType == OSType.WINDOWS) { - return "mvn.cmd"; - } else { - return "mvn"; + private List buildMavenCommand(final String projectList) { + final MavenProcessBuilder command = MavenProcessBuilder.create().addArguments("--batch-mode", + "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", + "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", + "-DprojectsToCrawl=" + projectList, + /* + * We need to disable the model cache here since it caches the parent poms with {revision} as version + * and then runs into trouble since the cache is different when reading the old pom (for comparing + * dependencies). + */ + "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true"); + + if (this.mvnRepositoryOverride != null) { + command.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); } + return command.build(); } private String getRunFailedMessage() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java new file mode 100644 index 00000000..c546567d --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -0,0 +1,72 @@ +package com.exasol.projectkeeper.sources.analyze.generic; + +import static java.util.Arrays.asList; + +import java.util.ArrayList; +import java.util.List; + +import com.exasol.projectkeeper.OsCheck; +import com.exasol.projectkeeper.OsCheck.OSType; + +/** + * This class allows building and starting a {@code mvn} command. + */ +public class MavenProcessBuilder { + + private final List command = new ArrayList<>(); + + private MavenProcessBuilder() { + // Use create() method + } + + /** + * Create a new builder. + * + * @return new builder + */ + public static MavenProcessBuilder create() { + final MavenProcessBuilder builder = new MavenProcessBuilder(); + builder.addArgument(getMavenExecutable()); + return builder; + } + + /** + * Add the given arguments to the command. + * + * @param arguments arguments to add + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder addArguments(final String... arguments) { + command.addAll(asList(arguments)); + return this; + } + + /** + * Add the given argument to the command. + * + * @param argument argument to add + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder addArgument(final String argument) { + command.add(argument); + return this; + } + + /** + * Build the command that can be used as argument for {@link ProcessBuilder}. + * + * @return the command + */ + public List build() { + return List.copyOf(this.command); + } + + private static String getMavenExecutable() { + final OSType osType = new OsCheck().getOperatingSystemType(); + if (osType == OSType.WINDOWS) { + return "mvn.cmd"; + } else { + return "mvn"; + } + } +} From 5fc7c70d357cf22564d8d293c2fd89827ba66a1f Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 12:10:14 +0100 Subject: [PATCH 34/78] Add integration test for updating dependencies --- ...nProjectWithProjectKeeperPluginWriter.java | 41 ++++++++++++------- .../plugin/ProjectKeeperMojoIT.java | 10 ++++- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java index 45437f20..9b5b8205 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java @@ -1,34 +1,47 @@ package com.exasol.projectkeeper.plugin; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.nio.file.Path; import java.util.List; import org.apache.maven.model.*; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; -public class MvnProjectWithProjectKeeperPluginWriter extends Model { - private static final long serialVersionUID = -8757020322006895512L; +public class MvnProjectWithProjectKeeperPluginWriter { public static final String PROJECT_ARTIFACT_ID = "my-test-project"; public static final String PROJECT_VERSION = "0.1.0"; + private final Model model; public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion) { - this.setBuild(new Build()); - this.setVersion(PROJECT_VERSION); - this.setArtifactId(PROJECT_ARTIFACT_ID); - this.setGroupId("com.exasol"); - this.setModelVersion("4.0.0"); - this.setDescription("my project description"); + this.model = new Model(); + this.model.setBuild(new Build()); + this.model.setVersion(PROJECT_VERSION); + this.model.setArtifactId(PROJECT_ARTIFACT_ID); + this.model.setGroupId("com.exasol"); + this.model.setModelVersion("4.0.0"); + this.model.setDescription("my project description"); addProjectKeeperPlugin(projectKeeperVersion); } - public void writeAsPomToProject(final Path projectDir) throws IOException { - try (final FileWriter fileWriter = new FileWriter(projectDir.resolve("pom.xml").toFile())) { - new MavenXpp3Writer().write(fileWriter, this); + public void writeAsPomToProject(final Path projectDir) { + final Path path = projectDir.resolve("pom.xml"); + try (final FileWriter fileWriter = new FileWriter(path.toFile())) { + new MavenXpp3Writer().write(fileWriter, this.model); + } catch (final IOException exception) { + throw new UncheckedIOException("Failed writing POM to file " + path, exception); } } + public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId, + final String version) { + final Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + this.model.getDependencies().add(dependency); + return this; + } + private void addProjectKeeperPlugin(final String version) { final Plugin projectKeeperPlugin = new Plugin(); projectKeeperPlugin.setGroupId("com.exasol"); @@ -37,6 +50,6 @@ private void addProjectKeeperPlugin(final String version) { final PluginExecution execution = new PluginExecution(); execution.setGoals(List.of("verify")); projectKeeperPlugin.setExecutions(List.of(execution)); - this.getBuild().addPlugin(projectKeeperPlugin); + this.model.getBuild().addPlugin(projectKeeperPlugin); } } diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index 87aa7a7b..bdf2d234 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -31,6 +31,7 @@ import com.exasol.mavenpluginintegrationtesting.MavenIntegrationTestEnvironment; class ProjectKeeperMojoIT { + private static final String ORIGINAL_SLF4J_VERSION = "1.7.36"; private static MavenIntegrationTestEnvironment mavenIntegrationTestEnvironment; private static final Logger LOG = Logger.getLogger(ProjectKeeperMojoIT.class.getName()); @@ -46,7 +47,9 @@ static void beforeAll() { @BeforeEach void beforeEach(final TestInfo test) throws IOException, GitAPIException { Git.init().setDirectory(this.projectDir.toFile()).call().close(); - new MvnProjectWithProjectKeeperPluginWriter(CURRENT_VERSION).writeAsPomToProject(this.projectDir); + new MvnProjectWithProjectKeeperPluginWriter(CURRENT_VERSION) // + .addDependency("org.slf4j", "slf4j-api", ORIGINAL_SLF4J_VERSION) // + .writeAsPomToProject(this.projectDir); LOG.info(() -> "Running test " + test.getDisplayName() + "..."); verifier = mavenIntegrationTestEnvironment.getVerifier(this.projectDir); } @@ -103,7 +106,10 @@ void testUpgradeDependencies() throws VerificationException, IOException { verifier.executeGoal("project-keeper:update-dependencies"); verifier.verify(true); - assertThat("incremented version", readPom().getVersion(), equalTo("0.1.1")); + final Model updatedPom = readPom(); + assertThat("incremented version", updatedPom.getVersion(), equalTo("0.1.1")); + assertThat("updated SLF4J version", updatedPom.getDependencies().get(0).getVersion(), + allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), startsWith("2."))); } private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) { From 30b07e59d29689036bbb135ab06ae1b6b576a868 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 12:16:51 +0100 Subject: [PATCH 35/78] Configure versions plugin --- maven-project-crawler/pk_generated_parent.pom | 2 ++ project-keeper-cli/pk_generated_parent.pom | 2 ++ project-keeper-maven-plugin/pk_generated_parent.pom | 2 ++ project-keeper/pk_generated_parent.pom | 2 ++ .../main/resources/maven_templates/versions-maven-plugin.xml | 2 ++ shared-model-classes/pk_generated_parent.pom | 2 ++ shared-test-setup/pk_generated_parent.pom | 2 ++ 7 files changed, 14 insertions(+) diff --git a/maven-project-crawler/pk_generated_parent.pom b/maven-project-crawler/pk_generated_parent.pom index 2b3666f4..266874fa 100644 --- a/maven-project-crawler/pk_generated_parent.pom +++ b/maven-project-crawler/pk_generated_parent.pom @@ -198,6 +198,8 @@ true true false + true + true diff --git a/project-keeper-cli/pk_generated_parent.pom b/project-keeper-cli/pk_generated_parent.pom index ba30b7ba..21714a21 100644 --- a/project-keeper-cli/pk_generated_parent.pom +++ b/project-keeper-cli/pk_generated_parent.pom @@ -190,6 +190,8 @@ true true false + true + true diff --git a/project-keeper-maven-plugin/pk_generated_parent.pom b/project-keeper-maven-plugin/pk_generated_parent.pom index 8183b84e..c9739780 100644 --- a/project-keeper-maven-plugin/pk_generated_parent.pom +++ b/project-keeper-maven-plugin/pk_generated_parent.pom @@ -198,6 +198,8 @@ true true false + true + true diff --git a/project-keeper/pk_generated_parent.pom b/project-keeper/pk_generated_parent.pom index 06bead2f..35f33b92 100644 --- a/project-keeper/pk_generated_parent.pom +++ b/project-keeper/pk_generated_parent.pom @@ -190,6 +190,8 @@ true true false + true + true diff --git a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml index 12245b95..d3e43388 100644 --- a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml @@ -23,5 +23,7 @@ true true false + true + true diff --git a/shared-model-classes/pk_generated_parent.pom b/shared-model-classes/pk_generated_parent.pom index ca085d17..2bde1923 100644 --- a/shared-model-classes/pk_generated_parent.pom +++ b/shared-model-classes/pk_generated_parent.pom @@ -190,6 +190,8 @@ true true false + true + true diff --git a/shared-test-setup/pk_generated_parent.pom b/shared-test-setup/pk_generated_parent.pom index 1f787939..299d5f54 100644 --- a/shared-test-setup/pk_generated_parent.pom +++ b/shared-test-setup/pk_generated_parent.pom @@ -179,6 +179,8 @@ true true false + true + true From e66ea89ee9ea8fd4f383762d9b5272f8248d110d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 12:21:19 +0100 Subject: [PATCH 36/78] Fix jgit version --- dependencies.md | 477 +++++++++++++++++------------------ doc/changes/changes_4.0.0.md | 5 - parent-pom/pom.xml | 6 +- 3 files changed, 242 insertions(+), 246 deletions(-) diff --git a/dependencies.md b/dependencies.md index b38bad1e..c623cd8e 100644 --- a/dependencies.md +++ b/dependencies.md @@ -11,42 +11,42 @@ | [JSON-B API][3] | [Eclipse Public License 2.0][1]; [GNU General Public License, version 2 with the GNU Classpath Exception][2] | | [Yasson][4] | [Eclipse Public License v. 2.0][5]; [Eclipse Distribution License v. 1.0][6] | | [error-reporting-java][7] | [MIT License][8] | -| [JGit - Core][9] | [BSD-3-Clause][10] | +| [JGit - Core][9] | Eclipse Distribution License (New BSD License) | ### Test Dependencies | Dependency | License | | ------------------------------------------ | --------------------------------- | -| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | -| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | -| [Hamcrest][13] | [BSD License 3][14] | -| [JUnit5 System Extensions][15] | [Eclipse Public License v2.0][5] | -| [EqualsVerifier \| release normal jar][16] | [Apache License, Version 2.0][17] | -| [to-string-verifier][18] | [MIT License][19] | -| [mockito-core][20] | [MIT][21] | -| [SLF4J JDK14 Binding][22] | [MIT License][19] | +| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | +| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | +| [Hamcrest][12] | [BSD License 3][13] | +| [JUnit5 System Extensions][14] | [Eclipse Public License v2.0][5] | +| [EqualsVerifier \| release normal jar][15] | [Apache License, Version 2.0][16] | +| [to-string-verifier][17] | [MIT License][18] | +| [mockito-core][19] | [MIT][20] | +| [SLF4J JDK14 Binding][21] | [MIT License][18] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | -| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | -| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | -| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | -| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | +| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | +| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | +| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | +| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | ## Project Keeper Core @@ -54,59 +54,59 @@ | Dependency | License | | ----------------------------------------- | ---------------------------------------------- | -| [Project Keeper shared model classes][46] | [The MIT License][47] | -| [org.xmlunit:xmlunit-core][48] | [The Apache Software License, Version 2.0][30] | +| [Project Keeper shared model classes][45] | [The MIT License][46] | +| [org.xmlunit:xmlunit-core][47] | [The Apache Software License, Version 2.0][29] | | [error-reporting-java][7] | [MIT License][8] | -| [Markdown Generator][49] | [The Apache Software License, Version 2.0][30] | -| [semver4j][50] | [The MIT License][19] | -| [SnakeYAML][51] | [Apache License, Version 2.0][30] | -| [Maven Model][52] | [Apache-2.0][17] | +| [Markdown Generator][48] | [The Apache Software License, Version 2.0][29] | +| [semver4j][49] | [The MIT License][18] | +| [SnakeYAML][50] | [Apache License, Version 2.0][29] | +| [Maven Model][51] | [Apache-2.0][16] | ### Test Dependencies | Dependency | License | | ------------------------------------------ | ---------------------------------------------- | -| [Project Keeper shared test setup][46] | [The MIT License][47] | -| [Maven Project Version Getter][53] | [MIT License][54] | -| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | -| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | -| [Hamcrest][13] | [BSD License 3][14] | -| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | -| [mockito-junit-jupiter][20] | [MIT][21] | -| [Maven Plugin Integration Testing][55] | [MIT License][56] | -| [EqualsVerifier \| release normal jar][16] | [Apache License, Version 2.0][17] | -| [to-string-verifier][18] | [MIT License][19] | -| [SLF4J JDK14 Binding][22] | [MIT License][19] | +| [Project Keeper shared test setup][45] | [The MIT License][46] | +| [Maven Project Version Getter][52] | [MIT License][53] | +| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | +| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | +| [Hamcrest][12] | [BSD License 3][13] | +| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | +| [mockito-junit-jupiter][19] | [MIT][20] | +| [Maven Plugin Integration Testing][54] | [MIT License][55] | +| [EqualsVerifier \| release normal jar][15] | [Apache License, Version 2.0][16] | +| [to-string-verifier][17] | [MIT License][18] | +| [SLF4J JDK14 Binding][21] | [MIT License][18] | ### Runtime Dependencies | Dependency | License | | ----------------------------------------- | --------------------- | -| [Project Keeper Java project crawler][46] | [The MIT License][47] | +| [Project Keeper Java project crawler][45] | [The MIT License][46] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | -| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | -| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | -| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | -| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | -| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | +| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | +| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | +| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | +| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | ## Project Keeper Command Line Interface @@ -114,51 +114,51 @@ | Dependency | License | | ------------------------- | --------------------- | -| [Project Keeper Core][46] | [The MIT License][47] | +| [Project Keeper Core][45] | [The MIT License][46] | | [error-reporting-java][7] | [MIT License][8] | -| [Maven Model][52] | [Apache-2.0][17] | +| [Maven Model][51] | [Apache-2.0][16] | ### Test Dependencies | Dependency | License | | -------------------------------------- | --------------------------------- | -| [Project Keeper shared test setup][46] | [The MIT License][47] | -| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | -| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | -| [Hamcrest][13] | [BSD License 3][14] | -| [Maven Project Version Getter][53] | [MIT License][54] | +| [Project Keeper shared test setup][45] | [The MIT License][46] | +| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | +| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | +| [Hamcrest][12] | [BSD License 3][13] | +| [Maven Project Version Getter][52] | [MIT License][53] | ### Runtime Dependencies | Dependency | License | | ------------------------- | ----------------- | -| [SLF4J JDK14 Binding][22] | [MIT License][19] | +| [SLF4J JDK14 Binding][21] | [MIT License][18] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [Apache Maven Assembly Plugin][59] | [Apache-2.0][17] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | -| [Artifact reference checker and unifier][60] | [MIT License][61] | -| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | -| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | -| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | -| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | -| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | -| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | +| [Artifact reference checker and unifier][59] | [MIT License][60] | +| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | +| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | +| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | +| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | +| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | ## Project Keeper Maven Plugin @@ -166,105 +166,105 @@ | Dependency | License | | ----------------------------------------- | --------------------- | -| [Project Keeper Core][46] | [The MIT License][47] | -| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][17] | -| [Maven Plugin API][63] | [Apache-2.0][17] | -| [Maven Core][64] | [Apache-2.0][17] | +| [Project Keeper Core][45] | [The MIT License][46] | +| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | +| [Maven Plugin API][62] | [Apache-2.0][16] | +| [Maven Core][63] | [Apache-2.0][16] | | [error-reporting-java][7] | [MIT License][8] | ### Test Dependencies | Dependency | License | | -------------------------------------- | ---------------------------------------------- | -| [Maven Project Version Getter][53] | [MIT License][54] | -| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | -| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | -| [Hamcrest][13] | [BSD License 3][14] | -| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | -| [mockito-core][20] | [MIT][21] | -| [Maven Plugin Integration Testing][55] | [MIT License][56] | -| [SLF4J JDK14 Binding][22] | [MIT License][19] | -| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][42] | +| [Maven Project Version Getter][52] | [MIT License][53] | +| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | +| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | +| [Hamcrest][12] | [BSD License 3][13] | +| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | +| [mockito-core][19] | [MIT][20] | +| [Maven Plugin Integration Testing][54] | [MIT License][55] | +| [SLF4J JDK14 Binding][21] | [MIT License][18] | +| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Maven Plugin Plugin][66] | [Apache-2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | -| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | -| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | -| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | -| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | -| [Apache Maven Dependency Plugin][67] | [Apache-2.0][17] | -| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Maven Plugin Plugin][65] | [Apache-2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | +| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | +| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | +| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | +| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | +| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | ## Project Keeper Java Project Crawler ### Compile Dependencies -| Dependency | License | -| ----------------------------------------- | --------------------- | -| [Project Keeper shared model classes][46] | [The MIT License][47] | -| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][17] | -| [Maven Plugin API][63] | [Apache-2.0][17] | -| [error-reporting-java][7] | [MIT License][8] | -| [JGit - Core][9] | [BSD-3-Clause][10] | -| [semver4j][50] | [The MIT License][19] | -| [Maven Core][64] | [Apache-2.0][17] | +| Dependency | License | +| ----------------------------------------- | ---------------------------------------------- | +| [Project Keeper shared model classes][45] | [The MIT License][46] | +| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | +| [Maven Plugin API][62] | [Apache-2.0][16] | +| [error-reporting-java][7] | [MIT License][8] | +| [JGit - Core][9] | Eclipse Distribution License (New BSD License) | +| [semver4j][49] | [The MIT License][18] | +| [Maven Core][63] | [Apache-2.0][16] | ### Test Dependencies | Dependency | License | | -------------------------------------- | ---------------------------------------------- | -| [Maven Project Version Getter][53] | [MIT License][54] | -| [JUnit Jupiter Engine][11] | [Eclipse Public License v2.0][12] | -| [JUnit Jupiter Params][11] | [Eclipse Public License v2.0][12] | -| [Hamcrest][13] | [BSD License 3][14] | -| [org.xmlunit:xmlunit-matchers][48] | [The Apache Software License, Version 2.0][30] | -| [SLF4J JDK14 Binding][22] | [MIT License][19] | -| [mockito-core][20] | [MIT][21] | -| [mockito-junit-jupiter][20] | [MIT][21] | -| [Maven Plugin Integration Testing][55] | [MIT License][56] | -| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][42] | +| [Maven Project Version Getter][52] | [MIT License][53] | +| [JUnit Jupiter Engine][10] | [Eclipse Public License v2.0][11] | +| [JUnit Jupiter Params][10] | [Eclipse Public License v2.0][11] | +| [Hamcrest][12] | [BSD License 3][13] | +| [org.xmlunit:xmlunit-matchers][47] | [The Apache Software License, Version 2.0][29] | +| [SLF4J JDK14 Binding][21] | [MIT License][18] | +| [mockito-core][19] | [MIT][20] | +| [mockito-junit-jupiter][19] | [MIT][20] | +| [Maven Plugin Integration Testing][54] | [MIT License][55] | +| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [Maven Plugin Plugin][66] | [Apache-2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [Apache Maven Deploy Plugin][35] | [Apache-2.0][17] | -| [Apache Maven GPG Plugin][36] | [Apache-2.0][17] | -| [Apache Maven Source Plugin][37] | [Apache License, Version 2.0][17] | -| [Apache Maven Javadoc Plugin][38] | [Apache-2.0][17] | -| [Nexus Staging Maven Plugin][39] | [Eclipse Public License][40] | -| [Apache Maven Dependency Plugin][67] | [Apache-2.0][17] | -| [Maven Failsafe Plugin][58] | [Apache-2.0][17] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [Maven Plugin Plugin][65] | [Apache-2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | +| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | +| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | +| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | +| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | +| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | ## Project Keeper Shared Test Setup @@ -272,27 +272,27 @@ | Dependency | License | | ----------------------------------------- | --------------------------------- | -| [Project Keeper shared model classes][46] | [The MIT License][47] | -| [SnakeYAML][51] | [Apache License, Version 2.0][30] | -| [Hamcrest][13] | [BSD License 3][14] | -| [Maven Model][52] | [Apache-2.0][17] | +| [Project Keeper shared model classes][45] | [The MIT License][46] | +| [SnakeYAML][50] | [Apache License, Version 2.0][29] | +| [Hamcrest][12] | [BSD License 3][13] | +| [Maven Model][51] | [Apache-2.0][16] | ### Plugin Dependencies | Dependency | License | | ------------------------------------------------------- | --------------------------------- | -| [SonarQube Scanner for Maven][23] | [GNU LGPL 3][24] | -| [Apache Maven Toolchains Plugin][25] | [Apache License, Version 2.0][17] | -| [Apache Maven Compiler Plugin][26] | [Apache-2.0][17] | -| [Apache Maven Enforcer Plugin][27] | [Apache-2.0][17] | -| [Maven Flatten Plugin][28] | [Apache Software Licenese][17] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][29] | [ASL2][30] | -| [Maven Surefire Plugin][31] | [Apache-2.0][17] | -| [Versions Maven Plugin][32] | [Apache License, Version 2.0][17] | -| [duplicate-finder-maven-plugin Maven Mojo][33] | [Apache License 2.0][34] | -| [JaCoCo :: Maven Plugin][41] | [Eclipse Public License 2.0][42] | -| [error-code-crawler-maven-plugin][43] | [MIT License][44] | -| [Reproducible Build Maven Plugin][45] | [Apache 2.0][30] | +| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | +| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | +| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | +| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | +| [Maven Surefire Plugin][30] | [Apache-2.0][16] | +| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | +| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | +| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | +| [error-code-crawler-maven-plugin][42] | [MIT License][43] | +| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | [0]: https://github.com/eclipse-ee4j/jsonp [1]: https://projects.eclipse.org/license/epl-2.0 @@ -304,61 +304,60 @@ [7]: https://github.com/exasol/error-reporting-java/ [8]: https://github.com/exasol/error-reporting-java/blob/main/LICENSE [9]: https://www.eclipse.org/jgit/ -[10]: https://www.eclipse.org/org/documents/edl-v10.php -[11]: https://junit.org/junit5/ -[12]: https://www.eclipse.org/legal/epl-v20.html -[13]: http://hamcrest.org/JavaHamcrest/ -[14]: http://opensource.org/licenses/BSD-3-Clause -[15]: https://github.com/itsallcode/junit5-system-extensions -[16]: https://www.jqno.nl/equalsverifier -[17]: https://www.apache.org/licenses/LICENSE-2.0.txt -[18]: https://github.com/jparams/to-string-verifier -[19]: http://www.opensource.org/licenses/mit-license.php -[20]: https://github.com/mockito/mockito -[21]: https://opensource.org/licenses/MIT -[22]: http://www.slf4j.org -[23]: http://sonarsource.github.io/sonar-scanner-maven/ -[24]: http://www.gnu.org/licenses/lgpl.txt -[25]: https://maven.apache.org/plugins/maven-toolchains-plugin/ -[26]: https://maven.apache.org/plugins/maven-compiler-plugin/ -[27]: https://maven.apache.org/enforcer/maven-enforcer-plugin/ -[28]: https://www.mojohaus.org/flatten-maven-plugin/ -[29]: https://sonatype.github.io/ossindex-maven/maven-plugin/ -[30]: http://www.apache.org/licenses/LICENSE-2.0.txt -[31]: https://maven.apache.org/surefire/maven-surefire-plugin/ -[32]: https://www.mojohaus.org/versions/versions-maven-plugin/ -[33]: https://basepom.github.io/duplicate-finder-maven-plugin -[34]: http://www.apache.org/licenses/LICENSE-2.0.html -[35]: https://maven.apache.org/plugins/maven-deploy-plugin/ -[36]: https://maven.apache.org/plugins/maven-gpg-plugin/ -[37]: https://maven.apache.org/plugins/maven-source-plugin/ -[38]: https://maven.apache.org/plugins/maven-javadoc-plugin/ -[39]: http://www.sonatype.com/public-parent/nexus-maven-plugins/nexus-staging/nexus-staging-maven-plugin/ -[40]: http://www.eclipse.org/legal/epl-v10.html -[41]: https://www.jacoco.org/jacoco/trunk/doc/maven.html -[42]: https://www.eclipse.org/legal/epl-2.0/ -[43]: https://github.com/exasol/error-code-crawler-maven-plugin/ -[44]: https://github.com/exasol/error-code-crawler-maven-plugin/blob/main/LICENSE -[45]: http://zlika.github.io/reproducible-build-maven-plugin -[46]: https://github.com/exasol/project-keeper/ -[47]: https://github.com/exasol/project-keeper/blob/main/LICENSE -[48]: https://www.xmlunit.org/ -[49]: https://github.com/Steppschuh/Java-Markdown-Generator -[50]: https://github.com/vdurmont/semver4j -[51]: https://bitbucket.org/snakeyaml/snakeyaml -[52]: https://maven.apache.org/ref/3.9.6/maven-model/ -[53]: https://github.com/exasol/maven-project-version-getter/ -[54]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE -[55]: https://github.com/exasol/maven-plugin-integration-testing/ -[56]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE -[57]: https://maven.apache.org/plugins/maven-jar-plugin/ -[58]: https://maven.apache.org/surefire/maven-failsafe-plugin/ -[59]: https://maven.apache.org/plugins/maven-assembly-plugin/ -[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ -[61]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE -[62]: https://maven.apache.org/plugin-tools/maven-plugin-annotations -[63]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ -[64]: https://maven.apache.org/ref/3.9.6/maven-core/ -[65]: https://www.eclemma.org/jacoco/index.html -[66]: https://maven.apache.org/plugin-tools/maven-plugin-plugin -[67]: https://maven.apache.org/plugins/maven-dependency-plugin/ +[10]: https://junit.org/junit5/ +[11]: https://www.eclipse.org/legal/epl-v20.html +[12]: http://hamcrest.org/JavaHamcrest/ +[13]: http://opensource.org/licenses/BSD-3-Clause +[14]: https://github.com/itsallcode/junit5-system-extensions +[15]: https://www.jqno.nl/equalsverifier +[16]: https://www.apache.org/licenses/LICENSE-2.0.txt +[17]: https://github.com/jparams/to-string-verifier +[18]: http://www.opensource.org/licenses/mit-license.php +[19]: https://github.com/mockito/mockito +[20]: https://opensource.org/licenses/MIT +[21]: http://www.slf4j.org +[22]: http://sonarsource.github.io/sonar-scanner-maven/ +[23]: http://www.gnu.org/licenses/lgpl.txt +[24]: https://maven.apache.org/plugins/maven-toolchains-plugin/ +[25]: https://maven.apache.org/plugins/maven-compiler-plugin/ +[26]: https://maven.apache.org/enforcer/maven-enforcer-plugin/ +[27]: https://www.mojohaus.org/flatten-maven-plugin/ +[28]: https://sonatype.github.io/ossindex-maven/maven-plugin/ +[29]: http://www.apache.org/licenses/LICENSE-2.0.txt +[30]: https://maven.apache.org/surefire/maven-surefire-plugin/ +[31]: https://www.mojohaus.org/versions/versions-maven-plugin/ +[32]: https://basepom.github.io/duplicate-finder-maven-plugin +[33]: http://www.apache.org/licenses/LICENSE-2.0.html +[34]: https://maven.apache.org/plugins/maven-deploy-plugin/ +[35]: https://maven.apache.org/plugins/maven-gpg-plugin/ +[36]: https://maven.apache.org/plugins/maven-source-plugin/ +[37]: https://maven.apache.org/plugins/maven-javadoc-plugin/ +[38]: http://www.sonatype.com/public-parent/nexus-maven-plugins/nexus-staging/nexus-staging-maven-plugin/ +[39]: http://www.eclipse.org/legal/epl-v10.html +[40]: https://www.jacoco.org/jacoco/trunk/doc/maven.html +[41]: https://www.eclipse.org/legal/epl-2.0/ +[42]: https://github.com/exasol/error-code-crawler-maven-plugin/ +[43]: https://github.com/exasol/error-code-crawler-maven-plugin/blob/main/LICENSE +[44]: http://zlika.github.io/reproducible-build-maven-plugin +[45]: https://github.com/exasol/project-keeper/ +[46]: https://github.com/exasol/project-keeper/blob/main/LICENSE +[47]: https://www.xmlunit.org/ +[48]: https://github.com/Steppschuh/Java-Markdown-Generator +[49]: https://github.com/vdurmont/semver4j +[50]: https://bitbucket.org/snakeyaml/snakeyaml +[51]: https://maven.apache.org/ref/3.9.6/maven-model/ +[52]: https://github.com/exasol/maven-project-version-getter/ +[53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE +[54]: https://github.com/exasol/maven-plugin-integration-testing/ +[55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE +[56]: https://maven.apache.org/plugins/maven-jar-plugin/ +[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/ +[58]: https://maven.apache.org/plugins/maven-assembly-plugin/ +[59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ +[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE +[61]: https://maven.apache.org/plugin-tools/maven-plugin-annotations +[62]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ +[63]: https://maven.apache.org/ref/3.9.6/maven-core/ +[64]: https://www.eclemma.org/jacoco/index.html +[65]: https://maven.apache.org/plugin-tools/maven-plugin-plugin +[66]: https://maven.apache.org/plugins/maven-dependency-plugin/ diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md index 6978dfeb..7e6892a8 100644 --- a/doc/changes/changes_4.0.0.md +++ b/doc/changes/changes_4.0.0.md @@ -12,10 +12,6 @@ Code name: Automatic Security Updates ### Project Keeper Shared Model Classes -#### Compile Dependency Updates - -* Updated `org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r` to `6.8.0.202311291450-r` - #### Test Dependency Updates * Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` @@ -94,7 +90,6 @@ Code name: Automatic Security Updates #### Compile Dependency Updates * Updated `com.exasol:project-keeper-shared-model-classes:3.0.1` to `4.0.0` -* Updated `org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r` to `6.8.0.202311291450-r` #### Test Dependency Updates diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index 3044a23c..6993b74f 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -111,8 +111,8 @@ org.eclipse.jgit org.eclipse.jgit - - 6.8.0.202311291450-r + + 6.7.0.202309050840-r net.steppschuh.markdowngenerator @@ -255,6 +255,8 @@ org.slf4j:slf4j-jdk14:jar:*:* + + org.eclipse.jgit:org.eclipse.jgit:jar:*:6.8.0.202311291450-r From 34e85928c34e051dbf0dd21be1cae435aafaf2c6 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 13:03:35 +0100 Subject: [PATCH 37/78] Run dependency update & PK fix --- project-keeper/error_code_config.yml | 2 +- .../exasol/projectkeeper/ProjectKeeper.java | 2 +- .../dependencyupdate/DependencyUpdater.java | 43 ++++++++++++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml index 5d506759..5cd01760 100644 --- a/project-keeper/error_code_config.yml +++ b/project-keeper/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CORE: packages: - com.exasol.projectkeeper - highest-index: 176 + highest-index: 177 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index a43e0553..1e457768 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -314,6 +314,6 @@ private Provision getValidationProvision() { */ public boolean updateDependencies() { final Provision provision = getValidationProvision(); - return DependencyUpdater.create(logger, projectDir, provision.projectVersion()).updateDependencies(); + return DependencyUpdater.create(this, logger, projectDir, provision.projectVersion()).updateDependencies(); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index aa48869c..df0c7a4d 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -1,34 +1,49 @@ package com.exasol.projectkeeper.dependencyupdate; import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Logger; +import com.exasol.projectkeeper.ProjectKeeper; +import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; +import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; /** * This class runs the dependency update process. */ public class DependencyUpdater { + private static final Duration MAVEN_COMMAND_TIMEOUT = Duration.ofSeconds(60); + private final ProjectKeeper projectKeeper; private final Logger logger; + private final Path projectDir; private final ProjectVersionIncrementor projectVersionIncrementor; - DependencyUpdater(final Logger logger, final ProjectVersionIncrementor projectVersionIncrementor) { + DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir, + final ProjectVersionIncrementor projectVersionIncrementor) { + this.projectKeeper = projectKeeper; this.logger = logger; + this.projectDir = projectDir; this.projectVersionIncrementor = projectVersionIncrementor; - } /** * Create a new instance. * + * @param projectKeeper + * * @param logger the logger to which we should write log messages * @param projectDir the project directory * @param currentProjectVersion the project's current version * @return a new dependency updater */ - public static DependencyUpdater create(final Logger logger, final Path projectDir, - final String currentProjectVersion) { - return new DependencyUpdater(logger, new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion)); + public static DependencyUpdater create(final ProjectKeeper projectKeeper, final Logger logger, + final Path projectDir, final String currentProjectVersion) { + return new DependencyUpdater(projectKeeper, logger, projectDir, + new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion)); } /** @@ -60,11 +75,25 @@ private void incrementProjectVersion() { } private void updateDependencyVersions() { - // TODO Auto-generated method stub + runMaven("versions:use-latest-releases"); + runMaven("versions:update-properties"); + } + + private void runMaven(final String mavenGoal) { + final List command = MavenProcessBuilder.create().addArgument("--batch-mode").addArgument(mavenGoal) + .build(); + final Instant start = Instant.now(); + SimpleProcess.start(projectDir, command).waitUntilFinished(MAVEN_COMMAND_TIMEOUT); + logger.info("Running maven goal " + mavenGoal + " took " + Duration.between(start, Instant.now())); } private void runProjectKeeperFix() { - // TODO Auto-generated method stub + logger.info("Running project-keeper fix"); + if (!projectKeeper.fix()) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-177") + .message("Running project-keeper fix failed, see errors above.") + .mitigation("Fix findings and try again.").toString()); + } } private void updateChangelog() { From 0addf51009d3d46096fc729d560af8777f37093d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 13:03:50 +0100 Subject: [PATCH 38/78] Move ChangesFileName to separate file --- .../plugin/ProjectKeeperMojoIT.java | 11 ++- .../validators/VersionCollector.java | 6 +- .../changelog/ChangelogFileGenerator.java | 7 +- .../changelog/ChangelogFileValidator.java | 6 +- .../validators/changesfile/ChangesFile.java | 78 +---------------- .../validators/changesfile/ChangesFileIO.java | 17 ++-- .../changesfile/ChangesFileName.java | 83 +++++++++++++++++++ .../files/LatestChangesFileValidator.java | 6 +- .../validators/VersionCollectorTest.java | 13 ++- .../changelog/ChangelogFileGeneratorTest.java | 8 +- .../changesfile/ChangesFileIOTest.java | 56 +++++++++---- .../changesfile/ChangesFileNameTest.java | 12 +++ .../changesfile/ChangesFileTest.java | 6 -- .../files/LatestChangesFileValidatorTest.java | 4 +- 14 files changed, 179 insertions(+), 134 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index bdf2d234..66afb394 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -29,6 +29,7 @@ import org.junit.jupiter.params.provider.ValueSource; import com.exasol.mavenpluginintegrationtesting.MavenIntegrationTestEnvironment; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; class ProjectKeeperMojoIT { private static final String ORIGINAL_SLF4J_VERSION = "1.7.36"; @@ -107,9 +108,13 @@ void testUpgradeDependencies() throws VerificationException, IOException { verifier.verify(true); final Model updatedPom = readPom(); - assertThat("incremented version", updatedPom.getVersion(), equalTo("0.1.1")); - assertThat("updated SLF4J version", updatedPom.getDependencies().get(0).getVersion(), - allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), startsWith("2."))); + final String newVersion = "0.1.1"; + assertThat("incremented version", updatedPom.getVersion(), equalTo(newVersion)); + final String updatedSlf4jVersion = updatedPom.getDependencies().get(0).getVersion(); + assertThat("updated SLF4J version", updatedSlf4jVersion, + allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2."))); + final String changesContent = Files.readString(projectDir.resolve(ChangesFile.getPathForVersion(newVersion))); + assertThat(changesContent, allOf(startsWith("blah"))); } private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java index e3030c8f..f5674c74 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; /** * This class list all project-versions by scanning the doc/changes/ folder. @@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) { * * @return list of changes files */ - public List collectChangesFiles() { + public List collectChangesFiles() { try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) { return filesStream // - .map(ChangesFile.Filename::from) // + .map(ChangesFileName::from) // .flatMap(Optional::stream) // .sorted(Comparator.reverseOrder()) // .collect(Collectors.toList()); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java index ea1a64f7..8e7ff839 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java @@ -2,8 +2,7 @@ import java.util.List; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; /** * This class generates the content for the changelog file. @@ -19,9 +18,9 @@ class ChangelogFileGenerator { */ final StringBuilder templateBuilder = new StringBuilder(); - String generate(final List filenames) { + String generate(final List filenames) { this.templateBuilder.append("# Changes" + NL + NL); - for (final Filename file : filenames) { + for (final ChangesFileName file : filenames) { this.templateBuilder.append("* [" + file.version() + "](" + file.filename() + ")" + NL); } return this.templateBuilder.toString(); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java index a6dc485c..111612d0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java @@ -8,14 +8,14 @@ import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.AbstractFileContentValidator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; /** * This is a {@link Validator} for the changelog files. */ -//[impl->dsn~verify-changelog-file~1] +// [impl->dsn~verify-changelog-file~1] public class ChangelogFileValidator extends AbstractFileContentValidator { private final Path projectDirectory; @@ -44,7 +44,7 @@ protected List validateContent(final String content) { @Override protected String getTemplate() { - final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles(); return new ChangelogFileGenerator().generate(versions); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 41ecaa29..722c9e8a 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -4,13 +4,9 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import com.exasol.projectkeeper.mavenrepo.Version; import com.vdurmont.semver4j.Semver; -import com.vdurmont.semver4j.Semver.SemverType; /** * This class represents a doc/changes/changes_x.x.x.md file. @@ -39,79 +35,7 @@ private ChangesFile(final Builder builder) { * @return relative path of the changes file, e.g. {@code doc/changes/changes_1.2.3.md} */ public static Path getPathForVersion(final String projectVersion) { - return Path.of("doc", "changes", new Filename(projectVersion).filename()); - } - - /** - * Filename of a changes file, e.g. {@code changes_1.2.3.md}. - */ - public static final class Filename implements Comparable { - /** Regular expression to identify valid names of changes files and to extract version number. **/ - public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md"); - - /** - * @param path path to create a {@link Filename} for - * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a - * new instance of {@link Filename}, otherwise {@code Optional.empty()}. - */ - public static Optional from(final Path path) { - final String filename = path.getFileName().toString(); - final Matcher matcher = PATTERN.matcher(filename); - if (!matcher.matches()) { - return Optional.empty(); - } - return Optional.of(new Filename(matcher.replaceFirst("$1"))); - } - - private final Semver version; - - /** - * Create a new instance of {@link ChangesFile.Filename}. - * - * @param version version to use for new instance - */ - public Filename(final String version) { - this.version = new Semver(version, SemverType.LOOSE); - } - - /** - * @return filename of the current {@link ChangesFile.Filename} as string - */ - public String filename() { - return "changes_" + this.version + ".md"; - } - - @Override - public int compareTo(final Filename o) { - return this.version.compareTo(o.version); - } - - /** - * @return version number contained in the filename of current {@link ChangesFile.Filename} - */ - public String version() { - return this.version.getValue(); - } - - @Override - public int hashCode() { - return Objects.hash(this.version); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Filename other = (Filename) obj; - return Objects.equals(this.version, other.version); - } + return Path.of("doc", "changes", new ChangesFileName(projectVersion).filename()); } /** diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 39daca08..bf212363 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -92,12 +92,8 @@ private void makeSection(final String sectionHeader, final ChangesFile.Builder b * @param destinationFile file to write to */ public void write(final ChangesFile changesFile, final Path destinationFile) { - try (final var fileWriter = new BufferedWriter(new FileWriter(destinationFile.toFile()))) { - writeSection(fileWriter, changesFile.getHeaderSectionLines()); - for (final ChangesFileSection section : changesFile.getSections()) { - writeSection(fileWriter, section.getContent()); - } - fileWriter.flush(); + try (final var writer = new BufferedWriter(new FileWriter(destinationFile.toFile()))) { + write(changesFile, writer); } catch (final IOException exception) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CORE-41").message("Failed to write changes file {{file name}}.") @@ -106,7 +102,14 @@ public void write(final ChangesFile changesFile, final Path destinationFile) { } } - private void writeSection(final BufferedWriter fileWriter, final List content) throws IOException { + void write(final ChangesFile changesFile, final Writer writer) throws IOException { + writeSection(writer, changesFile.getHeaderSectionLines()); + for (final ChangesFileSection section : changesFile.getSections()) { + writeSection(writer, section.getContent()); + } + } + + private void writeSection(final Writer fileWriter, final List content) throws IOException { for (final String line : content) { fileWriter.write(line); fileWriter.write(LINE_SEPARATOR); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java new file mode 100644 index 00000000..390c6df5 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java @@ -0,0 +1,83 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.exasol.projectkeeper.mavenrepo.Version; +import com.vdurmont.semver4j.Semver; +import com.vdurmont.semver4j.Semver.SemverType; + +/** + * Filename of a changes file, e.g. {@code changes_1.2.3.md}. + */ +public final class ChangesFileName implements Comparable { + /** Regular expression to identify valid names of changes files and to extract version number. **/ + public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md"); + + /** + * @param path path to create a {@link ChangesFileName} for + * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a new + * instance of {@link ChangesFileName}, otherwise {@code Optional.empty()}. + */ + public static Optional from(final Path path) { + final String filename = path.getFileName().toString(); + final Matcher matcher = PATTERN.matcher(filename); + if (!matcher.matches()) { + return Optional.empty(); + } + return Optional.of(new ChangesFileName(matcher.replaceFirst("$1"))); + } + + private final Semver version; + + /** + * Create a new instance of {@link ChangesFileName}. + * + * @param version version to use for new instance + */ + public ChangesFileName(final String version) { + this.version = new Semver(version, SemverType.LOOSE); + } + + /** + * @return filename of the current {@link ChangesFileName} as string + */ + public String filename() { + return "changes_" + this.version + ".md"; + } + + @Override + public int compareTo(final ChangesFileName o) { + return this.version.compareTo(o.version); + } + + /** + * @return version number contained in the filename of current {@link ChangesFileName} + */ + public String version() { + return this.version.getValue(); + } + + @Override + public int hashCode() { + return Objects.hash(this.version); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFileName other = (ChangesFileName) obj; + return Objects.equals(this.version, other.version); + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java index c7e457c1..86236087 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java @@ -7,7 +7,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; @@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer @Override public List validate() { final List empty = Collections.emptyList(); - final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); if (list.isEmpty()) { return empty; } - final Filename latest = list.get(0); + final ChangesFileName latest = list.get(0); if (latest.version().equals(this.projectVersion)) { return empty; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java index 56c91af0..230506a1 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java @@ -13,8 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; class VersionCollectorTest { @Test @@ -29,20 +28,20 @@ void sorted(@TempDir final Path tempDir) throws IOException { "1.0.0")) { createChangesFile(folder, version); } - final List expected = Stream.of( // + final List expected = Stream.of( // "1.1.0", // "1.0.10", // "1.0.2", // "1.0.0", // "0.3.0") // - .map(ChangesFile.Filename::new) // + .map(ChangesFileName::new) // .collect(Collectors.toList()); assertThat(new VersionCollector(tempDir).collectChangesFiles(), equalTo(expected)); } - private ChangesFile.Filename createChangesFile(final Path folder, final String version) throws IOException { - final Filename cfile = new Filename(version); + private ChangesFileName createChangesFile(final Path folder, final String version) throws IOException { + final ChangesFileName cfile = new ChangesFileName(version); Files.createFile(folder.resolve(cfile.filename())); return cfile; } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java index 58a45393..3f66983a 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java @@ -12,7 +12,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; class ChangelogFileGeneratorTest { @Test @@ -27,7 +27,7 @@ void testNonStandardVersionFormats(final String version) { assertThat(new ChangelogFileGenerator().generate(files(version)), containsString(version)); } - private List files(final String... versions) { - return Arrays.stream(versions).map(ChangesFile.Filename::new).collect(Collectors.toList()); + private List files(final String... versions) { + return Arrays.stream(versions).map(ChangesFileName::new).collect(Collectors.toList()); } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 8faa532c..5de75b22 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.time.LocalDate; import java.util.List; @@ -42,50 +43,75 @@ void testWriting() throws IOException { @Test void testReadAndWrite() throws IOException { - final Path changesFilePath = loadExampleFileToTempDir(); - final ChangesFileIO changesFileIO = new ChangesFileIO(); - final ChangesFile changesFile = changesFileIO.read(changesFilePath); - final Path testFile = this.tempDir.resolve("result.md"); - changesFileIO.write(changesFile, testFile); - assertThat(Files.readString(testFile), equalTo(Files.readString(changesFilePath))); + final String content = readExampleFile(); + assertReadWrite(content); } @Test void testReadInvalidFirstLineFails() { final IllegalStateException exception = assertThrows(IllegalStateException.class, - () -> read("# invalid first line")); + () -> readFromString("# invalid first line")); assertThat(exception.getMessage(), startsWith( "E-PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex")); } @Test void testReadFirstLineWithDummyReleaseDate() throws IOException { - final ChangesFile changesFile = read("# Project Name 1.2.3, released 2024-??-??"); + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-??-??"); assertThat(changesFile.getProjectName(), equalTo("Project Name")); assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??")); assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false)); + assertWriteRead(changesFile); } @Test void testReadFirstLineWithValidReleaseDate() throws IOException { - final ChangesFile changesFile = read("# Project Name 1.2.3, released 2024-01-29"); + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29"); assertThat(changesFile.getProjectName(), equalTo("Project Name")); assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29")); assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("2024-01-29"))); - } - - ChangesFile read(final String content) throws IOException { - return new ChangesFileIO().read(Path.of("dummy-file"), new BufferedReader(new StringReader(content))); + assertWriteRead(changesFile); } private Path loadExampleFileToTempDir() throws IOException { final Path changesFile = this.tempDir.resolve("changed_0.1.0.md"); - try (final InputStream exampleFileStream = getClass().getClassLoader() - .getResourceAsStream("changesFileExample1.md")) { + try (final InputStream exampleFileStream = getExampleFileStream()) { Files.copy(Objects.requireNonNull(exampleFileStream), changesFile, StandardCopyOption.REPLACE_EXISTING); } return changesFile; } + + private String readExampleFile() throws IOException { + try (final InputStream exampleFileStream = getExampleFileStream()) { + return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8); + } + } + + private InputStream getExampleFileStream() { + return getClass().getClassLoader().getResourceAsStream("changesFileExample1.md"); + } + + private void assertWriteRead(final ChangesFile changesFile) throws IOException { + final String content = writeToString(changesFile); + final ChangesFile readChangesFile = readFromString(content); + assertThat(readChangesFile, equalTo(changesFile)); + } + + private void assertReadWrite(final String content) throws IOException { + final ChangesFile changesFile = readFromString(content); + final String writtenContent = writeToString(changesFile); + assertThat(writtenContent, equalTo(content)); + } + + private String writeToString(final ChangesFile changesFile) throws IOException { + final StringWriter stringWriter = new StringWriter(); + new ChangesFileIO().write(changesFile, stringWriter); + return stringWriter.toString(); + } + + private ChangesFile readFromString(final String content) throws IOException { + return new ChangesFileIO().read(Path.of("dummy-file"), new BufferedReader(new StringReader(content))); + } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java new file mode 100644 index 00000000..d1a792ee --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java @@ -0,0 +1,12 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileNameTest { + @Test + void equalsContractFilename() { + EqualsVerifier.forClass(ChangesFileName.class).verify(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java index da862e8e..e8fff56f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.Test; import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; import nl.jqno.equalsverifier.EqualsVerifier; @@ -22,11 +21,6 @@ void equalsContract() { EqualsVerifier.forClass(ChangesFile.class).verify(); } - @Test - void equalsContractFilename() { - EqualsVerifier.forClass(Filename.class).verify(); - } - @Test void getPathForVersion() { assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md"))); diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java index 404adc38..e3519302 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; class LatestChangesFileValidatorTest { @@ -38,7 +38,7 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve final Path folder = tempDir.resolve(Path.of("doc", "changes")); Files.createDirectories(folder); for (final String v : versions) { - final Filename cfile = new Filename(v); + final ChangesFileName cfile = new ChangesFileName(v); Files.createFile(folder.resolve(cfile.filename())); } return new LatestChangesFileValidator(tempDir, "2.0.0"); From 435d6b98dbb04c2fe02226dafb2946f6cd63f9a7 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 13:08:02 +0100 Subject: [PATCH 39/78] Remove unused methods --- .../validators/changesfile/ChangesFile.java | 18 ------------------ .../changesfile/ChangesFileIOTest.java | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 722c9e8a..47bffa7a 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -111,15 +111,6 @@ public List getHeaderSectionLines() { return this.headerSectionLines; } - /** - * Get the heading of the file. - * - * @return heading (1. line) - */ - public String getHeading() { - return this.headerSectionLines.get(0); - } - /** * Get a list of sections (starting with a ## heading). * @@ -247,13 +238,4 @@ public ChangesFile build() { return new ChangesFile(this); } } - - /** - * Get the heading for the dependency updates section. - * - * @return heading - */ - public static String getDependencyUpdatesHeading() { - return DEPENDENCY_UPDATES_HEADING; - } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 5de75b22..562592b5 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -25,7 +25,7 @@ void testParsing() throws IOException { final ChangesFile changesFile = new ChangesFileIO().read(changesFilePath); final List headings = changesFile.getSections().stream().map(ChangesFileSection::getHeading) .collect(Collectors.toList()); - assertThat(changesFile.getHeading(), equalTo("# My Project 0.1.0, released 1980-01-01")); + assertThat(changesFile.getHeaderSectionLines().get(0), equalTo("# My Project 0.1.0, released 1980-01-01")); assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring", "## Dependency Updates")); } From 00fd12a01e07b66d764e9a471d7358fb330213b3 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Tue, 30 Jan 2024 13:18:40 +0100 Subject: [PATCH 40/78] Generate first line separately --- .../dependencyupdate/DependencyUpdater.java | 1 + .../validators/changesfile/ChangesFileIO.java | 18 ++++++++--- .../changesfile/ChangesFileValidator.java | 4 +-- .../changesfile/ChangesFileIOTest.java | 10 ++++-- .../changesfile/ChangesFileValidatorTest.java | 31 ++++++++++++++----- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index df0c7a4d..5dcb5121 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -35,6 +35,7 @@ public class DependencyUpdater { * * @param projectKeeper * + * @param projectKeeper project keeper reference * @param logger the logger to which we should write log messages * @param projectDir the project directory * @param currentProjectVersion the project's current version diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index bf212363..90f4be3c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -47,12 +47,13 @@ ChangesFile read(final Path file, final BufferedReader fileReader) throws IOExce while ((line = fileReader.readLine()) != null) { if (lineCount == 0) { parseFirstLine(file, line, builder); + } else { + if (SECTION_HEADING_PATTERN.matcher(line).matches()) { + makeSection(sectionHeader, builder, lineBuffer); + sectionHeader = line; + } + lineBuffer.add(line); } - if (SECTION_HEADING_PATTERN.matcher(line).matches()) { - makeSection(sectionHeader, builder, lineBuffer); - sectionHeader = line; - } - lineBuffer.add(line); lineCount++; } makeSection(sectionHeader, builder, lineBuffer); @@ -103,12 +104,19 @@ public void write(final ChangesFile changesFile, final Path destinationFile) { } void write(final ChangesFile changesFile, final Writer writer) throws IOException { + writeFirstLine(writer, changesFile); writeSection(writer, changesFile.getHeaderSectionLines()); for (final ChangesFileSection section : changesFile.getSections()) { writeSection(writer, section.getContent()); } } + private void writeFirstLine(final Writer writer, final ChangesFile changesFile) throws IOException { + writer.write("# " + changesFile.getProjectName() + " " + changesFile.getProjectVersion() + ", released " + + changesFile.getReleaseDate()); + writer.write(LINE_SEPARATOR); + } + private void writeSection(final Writer fileWriter, final List content) throws IOException { for (final String line : content) { fileWriter.write(line); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java index 47ee1961..db520196 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java @@ -74,9 +74,7 @@ private ChangesFile fixSections(final ChangesFile changesFile) { private ChangesFile getTemplate() { final String releaseDate = LocalDateTime.now().getYear() + "-??-??"; final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion) - .releaseDate(releaseDate) - .setHeader(List.of("# " + this.projectName + " " + this.projectVersion + ", released " + releaseDate, - "", "Code name:", "")) // + .releaseDate(releaseDate).setHeader(List.of("", "Code name:", "")) // .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) // .build(); return fixSections(changesFile); diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 562592b5..4971e431 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -25,7 +25,10 @@ void testParsing() throws IOException { final ChangesFile changesFile = new ChangesFileIO().read(changesFilePath); final List headings = changesFile.getSections().stream().map(ChangesFileSection::getHeading) .collect(Collectors.toList()); - assertThat(changesFile.getHeaderSectionLines().get(0), equalTo("# My Project 0.1.0, released 1980-01-01")); + assertThat(changesFile.getProjectName(), equalTo("My Project")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("0.1.0")); + assertThat(changesFile.getReleaseDate(), equalTo("1980-01-01")); + assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("1980-01-01"))); assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring", "## Dependency Updates")); } @@ -37,8 +40,9 @@ void testWriting() throws IOException { .build(); final Path testFile = this.tempDir.resolve("myFile.md"); new ChangesFileIO().write(changesFile, testFile); - assertThat(Files.readString(testFile), - equalTo("# MyChanges" + System.lineSeparator() + "## My Subsection" + System.lineSeparator())); + assertThat(Files.readString(testFile), equalTo("# project 1.2.3, released 2023-??-??" + System.lineSeparator() + // + "# MyChanges" + System.lineSeparator() + // + "## My Subsection" + System.lineSeparator())); } @Test diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java index 9cf9bf31..5eca082b 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java @@ -4,10 +4,8 @@ import static com.exasol.projectkeeper.HasNoMoreFindingsAfterApplyingFixesMatcher.hasNoMoreFindingsAfterApplyingFixes; import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasNoValidationFindings; import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasValidationFindingWithMessage; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -35,6 +33,7 @@ class ChangesFileValidatorTest { private static final String A_VERSION = "1.2.3"; private static final String A_PROJECT_NAME = "my-project"; + private static final String LINE_SEPARATOR = System.lineSeparator(); @TempDir Path tempDir; @@ -55,12 +54,18 @@ void testValidationForSnapshotVersion() throws IOException { } @Test - void noDepdendencyUpdates() throws IOException { + void noDependencyUpdates() throws IOException { final AnalyzedMavenSource source = createTestSetup(new TestMavenModel(), Collections.emptyList()); final Logger log = mock(Logger.class); createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding))); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release"))); + assertThat(changesFile, + hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR // + + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR))); + verify(log).info("Created 'doc" + File.separator + "changes" + File.separator + "changes_1.2.3.md'. Don't forget to update its content!"); final List findings = createValidator(source).validate(); @@ -73,7 +78,15 @@ void testFixCreatedTemplate() throws IOException { final Logger log = mock(Logger.class); createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding))); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release"))); + assertThat(changesFile, + hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR // + + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR + + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR))); verify(log).info("Created 'doc" + File.separator + "changes" + File.separator + "changes_1.2.3.md'. Don't forget to update its content!"); } @@ -85,7 +98,9 @@ void testFixContainsDependencyUpdates() throws IOException { final AnalyzedMavenSource source = createTestSetup(model); createValidator(source).validate().forEach(FindingFixHelper::fix); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(containsString("my-lib"))); + assertThat(changesFile, hasContent(endsWith("## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR))); } @Test @@ -117,4 +132,4 @@ private AnalyzedMavenSource createTestSetup(final TestMavenModel mavenModel, .dependencyChanges(DependencyChangeReport.builder().typed(Type.COMPILE, dependencyChanges).build()) // .build(); } -} \ No newline at end of file +} From 022a555cfd529bee171965fc99340a70c580cc22 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 11:43:50 +0100 Subject: [PATCH 41/78] Allow specifying code name, summary & dependency changes for ChangesFile --- project-keeper/error_code_config.yml | 2 +- .../validators/changesfile/ChangesFile.java | 150 +++++++++++++----- .../validators/changesfile/ChangesFileIO.java | 141 ++++++++++------ .../changesfile/ChangesFileSection.java | 81 +++++++--- .../changesfile/ChangesFileValidator.java | 7 +- .../changesfile/DependencySectionFixer.java | 18 +-- .../DependencyChangeReportRenderer.java | 18 +-- .../changesfile/ChangesFileIOTest.java | 66 ++++++-- .../changesfile/ChangesFileTest.java | 10 +- .../changesfile/ChangesFileValidatorTest.java | 2 +- .../DependencySectionFixerTest.java | 47 +++--- .../DependencyChangeReportRendererTest.java | 28 ++-- .../src/test/resources/changesFileExample1.md | 1 - 13 files changed, 388 insertions(+), 183 deletions(-) diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml index 5cd01760..53d3c5ac 100644 --- a/project-keeper/error_code_config.yml +++ b/project-keeper/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CORE: packages: - com.exasol.projectkeeper - highest-index: 177 + highest-index: 179 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 47bffa7a..b9d695f7 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -4,8 +4,8 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; import java.util.*; -import java.util.stream.Collectors; +import com.exasol.errorreporting.ExaError; import com.vdurmont.semver4j.Semver; /** @@ -14,18 +14,24 @@ public final class ChangesFile { /** Headline of the dependency updates section. */ public static final String DEPENDENCY_UPDATES_HEADING = "## Dependency Updates"; + /** Headline of the Summary section. */ + public static final String SUMMARY_HEADING = "## Summary"; private final String projectName; private final Semver projectVersion; private final String releaseDate; - private final List headerSectionLines; + private final String codeName; + private final ChangesFileSection summarySection; private final List sections; + private final ChangesFileSection dependencyChangeSection; private ChangesFile(final Builder builder) { - this.projectName = Objects.requireNonNull(builder.projectName, "projectName"); - this.projectVersion = Objects.requireNonNull(builder.projectVersion, "projectVersion"); - this.releaseDate = Objects.requireNonNull(builder.releaseDate, "releaseDate"); - this.headerSectionLines = List.copyOf(Objects.requireNonNull(builder.header, "header")); - this.sections = List.copyOf(Objects.requireNonNull(builder.sections, "sections")); + this.projectName = Objects.requireNonNull(builder.projectName, "missing projectName"); + this.projectVersion = Objects.requireNonNull(builder.projectVersion, "missing projectVersion"); + this.releaseDate = Objects.requireNonNull(builder.releaseDate, "missing releaseDate"); + this.codeName = builder.codeName; + this.summarySection = builder.summarySection; + this.sections = List.copyOf(Objects.requireNonNull(builder.sections, "missing sections")); + this.dependencyChangeSection = builder.dependencyChangeSection; } /** @@ -55,7 +61,8 @@ public static Builder builder() { */ public Builder toBuilder() { return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString()) - .releaseDate(this.releaseDate).setHeader(this.headerSectionLines).sections(this.sections); + .releaseDate(this.releaseDate).summary(this.summarySection).sections(List.copyOf(this.sections)) + .dependencyChangeSection(this.dependencyChangeSection); } /** @@ -85,6 +92,15 @@ public String getReleaseDate() { return releaseDate; } + /** + * Get the code name of the release. + * + * @return code name + */ + public String getCodeName() { + return codeName; + } + /** * Get the parsed release date for the first header line. If the date is not valid (e.g. {@code 2024-??-??}), this * will return an empty {@link Optional}. @@ -100,24 +116,43 @@ public Optional getParsedReleaseDate() { } /** - * Get the header of the changes section. - *

- * The header includes all lines until the first section {@code ##} starts. - *

+ * Get a list of sections (starting with a ## heading). * - * @return list of lines of the header + * @return list of sections */ - public List getHeaderSectionLines() { - return this.headerSectionLines; + public List getSections() { + return this.sections; } /** - * Get a list of sections (starting with a ## heading). + * Get the dependency change section. + * + * @return dependency change section + */ + public Optional getDependencyChangeSection() { + return Optional.ofNullable(dependencyChangeSection); + } + + /** + * Get the summary section. * - * @return list of sections + * @return summary section */ - public List getSections() { - return this.sections; + public Optional getSummarySection() { + return Optional.ofNullable(this.summarySection); + } + + @Override + public String toString() { + return "ChangesFile [projectName=" + projectName + ", projectVersion=" + projectVersion + ", releaseDate=" + + releaseDate + ", codeName=" + codeName + ", summarySection=" + summarySection + ", sections=" + + sections + ", dependencyChangeSection=" + dependencyChangeSection + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(projectName, projectVersion, releaseDate, codeName, summarySection, sections, + dependencyChangeSection); } @Override @@ -133,31 +168,23 @@ public boolean equals(final Object obj) { } final ChangesFile other = (ChangesFile) obj; return Objects.equals(projectName, other.projectName) && Objects.equals(projectVersion, other.projectVersion) - && Objects.equals(releaseDate, other.releaseDate) - && Objects.equals(headerSectionLines, other.headerSectionLines) - && Objects.equals(sections, other.sections); - } - - @Override - public int hashCode() { - return Objects.hash(projectName, projectVersion, releaseDate, headerSectionLines, sections); - } - - @Override - public String toString() { - return String.join("\n", this.headerSectionLines) + "\n" - + this.sections.stream().map(ChangesFileSection::toString).collect(Collectors.joining("\n")); + && Objects.equals(releaseDate, other.releaseDate) && Objects.equals(codeName, other.codeName) + && Objects.equals(summarySection, other.summarySection) && Objects.equals(sections, other.sections) + && Objects.equals(dependencyChangeSection, other.dependencyChangeSection); } /** * Builder for {@link ChangesFile}. */ public static class Builder { + private String projectName; private Semver projectVersion; private String releaseDate; + private String codeName; + private ChangesFileSection summarySection; private List sections = new ArrayList<>(); - private List header = Collections.emptyList(); + private ChangesFileSection dependencyChangeSection; private Builder() { // private constructor to hide public default @@ -197,24 +224,44 @@ public Builder releaseDate(final String releaseDate) { } /** - * Set the header of the changes file. + * Set the code name of the release. * - * @param header list of lines + * @param codeName code name * @return self for fluent programming */ - public Builder setHeader(final List header) { - this.header = header; + public Builder codeName(final String codeName) { + this.codeName = codeName.isBlank() ? null : codeName; return this; } /** * Add a section to the changes file. * - * @param lines list of lines + * @param section section * @return self for fluent programming */ - public Builder addSection(final List lines) { - this.sections.add(new ChangesFileSection(lines)); + public Builder addSection(final ChangesFileSection section) { + this.sections.add(section); + return this; + } + + /** + * Set the {@code Summary} section for the changes file. + * + * @param section section + * @return self for fluent programming + */ + public Builder summary(final ChangesFileSection section) { + if (section == null) { + this.summarySection = null; + return this; + } + if (!section.getHeading().equals(SUMMARY_HEADING)) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message( + "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}", + section.getHeading(), SUMMARY_HEADING).ticketMitigation().toString()); + } + this.summarySection = section; return this; } @@ -229,6 +276,26 @@ public Builder sections(final List sections) { return this; } + /** + * Add a an optional {@code Dependency Updates} section to the changes file. + * + * @param section section + * @return self for fluent programming + */ + public Builder dependencyChangeSection(final ChangesFileSection section) { + if (section == null) { + this.dependencyChangeSection = null; + return this; + } + if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message( + "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}", + section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString()); + } + this.dependencyChangeSection = section; + return this; + } + /** * Build the {@link ChangesFile}. * @@ -237,5 +304,6 @@ public Builder sections(final List sections) { public ChangesFile build() { return new ChangesFile(this); } + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 90f4be3c..07aa3acd 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -2,8 +2,7 @@ import java.io.*; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,6 +13,7 @@ * This class reads and writes a {@link ChangesFile} from disk. */ public class ChangesFileIO { + private static final String CODE_NAME = "Code name:"; private static final String PROJECT_NAME_PATTERN = "[\\w\\s-]+"; private static final String VERSION_PATTERN = "\\d+\\.\\d+\\.\\d+"; private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}"; @@ -39,50 +39,84 @@ public ChangesFile read(final Path file) { } ChangesFile read(final Path file, final BufferedReader fileReader) throws IOException { - String sectionHeader = null; - String line; - int lineCount = 0; - final var builder = ChangesFile.builder(); + return new Parser(file, fileReader).parse(); + } + + private static class Parser { + final Path file; + final BufferedReader reader; + final Builder builder = ChangesFile.builder(); + ChangesFileSection.Builder currentSection; + final List lineBuffer = new ArrayList<>(); - while ((line = fileReader.readLine()) != null) { + int lineCount = 0; + + Parser(final Path file, final BufferedReader reader) { + this.file = file; + this.reader = reader; + } + + ChangesFile parse() throws IOException { + String line; + while ((line = reader.readLine()) != null) { + parseLine(line); + lineCount++; + } + addSection(); + return builder.build(); + } + + private void parseLine(final String line) { if (lineCount == 0) { - parseFirstLine(file, line, builder); - } else { - if (SECTION_HEADING_PATTERN.matcher(line).matches()) { - makeSection(sectionHeader, builder, lineBuffer); - sectionHeader = line; - } - lineBuffer.add(line); + parseFirstLine(file, line); + return; + } + if (line.startsWith(CODE_NAME)) { + builder.codeName(line.substring(CODE_NAME.length()).trim()); + return; + } + if (line.startsWith("## ")) { + addSection(); + currentSection = ChangesFileSection.builder(line); + return; + } + if (currentSection != null) { + currentSection.addLine(line); } - lineCount++; } - makeSection(sectionHeader, builder, lineBuffer); - return builder.build(); - } - private void parseFirstLine(final Path filePath, final String line, final Builder builder) { - final Matcher matcher = FIRST_LINE_PATTERN.matcher(line); - if (!matcher.matches()) { - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171") - .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, line) - .mitigation("Update first line so that it matches regex {{expected regular expression}}", - FIRST_LINE_PATTERN) - .toString()); + private void addSection() { + if (currentSection == null) { + return; + } + final ChangesFileSection section = currentSection.build(); + currentSection = null; + switch (section.getHeading()) { + case ChangesFile.SUMMARY_HEADING: + builder.summary(section); + break; + case ChangesFile.DEPENDENCY_UPDATES_HEADING: + builder.dependencyChangeSection(section); + break; + default: + builder.addSection(section); + break; + } } - builder.projectName(matcher.group(1)) // - .projectVersion(matcher.group(2)) // - .releaseDate(matcher.group(3)); - } - private void makeSection(final String sectionHeader, final ChangesFile.Builder builder, - final List lineBuffer) { - if (!lineBuffer.isEmpty()) { - if (sectionHeader == null) { - builder.setHeader(List.copyOf(lineBuffer)); - } else { - builder.addSection(List.copyOf(lineBuffer)); + private void parseFirstLine(final Path filePath, final String line) { + final Matcher matcher = FIRST_LINE_PATTERN.matcher(line); + if (!matcher.matches()) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171") + .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, + line) + .mitigation("Update first line so that it matches regex {{expected regular expression}}", + FIRST_LINE_PATTERN) + .toString()); } - lineBuffer.clear(); + builder.projectName(matcher.group(1)) // + .projectVersion(matcher.group(2)) // + .releaseDate(matcher.group(3)); } } @@ -104,23 +138,38 @@ public void write(final ChangesFile changesFile, final Path destinationFile) { } void write(final ChangesFile changesFile, final Writer writer) throws IOException { - writeFirstLine(writer, changesFile); - writeSection(writer, changesFile.getHeaderSectionLines()); + writeHeader(writer, changesFile); for (final ChangesFileSection section : changesFile.getSections()) { - writeSection(writer, section.getContent()); + writeSection(writer, section); + } + final Optional dependencyChangeSection = changesFile.getDependencyChangeSection(); + if (dependencyChangeSection.isPresent()) { + writer.write(dependencyChangeSection.get().toString()); + writer.write(LINE_SEPARATOR); } } - private void writeFirstLine(final Writer writer, final ChangesFile changesFile) throws IOException { + private void writeHeader(final Writer writer, final ChangesFile changesFile) throws IOException { writer.write("# " + changesFile.getProjectName() + " " + changesFile.getProjectVersion() + ", released " + changesFile.getReleaseDate()); writer.write(LINE_SEPARATOR); + writer.write(LINE_SEPARATOR); + writer.write(CODE_NAME + (changesFile.getCodeName() != null ? " " + changesFile.getCodeName() : "")); + writer.write(LINE_SEPARATOR); + writer.write(LINE_SEPARATOR); + final Optional summarySection = changesFile.getSummarySection(); + if (summarySection.isPresent()) { + writer.write(summarySection.get().toString()); + writer.write(LINE_SEPARATOR); + } } - private void writeSection(final Writer fileWriter, final List content) throws IOException { - for (final String line : content) { - fileWriter.write(line); - fileWriter.write(LINE_SEPARATOR); + private void writeSection(final Writer writer, final ChangesFileSection section) throws IOException { + writer.write(section.getHeading()); + writer.write(LINE_SEPARATOR); + for (final String line : section.getContent()) { + writer.write(line); + writer.write(LINE_SEPARATOR); } } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java index 26a27080..9a71af5a 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java @@ -1,9 +1,8 @@ package com.exasol.projectkeeper.validators.changesfile; -import java.util.List; -import java.util.Objects; +import static java.util.Arrays.asList; -import com.exasol.errorreporting.ExaError; +import java.util.*; /** * Section of a {@link ChangesFile}. @@ -12,19 +11,13 @@ *

*/ public final class ChangesFileSection { + + private final String heading; private final List content; - /** - * Create a new instance of {@link ChangesFileSection}. - * - * @param content lines - */ - public ChangesFileSection(final List content) { - if (content.isEmpty()) { - throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-36") - .message("changes file sections must not be empty.").ticketMitigation().toString()); - } - this.content = List.copyOf(content); + private ChangesFileSection(final Builder builder) { + this.heading = Objects.requireNonNull(builder.heading, "header"); + this.content = List.copyOf(builder.lines); } /** @@ -33,7 +26,7 @@ public ChangesFileSection(final List content) { * @return heading */ public String getHeading() { - return this.content.get(0); + return this.heading; } /** @@ -46,22 +39,60 @@ public List getContent() { } @Override - public boolean equals(final Object other) { - if (this == other) - return true; - if (other == null || getClass() != other.getClass()) - return false; - final ChangesFileSection that = (ChangesFileSection) other; - return Objects.equals(this.content, that.content); + public int hashCode() { + return Objects.hash(heading, content); } @Override - public int hashCode() { - return Objects.hash(this.content); + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFileSection other = (ChangesFileSection) obj; + return Objects.equals(heading, other.heading) && Objects.equals(content, other.content); } @Override public String toString() { - return String.join("\n", this.content); + return heading + "\n" + String.join("\n", this.content); + } + + public static Builder builder(final String heading) { + return new Builder(heading); + } + + public static class Builder { + + private final String heading; + private final List lines = new ArrayList<>(); + + private Builder(final String heading) { + this.heading = heading; + } + + public Builder addLines(final String... lines) { + this.lines.addAll(asList(lines)); + return this; + } + + public Builder addLines(final List lines) { + this.lines.addAll(lines); + return this; + } + + public Builder addLine(final String line) { + this.lines.add(line); + return this; + } + + public ChangesFileSection build() { + return new ChangesFileSection(this); + } } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java index db520196..ba21db83 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java @@ -74,8 +74,11 @@ private ChangesFile fixSections(final ChangesFile changesFile) { private ChangesFile getTemplate() { final String releaseDate = LocalDateTime.now().getYear() + "-??-??"; final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion) - .releaseDate(releaseDate).setHeader(List.of("", "Code name:", "")) // - .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) // + .releaseDate(releaseDate) // + .codeName("") // + .summary(ChangesFileSection.builder("## Summary").build()) + .addSection(ChangesFileSection.builder("## Features").addLines("", "* ISSUE_NUMBER: description", "") + .build()) // .build(); return fixSections(changesFile); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java index 60f4ddf9..9db14cf0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java @@ -1,9 +1,7 @@ package com.exasol.projectkeeper.validators.changesfile; -import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING; - -import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import com.exasol.projectkeeper.sources.AnalyzedSource; @@ -35,20 +33,12 @@ public DependencySectionFixer(final List sources) { public ChangesFile fix(final ChangesFile changesFile) { final List reports = this.sources.stream().map(this::getDependencyChangesOfSource) .collect(Collectors.toList()); - final List renderedReport = new DependencyChangeReportRenderer().render(reports); - final List sections = new ArrayList<>(changesFile.getSections()); - removeDependencySection(sections); - if (!renderedReport.isEmpty()) { - sections.add(new ChangesFileSection(renderedReport)); - } - return changesFile.toBuilder().sections(sections).build(); + final Optional dependencyChanges = new DependencyChangeReportRenderer().render(reports); + return changesFile.toBuilder() // + .dependencyChangeSection(dependencyChanges.orElse(null)).build(); } private NamedDependencyChangeReport getDependencyChangesOfSource(final AnalyzedSource source) { return new NamedDependencyChangeReport(source.getProjectName(), source.getDependencyChanges()); } - - private void removeDependencySection(final List sections) { - sections.removeIf(section -> section.getHeading().compareToIgnoreCase(DEPENDENCY_UPDATES_HEADING) == 0); - } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java index aca0d23d..34695e34 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java @@ -2,14 +2,12 @@ import static com.exasol.projectkeeper.ApStyleFormatter.capitalizeApStyle; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChange; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport; +import com.exasol.projectkeeper.validators.changesfile.*; /** * String renderer for {@link DependencyChangeReport}. @@ -20,17 +18,15 @@ public class DependencyChangeReportRenderer { * Render a {@link DependencyChangeReport} to string. * * @param reports reports to render - * @return rendered report as a list of lines + * @return rendered report as a section */ - public List render(final List reports) { + public Optional render(final List reports) { final List content = renderContent(reports); - final List lines = new ArrayList<>(); if (content.isEmpty()) { - return lines; + return Optional.empty(); } - lines.add(ChangesFile.DEPENDENCY_UPDATES_HEADING); - lines.addAll(content); - return lines; + return Optional.of(ChangesFileSection.builder(ChangesFile.DEPENDENCY_UPDATES_HEADING) // + .addLines(content).build()); } private List renderContent(final List reports) { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 4971e431..cc140a7c 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -15,6 +15,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import com.github.hamstercommunity.matcher.auto.AutoMatcher; + class ChangesFileIOTest { @TempDir Path tempDir; @@ -29,20 +31,23 @@ void testParsing() throws IOException { assertThat(changesFile.getProjectVersion().toString(), equalTo("0.1.0")); assertThat(changesFile.getReleaseDate(), equalTo("1980-01-01")); assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("1980-01-01"))); - assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring", - "## Dependency Updates")); + assertThat(changesFile.getSummarySection().get().getContent(), contains("", "My summary", "")); + assertThat(headings, contains("## Features", "## Bug Fixes", "## Documentation", "## Refactoring")); + assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates")); + assertThat(changesFile.getDependencyChangeSection().get().getContent(), hasSize(18)); } @Test void testWriting() throws IOException { final ChangesFile changesFile = ChangesFile.builder().projectName("project").projectVersion("1.2.3") - .releaseDate("2023-??-??").setHeader(List.of("# MyChanges")).addSection(List.of("## My Subsection")) - .build(); + .releaseDate("2023-??-??").codeName("my code name") + .summary(ChangesFileSection.builder("## Summary").addLine("my summary content").build()) + .addSection(ChangesFileSection.builder("# MyChanges").build()) + .addSection(ChangesFileSection.builder("## My Subsection").addLine("content").build()).build(); final Path testFile = this.tempDir.resolve("myFile.md"); new ChangesFileIO().write(changesFile, testFile); - assertThat(Files.readString(testFile), equalTo("# project 1.2.3, released 2023-??-??" + System.lineSeparator() + // - "# MyChanges" + System.lineSeparator() + // - "## My Subsection" + System.lineSeparator())); + assertThat(Files.readString(testFile), equalTo( + "# project 1.2.3, released 2023-??-??\n\nCode name: my code name\n\n## Summary\nmy summary content\n# MyChanges\n## My Subsection\ncontent\n")); } @Test @@ -61,17 +66,19 @@ void testReadInvalidFirstLineFails() { @Test void testReadFirstLineWithDummyReleaseDate() throws IOException { - final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-??-??"); + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-??-??\nCode name: my code name\n## Summary\n\n"); assertThat(changesFile.getProjectName(), equalTo("Project Name")); assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??")); + assertThat(changesFile.getCodeName(), equalTo("my code name")); assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false)); assertWriteRead(changesFile); } @Test void testReadFirstLineWithValidReleaseDate() throws IOException { - final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29"); + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary\n\n"); assertThat(changesFile.getProjectName(), equalTo("Project Name")); assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29")); @@ -79,6 +86,45 @@ void testReadFirstLineWithValidReleaseDate() throws IOException { assertWriteRead(changesFile); } + @Test + void testReadMissingSummary() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29"); + assertThat(changesFile.getSummarySection().isEmpty(), is(true)); + } + + @Test + void testReadEmptySummary() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary"); + final ChangesFileSection summary = changesFile.getSummarySection().get(); + assertThat(summary.getHeading(), equalTo("## Summary")); + assertThat(summary.getContent(), emptyIterable()); + } + + @Test + void testReadSummary() throws IOException { + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-01-29\n## Summary\nmy\ncontent\n"); + final ChangesFileSection summary = changesFile.getSummarySection().get(); + assertThat(summary.getHeading(), equalTo("## Summary")); + assertThat(summary.getContent(), contains("my", "content")); + assertWriteRead(changesFile); + } + + @Test + void testReadNoDependencySection() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary"); + assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(true)); + } + + @Test + void testReadDependencySection() throws IOException { + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-01-29\n## Summary\n## Dependency Updates\nmy\ncontent"); + assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(false)); + assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates")); + assertThat(changesFile.getDependencyChangeSection().get().getContent(), contains("my", "content")); + } + private Path loadExampleFileToTempDir() throws IOException { final Path changesFile = this.tempDir.resolve("changed_0.1.0.md"); try (final InputStream exampleFileStream = getExampleFileStream()) { @@ -100,6 +146,8 @@ private InputStream getExampleFileStream() { private void assertWriteRead(final ChangesFile changesFile) throws IOException { final String content = writeToString(changesFile); final ChangesFile readChangesFile = readFromString(content); + assertThat(readChangesFile.toString(), equalTo(changesFile.toString())); + assertThat(readChangesFile, AutoMatcher.equalTo(changesFile)); assertThat(readChangesFile, equalTo(changesFile)); } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java index e8fff56f..86701f2f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java @@ -6,11 +6,11 @@ import java.nio.file.Path; import java.time.LocalDate; -import java.util.List; import org.junit.jupiter.api.Test; import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; +import com.jparams.verifier.tostring.ToStringVerifier; import nl.jqno.equalsverifier.EqualsVerifier; @@ -21,6 +21,11 @@ void equalsContract() { EqualsVerifier.forClass(ChangesFile.class).verify(); } + @Test + void testToString() { + ToStringVerifier.forClass(ChangesFile.class).verify(); + } + @Test void getPathForVersion() { assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md"))); @@ -36,7 +41,8 @@ void toBuilderCreatesCopy() { private Builder builder() { return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??") - .addSection(List.of("section 1")).setHeader(List.of("header 1")); + .summary(ChangesFileSection.builder("## Summary").build()) + .addSection(ChangesFileSection.builder("section 1").build()); } @Test diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java index 5eca082b..62234975 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java @@ -33,7 +33,7 @@ class ChangesFileValidatorTest { private static final String A_VERSION = "1.2.3"; private static final String A_PROJECT_NAME = "my-project"; - private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String LINE_SEPARATOR = "\n"; @TempDir Path tempDir; diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java index f9391bba..d02f8e7f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java @@ -2,8 +2,7 @@ import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.*; import java.util.List; @@ -33,33 +32,43 @@ static void beforeAll() { @Test void testSectionIsAdded() { - final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")).build(); - final List sections = new DependencySectionFixer(List.of(source)).fix(changesFile) - .getSections(); - assertThat(sections.size(), equalTo(1)); - assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); + final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build()) + .build(); + final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); + assertThat(fixedChangesFile.getDependencyChangeSection().get().getHeading(), + equalTo(DEPENDENCY_UPDATES_HEADING)); } private Builder changesFileBuilder() { - return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate"); + return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate") + .summary(ChangesFileSection.builder("## Summary").build()); } @Test void testSectionIsUpdated() { - final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")) - .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); + final ChangesFile changesFile = changesFileBuilder().dependencyChangeSection( + ChangesFileSection.builder("## Dependency Updates").addLine("content will be overwritten").build()) + .build(); final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); - final List sections = fixedChangesFile.getSections(); - assertThat(sections.size(), equalTo(1)); - assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); - assertThat("dependency fixer changed the changes file", changesFile, not(equalTo(fixedChangesFile))); + final ChangesFileSection changesFileSection = fixedChangesFile.getDependencyChangeSection().get(); + assertThat(changesFileSection.getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); + assertThat(changesFileSection.getContent(), + contains("", "### Compile Dependency Updates", "", "* Added `com.example:my-lib:1.2.3`")); + assertThat("dependency fixer changed the changes file", changesFile, + allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile)))); } @Test - void testHeaderIsPreserved() { - final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")) - .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); - final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); - assertThat(changesFile.getHeaderSectionLines(), equalTo(fixedChangesFile.getHeaderSectionLines())); + void testDependencySectionIsRemoved() { + final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build()) + .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates") + .addLine("content will be preserved").build()) + .build(); + final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of()).fix(changesFile); + + assertThat(fixedChangesFile.getDependencyChangeSection().isPresent(), is(false)); + assertThat(fixedChangesFile, not(sameInstance(changesFile))); + assertThat("dependency fixer changed the changes file", changesFile, + allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile)))); } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java index 6ad5cde4..12eb1942 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java @@ -1,16 +1,19 @@ package com.exasol.projectkeeper.validators.changesfile.dependencies; +import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; import com.exasol.projectkeeper.shared.dependencychanges.NewDependency; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileSection; import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport; class DependencyChangeReportRendererTest { @@ -22,17 +25,15 @@ class DependencyChangeReportRendererTest { @Test void testRenderSingleSourceReport() { final NamedDependencyChangeReport namedReport = new NamedDependencyChangeReport("my-project", REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(namedReport))); - assertThat(result, equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + "\n" - + "* Added `com.example:my-lib:1.2.3`")); + assertThat(render(namedReport), equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + + "\n" + "* Added `com.example:my-lib:1.2.3`")); } @Test void testRenderMultiSourceReport() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT); final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB))); - assertThat(result, equalTo( + assertThat(render(sourceA, sourceB), equalTo( "## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`\n\n### Project B\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`")); } @@ -40,15 +41,20 @@ void testRenderMultiSourceReport() { void testRenderMultiSourceReportWithNoChangesInOneReport() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT); final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", EMPTY_REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB))); - assertThat(result, equalTo( + assertThat(render(sourceA, sourceB), equalTo( "## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`")); } @Test void testRenderSourceReportWithoutChanges() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", EMPTY_REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA))); - assertThat(result, emptyString()); + final Optional result = new DependencyChangeReportRenderer().render(List.of(sourceA)); + assertThat(result.isPresent(), is(false)); } -} \ No newline at end of file + + private String render(final NamedDependencyChangeReport... reports) { + final Optional section = new DependencyChangeReportRenderer().render(asList(reports)); + assertThat(section.isPresent(), is(true)); + return section.get().toString(); + } +} diff --git a/project-keeper/src/test/resources/changesFileExample1.md b/project-keeper/src/test/resources/changesFileExample1.md index 4791e2ef..49211dfd 100644 --- a/project-keeper/src/test/resources/changesFileExample1.md +++ b/project-keeper/src/test/resources/changesFileExample1.md @@ -49,4 +49,3 @@ My summary * Added `::` * Updated `::` to `` * Removed `::` - From 1f01a2bb92ff19ecaccde5e239eb6a5783acc7ab Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 11:49:52 +0100 Subject: [PATCH 42/78] Fix javadoc & error codes --- parent-pom/error_code_config.yml | 8 +++++ .../dependencyupdate/DependencyUpdater.java | 2 -- .../validators/changesfile/ChangesFile.java | 2 +- .../changesfile/ChangesFileSection.java | 33 ++++++++++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 parent-pom/error_code_config.yml diff --git a/parent-pom/error_code_config.yml b/parent-pom/error_code_config.yml new file mode 100644 index 00000000..1389755e --- /dev/null +++ b/parent-pom/error_code_config.yml @@ -0,0 +1,8 @@ +# This file is only used for release guide. +# Actual error codes are based on files error_code_config.yml in individual subfolders. + +error-tags: + PK-PARENT: + packages: + - dummy + highest-index: 1 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 5dcb5121..293a7475 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -33,8 +33,6 @@ public class DependencyUpdater { /** * Create a new instance. * - * @param projectKeeper - * * @param projectKeeper project keeper reference * @param logger the logger to which we should write log messages * @param projectDir the project directory diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index b9d695f7..d95e836e 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -288,7 +288,7 @@ public Builder dependencyChangeSection(final ChangesFileSection section) { return this; } if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) { - throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message( + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-179").message( "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}", section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString()); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java index 9a71af5a..5e5a1ac1 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java @@ -63,12 +63,20 @@ public String toString() { return heading + "\n" + String.join("\n", this.content); } + /** + * Create a new {@link Builder} for creating a {@link ChangesFileSection}. + * + * @param heading the heading for the new section + * @return a new builder + */ public static Builder builder(final String heading) { return new Builder(heading); } + /** + * A builder for creating {@link ChangesFileSection}s. + */ public static class Builder { - private final String heading; private final List lines = new ArrayList<>(); @@ -76,21 +84,44 @@ private Builder(final String heading) { this.heading = heading; } + /** + * Add the given lines to the content of the new {@code ChangesFileSection}. + * + * @param lines lines to add + * @return {@code this} for fluent programming + */ public Builder addLines(final String... lines) { this.lines.addAll(asList(lines)); return this; } + /** + * Add the given lines to the content of the new {@code ChangesFileSection}. + * + * @param lines lines to add + * @return {@code this} for fluent programming + */ public Builder addLines(final List lines) { this.lines.addAll(lines); return this; } + /** + * Add the given line to the content of the new {@code ChangesFileSection}. + * + * @param line line to add + * @return {@code this} for fluent programming + */ public Builder addLine(final String line) { this.lines.add(line); return this; } + /** + * Build a new {@link ChangesFileSection}. + * + * @return a new {@link ChangesFileSection}. + */ public ChangesFileSection build() { return new ChangesFileSection(this); } From 678ab3160e8a28b3fd17f908a3e00d50430ef087 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 13:21:40 +0100 Subject: [PATCH 43/78] Remove unwanted import --- .../validators/changesfile/ChangesFileIOTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index cc140a7c..5da24627 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -15,8 +15,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.github.hamstercommunity.matcher.auto.AutoMatcher; - class ChangesFileIOTest { @TempDir Path tempDir; @@ -147,7 +145,6 @@ private void assertWriteRead(final ChangesFile changesFile) throws IOException { final String content = writeToString(changesFile); final ChangesFile readChangesFile = readFromString(content); assertThat(readChangesFile.toString(), equalTo(changesFile.toString())); - assertThat(readChangesFile, AutoMatcher.equalTo(changesFile)); assertThat(readChangesFile, equalTo(changesFile)); } From e144e11b72262a85d1ed75a8db92d2b00557d41d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 15:29:26 +0100 Subject: [PATCH 44/78] Refactor project crawler runner --- maven-project-crawler/error_code_config.yml | 2 +- .../MavenProjectCrawlerMojo.java | 5 + .../JavaProjectCrawlerRunner.java | 93 ++++++------------- .../analyze/generic/MavenProcessBuilder.java | 26 +++++- 4 files changed, 58 insertions(+), 68 deletions(-) diff --git a/maven-project-crawler/error_code_config.yml b/maven-project-crawler/error_code_config.yml index 867099b3..cf122110 100644 --- a/maven-project-crawler/error_code_config.yml +++ b/maven-project-crawler/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-MPC: packages: - com.exasol.projectkeeper - highest-index: 63 \ No newline at end of file + highest-index: 64 diff --git a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java index f8266227..85cc9ec6 100644 --- a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java +++ b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java @@ -39,6 +39,11 @@ public class MavenProjectCrawlerMojo extends AbstractMojo { // [impl -> dsn~eclipse-prefs-java-version~1] @Override public void execute() { + if (projectsToCrawl == null || projectsToCrawl.isBlank()) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-MPC-64") + .message("Property {{property name}} is not defined or empty.", PROPERTY_PROJECTS_TO_CRAWL) + .mitigation("Specify property with least one pom file.").toString()); + } final MavenProjectFromFileReader mavenProjectReader = new DefaultMavenProjectFromFileReader( this.mavenProjectBuilder, this.session); final MavenModelFromRepositoryReader modelFromRepositoryReader = new MavenModelFromRepositoryReader( diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java index e8aa3ecd..18dcf1ed 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java @@ -1,37 +1,28 @@ package com.exasol.projectkeeper; -import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.time.Duration; import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Collectors; -import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder; import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; -import com.exasol.projectkeeper.stream.AsyncStreamReader; -import com.exasol.projectkeeper.stream.CollectingConsumer; +import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; /** * Runs the maven plugin goal on the current repository and returns the parsed result. */ public class JavaProjectCrawlerRunner { - private static final Logger LOGGER = Logger.getLogger(JavaProjectCrawlerRunner.class.getName()); - private static final Duration STREAM_READING_TIMEOUT = Duration.ofSeconds(1); private final Path mvnRepositoryOverride; private final String ownVersion; /** * Create a new instance of {@link JavaProjectCrawlerRunner}. * - * @param mvnRepositoryOverride maven repository override. Use {@code null} for default + * @param mvnRepositoryOverride Maven repository override. This is useful for running integration tests. Use + * {@code null} for default. * @param ownVersion project-keeper version */ public JavaProjectCrawlerRunner(final Path mvnRepositoryOverride, final String ownVersion) { @@ -51,63 +42,39 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) { } private String runCrawlerPlugin(final Path... pomFiles) { - final String projectList = Arrays.stream(pomFiles).map(pomFile -> pomFile.toAbsolutePath().toString() - // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540 - .replace(FileSystems.getDefault().getSeparator(), "/")).collect(Collectors.joining(";")); - final List commandParts = buildMavenCommand(projectList); - LOGGER.fine(() -> "Executing command " + commandParts); - try { - final Process proc = new ProcessBuilder(commandParts).redirectErrorStream(true).start(); - - final CollectingConsumer outputStreamConsumer = new AsyncStreamReader() - .startCollectingConsumer(proc.getInputStream()); - final CollectingConsumer errorStreamConsumer = new AsyncStreamReader() - .startCollectingConsumer(proc.getErrorStream()); - - if (!proc.waitFor(90, TimeUnit.SECONDS)) { - final String stdOutput = outputStreamConsumer.getCurrentContent(); - final String stdError = errorStreamConsumer.getCurrentContent(); - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-81").message( - "Timeout while executing command {{executed command|u}}. Output: {{std output}}, error: {{std error}}", - commandParts, stdOutput, stdError).toString()); - } - final int exitCode = proc.exitValue(); - final String output = outputStreamConsumer.getContent(STREAM_READING_TIMEOUT); - if (exitCode != 0) { - LOGGER.log(Level.SEVERE, output); - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-78").message( - "Failed to run command {{executed command|u}}, exit code was {{exit code}}. Output:\n{{output}}", - commandParts, exitCode, output).toString()); - } - return new ResponseCoder().decodeResponse(output); - } catch (final IOException exception) { - throw new UncheckedIOException(getRunFailedMessage(), exception); - } catch (final InterruptedException exception) { - Thread.currentThread().interrupt(); - throw new IllegalStateException(getRunFailedMessage(), exception); - } + final MavenProcessBuilder builder = buildMavenCommand(pomFiles); + final SimpleProcess process = builder.startSimpleProcess(); + process.waitUntilFinished(Duration.ofSeconds(90)); + return new ResponseCoder().decodeResponse(process.getOutputStreamContent()); } - private List buildMavenCommand(final String projectList) { - final MavenProcessBuilder command = MavenProcessBuilder.create().addArguments("--batch-mode", - "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", - "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", - "-DprojectsToCrawl=" + projectList, - /* - * We need to disable the model cache here since it caches the parent poms with {revision} as version - * and then runs into trouble since the cache is different when reading the old pom (for comparing - * dependencies). - */ - "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true"); + private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { + final MavenProcessBuilder builder = MavenProcessBuilder.create() + .addArguments( + "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", + "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", + "-DprojectsToCrawl=" + getProjectList(pomFiles), + /* + * We need to disable the model cache here since it caches the parent poms with {revision} as + * version and then runs into trouble since the cache is different when reading the old pom (for + * comparing dependencies). + */ + "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true") + .workingDir(null); if (this.mvnRepositoryOverride != null) { - command.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); + builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); } - return command.build(); + return builder; } - private String getRunFailedMessage() { - return ExaError.messageBuilder("E-PK-CORE-80").message("Failed to run project-keeper-java-project-crawler.") - .toString(); + private String getProjectList(final Path... pomFiles) { + return Arrays.stream(pomFiles).map(this::formatPath).collect(Collectors.joining(";")); + } + + private String formatPath(final Path pomFile) { + return pomFile.toAbsolutePath().toString() + // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540 + .replace(FileSystems.getDefault().getSeparator(), "/"); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java index c546567d..cfbf386b 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -2,8 +2,11 @@ import static java.util.Arrays.asList; +import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; import com.exasol.projectkeeper.OsCheck; import com.exasol.projectkeeper.OsCheck.OSType; @@ -13,7 +16,10 @@ */ public class MavenProcessBuilder { + private static final Logger LOG = Logger.getLogger(MavenProcessBuilder.class.getName()); + private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30); private final List command = new ArrayList<>(); + private Path workingDir = null; private MavenProcessBuilder() { // Use create() method @@ -27,6 +33,7 @@ private MavenProcessBuilder() { public static MavenProcessBuilder create() { final MavenProcessBuilder builder = new MavenProcessBuilder(); builder.addArgument(getMavenExecutable()); + builder.addArgument("--batch-mode"); return builder; } @@ -53,12 +60,23 @@ public MavenProcessBuilder addArgument(final String argument) { } /** - * Build the command that can be used as argument for {@link ProcessBuilder}. + * Define the working directory where to execute the command. Default: {@code null}. * - * @return the command + * @param workingDir working dir + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder workingDir(final Path workingDir) { + this.workingDir = workingDir; + return this; + } + + /** + * Build the command and run it. + * + * @return the running {@link SimpleProcess} */ - public List build() { - return List.copyOf(this.command); + public SimpleProcess startSimpleProcess() { + return SimpleProcess.start(workingDir, command); } private static String getMavenExecutable() { From a62cee9092164263fc49fd59586e9ac2fa8b27f0 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 15:29:54 +0100 Subject: [PATCH 45/78] Update references after incrementing the version --- ...nProjectWithProjectKeeperPluginWriter.java | 14 +++++ .../plugin/ProjectKeeperMojoIT.java | 34 ++++++++++--- .../exasol/projectkeeper/ProjectKeeper.java | 3 +- .../dependencyupdate/DependencyUpdater.java | 18 +++---- .../ProjectVersionIncrementor.java | 51 ++++++++++++++----- .../JavaProjectCrawlerRunnerIT.java | 28 ++++++++-- 6 files changed, 113 insertions(+), 35 deletions(-) diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java index 9b5b8205..11953af5 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java @@ -6,6 +6,7 @@ import org.apache.maven.model.*; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; public class MvnProjectWithProjectKeeperPluginWriter { public static final String PROJECT_ARTIFACT_ID = "my-test-project"; @@ -42,6 +43,19 @@ public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupI return this; } + public MvnProjectWithProjectKeeperPluginWriter setArtifactFinalName(final String finalName) { + final Plugin plugin = new Plugin(); + plugin.setGroupId("org.apache.maven.plugins"); + plugin.setArtifactId("maven-assembly-plugin"); + final Xpp3Dom configuration = new Xpp3Dom("configuration"); + final Xpp3Dom finalNameElement = new Xpp3Dom("finalName"); + finalNameElement.setValue(finalName); + configuration.addChild(finalNameElement); + plugin.setConfiguration(configuration); + this.model.getBuild().addPlugin(plugin); + return this; + } + private void addProjectKeeperPlugin(final String version) { final Plugin projectKeeperPlugin = new Plugin(); projectKeeperPlugin.setGroupId("com.exasol"); diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index 66afb394..c80ba521 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -23,6 +23,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.hamcrest.Matcher; import org.junit.jupiter.api.*; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; @@ -50,8 +51,9 @@ void beforeEach(final TestInfo test) throws IOException, GitAPIException { Git.init().setDirectory(this.projectDir.toFile()).call().close(); new MvnProjectWithProjectKeeperPluginWriter(CURRENT_VERSION) // .addDependency("org.slf4j", "slf4j-api", ORIGINAL_SLF4J_VERSION) // + .setArtifactFinalName("dummy-${project.version}") // .writeAsPomToProject(this.projectDir); - LOG.info(() -> "Running test " + test.getDisplayName() + "..."); + LOG.info(() -> "Running test " + test.getDisplayName() + " using project " + this.projectDir + "..."); verifier = mavenIntegrationTestEnvironment.getVerifier(this.projectDir); } @@ -89,15 +91,19 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException { " - udf_coverage\n"); verifier.executeGoal("project-keeper:fix"); verifier.executeGoal("package"); - assertThat(this.projectDir.resolve(Path.of("target", "jacoco-agent", "org.jacoco.agent-runtime.jar")).toFile(), - anExistingFile()); + assertThat(projectDir.resolve("target/jacoco-agent/org.jacoco.agent-runtime.jar").toFile(), anExistingFile()); } @Test void testUpgradeDependencies() throws VerificationException, IOException { writeProjectKeeperConfig("sources:\n" + // " - type: maven\n" + // - " path: pom.xml\n"); + " path: pom.xml\n" + // + " modules:\n" + // + " - jar_artifact\n"); + final Path userGuidePath = projectDir.resolve("user_guide.md"); + writeFile(userGuidePath, "artifact reference: dummy-0.1.0.jar"); + verifier.executeGoal("project-keeper:fix"); assertThat("original version", readPom().getVersion(), equalTo("0.1.0")); @@ -113,8 +119,10 @@ void testUpgradeDependencies() throws VerificationException, IOException { final String updatedSlf4jVersion = updatedPom.getDependencies().get(0).getVersion(); assertThat("updated SLF4J version", updatedSlf4jVersion, allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2."))); - final String changesContent = Files.readString(projectDir.resolve(ChangesFile.getPathForVersion(newVersion))); - assertThat(changesContent, allOf(startsWith("blah"))); + assertContent(userGuidePath, equalTo("artifact reference: dummy-0.1.1.jar\n")); + assertContent(ChangesFile.getPathForVersion(newVersion), + allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"), + containsString("* Added `org.slf4j:slf4j-api:"))); } private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) { @@ -150,6 +158,18 @@ void testSkip(final String phase) throws IOException, VerificationException { } private void writeProjectKeeperConfig(final String content) throws IOException { - Files.writeString(this.projectDir.resolve(".project-keeper.yml"), content); + writeFile(this.projectDir.resolve(".project-keeper.yml"), content); + } + + private void writeFile(final Path path, final String content) throws IOException { + Files.writeString(path, content); + } + + private void assertContent(Path path, final Matcher contentMatcher) throws IOException { + if (!path.isAbsolute()) { + path = projectDir.resolve(path); + } + final String changesContent = Files.readString(path); + assertThat(changesContent, contentMatcher); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index 1e457768..6f9f1cdd 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -314,6 +314,7 @@ private Provision getValidationProvision() { */ public boolean updateDependencies() { final Provision provision = getValidationProvision(); - return DependencyUpdater.create(this, logger, projectDir, provision.projectVersion()).updateDependencies(); + return DependencyUpdater.create(this, config, logger, projectDir, provision.projectVersion()) + .updateDependencies(); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 293a7475..7c6d2940 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -2,14 +2,12 @@ import java.nio.file.Path; import java.time.Duration; -import java.time.Instant; -import java.util.List; import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Logger; import com.exasol.projectkeeper.ProjectKeeper; +import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; -import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; /** * This class runs the dependency update process. @@ -34,15 +32,16 @@ public class DependencyUpdater { * Create a new instance. * * @param projectKeeper project keeper reference + * @param config * @param logger the logger to which we should write log messages * @param projectDir the project directory * @param currentProjectVersion the project's current version * @return a new dependency updater */ - public static DependencyUpdater create(final ProjectKeeper projectKeeper, final Logger logger, - final Path projectDir, final String currentProjectVersion) { + public static DependencyUpdater create(final ProjectKeeper projectKeeper, ProjectKeeperConfig config, + final Logger logger, final Path projectDir, final String currentProjectVersion) { return new DependencyUpdater(projectKeeper, logger, projectDir, - new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion)); + new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion)); } /** @@ -79,11 +78,8 @@ private void updateDependencyVersions() { } private void runMaven(final String mavenGoal) { - final List command = MavenProcessBuilder.create().addArgument("--batch-mode").addArgument(mavenGoal) - .build(); - final Instant start = Instant.now(); - SimpleProcess.start(projectDir, command).waitUntilFinished(MAVEN_COMMAND_TIMEOUT); - logger.info("Running maven goal " + mavenGoal + " took " + Duration.between(start, Instant.now())); + MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir).startSimpleProcess() + .waitUntilFinished(MAVEN_COMMAND_TIMEOUT); } private void runProjectKeeperFix() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index 7a07464a..27d0209a 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -1,5 +1,7 @@ package com.exasol.projectkeeper.dependencyupdate; +import static com.exasol.projectkeeper.shared.config.ProjectKeeperModule.JAR_ARTIFACT; + import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -15,24 +17,29 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Logger; +import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; +import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; import com.vdurmont.semver4j.Semver; class ProjectVersionIncrementor { private static final ZoneId UTC_ZONE = ZoneId.of("UTC"); + private final ProjectKeeperConfig config; private final String currentProjectVersion; private final ChangesFileIO changesFileIO; private final Clock clock; private final Path projectDir; private final Logger logger; - ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion) { - this(logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC()); + ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, + final String currentProjectVersion) { + this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC()); } - ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion, - final ChangesFileIO changesFileIO, final Clock clock) { + ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, + final String currentProjectVersion, final ChangesFileIO changesFileIO, final Clock clock) { + this.config = config; this.logger = logger; this.projectDir = projectDir; this.changesFileIO = changesFileIO; @@ -68,17 +75,35 @@ private LocalDate today() { } void incrementProjectVersion() { - final Path path = getPomPath(); - final Model pom = readPom(path); + + final Model pom = readPom(); if (!this.currentProjectVersion.equals(pom.getVersion())) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message( "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}", - pom.getVersion(), path, currentProjectVersion).toString()); + pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString()); } + incrementVersion(pom); + if (usesReferenceCheckerPlugin()) { + updateReferences(); + } + } + + private boolean usesReferenceCheckerPlugin() { + return config.getSources().stream().anyMatch(source -> source.getModules().contains(JAR_ARTIFACT)); + } + + private void updateReferences() { + logger.info("Unify artifact references"); + MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify").workingDir(projectDir) + .startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30)); + } + + private void incrementVersion(final Model pom) { final String nextVersion = getIncrementedVersion(currentProjectVersion); - logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + path); + logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + + pom.getPomFile()); pom.setVersion(nextVersion); - writePom(path, pom); + writePom(pom); } static String getIncrementedVersion(final String version) { @@ -86,7 +111,8 @@ static String getIncrementedVersion(final String version) { return current.nextPatch().toString(); } - private Model readPom(final Path path) { + private Model readPom() { + final Path path = getPomPath(); try { return new MavenXpp3Reader().read(Files.newBufferedReader(path)); } catch (IOException | XmlPullParserException exception) { @@ -95,9 +121,10 @@ private Model readPom(final Path path) { } } - private void writePom(final Path path, final Model pom) { + private void writePom(final Model pom) { + final Path path = getPomPath(); try { - new MavenXpp3Writer().write(Files.newOutputStream(getPomPath()), pom); + new MavenXpp3Writer().write(Files.newOutputStream(path), pom); } catch (final IOException exception) { throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173") .message("Failed to write pom {{pom file path}}", path).toString(), exception); diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java index 0d378c26..56619d8b 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java @@ -2,8 +2,9 @@ import static com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type.COMPILE; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.FileWriter; import java.io.IOException; @@ -44,8 +45,7 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio Git.init().setDirectory(tempDir.toFile()).call().close(); final Path pomFile = tempDir.resolve("pom.xml"); writePomFile(pomFile); - final MavenProjectCrawlResult result = new JavaProjectCrawlerRunner(testMavenRepo, - TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFile); + final MavenProjectCrawlResult result = crawlProject(pomFile); final CrawledMavenProject mavenProject = result.getCrawledProjects() .get(pomFile.toAbsolutePath().toString().replace("\\", "/")); final ProjectDependency expectedDependency = ProjectDependency.builder() // @@ -63,6 +63,26 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio ); } + MavenProjectCrawlResult crawlProject(final Path... pomFiles) { + return new JavaProjectCrawlerRunner(testMavenRepo, TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFiles); + } + + @Test + void testGetDependencyChangesFailsForEmptyPomList() throws GitAPIException, IOException { + final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> crawlProject()); + assertThat(exception.getMessage(), containsString( + "E-PK-MPC-64: Property 'projectsToCrawl' is not defined or empty. Specify property with least one pom file.")); + } + + @Test + void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOException { + final Path missingPomFile = Path.of("missing-pom-file"); + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> this.crawlProject(missingPomFile)); + assertThat(exception.getMessage(), allOf(containsString("[FATAL] Non-readable POM"), + containsString(missingPomFile + " (No such file or directory)"))); + } + private void writePomFile(final Path pomFile) throws IOException { final TestMavenModel model = new TestMavenModel(); model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION); @@ -70,4 +90,4 @@ private void writePomFile(final Path pomFile) throws IOException { new MavenXpp3Writer().write(fileWriter, model); } } -} \ No newline at end of file +} From 5f6cd41dde9da9b61e298df1d3e455b38d590efc Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 15:38:48 +0100 Subject: [PATCH 46/78] Fix error message --- .../projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java index 3af17dca..9bef4677 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java @@ -30,7 +30,7 @@ void analyzingSourcesWithInvalidOwnVersionFails() { final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> analyze(OWN_VERSION, mavenSources)); assertThat(exception.getMessage(), - allOf(containsString("E-PK-CORE-78: Failed to run command"), + allOf(containsString("E-PK-CORE-126: Failed to run command"), containsString("[ERROR] Plugin com.exasol:project-keeper-java-project-crawler:" + OWN_VERSION + " or one of its dependencies could not be resolved"))); } From 5e30b367d531454e4e6bec34af5b869db375a4f3 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 15:42:12 +0100 Subject: [PATCH 47/78] Fix javadoc --- .../projectkeeper/dependencyupdate/DependencyUpdater.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 7c6d2940..72345744 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -32,13 +32,13 @@ public class DependencyUpdater { * Create a new instance. * * @param projectKeeper project keeper reference - * @param config + * @param config project keeper configuration * @param logger the logger to which we should write log messages * @param projectDir the project directory * @param currentProjectVersion the project's current version * @return a new dependency updater */ - public static DependencyUpdater create(final ProjectKeeper projectKeeper, ProjectKeeperConfig config, + public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion) { return new DependencyUpdater(projectKeeper, logger, projectDir, new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion)); From eff0e2911f4ce0be6687aa75aaf469698a8fb06c Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 15:56:23 +0100 Subject: [PATCH 48/78] Use \n as line separator for changes file --- .../projectkeeper/validators/changesfile/ChangesFileIO.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 07aa3acd..6045a3a6 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -19,8 +19,7 @@ public class ChangesFileIO { private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}"; private static final Pattern FIRST_LINE_PATTERN = Pattern .compile("^# (" + PROJECT_NAME_PATTERN + ") (" + VERSION_PATTERN + "), released (" + DATE_PATTERN + ")$"); - private static final Pattern SECTION_HEADING_PATTERN = Pattern.compile("\\s*##\\s.*"); - private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String LINE_SEPARATOR = "\n"; /** * Read a {@link ChangesFile} from disk. From f262f4e9659d23633bc5a10701744262c09e2f3f Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 16:02:15 +0100 Subject: [PATCH 49/78] Copy codename when fixing changes file --- .../validators/changesfile/ChangesFile.java | 12 ++++++------ .../validators/changesfile/ChangesFileTest.java | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index d95e836e..d2d54039 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -25,12 +25,12 @@ public final class ChangesFile { private final ChangesFileSection dependencyChangeSection; private ChangesFile(final Builder builder) { - this.projectName = Objects.requireNonNull(builder.projectName, "missing projectName"); - this.projectVersion = Objects.requireNonNull(builder.projectVersion, "missing projectVersion"); - this.releaseDate = Objects.requireNonNull(builder.releaseDate, "missing releaseDate"); + this.projectName = builder.projectName; + this.projectVersion = builder.projectVersion; + this.releaseDate = builder.releaseDate; this.codeName = builder.codeName; this.summarySection = builder.summarySection; - this.sections = List.copyOf(Objects.requireNonNull(builder.sections, "missing sections")); + this.sections = List.copyOf(builder.sections); this.dependencyChangeSection = builder.dependencyChangeSection; } @@ -61,8 +61,8 @@ public static Builder builder() { */ public Builder toBuilder() { return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString()) - .releaseDate(this.releaseDate).summary(this.summarySection).sections(List.copyOf(this.sections)) - .dependencyChangeSection(this.dependencyChangeSection); + .releaseDate(this.releaseDate).codeName(this.codeName).summary(this.summarySection) + .sections(List.copyOf(this.sections)).dependencyChangeSection(this.dependencyChangeSection); } /** diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java index 86701f2f..d4b3ab20 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java @@ -41,7 +41,10 @@ void toBuilderCreatesCopy() { private Builder builder() { return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??") - .summary(ChangesFileSection.builder("## Summary").build()) + .codeName("my code name") + .summary(ChangesFileSection.builder("## Summary").addLine("summary content").build()) + .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates") + .addLine("dependency update content").build()) .addSection(ChangesFileSection.builder("section 1").build()); } From 562db8c090ea57b2af56fa44cb15414ff8d6922e Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 16:24:32 +0100 Subject: [PATCH 50/78] Fix failing tests --- .../projectkeeper/validators/changesfile/ChangesFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index d2d54039..b6e1020b 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -230,7 +230,7 @@ public Builder releaseDate(final String releaseDate) { * @return self for fluent programming */ public Builder codeName(final String codeName) { - this.codeName = codeName.isBlank() ? null : codeName; + this.codeName = codeName != null && codeName.isBlank() ? null : codeName; return this; } From 7e5c1393a47d2a8f6dadef16aa2627adf726ac80 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 16:37:13 +0100 Subject: [PATCH 51/78] Fix windows tests --- .../projectkeeper/validators/changesfile/ChangesFileIOTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 5da24627..3f7748c1 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -133,7 +133,7 @@ private Path loadExampleFileToTempDir() throws IOException { private String readExampleFile() throws IOException { try (final InputStream exampleFileStream = getExampleFileStream()) { - return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8); + return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8).replace("\r\n", "\n"); } } From ef6c30b91576b58e1469e0f60103d96ef47b8d58 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 31 Jan 2024 16:50:03 +0100 Subject: [PATCH 52/78] Adapt error message to windows --- .../com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java index 56619d8b..ea11a2c7 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java @@ -79,8 +79,8 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce final Path missingPomFile = Path.of("missing-pom-file"); final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> this.crawlProject(missingPomFile)); - assertThat(exception.getMessage(), allOf(containsString("[FATAL] Non-readable POM"), - containsString(missingPomFile + " (No such file or directory)"))); + assertThat(exception.getMessage(), + allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString()))); } private void writePomFile(final Path pomFile) throws IOException { From a69afaf6ad0dff7e82be9f029e76dbd62791d912 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 1 Feb 2024 07:46:02 +0100 Subject: [PATCH 53/78] Fix integration test for windows --- .../plugin/ProjectKeeperMojoIT.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index c80ba521..c7ea6a74 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -115,14 +115,14 @@ void testUpgradeDependencies() throws VerificationException, IOException { final Model updatedPom = readPom(); final String newVersion = "0.1.1"; - assertThat("incremented version", updatedPom.getVersion(), equalTo(newVersion)); final String updatedSlf4jVersion = updatedPom.getDependencies().get(0).getVersion(); - assertThat("updated SLF4J version", updatedSlf4jVersion, - allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2."))); - assertContent(userGuidePath, equalTo("artifact reference: dummy-0.1.1.jar\n")); - assertContent(ChangesFile.getPathForVersion(newVersion), - allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"), - containsString("* Added `org.slf4j:slf4j-api:"))); + assertAll(() -> assertThat("incremented version", updatedPom.getVersion(), equalTo(newVersion)), + () -> assertThat("updated SLF4J version", updatedSlf4jVersion, + allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2."))), + () -> assertContent(userGuidePath, startsWith("artifact reference: dummy-0.1.1.jar")), + () -> assertContent(ChangesFile.getPathForVersion(newVersion), + allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"), + containsString("* Added `org.slf4j:slf4j-api:")))); } private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) { @@ -170,6 +170,6 @@ private void assertContent(Path path, final Matcher contentMatcher) thro path = projectDir.resolve(path); } final String changesContent = Files.readString(path); - assertThat(changesContent, contentMatcher); + assertThat("content of file " + path, changesContent, contentMatcher); } } From 56ad0d2265602e1f9e08d9dbef6659e962a7dd40 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 1 Feb 2024 07:53:08 +0100 Subject: [PATCH 54/78] Remove unused code --- .../sources/analyze/generic/MavenProcessBuilder.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java index cfbf386b..56a0cf28 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -3,10 +3,8 @@ import static java.util.Arrays.asList; import java.nio.file.Path; -import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.logging.Logger; import com.exasol.projectkeeper.OsCheck; import com.exasol.projectkeeper.OsCheck.OSType; @@ -15,9 +13,6 @@ * This class allows building and starting a {@code mvn} command. */ public class MavenProcessBuilder { - - private static final Logger LOG = Logger.getLogger(MavenProcessBuilder.class.getName()); - private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30); private final List command = new ArrayList<>(); private Path workingDir = null; From 912573b56f313f0c7927747191e78ee19a50c6c5 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 1 Feb 2024 16:08:45 +0100 Subject: [PATCH 55/78] Dependency upgrade process Fixes #515 --- parent-pom/pom.xml | 6 ++++ .../dependencyupdate/ChangesFileUpdater.java | 16 +++++++++ .../dependencyupdate/DependencyUpdater.java | 36 ++++++++++++++----- .../ProjectVersionIncrementor.java | 9 ++--- 4 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index 6993b74f..c61362f7 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -214,6 +214,12 @@ 1.4.8 test + + org.itsallcode + hamcrest-auto-matcher + 0.6.0 + test + diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java new file mode 100644 index 00000000..e8c2667e --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java @@ -0,0 +1,16 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; + +class ChangesFileUpdater { + ChangesFile update(final ChangesFile changesFile) { + final Builder builder = changesFile.toBuilder(); + update(builder); + return builder.build(); + } + + private void update(final Builder builder) { + + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 72345744..aec19dd7 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -8,6 +8,8 @@ import com.exasol.projectkeeper.ProjectKeeper; import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; /** * This class runs the dependency update process. @@ -19,13 +21,20 @@ public class DependencyUpdater { private final Logger logger; private final Path projectDir; private final ProjectVersionIncrementor projectVersionIncrementor; + private final ChangesFileIO changesFileIO; + private final String currentProjectVersion; + private final ChangesFileUpdater changesFileUpdater; DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir, - final ProjectVersionIncrementor projectVersionIncrementor) { + final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor, + final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater) { this.projectKeeper = projectKeeper; this.logger = logger; this.projectDir = projectDir; + this.currentProjectVersion = currentProjectVersion; this.projectVersionIncrementor = projectVersionIncrementor; + this.changesFileIO = changesFileIO; + this.changesFileUpdater = changesFileUpdater; } /** @@ -40,8 +49,9 @@ public class DependencyUpdater { */ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion) { - return new DependencyUpdater(projectKeeper, logger, projectDir, - new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion)); + return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion, + new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(), + new ChangesFileUpdater()); } /** @@ -56,19 +66,20 @@ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final * @return {@code true} if the process succeeded. */ public boolean updateDependencies() { - incrementProjectVersion(); + final String version = incrementProjectVersion(); updateDependencyVersions(); runProjectKeeperFix(); - updateChangelog(); + updateChangelog(version); return true; } - private void incrementProjectVersion() { + private String incrementProjectVersion() { if (projectVersionIncrementor.isCurrentVersionReleased()) { logger.info("Current version was already released: increment version"); - projectVersionIncrementor.incrementProjectVersion(); + return projectVersionIncrementor.incrementProjectVersion(); } else { logger.info("Current version was not yet released: no need to increment"); + return currentProjectVersion; } } @@ -91,7 +102,14 @@ private void runProjectKeeperFix() { } } - private void updateChangelog() { - // TODO Auto-generated method stub + private void updateChangelog(final String version) { + final Path changesFilePath = getChangesFilePath(version); + final ChangesFile changesFile = changesFileIO.read(changesFilePath); + final ChangesFile updatedChanges = changesFileUpdater.update(changesFile); + changesFileIO.write(updatedChanges, changesFilePath); + } + + private Path getChangesFilePath(final String version) { + return projectDir.resolve(ChangesFile.getPathForVersion(version)); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index 27d0209a..95f2f383 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -74,18 +74,18 @@ private LocalDate today() { return LocalDate.ofInstant(clock.instant(), UTC_ZONE); } - void incrementProjectVersion() { - + String incrementProjectVersion() { final Model pom = readPom(); if (!this.currentProjectVersion.equals(pom.getVersion())) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message( "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}", pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString()); } - incrementVersion(pom); + final String nextVersion = incrementVersion(pom); if (usesReferenceCheckerPlugin()) { updateReferences(); } + return nextVersion; } private boolean usesReferenceCheckerPlugin() { @@ -98,12 +98,13 @@ private void updateReferences() { .startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30)); } - private void incrementVersion(final Model pom) { + private String incrementVersion(final Model pom) { final String nextVersion = getIncrementedVersion(currentProjectVersion); logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + pom.getPomFile()); pom.setVersion(nextVersion); writePom(pom); + return nextVersion; } static String getIncrementedVersion(final String version) { From 9f86d24b414b9ce0364d6f4584dd7798503573d5 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 1 Feb 2024 16:51:05 +0100 Subject: [PATCH 56/78] Increase timeout --- .../sources/analyze/generic/SimpleProcessIT.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java index 9a8c7b81..1c9828cc 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java @@ -11,11 +11,11 @@ import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; -// Windows has problems with the timeout of 10ms. Running these tests under Unix is enough. +// Windows has problems with the timeout of 20ms. Running these tests under Unix is enough. @DisabledOnOs(OS.WINDOWS) class SimpleProcessIT { - private static final Duration TIMEOUT = Duration.ofMillis(10); + private static final Duration TIMEOUT = Duration.ofMillis(20); @Test void outputStream() { @@ -60,7 +60,7 @@ void processTimeout() { final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> process.waitUntilFinished(TIMEOUT)); assertThat(exception.getMessage(), equalTo( - "E-PK-CORE-128: Timeout while waiting 10ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n" + "E-PK-CORE-128: Timeout while waiting 20ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n" + "Error output: 'error'")); } From b3c51f185685f96d4dfe536fcb111d2a5b2cce18 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 7 Feb 2024 10:44:53 +0100 Subject: [PATCH 57/78] Remove duplicate files --- .../dependencies_update_process.plantuml | 53 ------------------- doc/images/dependencies_update_process.svg | 1 - doc/images/release_process.plantuml | 51 ------------------ doc/images/release_process.svg | 1 - 4 files changed, 106 deletions(-) delete mode 100644 doc/images/dependencies_update_process.plantuml delete mode 100644 doc/images/dependencies_update_process.svg delete mode 100644 doc/images/release_process.plantuml delete mode 100644 doc/images/release_process.svg diff --git a/doc/images/dependencies_update_process.plantuml b/doc/images/dependencies_update_process.plantuml deleted file mode 100644 index 5de174ae..00000000 --- a/doc/images/dependencies_update_process.plantuml +++ /dev/null @@ -1,53 +0,0 @@ -@startuml dependencies_update_process - -start -:**dependencies_check.yml** workflow -(triggered daily); -note right - Pass information about created - issues & vulnerabilities to - **dependencies_update.yml** -end note -if(Vulnerable dependencies found?) then (yes) - group **dependencies_update.yml** workflow - note right - GitHub Workflow - generated by PK - end note - :Run PK **update-dependencies** as Maven plugin; - group PK **update-dependencies** - note right - Implement - in PK - end note - if(Latest version already released?) then (yes) - :Increment project version; - else (no) - endif - :Update dependencies; - :Run PK fix; - note right - Add dependency changes to - changelog, Update list of - dependencies, ... - end note - :Update changlog: add fixed vulnerabilites; - if(pom.xml contains artifact-reference-checker-maven-plugin) then (yes) - :Run artifact-reference-checker-maven-plugin:fix; - else (no) - endif - end group - :Create branch, commit, push & - create pull request; - note right - Needs information about - issues & vulnerabilities - end note - :Send Slack notification - for success and failure; - end group -else (no) - stop -endif -stop -@enduml diff --git a/doc/images/dependencies_update_process.svg b/doc/images/dependencies_update_process.svg deleted file mode 100644 index 8fe162b6..00000000 --- a/doc/images/dependencies_update_process.svg +++ /dev/null @@ -1 +0,0 @@ -Pass information about createdissues & vulnerabilities todependencies_update.ymldependencies_check.ymlworkflow(triggered daily)dependencies_update.ymlworkflowGitHub Workflowgenerated by PKRun PKupdate-dependenciesas Maven pluginPKupdate-dependenciesImplementin PKIncrement project versionyesLatest version already released?noUpdate dependenciesAdd dependency changes tochangelog, Update list ofdependencies, ...Run PK fixUpdate changlog: add fixed vulnerabilitesRun artifact-reference-checker-maven-plugin:fixyespom.xml contains artifact-reference-checker-maven-pluginnoNeeds information aboutissues & vulnerabilitiesCreate branch, commit, push &create pull requestSend Slack notificationfor success and failureyesVulnerable dependencies found?no \ No newline at end of file diff --git a/doc/images/release_process.plantuml b/doc/images/release_process.plantuml deleted file mode 100644 index 6f54aa41..00000000 --- a/doc/images/release_process.plantuml +++ /dev/null @@ -1,51 +0,0 @@ -@startuml release_process - -start -note right - Triggered manually or - on pushes to main branch. -end note -group **release.yml** workflow - note right - Generated - by PK - end note - :Run PK **verify-release** as Maven plugin; - group PK **verify-release** - note right - Implemented - in PK - end note - if(Release date up-to-date?\n(allow skipping the release)) then (up-to-date) - :Run PK **verify**; - :Run additional release checks; - :Write changelog content to file; - note right - Required for creating - the GitHub release - end note - else (invalid/outdated) - :Fail build; - stop - endif - end group - :Run **mvn verify**; - if(Maven Central deployment required) then (required) - :Run **mvn deploy**; - endif - :Calculate checksums for release artifacts; - :Create GitHub release; - note right - Reads changelog - content from file - end note - :Attach release artifacts and - checksums to GitHub release; - note right - Customizable - end note - :Send Slack notification - for success & failure; -end group -stop -@enduml diff --git a/doc/images/release_process.svg b/doc/images/release_process.svg deleted file mode 100644 index 850f6913..00000000 --- a/doc/images/release_process.svg +++ /dev/null @@ -1 +0,0 @@ -Triggered manually oron pushes to main branch.release.ymlworkflowGeneratedby PKRun PKverify-releaseas Maven pluginPKverify-releaseImplementedin PKRelease date up-to-date?(allow skipping the release)up-to-dateinvalid/outdatedRun PKverifyRun additional release checksRequired for creatingthe GitHub releaseWrite changelog content to fileFail buildRunmvn verifyRunmvn deployrequiredMaven Central deployment requiredCalculate checksums for release artifactsReads changelogcontent from fileCreate GitHub releaseCustomizableAttach release artifacts andchecksums to GitHub releaseSend Slack notificationfor success & failure \ No newline at end of file From db954a637b10dedd9ba47744d656e67f9e4bf41a Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 7 Feb 2024 11:51:44 +0100 Subject: [PATCH 58/78] Upgrade dependencies --- .vscode/settings.json | 3 +- dependencies.md | 20 ++++---- doc/changes/changes_4.0.0.md | 10 ++++ maven-project-crawler/pk_generated_parent.pom | 11 +++++ parent-pom/error_code_config.yml | 8 ++++ parent-pom/pom.xml | 47 +++++++++++++++++-- pom.xml | 1 + project-keeper-cli/pk_generated_parent.pom | 11 +++++ project-keeper-cli/pom.xml | 11 +++++ .../pk_generated_parent.pom | 11 +++++ project-keeper-maven-plugin/pom.xml | 11 +++++ project-keeper/pk_generated_parent.pom | 11 +++++ project-keeper/pom.xml | 11 +++++ .../maven_templates/versions-maven-plugin.xml | 11 +++++ shared-model-classes/pk_generated_parent.pom | 11 +++++ shared-model-classes/pom.xml | 15 ++++++ shared-test-setup/pk_generated_parent.pom | 11 +++++ shared-test-setup/pom.xml | 15 ++++++ 18 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 parent-pom/error_code_config.yml diff --git a/.vscode/settings.json b/.vscode/settings.json index 4f1536d8..e5310098 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,8 @@ "java.sources.organizeImports.staticStarThreshold": 3, "java.test.config": { "vmArgs": [ - "-Djava.util.logging.config.file=src/test/resources/logging.properties" + "-Djava.util.logging.config.file=src/test/resources/logging.properties", + "-Dcom.exasol.projectkeeper.ownVersion=4.0.0" ] }, "sonarlint.connectedMode.project": { diff --git a/dependencies.md b/dependencies.md index fcd2d32f..c623cd8e 100644 --- a/dependencies.md +++ b/dependencies.md @@ -90,6 +90,7 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | @@ -102,11 +103,10 @@ | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | ## Project Keeper Command Line Interface @@ -148,14 +148,14 @@ | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [Artifact reference checker and unifier][59] | [MIT License][60] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -192,14 +192,14 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | +| [Maven Plugin Plugin][65] | [Apache-2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | | [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | | [Maven Surefire Plugin][30] | [Apache-2.0][16] | | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | @@ -207,7 +207,7 @@ | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | | [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -261,7 +261,7 @@ | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | | [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][56] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -350,8 +350,8 @@ [53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE [54]: https://github.com/exasol/maven-plugin-integration-testing/ [55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE -[56]: https://maven.apache.org/surefire/maven-failsafe-plugin/ -[57]: https://maven.apache.org/plugins/maven-jar-plugin/ +[56]: https://maven.apache.org/plugins/maven-jar-plugin/ +[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/ [58]: https://maven.apache.org/plugins/maven-assembly-plugin/ [59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ [60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md index b249b9da..bee44ffd 100644 --- a/doc/changes/changes_4.0.0.md +++ b/doc/changes/changes_4.0.0.md @@ -15,6 +15,8 @@ Code name: Automatic Security Updates #### Test Dependency Updates * Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` +* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` +* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` * Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` #### Plugin Dependency Updates @@ -38,6 +40,8 @@ Code name: Automatic Security Updates * Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` * Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` +* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` +* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` * Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0` #### Plugin Dependency Updates @@ -57,6 +61,8 @@ Code name: Automatic Security Updates #### Test Dependency Updates * Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` +* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` +* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` #### Plugin Dependency Updates @@ -74,6 +80,8 @@ Code name: Automatic Security Updates #### Test Dependency Updates +* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` +* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` * Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` #### Plugin Dependency Updates @@ -93,6 +101,8 @@ Code name: Automatic Security Updates #### Test Dependency Updates +* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` +* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` * Updated `org.mockito:mockito-core:5.8.0` to `5.10.0` * Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0` diff --git a/maven-project-crawler/pk_generated_parent.pom b/maven-project-crawler/pk_generated_parent.pom index b9745cc7..266874fa 100644 --- a/maven-project-crawler/pk_generated_parent.pom +++ b/maven-project-crawler/pk_generated_parent.pom @@ -189,6 +189,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/parent-pom/error_code_config.yml b/parent-pom/error_code_config.yml new file mode 100644 index 00000000..1389755e --- /dev/null +++ b/parent-pom/error_code_config.yml @@ -0,0 +1,8 @@ +# This file is only used for release guide. +# Actual error codes are based on files error_code_config.yml in individual subfolders. + +error-tags: + PK-PARENT: + packages: + - dummy + highest-index: 1 diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index db5a528b..a0ee2850 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -5,7 +5,7 @@ project-keeper-parent-pom pom ${revision} - Project Keeper parent pom + Project Keeper Parent POM This tool checks and unifies a project's structure according to the Exasol integration team's repository standards. @@ -31,7 +31,7 @@ 4.0.0 3.9.6 3.6.3 - 5.10.1 + 5.10.2 2.9.1 5.10.0 UTF-8 @@ -111,7 +111,7 @@ org.eclipse.jgit org.eclipse.jgit - + 6.7.0.202309050840-r @@ -214,6 +214,12 @@ 1.4.8 test + + org.itsallcode + hamcrest-auto-matcher + 0.6.0 + test + @@ -226,5 +232,40 @@ + + + org.codehaus.mojo + versions-maven-plugin + 2.16.2 + + + display-updates + package + + display-plugin-updates + display-dependency-updates + + + + + file:///${project.basedir}/../project-keeper/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + + + org.slf4j:slf4j-jdk14:jar:*:* + + org.eclipse.jgit:org.eclipse.jgit:jar:*:6.8.0.202311291450-r + + + + diff --git a/pom.xml b/pom.xml index a2d83f9e..def9b3ba 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ shared-test-setup maven-project-crawler project-keeper-maven-plugin + parent-pom Project Keeper Root Project diff --git a/project-keeper-cli/pk_generated_parent.pom b/project-keeper-cli/pk_generated_parent.pom index 2f2022b7..21714a21 100644 --- a/project-keeper-cli/pk_generated_parent.pom +++ b/project-keeper-cli/pk_generated_parent.pom @@ -181,6 +181,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/project-keeper-cli/pom.xml b/project-keeper-cli/pom.xml index 084c8570..bb11e9b5 100644 --- a/project-keeper-cli/pom.xml +++ b/project-keeper-cli/pom.xml @@ -59,6 +59,17 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + org.apache.maven.plugins maven-assembly-plugin diff --git a/project-keeper-maven-plugin/pk_generated_parent.pom b/project-keeper-maven-plugin/pk_generated_parent.pom index 7b91571e..c9739780 100644 --- a/project-keeper-maven-plugin/pk_generated_parent.pom +++ b/project-keeper-maven-plugin/pk_generated_parent.pom @@ -189,6 +189,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/project-keeper-maven-plugin/pom.xml b/project-keeper-maven-plugin/pom.xml index 06af4b13..f5a387f5 100644 --- a/project-keeper-maven-plugin/pom.xml +++ b/project-keeper-maven-plugin/pom.xml @@ -95,6 +95,17 @@ project-keeper + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + org.apache.maven.plugins maven-jar-plugin diff --git a/project-keeper/pk_generated_parent.pom b/project-keeper/pk_generated_parent.pom index 44c2a879..35f33b92 100644 --- a/project-keeper/pk_generated_parent.pom +++ b/project-keeper/pk_generated_parent.pom @@ -181,6 +181,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/project-keeper/pom.xml b/project-keeper/pom.xml index 31e652b2..08f81c72 100644 --- a/project-keeper/pom.xml +++ b/project-keeper/pom.xml @@ -119,6 +119,17 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + diff --git a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml index a16896b7..d3e43388 100644 --- a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml +++ b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml @@ -14,5 +14,16 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/shared-model-classes/pk_generated_parent.pom b/shared-model-classes/pk_generated_parent.pom index e5e3dba0..2bde1923 100644 --- a/shared-model-classes/pk_generated_parent.pom +++ b/shared-model-classes/pk_generated_parent.pom @@ -181,6 +181,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/shared-model-classes/pom.xml b/shared-model-classes/pom.xml index 6ec90efd..d9133db8 100644 --- a/shared-model-classes/pom.xml +++ b/shared-model-classes/pom.xml @@ -75,4 +75,19 @@ test + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + + + diff --git a/shared-test-setup/pk_generated_parent.pom b/shared-test-setup/pk_generated_parent.pom index 91f61d03..299d5f54 100644 --- a/shared-test-setup/pk_generated_parent.pom +++ b/shared-test-setup/pk_generated_parent.pom @@ -170,6 +170,17 @@ file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true diff --git a/shared-test-setup/pom.xml b/shared-test-setup/pom.xml index 9b492f1f..f5d81b06 100644 --- a/shared-test-setup/pom.xml +++ b/shared-test-setup/pom.xml @@ -34,4 +34,19 @@ maven-model + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + -Xlint:all,-processing + -Werror + + + + + From d354a61bb1aaee3d137bff71808e043639d3f803 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 7 Feb 2024 12:01:51 +0100 Subject: [PATCH 59/78] #515: Refactoring --- maven-project-crawler/error_code_config.yml | 2 +- .../MavenProjectCrawlerMojo.java | 5 + .../plugin/ProjectKeeperFixMojo.java | 2 +- .../plugin/ProjectKeeperVerifyMojo.java | 2 +- ...nProjectWithProjectKeeperPluginWriter.java | 55 +++++++--- project-keeper/error_code_config.yml | 2 +- .../JavaProjectCrawlerRunner.java | 100 ++++++------------ .../analyze/generic/MavenProcessBuilder.java | 85 +++++++++++++++ .../validators/VersionCollector.java | 6 +- .../files/LatestChangesFileValidator.java | 6 +- .../JavaProjectCrawlerRunnerIT.java | 28 ++++- .../analyze/MavenSourceAnalyzerTest.java | 2 +- .../analyze/generic/SimpleProcessIT.java | 6 +- .../files/LatestChangesFileValidatorTest.java | 4 +- .../src/test/resources/changesFileExample1.md | 1 - .../MavenProjectCrawlResult.java | 2 + .../shared/repository/GitRepositoryTest.java | 6 +- 17 files changed, 209 insertions(+), 105 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java diff --git a/maven-project-crawler/error_code_config.yml b/maven-project-crawler/error_code_config.yml index 867099b3..cf122110 100644 --- a/maven-project-crawler/error_code_config.yml +++ b/maven-project-crawler/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-MPC: packages: - com.exasol.projectkeeper - highest-index: 63 \ No newline at end of file + highest-index: 64 diff --git a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java index f8266227..85cc9ec6 100644 --- a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java +++ b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java @@ -39,6 +39,11 @@ public class MavenProjectCrawlerMojo extends AbstractMojo { // [impl -> dsn~eclipse-prefs-java-version~1] @Override public void execute() { + if (projectsToCrawl == null || projectsToCrawl.isBlank()) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-MPC-64") + .message("Property {{property name}} is not defined or empty.", PROPERTY_PROJECTS_TO_CRAWL) + .mitigation("Specify property with least one pom file.").toString()); + } final MavenProjectFromFileReader mavenProjectReader = new DefaultMavenProjectFromFileReader( this.mavenProjectBuilder, this.session); final MavenModelFromRepositoryReader modelFromRepositoryReader = new MavenModelFromRepositoryReader( diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java index 38fddf9a..5f310cea 100644 --- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java +++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java @@ -6,7 +6,7 @@ import com.exasol.projectkeeper.ProjectKeeper; /** - * Entry point for the fix goal. + * Entry point for the {@code fix} goal. *

* Run using {@code mvn project-keeper:fix} *

diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java index 2524c634..e28c1875 100644 --- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java +++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java @@ -7,7 +7,7 @@ import com.exasol.projectkeeper.ProjectKeeper; /** - * Entry point for the verify goal. + * Entry point for the {code verify} goal. *

* Run using {@code mvn project-keeper:verify} *

diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java index 45437f20..11953af5 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java @@ -1,34 +1,61 @@ package com.exasol.projectkeeper.plugin; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.nio.file.Path; import java.util.List; import org.apache.maven.model.*; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; -public class MvnProjectWithProjectKeeperPluginWriter extends Model { - private static final long serialVersionUID = -8757020322006895512L; +public class MvnProjectWithProjectKeeperPluginWriter { public static final String PROJECT_ARTIFACT_ID = "my-test-project"; public static final String PROJECT_VERSION = "0.1.0"; + private final Model model; public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion) { - this.setBuild(new Build()); - this.setVersion(PROJECT_VERSION); - this.setArtifactId(PROJECT_ARTIFACT_ID); - this.setGroupId("com.exasol"); - this.setModelVersion("4.0.0"); - this.setDescription("my project description"); + this.model = new Model(); + this.model.setBuild(new Build()); + this.model.setVersion(PROJECT_VERSION); + this.model.setArtifactId(PROJECT_ARTIFACT_ID); + this.model.setGroupId("com.exasol"); + this.model.setModelVersion("4.0.0"); + this.model.setDescription("my project description"); addProjectKeeperPlugin(projectKeeperVersion); } - public void writeAsPomToProject(final Path projectDir) throws IOException { - try (final FileWriter fileWriter = new FileWriter(projectDir.resolve("pom.xml").toFile())) { - new MavenXpp3Writer().write(fileWriter, this); + public void writeAsPomToProject(final Path projectDir) { + final Path path = projectDir.resolve("pom.xml"); + try (final FileWriter fileWriter = new FileWriter(path.toFile())) { + new MavenXpp3Writer().write(fileWriter, this.model); + } catch (final IOException exception) { + throw new UncheckedIOException("Failed writing POM to file " + path, exception); } } + public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId, + final String version) { + final Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + this.model.getDependencies().add(dependency); + return this; + } + + public MvnProjectWithProjectKeeperPluginWriter setArtifactFinalName(final String finalName) { + final Plugin plugin = new Plugin(); + plugin.setGroupId("org.apache.maven.plugins"); + plugin.setArtifactId("maven-assembly-plugin"); + final Xpp3Dom configuration = new Xpp3Dom("configuration"); + final Xpp3Dom finalNameElement = new Xpp3Dom("finalName"); + finalNameElement.setValue(finalName); + configuration.addChild(finalNameElement); + plugin.setConfiguration(configuration); + this.model.getBuild().addPlugin(plugin); + return this; + } + private void addProjectKeeperPlugin(final String version) { final Plugin projectKeeperPlugin = new Plugin(); projectKeeperPlugin.setGroupId("com.exasol"); @@ -37,6 +64,6 @@ private void addProjectKeeperPlugin(final String version) { final PluginExecution execution = new PluginExecution(); execution.setGoals(List.of("verify")); projectKeeperPlugin.setExecutions(List.of(execution)); - this.getBuild().addPlugin(projectKeeperPlugin); + this.model.getBuild().addPlugin(projectKeeperPlugin); } } diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml index e550c0e8..53d3c5ac 100644 --- a/project-keeper/error_code_config.yml +++ b/project-keeper/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CORE: packages: - com.exasol.projectkeeper - highest-index: 170 + highest-index: 179 diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java index 3c4449ee..18dcf1ed 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java @@ -1,36 +1,28 @@ package com.exasol.projectkeeper; -import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.time.Duration; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.Arrays; import java.util.stream.Collectors; -import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.OsCheck.OSType; import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder; -import com.exasol.projectkeeper.stream.AsyncStreamReader; -import com.exasol.projectkeeper.stream.CollectingConsumer; +import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; +import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; /** * Runs the maven plugin goal on the current repository and returns the parsed result. */ public class JavaProjectCrawlerRunner { - private static final Logger LOGGER = Logger.getLogger(JavaProjectCrawlerRunner.class.getName()); - private static final Duration STREAM_READING_TIMEOUT = Duration.ofSeconds(1); private final Path mvnRepositoryOverride; private final String ownVersion; /** * Create a new instance of {@link JavaProjectCrawlerRunner}. * - * @param mvnRepositoryOverride maven repository override. Use {@code null} for default + * @param mvnRepositoryOverride Maven repository override. This is useful for running integration tests. Use + * {@code null} for default. * @param ownVersion project-keeper version */ public JavaProjectCrawlerRunner(final Path mvnRepositoryOverride, final String ownVersion) { @@ -50,67 +42,39 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) { } private String runCrawlerPlugin(final Path... pomFiles) { - final String projectList = Arrays.stream(pomFiles).map(pomFile -> pomFile.toAbsolutePath().toString() - // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540 - .replace(FileSystems.getDefault().getSeparator(), "/")).collect(Collectors.joining(";")); - try { - final List commandParts = new ArrayList<>(List.of(getMavenExecutable(), "--batch-mode", - "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", - "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", - "-DprojectsToCrawl=" + projectList, - /* - * We need to disable the model cache here since it caches the parent poms with {revision} as - * version and then runs into trouble since the cache is different when reading the old pom (for - * comparing dependencies). - */ - "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")); - if (this.mvnRepositoryOverride != null) { - commandParts.add("-Dmaven.repo.local=" + this.mvnRepositoryOverride); - } - - LOGGER.fine(() -> "Executing command " + commandParts); - final Process proc = new ProcessBuilder(commandParts).redirectErrorStream(true).start(); + final MavenProcessBuilder builder = buildMavenCommand(pomFiles); + final SimpleProcess process = builder.startSimpleProcess(); + process.waitUntilFinished(Duration.ofSeconds(90)); + return new ResponseCoder().decodeResponse(process.getOutputStreamContent()); + } - final CollectingConsumer outputStreamConsumer = new AsyncStreamReader() - .startCollectingConsumer(proc.getInputStream()); - final CollectingConsumer errorStreamConsumer = new AsyncStreamReader() - .startCollectingConsumer(proc.getErrorStream()); + private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { + final MavenProcessBuilder builder = MavenProcessBuilder.create() + .addArguments( + "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", + "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl", + "-DprojectsToCrawl=" + getProjectList(pomFiles), + /* + * We need to disable the model cache here since it caches the parent poms with {revision} as + * version and then runs into trouble since the cache is different when reading the old pom (for + * comparing dependencies). + */ + "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true") + .workingDir(null); - if (!proc.waitFor(90, TimeUnit.SECONDS)) { - final String stdOutput = outputStreamConsumer.getCurrentContent(); - final String stdError = errorStreamConsumer.getCurrentContent(); - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-81").message( - "Timeout while executing command {{executed command|u}}. Output: {{std output}}, error: {{std error}}", - commandParts, stdOutput, stdError).toString()); - } - final int exitCode = proc.exitValue(); - final String output = outputStreamConsumer.getContent(STREAM_READING_TIMEOUT); - if (exitCode != 0) { - LOGGER.log(Level.SEVERE, output); - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-78").message( - "Failed to run command {{executed command|u}}, exit code was {{exit code}}. Output:\n{{output}}", - commandParts, exitCode, output).toString()); - } - return new ResponseCoder().decodeResponse(output); - } catch (final IOException exception) { - throw new UncheckedIOException(getRunFailedMessage(), exception); - } catch (final InterruptedException exception) { - Thread.currentThread().interrupt(); - throw new IllegalStateException(getRunFailedMessage(), exception); + if (this.mvnRepositoryOverride != null) { + builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); } + return builder; } - private String getMavenExecutable() { - final OSType osType = new OsCheck().getOperatingSystemType(); - if (osType == OSType.WINDOWS) { - return "mvn.cmd"; - } else { - return "mvn"; - } + private String getProjectList(final Path... pomFiles) { + return Arrays.stream(pomFiles).map(this::formatPath).collect(Collectors.joining(";")); } - private String getRunFailedMessage() { - return ExaError.messageBuilder("E-PK-CORE-80").message("Failed to run project-keeper-java-project-crawler.") - .toString(); + private String formatPath(final Path pomFile) { + return pomFile.toAbsolutePath().toString() + // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540 + .replace(FileSystems.getDefault().getSeparator(), "/"); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java new file mode 100644 index 00000000..56a0cf28 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -0,0 +1,85 @@ +package com.exasol.projectkeeper.sources.analyze.generic; + +import static java.util.Arrays.asList; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import com.exasol.projectkeeper.OsCheck; +import com.exasol.projectkeeper.OsCheck.OSType; + +/** + * This class allows building and starting a {@code mvn} command. + */ +public class MavenProcessBuilder { + private final List command = new ArrayList<>(); + private Path workingDir = null; + + private MavenProcessBuilder() { + // Use create() method + } + + /** + * Create a new builder. + * + * @return new builder + */ + public static MavenProcessBuilder create() { + final MavenProcessBuilder builder = new MavenProcessBuilder(); + builder.addArgument(getMavenExecutable()); + builder.addArgument("--batch-mode"); + return builder; + } + + /** + * Add the given arguments to the command. + * + * @param arguments arguments to add + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder addArguments(final String... arguments) { + command.addAll(asList(arguments)); + return this; + } + + /** + * Add the given argument to the command. + * + * @param argument argument to add + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder addArgument(final String argument) { + command.add(argument); + return this; + } + + /** + * Define the working directory where to execute the command. Default: {@code null}. + * + * @param workingDir working dir + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder workingDir(final Path workingDir) { + this.workingDir = workingDir; + return this; + } + + /** + * Build the command and run it. + * + * @return the running {@link SimpleProcess} + */ + public SimpleProcess startSimpleProcess() { + return SimpleProcess.start(workingDir, command); + } + + private static String getMavenExecutable() { + final OSType osType = new OsCheck().getOperatingSystemType(); + if (osType == OSType.WINDOWS) { + return "mvn.cmd"; + } else { + return "mvn"; + } + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java index e3030c8f..f5674c74 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; /** * This class list all project-versions by scanning the doc/changes/ folder. @@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) { * * @return list of changes files */ - public List collectChangesFiles() { + public List collectChangesFiles() { try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) { return filesStream // - .map(ChangesFile.Filename::from) // + .map(ChangesFileName::from) // .flatMap(Optional::stream) // .sorted(Comparator.reverseOrder()) // .collect(Collectors.toList()); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java index c7e457c1..86236087 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java @@ -7,7 +7,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; @@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer @Override public List validate() { final List empty = Collections.emptyList(); - final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); if (list.isEmpty()) { return empty; } - final Filename latest = list.get(0); + final ChangesFileName latest = list.get(0); if (latest.version().equals(this.projectVersion)) { return empty; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java index 0d378c26..ea11a2c7 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java @@ -2,8 +2,9 @@ import static com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type.COMPILE; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.FileWriter; import java.io.IOException; @@ -44,8 +45,7 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio Git.init().setDirectory(tempDir.toFile()).call().close(); final Path pomFile = tempDir.resolve("pom.xml"); writePomFile(pomFile); - final MavenProjectCrawlResult result = new JavaProjectCrawlerRunner(testMavenRepo, - TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFile); + final MavenProjectCrawlResult result = crawlProject(pomFile); final CrawledMavenProject mavenProject = result.getCrawledProjects() .get(pomFile.toAbsolutePath().toString().replace("\\", "/")); final ProjectDependency expectedDependency = ProjectDependency.builder() // @@ -63,6 +63,26 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio ); } + MavenProjectCrawlResult crawlProject(final Path... pomFiles) { + return new JavaProjectCrawlerRunner(testMavenRepo, TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFiles); + } + + @Test + void testGetDependencyChangesFailsForEmptyPomList() throws GitAPIException, IOException { + final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> crawlProject()); + assertThat(exception.getMessage(), containsString( + "E-PK-MPC-64: Property 'projectsToCrawl' is not defined or empty. Specify property with least one pom file.")); + } + + @Test + void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOException { + final Path missingPomFile = Path.of("missing-pom-file"); + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> this.crawlProject(missingPomFile)); + assertThat(exception.getMessage(), + allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString()))); + } + private void writePomFile(final Path pomFile) throws IOException { final TestMavenModel model = new TestMavenModel(); model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION); @@ -70,4 +90,4 @@ private void writePomFile(final Path pomFile) throws IOException { new MavenXpp3Writer().write(fileWriter, model); } } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java index 3af17dca..9bef4677 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java @@ -30,7 +30,7 @@ void analyzingSourcesWithInvalidOwnVersionFails() { final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> analyze(OWN_VERSION, mavenSources)); assertThat(exception.getMessage(), - allOf(containsString("E-PK-CORE-78: Failed to run command"), + allOf(containsString("E-PK-CORE-126: Failed to run command"), containsString("[ERROR] Plugin com.exasol:project-keeper-java-project-crawler:" + OWN_VERSION + " or one of its dependencies could not be resolved"))); } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java index 9a8c7b81..1c9828cc 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java @@ -11,11 +11,11 @@ import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; -// Windows has problems with the timeout of 10ms. Running these tests under Unix is enough. +// Windows has problems with the timeout of 20ms. Running these tests under Unix is enough. @DisabledOnOs(OS.WINDOWS) class SimpleProcessIT { - private static final Duration TIMEOUT = Duration.ofMillis(10); + private static final Duration TIMEOUT = Duration.ofMillis(20); @Test void outputStream() { @@ -60,7 +60,7 @@ void processTimeout() { final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> process.waitUntilFinished(TIMEOUT)); assertThat(exception.getMessage(), equalTo( - "E-PK-CORE-128: Timeout while waiting 10ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n" + "E-PK-CORE-128: Timeout while waiting 20ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n" + "Error output: 'error'")); } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java index 404adc38..e3519302 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; class LatestChangesFileValidatorTest { @@ -38,7 +38,7 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve final Path folder = tempDir.resolve(Path.of("doc", "changes")); Files.createDirectories(folder); for (final String v : versions) { - final Filename cfile = new Filename(v); + final ChangesFileName cfile = new ChangesFileName(v); Files.createFile(folder.resolve(cfile.filename())); } return new LatestChangesFileValidator(tempDir, "2.0.0"); diff --git a/project-keeper/src/test/resources/changesFileExample1.md b/project-keeper/src/test/resources/changesFileExample1.md index 4791e2ef..49211dfd 100644 --- a/project-keeper/src/test/resources/changesFileExample1.md +++ b/project-keeper/src/test/resources/changesFileExample1.md @@ -49,4 +49,3 @@ My summary * Added `::` * Updated `::` to `` * Removed `::` - diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java index 254fa507..65fea867 100644 --- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java +++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java @@ -37,6 +37,7 @@ public MavenProjectCrawlResult(final Map crawledPro * @param json serialized JSON * @return deserialized {@link DependencyChangeReport}. */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public static MavenProjectCrawlResult fromJson(final String json) { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.fromJson(json, MavenProjectCrawlResult.class); @@ -51,6 +52,7 @@ public static MavenProjectCrawlResult fromJson(final String json) { * * @return JSON string */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public String toJson() { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.toJson(this); diff --git a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java index 7fd42a8d..bbd19c83 100644 --- a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java +++ b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java @@ -7,7 +7,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -176,6 +177,7 @@ void testGetRepoName() throws GitAPIException, IOException, URISyntaxException { } @Test + @SuppressWarnings("try") // auto-closeable resource git is never referenced in body of corresponding try statement void testFindLatestReleaseCommitNoCommit() throws IllegalStateException, GitAPIException, IOException { try (final Git git = gitInit()) { this.repository = openRepo(this.tempDir); @@ -267,4 +269,4 @@ private GitRepository openRepo(final Path path) { private Git gitInit() throws GitAPIException { return Git.init().setDirectory(this.tempDir.toFile()).call(); } -} \ No newline at end of file +} From 9543d5134553f4c2bc2e1ba875dcd44bb7b99765 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Wed, 7 Feb 2024 12:04:16 +0100 Subject: [PATCH 60/78] Fix compiler warnings --- .../shared/mavenprojectcrawler/MavenProjectCrawlResult.java | 2 ++ .../projectkeeper/shared/repository/GitRepositoryTest.java | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java index 254fa507..65fea867 100644 --- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java +++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java @@ -37,6 +37,7 @@ public MavenProjectCrawlResult(final Map crawledPro * @param json serialized JSON * @return deserialized {@link DependencyChangeReport}. */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public static MavenProjectCrawlResult fromJson(final String json) { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.fromJson(json, MavenProjectCrawlResult.class); @@ -51,6 +52,7 @@ public static MavenProjectCrawlResult fromJson(final String json) { * * @return JSON string */ + @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException public String toJson() { try (final Jsonb jsonb = JsonbBuilder.create()) { return jsonb.toJson(this); diff --git a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java index 7fd42a8d..bbd19c83 100644 --- a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java +++ b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java @@ -7,7 +7,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -176,6 +177,7 @@ void testGetRepoName() throws GitAPIException, IOException, URISyntaxException { } @Test + @SuppressWarnings("try") // auto-closeable resource git is never referenced in body of corresponding try statement void testFindLatestReleaseCommitNoCommit() throws IllegalStateException, GitAPIException, IOException { try (final Git git = gitInit()) { this.repository = openRepo(this.tempDir); @@ -267,4 +269,4 @@ private GitRepository openRepo(final Path path) { private Git gitInit() throws GitAPIException { return Git.init().setDirectory(this.tempDir.toFile()).call(); } -} \ No newline at end of file +} From 2045a90b02533ad12a4e10d0e6948fead523ecaa Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 04:58:18 +0100 Subject: [PATCH 61/78] Fix compile errors --- .../exasol/projectkeeper/validators/VersionCollector.java | 6 +++--- .../validators/files/LatestChangesFileValidator.java | 6 +++--- .../validators/files/LatestChangesFileValidatorTest.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java index f5674c74..e3030c8f 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; /** * This class list all project-versions by scanning the doc/changes/ folder. @@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) { * * @return list of changes files */ - public List collectChangesFiles() { + public List collectChangesFiles() { try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) { return filesStream // - .map(ChangesFileName::from) // + .map(ChangesFile.Filename::from) // .flatMap(Optional::stream) // .sorted(Comparator.reverseOrder()) // .collect(Collectors.toList()); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java index 86236087..afd5cb05 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java @@ -7,7 +7,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; @@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer @Override public List validate() { final List empty = Collections.emptyList(); - final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); if (list.isEmpty()) { return empty; } - final ChangesFileName latest = list.get(0); + final ChangesFile.Filename latest = list.get(0); if (latest.version().equals(this.projectVersion)) { return empty; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java index e3519302..a030479a 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; class LatestChangesFileValidatorTest { @@ -38,7 +38,7 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve final Path folder = tempDir.resolve(Path.of("doc", "changes")); Files.createDirectories(folder); for (final String v : versions) { - final ChangesFileName cfile = new ChangesFileName(v); + final ChangesFile.Filename cfile = new ChangesFile.Filename(v); Files.createFile(folder.resolve(cfile.filename())); } return new LatestChangesFileValidator(tempDir, "2.0.0"); From 33480d172df6a80b3ea0bfb537a9fa554e816e1f Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 05:05:50 +0100 Subject: [PATCH 62/78] Add trailing newline --- shared-model-classes/error_code_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-model-classes/error_code_config.yml b/shared-model-classes/error_code_config.yml index febfbc52..eec657cd 100644 --- a/shared-model-classes/error_code_config.yml +++ b/shared-model-classes/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-SMC: packages: - com.exasol.projectkeeper - highest-index: 81 \ No newline at end of file + highest-index: 81 From 0ad2a273f8138e36ef1f1468c4c9c08762113b9c Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 05:16:22 +0100 Subject: [PATCH 63/78] Fix compile errors --- .../validators/files/LatestChangesFileValidator.java | 6 +++--- .../projectkeeper/validators/VersionCollectorTest.java | 6 +++--- .../validators/files/LatestChangesFileValidatorTest.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java index afd5cb05..86236087 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java @@ -7,7 +7,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; @@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer @Override public List validate() { final List empty = Collections.emptyList(); - final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); if (list.isEmpty()) { return empty; } - final ChangesFile.Filename latest = list.get(0); + final ChangesFileName latest = list.get(0); if (latest.version().equals(this.projectVersion)) { return empty; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java index 230506a1..0f178b0f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java @@ -40,8 +40,8 @@ void sorted(@TempDir final Path tempDir) throws IOException { } private ChangesFileName createChangesFile(final Path folder, final String version) throws IOException { - final ChangesFileName cfile = new ChangesFileName(version); - Files.createFile(folder.resolve(cfile.filename())); - return cfile; + final ChangesFileName file = new ChangesFileName(version); + Files.createFile(folder.resolve(file.filename())); + return file; } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java index a030479a..64ba39c5 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; class LatestChangesFileValidatorTest { @@ -38,8 +38,8 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve final Path folder = tempDir.resolve(Path.of("doc", "changes")); Files.createDirectories(folder); for (final String v : versions) { - final ChangesFile.Filename cfile = new ChangesFile.Filename(v); - Files.createFile(folder.resolve(cfile.filename())); + final ChangesFileName file = new ChangesFileName(v); + Files.createFile(folder.resolve(file.filename())); } return new LatestChangesFileValidator(tempDir, "2.0.0"); } From 8628d0f4604d0107af1903919e1b48ca65244b5d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 05:22:11 +0100 Subject: [PATCH 64/78] Parse changesfile --- .../validators/VersionCollector.java | 6 +- .../changelog/ChangelogFileGenerator.java | 7 +- .../changelog/ChangelogFileValidator.java | 6 +- .../validators/changesfile/ChangesFile.java | 341 +++++++++++------- .../validators/changesfile/ChangesFileIO.java | 159 ++++++-- .../changesfile/ChangesFileName.java | 83 +++++ .../changesfile/ChangesFileSection.java | 114 ++++-- .../changesfile/ChangesFileValidator.java | 13 +- .../changesfile/DependencySectionFixer.java | 20 +- .../DependencyChangeReportRenderer.java | 18 +- .../files/LatestChangesFileValidator.java | 6 +- .../validators/VersionCollectorTest.java | 17 +- .../changelog/ChangelogFileGeneratorTest.java | 8 +- .../changesfile/ChangesFileIOTest.java | 146 +++++++- .../changesfile/ChangesFileNameTest.java | 12 + .../changesfile/ChangesFileSectionTest.java | 13 + .../changesfile/ChangesFileTest.java | 61 ++++ .../changesfile/ChangesFileValidatorTest.java | 31 +- .../DependencySectionFixerTest.java | 54 ++- .../DependencyChangeReportRendererTest.java | 28 +- .../files/LatestChangesFileValidatorTest.java | 6 +- 21 files changed, 848 insertions(+), 301 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java index e3030c8f..f5674c74 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; /** * This class list all project-versions by scanning the doc/changes/ folder. @@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) { * * @return list of changes files */ - public List collectChangesFiles() { + public List collectChangesFiles() { try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) { return filesStream // - .map(ChangesFile.Filename::from) // + .map(ChangesFileName::from) // .flatMap(Optional::stream) // .sorted(Comparator.reverseOrder()) // .collect(Collectors.toList()); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java index ea1a64f7..8e7ff839 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java @@ -2,8 +2,7 @@ import java.util.List; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; /** * This class generates the content for the changelog file. @@ -19,9 +18,9 @@ class ChangelogFileGenerator { */ final StringBuilder templateBuilder = new StringBuilder(); - String generate(final List filenames) { + String generate(final List filenames) { this.templateBuilder.append("# Changes" + NL + NL); - for (final Filename file : filenames) { + for (final ChangesFileName file : filenames) { this.templateBuilder.append("* [" + file.version() + "](" + file.filename() + ")" + NL); } return this.templateBuilder.toString(); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java index a6dc485c..111612d0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java @@ -8,14 +8,14 @@ import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.AbstractFileContentValidator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; /** * This is a {@link Validator} for the changelog files. */ -//[impl->dsn~verify-changelog-file~1] +// [impl->dsn~verify-changelog-file~1] public class ChangelogFileValidator extends AbstractFileContentValidator { private final Path projectDirectory; @@ -44,7 +44,7 @@ protected List validateContent(final String content) { @Override protected String getTemplate() { - final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles(); return new ChangelogFileGenerator().generate(versions); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 38e3c4fd..b6e1020b 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -1,105 +1,47 @@ package com.exasol.projectkeeper.validators.changesfile; import java.nio.file.Path; +import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import com.exasol.projectkeeper.mavenrepo.Version; +import com.exasol.errorreporting.ExaError; import com.vdurmont.semver4j.Semver; -import com.vdurmont.semver4j.Semver.SemverType; /** * This class represents a doc/changes/changes_x.x.x.md file. */ -public class ChangesFile { +public final class ChangesFile { /** Headline of the dependency updates section. */ public static final String DEPENDENCY_UPDATES_HEADING = "## Dependency Updates"; - private final List headerSectionLines; + /** Headline of the Summary section. */ + public static final String SUMMARY_HEADING = "## Summary"; + private final String projectName; + private final Semver projectVersion; + private final String releaseDate; + private final String codeName; + private final ChangesFileSection summarySection; private final List sections; + private final ChangesFileSection dependencyChangeSection; - /** - * Create a new instance of {@link ChangesFile}. - * - * @param headerLines lines of the changes file until the first level section - * @param sections sections of the changes file - */ - public ChangesFile(final List headerLines, final List sections) { - this.headerSectionLines = headerLines; - this.sections = sections; + private ChangesFile(final Builder builder) { + this.projectName = builder.projectName; + this.projectVersion = builder.projectVersion; + this.releaseDate = builder.releaseDate; + this.codeName = builder.codeName; + this.summarySection = builder.summarySection; + this.sections = List.copyOf(builder.sections); + this.dependencyChangeSection = builder.dependencyChangeSection; } /** - * Filename of a changes file, e.g. "changes_1.2.3.md". + * Get the relative path of the changes file for the given version. + * + * @param projectVersion project version + * @return relative path of the changes file, e.g. {@code doc/changes/changes_1.2.3.md} */ - public static class Filename implements Comparable { - /** Regular expression to identify valid names of changes files and to extract version number. **/ - public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md"); - - /** - * @param path path to create a {@link Filename} for - * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a - * new instance of {@link Filename}, otherwise {@code Optional.empty()}. - */ - public static Optional from(final Path path) { - final String filename = path.getFileName().toString(); - final Matcher matcher = PATTERN.matcher(filename); - if (!matcher.matches()) { - return Optional.empty(); - } - return Optional.of(new Filename(matcher.replaceFirst("$1"))); - } - - private final Semver version; - - /** - * Create a new instance of {@link ChangesFile.Filename}. - * - * @param version version to use for new instance - */ - public Filename(final String version) { - this.version = new Semver(version, SemverType.LOOSE); - } - - /** - * @return filename of the current {@link ChangesFile.Filename} as string - */ - public String filename() { - return "changes_" + this.version + ".md"; - } - - @Override - public int compareTo(final Filename o) { - return this.version.compareTo(o.version); - } - - /** - * @return version number contained in the filename of current {@link ChangesFile.Filename} - */ - public String version() { - return this.version.getValue(); - } - - @Override - public int hashCode() { - return Objects.hash(this.version); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Filename other = (Filename) obj; - return Objects.equals(this.version, other.version); - } + public static Path getPathForVersion(final String projectVersion) { + return Path.of("doc", "changes", new ChangesFileName(projectVersion).filename()); } /** @@ -112,24 +54,65 @@ public static Builder builder() { } /** - * Get the header of the changes section. - *

- * The header includes all lines until the first section {@code ##} starts. - *

- * - * @return list of lines of the header + * Get a builder configured with the this ChangesFile. This is useful for creating a copy and modify some parts of + * this object. + * + * @return a preconfigured builder */ - public List getHeaderSectionLines() { - return this.headerSectionLines; + public Builder toBuilder() { + return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString()) + .releaseDate(this.releaseDate).codeName(this.codeName).summary(this.summarySection) + .sections(List.copyOf(this.sections)).dependencyChangeSection(this.dependencyChangeSection); } /** - * Get the heading of the file. - * - * @return heading (1. line) + * Get the project name for the first header line, e.g. {@code Project Keeper}. + * + * @return project name + */ + public String getProjectName() { + return projectName; + } + + /** + * Get the project version for the first header line, e.g. {@code 1.2.3}. + * + * @return project version + */ + public Semver getProjectVersion() { + return projectVersion; + } + + /** + * Get the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}. + * + * @return release date + */ + public String getReleaseDate() { + return releaseDate; + } + + /** + * Get the code name of the release. + * + * @return code name */ - public String getHeading() { - return this.headerSectionLines.get(0); + public String getCodeName() { + return codeName; + } + + /** + * Get the parsed release date for the first header line. If the date is not valid (e.g. {@code 2024-??-??}), this + * will return an empty {@link Optional}. + * + * @return release date + */ + public Optional getParsedReleaseDate() { + try { + return Optional.of(LocalDate.parse(this.getReleaseDate())); + } catch (final DateTimeParseException exception) { + return Optional.empty(); + } } /** @@ -141,60 +124,175 @@ public List getSections() { return this.sections; } + /** + * Get the dependency change section. + * + * @return dependency change section + */ + public Optional getDependencyChangeSection() { + return Optional.ofNullable(dependencyChangeSection); + } + + /** + * Get the summary section. + * + * @return summary section + */ + public Optional getSummarySection() { + return Optional.ofNullable(this.summarySection); + } + @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - if ((other == null) || (getClass() != other.getClass())) { - return false; - } - final ChangesFile that = (ChangesFile) other; - return Objects.equals(this.headerSectionLines, that.headerSectionLines) - && Objects.equals(this.sections, that.sections); + public String toString() { + return "ChangesFile [projectName=" + projectName + ", projectVersion=" + projectVersion + ", releaseDate=" + + releaseDate + ", codeName=" + codeName + ", summarySection=" + summarySection + ", sections=" + + sections + ", dependencyChangeSection=" + dependencyChangeSection + "]"; } @Override public int hashCode() { - return Objects.hash(this.headerSectionLines, this.sections); + return Objects.hash(projectName, projectVersion, releaseDate, codeName, summarySection, sections, + dependencyChangeSection); } @Override - public String toString() { - return String.join("\n", this.headerSectionLines) + "\n" - + this.sections.stream().map(ChangesFileSection::toString).collect(Collectors.joining("\n")); + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFile other = (ChangesFile) obj; + return Objects.equals(projectName, other.projectName) && Objects.equals(projectVersion, other.projectVersion) + && Objects.equals(releaseDate, other.releaseDate) && Objects.equals(codeName, other.codeName) + && Objects.equals(summarySection, other.summarySection) && Objects.equals(sections, other.sections) + && Objects.equals(dependencyChangeSection, other.dependencyChangeSection); } /** * Builder for {@link ChangesFile}. */ public static class Builder { - private final List sections = new ArrayList<>(); - private List header = Collections.emptyList(); + + private String projectName; + private Semver projectVersion; + private String releaseDate; + private String codeName; + private ChangesFileSection summarySection; + private List sections = new ArrayList<>(); + private ChangesFileSection dependencyChangeSection; private Builder() { // private constructor to hide public default } /** - * Set the header of the changes file. + * Set the project name for the first header line, e.g. {@code Project Keeper}. + * + * @param projectName project name + * @return self for fluent programming + */ + public Builder projectName(final String projectName) { + this.projectName = projectName; + return this; + } + + /** + * Set the project version for the first header line, e.g. {@code 1.2.3}. * - * @param header list of lines + * @param projectVersion project version * @return self for fluent programming */ - public Builder setHeader(final List header) { - this.header = header; + public Builder projectVersion(final String projectVersion) { + this.projectVersion = new Semver(projectVersion); + return this; + } + + /** + * Set the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}. + * + * @param releaseDate release date + * @return self for fluent programming + */ + public Builder releaseDate(final String releaseDate) { + this.releaseDate = releaseDate; + return this; + } + + /** + * Set the code name of the release. + * + * @param codeName code name + * @return self for fluent programming + */ + public Builder codeName(final String codeName) { + this.codeName = codeName != null && codeName.isBlank() ? null : codeName; return this; } /** * Add a section to the changes file. * - * @param lines list of lines + * @param section section * @return self for fluent programming */ - public Builder addSection(final List lines) { - this.sections.add(new ChangesFileSection(lines)); + public Builder addSection(final ChangesFileSection section) { + this.sections.add(section); + return this; + } + + /** + * Set the {@code Summary} section for the changes file. + * + * @param section section + * @return self for fluent programming + */ + public Builder summary(final ChangesFileSection section) { + if (section == null) { + this.summarySection = null; + return this; + } + if (!section.getHeading().equals(SUMMARY_HEADING)) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message( + "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}", + section.getHeading(), SUMMARY_HEADING).ticketMitigation().toString()); + } + this.summarySection = section; + return this; + } + + /** + * Set all sections of the changes file. + * + * @param sections list of sections + * @return self for fluent programming + */ + public Builder sections(final List sections) { + this.sections = List.copyOf(sections); + return this; + } + + /** + * Add a an optional {@code Dependency Updates} section to the changes file. + * + * @param section section + * @return self for fluent programming + */ + public Builder dependencyChangeSection(final ChangesFileSection section) { + if (section == null) { + this.dependencyChangeSection = null; + return this; + } + if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) { + throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-179").message( + "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}", + section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString()); + } + this.dependencyChangeSection = section; return this; } @@ -204,7 +302,8 @@ public Builder addSection(final List lines) { * @return built {@link ChangesFile} */ public ChangesFile build() { - return new ChangesFile(this.header, this.sections); + return new ChangesFile(this); } + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java index 3853c6f2..6045a3a6 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java @@ -2,18 +2,24 @@ import java.io.*; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.regex.Matcher; import java.util.regex.Pattern; import com.exasol.errorreporting.ExaError; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; /** * This class reads and writes a {@link ChangesFile} from disk. */ public class ChangesFileIO { - private static final Pattern SECTION_HEADING_PATTERN = Pattern.compile("\\s*##\\s.*"); - private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String CODE_NAME = "Code name:"; + private static final String PROJECT_NAME_PATTERN = "[\\w\\s-]+"; + private static final String VERSION_PATTERN = "\\d+\\.\\d+\\.\\d+"; + private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}"; + private static final Pattern FIRST_LINE_PATTERN = Pattern + .compile("^# (" + PROJECT_NAME_PATTERN + ") (" + VERSION_PATTERN + "), released (" + DATE_PATTERN + ")$"); + private static final String LINE_SEPARATOR = "\n"; /** * Read a {@link ChangesFile} from disk. @@ -23,19 +29,7 @@ public class ChangesFileIO { */ public ChangesFile read(final Path file) { try (final var fileReader = new BufferedReader(new FileReader(file.toFile()))) { - String sectionHeader = null; - String line; - final var builder = ChangesFile.builder(); - final List lineBuffer = new ArrayList<>(); - while ((line = fileReader.readLine()) != null) { - if (SECTION_HEADING_PATTERN.matcher(line).matches()) { - makeSection(sectionHeader, builder, lineBuffer); - sectionHeader = line; - } - lineBuffer.add(line); - } - makeSection(sectionHeader, builder, lineBuffer); - return builder.build(); + return read(file, fileReader); } catch (final IOException exception) { throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-39") .message("Failed to read changes file {{file}}.").parameter("file", file.toString()).toString(), @@ -43,15 +37,85 @@ public ChangesFile read(final Path file) { } } - private void makeSection(final String sectionHeader, final ChangesFile.Builder builder, - final List lineBuffer) { - if (!lineBuffer.isEmpty()) { - if (sectionHeader == null) { - builder.setHeader(List.copyOf(lineBuffer)); - } else { - builder.addSection(List.copyOf(lineBuffer)); + ChangesFile read(final Path file, final BufferedReader fileReader) throws IOException { + return new Parser(file, fileReader).parse(); + } + + private static class Parser { + final Path file; + final BufferedReader reader; + final Builder builder = ChangesFile.builder(); + ChangesFileSection.Builder currentSection; + + final List lineBuffer = new ArrayList<>(); + int lineCount = 0; + + Parser(final Path file, final BufferedReader reader) { + this.file = file; + this.reader = reader; + } + + ChangesFile parse() throws IOException { + String line; + while ((line = reader.readLine()) != null) { + parseLine(line); + lineCount++; + } + addSection(); + return builder.build(); + } + + private void parseLine(final String line) { + if (lineCount == 0) { + parseFirstLine(file, line); + return; + } + if (line.startsWith(CODE_NAME)) { + builder.codeName(line.substring(CODE_NAME.length()).trim()); + return; + } + if (line.startsWith("## ")) { + addSection(); + currentSection = ChangesFileSection.builder(line); + return; + } + if (currentSection != null) { + currentSection.addLine(line); + } + } + + private void addSection() { + if (currentSection == null) { + return; + } + final ChangesFileSection section = currentSection.build(); + currentSection = null; + switch (section.getHeading()) { + case ChangesFile.SUMMARY_HEADING: + builder.summary(section); + break; + case ChangesFile.DEPENDENCY_UPDATES_HEADING: + builder.dependencyChangeSection(section); + break; + default: + builder.addSection(section); + break; + } + } + + private void parseFirstLine(final Path filePath, final String line) { + final Matcher matcher = FIRST_LINE_PATTERN.matcher(line); + if (!matcher.matches()) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171") + .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, + line) + .mitigation("Update first line so that it matches regex {{expected regular expression}}", + FIRST_LINE_PATTERN) + .toString()); } - lineBuffer.clear(); + builder.projectName(matcher.group(1)) // + .projectVersion(matcher.group(2)) // + .releaseDate(matcher.group(3)); } } @@ -62,12 +126,8 @@ private void makeSection(final String sectionHeader, final ChangesFile.Builder b * @param destinationFile file to write to */ public void write(final ChangesFile changesFile, final Path destinationFile) { - try (final var fileWriter = new BufferedWriter(new FileWriter(destinationFile.toFile()))) { - writeSection(fileWriter, changesFile.getHeaderSectionLines()); - for (final ChangesFileSection section : changesFile.getSections()) { - writeSection(fileWriter, section.getContent()); - } - fileWriter.flush(); + try (final var writer = new BufferedWriter(new FileWriter(destinationFile.toFile()))) { + write(changesFile, writer); } catch (final IOException exception) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CORE-41").message("Failed to write changes file {{file name}}.") @@ -76,10 +136,39 @@ public void write(final ChangesFile changesFile, final Path destinationFile) { } } - private void writeSection(final BufferedWriter fileWriter, final List content) throws IOException { - for (final String line : content) { - fileWriter.write(line); - fileWriter.write(LINE_SEPARATOR); + void write(final ChangesFile changesFile, final Writer writer) throws IOException { + writeHeader(writer, changesFile); + for (final ChangesFileSection section : changesFile.getSections()) { + writeSection(writer, section); + } + final Optional dependencyChangeSection = changesFile.getDependencyChangeSection(); + if (dependencyChangeSection.isPresent()) { + writer.write(dependencyChangeSection.get().toString()); + writer.write(LINE_SEPARATOR); + } + } + + private void writeHeader(final Writer writer, final ChangesFile changesFile) throws IOException { + writer.write("# " + changesFile.getProjectName() + " " + changesFile.getProjectVersion() + ", released " + + changesFile.getReleaseDate()); + writer.write(LINE_SEPARATOR); + writer.write(LINE_SEPARATOR); + writer.write(CODE_NAME + (changesFile.getCodeName() != null ? " " + changesFile.getCodeName() : "")); + writer.write(LINE_SEPARATOR); + writer.write(LINE_SEPARATOR); + final Optional summarySection = changesFile.getSummarySection(); + if (summarySection.isPresent()) { + writer.write(summarySection.get().toString()); + writer.write(LINE_SEPARATOR); + } + } + + private void writeSection(final Writer writer, final ChangesFileSection section) throws IOException { + writer.write(section.getHeading()); + writer.write(LINE_SEPARATOR); + for (final String line : section.getContent()) { + writer.write(line); + writer.write(LINE_SEPARATOR); } } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java new file mode 100644 index 00000000..390c6df5 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java @@ -0,0 +1,83 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.exasol.projectkeeper.mavenrepo.Version; +import com.vdurmont.semver4j.Semver; +import com.vdurmont.semver4j.Semver.SemverType; + +/** + * Filename of a changes file, e.g. {@code changes_1.2.3.md}. + */ +public final class ChangesFileName implements Comparable { + /** Regular expression to identify valid names of changes files and to extract version number. **/ + public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md"); + + /** + * @param path path to create a {@link ChangesFileName} for + * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a new + * instance of {@link ChangesFileName}, otherwise {@code Optional.empty()}. + */ + public static Optional from(final Path path) { + final String filename = path.getFileName().toString(); + final Matcher matcher = PATTERN.matcher(filename); + if (!matcher.matches()) { + return Optional.empty(); + } + return Optional.of(new ChangesFileName(matcher.replaceFirst("$1"))); + } + + private final Semver version; + + /** + * Create a new instance of {@link ChangesFileName}. + * + * @param version version to use for new instance + */ + public ChangesFileName(final String version) { + this.version = new Semver(version, SemverType.LOOSE); + } + + /** + * @return filename of the current {@link ChangesFileName} as string + */ + public String filename() { + return "changes_" + this.version + ".md"; + } + + @Override + public int compareTo(final ChangesFileName o) { + return this.version.compareTo(o.version); + } + + /** + * @return version number contained in the filename of current {@link ChangesFileName} + */ + public String version() { + return this.version.getValue(); + } + + @Override + public int hashCode() { + return Objects.hash(this.version); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFileName other = (ChangesFileName) obj; + return Objects.equals(this.version, other.version); + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java index b5109bf9..5e5a1ac1 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java @@ -1,9 +1,8 @@ package com.exasol.projectkeeper.validators.changesfile; -import java.util.List; -import java.util.Objects; +import static java.util.Arrays.asList; -import com.exasol.errorreporting.ExaError; +import java.util.*; /** * Section of a {@link ChangesFile}. @@ -11,20 +10,14 @@ * Each level two heading (##) starts a new section. *

*/ -public class ChangesFileSection { +public final class ChangesFileSection { + + private final String heading; private final List content; - /** - * Create a new instance of {@link ChangesFileSection}. - * - * @param content lines - */ - public ChangesFileSection(final List content) { - if (content.isEmpty()) { - throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-36") - .message("changes file sections must not be empty.").ticketMitigation().toString()); - } - this.content = content; + private ChangesFileSection(final Builder builder) { + this.heading = Objects.requireNonNull(builder.heading, "header"); + this.content = List.copyOf(builder.lines); } /** @@ -33,7 +26,7 @@ public ChangesFileSection(final List content) { * @return heading */ public String getHeading() { - return this.content.get(0); + return this.heading; } /** @@ -46,22 +39,91 @@ public List getContent() { } @Override - public boolean equals(final Object other) { - if (this == other) - return true; - if (other == null || getClass() != other.getClass()) - return false; - final ChangesFileSection that = (ChangesFileSection) other; - return Objects.equals(this.content, that.content); + public int hashCode() { + return Objects.hash(heading, content); } @Override - public int hashCode() { - return Objects.hash(this.content); + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChangesFileSection other = (ChangesFileSection) obj; + return Objects.equals(heading, other.heading) && Objects.equals(content, other.content); } @Override public String toString() { - return String.join("\n", this.content); + return heading + "\n" + String.join("\n", this.content); + } + + /** + * Create a new {@link Builder} for creating a {@link ChangesFileSection}. + * + * @param heading the heading for the new section + * @return a new builder + */ + public static Builder builder(final String heading) { + return new Builder(heading); + } + + /** + * A builder for creating {@link ChangesFileSection}s. + */ + public static class Builder { + private final String heading; + private final List lines = new ArrayList<>(); + + private Builder(final String heading) { + this.heading = heading; + } + + /** + * Add the given lines to the content of the new {@code ChangesFileSection}. + * + * @param lines lines to add + * @return {@code this} for fluent programming + */ + public Builder addLines(final String... lines) { + this.lines.addAll(asList(lines)); + return this; + } + + /** + * Add the given lines to the content of the new {@code ChangesFileSection}. + * + * @param lines lines to add + * @return {@code this} for fluent programming + */ + public Builder addLines(final List lines) { + this.lines.addAll(lines); + return this; + } + + /** + * Add the given line to the content of the new {@code ChangesFileSection}. + * + * @param line line to add + * @return {@code this} for fluent programming + */ + public Builder addLine(final String line) { + this.lines.add(line); + return this; + } + + /** + * Build a new {@link ChangesFileSection}. + * + * @return a new {@link ChangesFileSection}. + */ + public ChangesFileSection build() { + return new ChangesFileSection(this); + } } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java index 30a8bb5b..ba21db83 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java @@ -31,7 +31,7 @@ public class ChangesFileValidator extends AbstractFileValidator { */ public ChangesFileValidator(final String projectVersion, final String projectName, final Path projectDirectory, final List sources) { - super(projectDirectory, Path.of("doc", "changes", new ChangesFile.Filename(projectVersion).filename())); + super(projectDirectory, ChangesFile.getPathForVersion(projectVersion)); this.projectVersion = projectVersion; this.projectName = projectName; this.sources = sources; @@ -72,10 +72,13 @@ private ChangesFile fixSections(final ChangesFile changesFile) { } private ChangesFile getTemplate() { - final var changesFile = ChangesFile.builder() - .setHeader(List.of("# " + this.projectName + " " + this.projectVersion + ", released " - + LocalDateTime.now().getYear() + "-??-??", "", "Code name:", "")) // - .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) // + final String releaseDate = LocalDateTime.now().getYear() + "-??-??"; + final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion) + .releaseDate(releaseDate) // + .codeName("") // + .summary(ChangesFileSection.builder("## Summary").build()) + .addSection(ChangesFileSection.builder("## Features").addLines("", "* ISSUE_NUMBER: description", "") + .build()) // .build(); return fixSections(changesFile); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java index 01a08241..9db14cf0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java @@ -1,9 +1,7 @@ package com.exasol.projectkeeper.validators.changesfile; -import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING; - -import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import com.exasol.projectkeeper.sources.AnalyzedSource; @@ -12,7 +10,7 @@ /** * This class fixes the dependency section of a {@link ChangesFile}. */ -//[impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] +// [impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] class DependencySectionFixer { private final List sources; @@ -35,20 +33,12 @@ public DependencySectionFixer(final List sources) { public ChangesFile fix(final ChangesFile changesFile) { final List reports = this.sources.stream().map(this::getDependencyChangesOfSource) .collect(Collectors.toList()); - final List renderedReport = new DependencyChangeReportRenderer().render(reports); - final List sections = new ArrayList<>(changesFile.getSections()); - removeDependencySection(sections); - if (!renderedReport.isEmpty()) { - sections.add(new ChangesFileSection(renderedReport)); - } - return new ChangesFile(List.copyOf(changesFile.getHeaderSectionLines()), sections); + final Optional dependencyChanges = new DependencyChangeReportRenderer().render(reports); + return changesFile.toBuilder() // + .dependencyChangeSection(dependencyChanges.orElse(null)).build(); } private NamedDependencyChangeReport getDependencyChangesOfSource(final AnalyzedSource source) { return new NamedDependencyChangeReport(source.getProjectName(), source.getDependencyChanges()); } - - private void removeDependencySection(final List sections) { - sections.removeIf(section -> section.getHeading().compareToIgnoreCase(DEPENDENCY_UPDATES_HEADING) == 0); - } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java index aca0d23d..34695e34 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java @@ -2,14 +2,12 @@ import static com.exasol.projectkeeper.ApStyleFormatter.capitalizeApStyle; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChange; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport; +import com.exasol.projectkeeper.validators.changesfile.*; /** * String renderer for {@link DependencyChangeReport}. @@ -20,17 +18,15 @@ public class DependencyChangeReportRenderer { * Render a {@link DependencyChangeReport} to string. * * @param reports reports to render - * @return rendered report as a list of lines + * @return rendered report as a section */ - public List render(final List reports) { + public Optional render(final List reports) { final List content = renderContent(reports); - final List lines = new ArrayList<>(); if (content.isEmpty()) { - return lines; + return Optional.empty(); } - lines.add(ChangesFile.DEPENDENCY_UPDATES_HEADING); - lines.addAll(content); - return lines; + return Optional.of(ChangesFileSection.builder(ChangesFile.DEPENDENCY_UPDATES_HEADING) // + .addLines(content).build()); } private List renderContent(final List reports) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java index afd5cb05..86236087 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java @@ -7,7 +7,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Validator; import com.exasol.projectkeeper.validators.VersionCollector; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; import com.exasol.projectkeeper.validators.finding.ValidationFinding; @@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer @Override public List validate() { final List empty = Collections.emptyList(); - final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); + final List list = new VersionCollector(this.projectDirectory).collectChangesFiles(); if (list.isEmpty()) { return empty; } - final ChangesFile.Filename latest = list.get(0); + final ChangesFileName latest = list.get(0); if (latest.version().equals(this.projectVersion)) { return empty; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java index 56c91af0..0f178b0f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java @@ -13,8 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; class VersionCollectorTest { @Test @@ -29,20 +28,20 @@ void sorted(@TempDir final Path tempDir) throws IOException { "1.0.0")) { createChangesFile(folder, version); } - final List expected = Stream.of( // + final List expected = Stream.of( // "1.1.0", // "1.0.10", // "1.0.2", // "1.0.0", // "0.3.0") // - .map(ChangesFile.Filename::new) // + .map(ChangesFileName::new) // .collect(Collectors.toList()); assertThat(new VersionCollector(tempDir).collectChangesFiles(), equalTo(expected)); } - private ChangesFile.Filename createChangesFile(final Path folder, final String version) throws IOException { - final Filename cfile = new Filename(version); - Files.createFile(folder.resolve(cfile.filename())); - return cfile; + private ChangesFileName createChangesFile(final Path folder, final String version) throws IOException { + final ChangesFileName file = new ChangesFileName(version); + Files.createFile(folder.resolve(file.filename())); + return file; } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java index 58a45393..3f66983a 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java @@ -12,7 +12,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; class ChangelogFileGeneratorTest { @Test @@ -27,7 +27,7 @@ void testNonStandardVersionFormats(final String version) { assertThat(new ChangelogFileGenerator().generate(files(version)), containsString(version)); } - private List files(final String... versions) { - return Arrays.stream(versions).map(ChangesFile.Filename::new).collect(Collectors.toList()); + private List files(final String... versions) { + return Arrays.stream(versions).map(ChangesFileName::new).collect(Collectors.toList()); } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java index 191984a6..3f7748c1 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java @@ -1,12 +1,13 @@ package com.exasol.projectkeeper.validators.changesfile; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.*; +import java.time.LocalDate; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -24,37 +25,142 @@ void testParsing() throws IOException { final ChangesFile changesFile = new ChangesFileIO().read(changesFilePath); final List headings = changesFile.getSections().stream().map(ChangesFileSection::getHeading) .collect(Collectors.toList()); - assertThat(changesFile.getHeading(), equalTo("# My Project 0.1.0, released 1980-01-01")); - assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring", - "## Dependency Updates")); + assertThat(changesFile.getProjectName(), equalTo("My Project")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("0.1.0")); + assertThat(changesFile.getReleaseDate(), equalTo("1980-01-01")); + assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("1980-01-01"))); + assertThat(changesFile.getSummarySection().get().getContent(), contains("", "My summary", "")); + assertThat(headings, contains("## Features", "## Bug Fixes", "## Documentation", "## Refactoring")); + assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates")); + assertThat(changesFile.getDependencyChangeSection().get().getContent(), hasSize(18)); } @Test void testWriting() throws IOException { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("# MyChanges")) - .addSection(List.of("## My Subsection")).build(); + final ChangesFile changesFile = ChangesFile.builder().projectName("project").projectVersion("1.2.3") + .releaseDate("2023-??-??").codeName("my code name") + .summary(ChangesFileSection.builder("## Summary").addLine("my summary content").build()) + .addSection(ChangesFileSection.builder("# MyChanges").build()) + .addSection(ChangesFileSection.builder("## My Subsection").addLine("content").build()).build(); final Path testFile = this.tempDir.resolve("myFile.md"); new ChangesFileIO().write(changesFile, testFile); - assertThat(Files.readString(testFile), - equalTo("# MyChanges" + System.lineSeparator() + "## My Subsection" + System.lineSeparator())); + assertThat(Files.readString(testFile), equalTo( + "# project 1.2.3, released 2023-??-??\n\nCode name: my code name\n\n## Summary\nmy summary content\n# MyChanges\n## My Subsection\ncontent\n")); } @Test void testReadAndWrite() throws IOException { - final Path changesFilePath = loadExampleFileToTempDir(); - final ChangesFileIO changesFileIO = new ChangesFileIO(); - final ChangesFile changesFile = changesFileIO.read(changesFilePath); - final Path testFile = this.tempDir.resolve("result.md"); - changesFileIO.write(changesFile, testFile); - assertThat(Files.readString(testFile), equalTo(Files.readString(changesFilePath))); + final String content = readExampleFile(); + assertReadWrite(content); + } + + @Test + void testReadInvalidFirstLineFails() { + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> readFromString("# invalid first line")); + assertThat(exception.getMessage(), startsWith( + "E-PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex")); + } + + @Test + void testReadFirstLineWithDummyReleaseDate() throws IOException { + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-??-??\nCode name: my code name\n## Summary\n\n"); + assertThat(changesFile.getProjectName(), equalTo("Project Name")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); + assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??")); + assertThat(changesFile.getCodeName(), equalTo("my code name")); + assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false)); + assertWriteRead(changesFile); + } + + @Test + void testReadFirstLineWithValidReleaseDate() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary\n\n"); + assertThat(changesFile.getProjectName(), equalTo("Project Name")); + assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3")); + assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29")); + assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("2024-01-29"))); + assertWriteRead(changesFile); + } + + @Test + void testReadMissingSummary() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29"); + assertThat(changesFile.getSummarySection().isEmpty(), is(true)); + } + + @Test + void testReadEmptySummary() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary"); + final ChangesFileSection summary = changesFile.getSummarySection().get(); + assertThat(summary.getHeading(), equalTo("## Summary")); + assertThat(summary.getContent(), emptyIterable()); + } + + @Test + void testReadSummary() throws IOException { + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-01-29\n## Summary\nmy\ncontent\n"); + final ChangesFileSection summary = changesFile.getSummarySection().get(); + assertThat(summary.getHeading(), equalTo("## Summary")); + assertThat(summary.getContent(), contains("my", "content")); + assertWriteRead(changesFile); + } + + @Test + void testReadNoDependencySection() throws IOException { + final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary"); + assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(true)); + } + + @Test + void testReadDependencySection() throws IOException { + final ChangesFile changesFile = readFromString( + "# Project Name 1.2.3, released 2024-01-29\n## Summary\n## Dependency Updates\nmy\ncontent"); + assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(false)); + assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates")); + assertThat(changesFile.getDependencyChangeSection().get().getContent(), contains("my", "content")); } private Path loadExampleFileToTempDir() throws IOException { final Path changesFile = this.tempDir.resolve("changed_0.1.0.md"); - try (final InputStream exampleFileStream = getClass().getClassLoader() - .getResourceAsStream("changesFileExample1.md")) { + try (final InputStream exampleFileStream = getExampleFileStream()) { Files.copy(Objects.requireNonNull(exampleFileStream), changesFile, StandardCopyOption.REPLACE_EXISTING); } return changesFile; } -} \ No newline at end of file + + private String readExampleFile() throws IOException { + try (final InputStream exampleFileStream = getExampleFileStream()) { + return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8).replace("\r\n", "\n"); + } + } + + private InputStream getExampleFileStream() { + return getClass().getClassLoader().getResourceAsStream("changesFileExample1.md"); + } + + private void assertWriteRead(final ChangesFile changesFile) throws IOException { + final String content = writeToString(changesFile); + final ChangesFile readChangesFile = readFromString(content); + assertThat(readChangesFile.toString(), equalTo(changesFile.toString())); + assertThat(readChangesFile, equalTo(changesFile)); + } + + private void assertReadWrite(final String content) throws IOException { + final ChangesFile changesFile = readFromString(content); + final String writtenContent = writeToString(changesFile); + assertThat(writtenContent, equalTo(content)); + } + + private String writeToString(final ChangesFile changesFile) throws IOException { + final StringWriter stringWriter = new StringWriter(); + new ChangesFileIO().write(changesFile, stringWriter); + return stringWriter.toString(); + } + + private ChangesFile readFromString(final String content) throws IOException { + return new ChangesFileIO().read(Path.of("dummy-file"), new BufferedReader(new StringReader(content))); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java new file mode 100644 index 00000000..d1a792ee --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java @@ -0,0 +1,12 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileNameTest { + @Test + void equalsContractFilename() { + EqualsVerifier.forClass(ChangesFileName.class).verify(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java new file mode 100644 index 00000000..929afba6 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java @@ -0,0 +1,13 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileSectionTest { + + @Test + void equalsContract() { + EqualsVerifier.forClass(ChangesFileSection.class).verify(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java new file mode 100644 index 00000000..d4b3ab20 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java @@ -0,0 +1,61 @@ +package com.exasol.projectkeeper.validators.changesfile; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +import java.nio.file.Path; +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; +import com.jparams.verifier.tostring.ToStringVerifier; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ChangesFileTest { + + @Test + void equalsContract() { + EqualsVerifier.forClass(ChangesFile.class).verify(); + } + + @Test + void testToString() { + ToStringVerifier.forClass(ChangesFile.class).verify(); + } + + @Test + void getPathForVersion() { + assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md"))); + } + + @Test + void toBuilderCreatesCopy() { + final ChangesFile changesFile = builder().build(); + final ChangesFile copy = changesFile.toBuilder().build(); + assertThat(copy, equalTo(changesFile)); + assertThat(changesFile.equals(copy), is(true)); + } + + private Builder builder() { + return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??") + .codeName("my code name") + .summary(ChangesFileSection.builder("## Summary").addLine("summary content").build()) + .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates") + .addLine("dependency update content").build()) + .addSection(ChangesFileSection.builder("section 1").build()); + } + + @Test + void getParsedReleaseDateValid() { + assertThat(builder().releaseDate("2024-01-29").build().getParsedReleaseDate().get(), + equalTo(LocalDate.of(2024, 1, 29))); + } + + @Test + void getParsedReleaseDateInvalid() { + assertThat(builder().releaseDate("invalid").build().getParsedReleaseDate().isPresent(), is(false)); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java index 9cf9bf31..62234975 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java @@ -4,10 +4,8 @@ import static com.exasol.projectkeeper.HasNoMoreFindingsAfterApplyingFixesMatcher.hasNoMoreFindingsAfterApplyingFixes; import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasNoValidationFindings; import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasValidationFindingWithMessage; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -35,6 +33,7 @@ class ChangesFileValidatorTest { private static final String A_VERSION = "1.2.3"; private static final String A_PROJECT_NAME = "my-project"; + private static final String LINE_SEPARATOR = "\n"; @TempDir Path tempDir; @@ -55,12 +54,18 @@ void testValidationForSnapshotVersion() throws IOException { } @Test - void noDepdendencyUpdates() throws IOException { + void noDependencyUpdates() throws IOException { final AnalyzedMavenSource source = createTestSetup(new TestMavenModel(), Collections.emptyList()); final Logger log = mock(Logger.class); createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding))); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release"))); + assertThat(changesFile, + hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR // + + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR))); + verify(log).info("Created 'doc" + File.separator + "changes" + File.separator + "changes_1.2.3.md'. Don't forget to update its content!"); final List findings = createValidator(source).validate(); @@ -73,7 +78,15 @@ void testFixCreatedTemplate() throws IOException { final Logger log = mock(Logger.class); createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding))); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release"))); + assertThat(changesFile, + hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR // + + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR // + + "## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR + + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR))); verify(log).info("Created 'doc" + File.separator + "changes" + File.separator + "changes_1.2.3.md'. Don't forget to update its content!"); } @@ -85,7 +98,9 @@ void testFixContainsDependencyUpdates() throws IOException { final AnalyzedMavenSource source = createTestSetup(model); createValidator(source).validate().forEach(FindingFixHelper::fix); final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md")); - assertThat(changesFile, hasContent(containsString("my-lib"))); + assertThat(changesFile, hasContent(endsWith("## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR // + + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR))); } @Test @@ -117,4 +132,4 @@ private AnalyzedMavenSource createTestSetup(final TestMavenModel mavenModel, .dependencyChanges(DependencyChangeReport.builder().typed(Type.COMPILE, dependencyChanges).build()) // .build(); } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java index 90ca108e..d02f8e7f 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java @@ -2,8 +2,7 @@ import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.*; import java.util.List; @@ -13,9 +12,10 @@ import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; import com.exasol.projectkeeper.shared.dependencychanges.NewDependency; import com.exasol.projectkeeper.sources.AnalyzedMavenSource; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; @Tag("integration") -//[utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] +// [utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1] class DependencySectionFixerTest { private static AnalyzedMavenSource source; @@ -32,29 +32,43 @@ static void beforeAll() { @Test void testSectionIsAdded() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")).build(); - final List sections = new DependencySectionFixer(List.of(source)).fix(changesFile) - .getSections(); - assertThat(sections.size(), equalTo(1)); - assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); + final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build()) + .build(); + final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); + assertThat(fixedChangesFile.getDependencyChangeSection().get().getHeading(), + equalTo(DEPENDENCY_UPDATES_HEADING)); + } + + private Builder changesFileBuilder() { + return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate") + .summary(ChangesFileSection.builder("## Summary").build()); } @Test void testSectionIsUpdated() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")) - .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); + final ChangesFile changesFile = changesFileBuilder().dependencyChangeSection( + ChangesFileSection.builder("## Dependency Updates").addLine("content will be overwritten").build()) + .build(); final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); - final List sections = fixedChangesFile.getSections(); - assertThat(sections.size(), equalTo(1)); - assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); - assertThat("dependency fixer changed the changes file", changesFile, not(equalTo(fixedChangesFile))); + final ChangesFileSection changesFileSection = fixedChangesFile.getDependencyChangeSection().get(); + assertThat(changesFileSection.getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING)); + assertThat(changesFileSection.getContent(), + contains("", "### Compile Dependency Updates", "", "* Added `com.example:my-lib:1.2.3`")); + assertThat("dependency fixer changed the changes file", changesFile, + allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile)))); } @Test - void testHeaderIsPreserved() { - final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")) - .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build(); - final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile); - assertThat(changesFile.getHeaderSectionLines(), equalTo(fixedChangesFile.getHeaderSectionLines())); + void testDependencySectionIsRemoved() { + final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build()) + .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates") + .addLine("content will be preserved").build()) + .build(); + final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of()).fix(changesFile); + + assertThat(fixedChangesFile.getDependencyChangeSection().isPresent(), is(false)); + assertThat(fixedChangesFile, not(sameInstance(changesFile))); + assertThat("dependency fixer changed the changes file", changesFile, + allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile)))); } -} \ No newline at end of file +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java index 6ad5cde4..12eb1942 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java @@ -1,16 +1,19 @@ package com.exasol.projectkeeper.validators.changesfile.dependencies; +import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type; import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport; import com.exasol.projectkeeper.shared.dependencychanges.NewDependency; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileSection; import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport; class DependencyChangeReportRendererTest { @@ -22,17 +25,15 @@ class DependencyChangeReportRendererTest { @Test void testRenderSingleSourceReport() { final NamedDependencyChangeReport namedReport = new NamedDependencyChangeReport("my-project", REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(namedReport))); - assertThat(result, equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + "\n" - + "* Added `com.example:my-lib:1.2.3`")); + assertThat(render(namedReport), equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + + "\n" + "* Added `com.example:my-lib:1.2.3`")); } @Test void testRenderMultiSourceReport() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT); final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB))); - assertThat(result, equalTo( + assertThat(render(sourceA, sourceB), equalTo( "## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`\n\n### Project B\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`")); } @@ -40,15 +41,20 @@ void testRenderMultiSourceReport() { void testRenderMultiSourceReportWithNoChangesInOneReport() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT); final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", EMPTY_REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB))); - assertThat(result, equalTo( + assertThat(render(sourceA, sourceB), equalTo( "## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`")); } @Test void testRenderSourceReportWithoutChanges() { final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", EMPTY_REPORT); - final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA))); - assertThat(result, emptyString()); + final Optional result = new DependencyChangeReportRenderer().render(List.of(sourceA)); + assertThat(result.isPresent(), is(false)); } -} \ No newline at end of file + + private String render(final NamedDependencyChangeReport... reports) { + final Optional section = new DependencyChangeReportRenderer().render(asList(reports)); + assertThat(section.isPresent(), is(true)); + return section.get().toString(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java index a030479a..64ba39c5 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileName; import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding; class LatestChangesFileValidatorTest { @@ -38,8 +38,8 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve final Path folder = tempDir.resolve(Path.of("doc", "changes")); Files.createDirectories(folder); for (final String v : versions) { - final ChangesFile.Filename cfile = new ChangesFile.Filename(v); - Files.createFile(folder.resolve(cfile.filename())); + final ChangesFileName file = new ChangesFileName(v); + Files.createFile(folder.resolve(file.filename())); } return new LatestChangesFileValidator(tempDir, "2.0.0"); } From 39575549485a2cf4d2c5f98bef3bb0585aa248cd Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 05:29:11 +0100 Subject: [PATCH 65/78] Fix sonar warning --- .../projectkeeper/dependencyupdate/ChangesFileUpdater.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java index e8c2667e..63637e06 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java @@ -6,11 +6,7 @@ class ChangesFileUpdater { ChangesFile update(final ChangesFile changesFile) { final Builder builder = changesFile.toBuilder(); - update(builder); + // Changes file will be updated in the next PR return builder.build(); } - - private void update(final Builder builder) { - - } } From 90196d89596d8b6eb847b5fb8c7100fbb8bde16c Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 06:30:45 +0100 Subject: [PATCH 66/78] Add unit tests for version incrementor --- ...nProjectWithProjectKeeperPluginWriter.java | 10 +- .../plugin/ProjectKeeperMojoIT.java | 10 +- .../ProjectVersionIncrementor.java | 39 ++---- .../sources/analyze/MavenSourceAnalyzer.java | 13 +- .../validators/changesfile/ChangesFile.java | 2 +- .../validators/pom/PomFileIO.java | 52 ++++++++ .../JavaProjectCrawlerRunnerIT.java | 9 +- .../ProjectVersionIncrementorTest.java | 118 ++++++++++++++++++ .../validators/pom/PomFileValidatorTest.java | 22 ++-- 9 files changed, 201 insertions(+), 74 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java index 11953af5..0cb66aef 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java @@ -1,13 +1,13 @@ package com.exasol.projectkeeper.plugin; -import java.io.*; import java.nio.file.Path; import java.util.List; import org.apache.maven.model.*; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.codehaus.plexus.util.xml.Xpp3Dom; +import com.exasol.projectkeeper.validators.pom.PomFileIO; + public class MvnProjectWithProjectKeeperPluginWriter { public static final String PROJECT_ARTIFACT_ID = "my-test-project"; public static final String PROJECT_VERSION = "0.1.0"; @@ -26,11 +26,7 @@ public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion public void writeAsPomToProject(final Path projectDir) { final Path path = projectDir.resolve("pom.xml"); - try (final FileWriter fileWriter = new FileWriter(path.toFile())) { - new MavenXpp3Writer().write(fileWriter, this.model); - } catch (final IOException exception) { - throw new UncheckedIOException("Failed writing POM to file " + path, exception); - } + new PomFileIO().writePom(model, path); } public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId, diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java index c7ea6a74..bf7c63ad 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java @@ -19,8 +19,6 @@ import org.apache.maven.it.VerificationException; import org.apache.maven.it.Verifier; import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.hamcrest.Matcher; @@ -31,6 +29,7 @@ import com.exasol.mavenpluginintegrationtesting.MavenIntegrationTestEnvironment; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.pom.PomFileIO; class ProjectKeeperMojoIT { private static final String ORIGINAL_SLF4J_VERSION = "1.7.36"; @@ -138,12 +137,7 @@ private void updateReleaseDate(final String changeLogVersion, final String newRe } private Model readPom() { - final Path path = projectDir.resolve("pom.xml"); - try { - return new MavenXpp3Reader().read(Files.newBufferedReader(path)); - } catch (IOException | XmlPullParserException exception) { - throw new IllegalStateException("failed to parse " + path + ": " + exception.getMessage(), exception); - } + return new PomFileIO().readPom(projectDir.resolve("pom.xml")); } @ParameterizedTest diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index 95f2f383..a9013644 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -2,18 +2,12 @@ import static com.exasol.projectkeeper.shared.config.ProjectKeeperModule.JAR_ARTIFACT; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; import java.nio.file.Path; import java.time.*; import java.util.Objects; import java.util.Optional; import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Logger; @@ -21,6 +15,7 @@ import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; +import com.exasol.projectkeeper.validators.pom.PomFileIO; import com.vdurmont.semver4j.Semver; class ProjectVersionIncrementor { @@ -31,18 +26,22 @@ class ProjectVersionIncrementor { private final Clock clock; private final Path projectDir; private final Logger logger; + private final PomFileIO pomFileIO; ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion) { - this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC()); + this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), new PomFileIO(), + Clock.systemUTC()); } ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, - final String currentProjectVersion, final ChangesFileIO changesFileIO, final Clock clock) { + final String currentProjectVersion, final ChangesFileIO changesFileIO, final PomFileIO pomFileIO, + final Clock clock) { this.config = config; this.logger = logger; this.projectDir = projectDir; this.changesFileIO = changesFileIO; + this.pomFileIO = pomFileIO; this.clock = clock; this.currentProjectVersion = Objects.requireNonNull(currentProjectVersion, "currentProjectVersion"); } @@ -75,11 +74,12 @@ private LocalDate today() { } String incrementProjectVersion() { - final Model pom = readPom(); + final Path path = getPomPath(); + final Model pom = pomFileIO.readPom(path); if (!this.currentProjectVersion.equals(pom.getVersion())) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message( - "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}", - pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString()); + "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}.", + pom.getVersion(), path, currentProjectVersion).ticketMitigation().toString()); } final String nextVersion = incrementVersion(pom); if (usesReferenceCheckerPlugin()) { @@ -112,24 +112,9 @@ static String getIncrementedVersion(final String version) { return current.nextPatch().toString(); } - private Model readPom() { - final Path path = getPomPath(); - try { - return new MavenXpp3Reader().read(Files.newBufferedReader(path)); - } catch (IOException | XmlPullParserException exception) { - throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172") - .message("Failed to read pom {{pom file path}}", path).toString(), exception); - } - } - private void writePom(final Model pom) { final Path path = getPomPath(); - try { - new MavenXpp3Writer().write(Files.newOutputStream(path), pom); - } catch (final IOException exception) { - throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173") - .message("Failed to write pom {{pom file path}}", path).toString(), exception); - } + pomFileIO.writePom(pom, path); } private Path getPomPath() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java index f02e8ff9..1f550b76 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java @@ -3,7 +3,6 @@ import static com.exasol.projectkeeper.shared.config.SourceType.MAVEN; import static java.util.Collections.emptyMap; -import java.io.FileInputStream; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.List; @@ -11,7 +10,6 @@ import java.util.stream.Collectors; import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.JavaProjectCrawlerRunner; @@ -19,6 +17,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject; import com.exasol.projectkeeper.sources.AnalyzedMavenSource; import com.exasol.projectkeeper.sources.AnalyzedSource; +import com.exasol.projectkeeper.validators.pom.PomFileIO; /** * This class analyzes Java Maven projects. @@ -106,14 +105,6 @@ private CrawledMavenProject getCrawlResultForProject(final Source source, } private Model readMavenModel(final Source source) { - try (final FileInputStream fileInputStream = new FileInputStream(source.getPath().toFile())) { - return new MavenXpp3Reader().read(fileInputStream); - } catch (final Exception exception) { - // Catch Exception instead of org.codehaus.plexus.util.xml.pull.XmlPullParserException helps avoid adding - // runtime dependency org.codehaus.plexus:plexus-utils - throw new IllegalStateException( - ExaError.messageBuilder("E-PK-CORE-94").message("Failed to analyze maven source.").toString(), - exception); - } + return new PomFileIO().readPom(source.getPath()); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index b6e1020b..6e04e2f0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -109,7 +109,7 @@ public String getCodeName() { */ public Optional getParsedReleaseDate() { try { - return Optional.of(LocalDate.parse(this.getReleaseDate())); + return Optional.ofNullable(this.getReleaseDate()).map(LocalDate::parse); } catch (final DateTimeParseException exception) { return Optional.empty(); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java new file mode 100644 index 00000000..9560b2fb --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java @@ -0,0 +1,52 @@ +package com.exasol.projectkeeper.validators.pom; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import com.exasol.errorreporting.ExaError; + +/** + * This class reads and writes POM files. + */ +public class PomFileIO { + + private static final MavenXpp3Writer WRITER = new MavenXpp3Writer(); + private static final MavenXpp3Reader READER = new MavenXpp3Reader(); + + /** + * Read the given file and parse it as a POM file. + * + * @param path path to read + * @return parsed POM model + */ + public Model readPom(final Path path) { + try { + return READER.read(Files.newBufferedReader(path)); + } catch (IOException | XmlPullParserException exception) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172") + .message("Failed to read pom {{pom file path}}", path).toString(), exception); + } + } + + /** + * Write a POM model to a file + * + * @param model the POM model to write + * @param path the path to write + */ + public void writePom(final Model model, final Path path) { + try { + WRITER.write(Files.newOutputStream(path), model); + } catch (final IOException exception) { + throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173") + .message("Failed to write pom {{pom file path}}", path).toString(), exception); + } + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java index ea11a2c7..0432ec36 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java @@ -6,12 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.FileWriter; import java.io.IOException; import java.nio.file.Path; import java.util.List; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.hamcrest.Matchers; @@ -26,6 +24,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject; import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.test.TestMavenModel; +import com.exasol.projectkeeper.validators.pom.PomFileIO; @Tag("integration") class JavaProjectCrawlerRunnerIT { @@ -83,11 +82,9 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString()))); } - private void writePomFile(final Path pomFile) throws IOException { + private void writePomFile(final Path pomFile) { final TestMavenModel model = new TestMavenModel(); model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION); - try (final FileWriter fileWriter = new FileWriter(pomFile.toFile())) { - new MavenXpp3Writer().write(fileWriter, model); - } + new PomFileIO().writePom(model, pomFile); } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java new file mode 100644 index 00000000..c41de2c0 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java @@ -0,0 +1,118 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; +import java.time.*; +import java.util.List; +import java.util.Set; + +import org.apache.maven.model.Model; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.projectkeeper.Logger; +import com.exasol.projectkeeper.shared.config.*; +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; +import com.exasol.projectkeeper.validators.pom.PomFileIO; + +@ExtendWith(MockitoExtension.class) +class ProjectVersionIncrementorTest { + + private static final Instant NOW = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final Path PROJECT_DIR = Path.of("ProjectDir"); + private static final Path POM_PATH = PROJECT_DIR.resolve("pom.xml"); + private static final String CURRENT_PROJECT_VERSION = "1.2.3"; + private static final Clock fixedClock = Clock.fixed(NOW, ZoneId.of("CET")); + + @Mock + private Logger loggerMock; + @Mock + private ChangesFileIO changesFileIOMock; + @Mock + private PomFileIO pomFileIOMock; + + @ParameterizedTest + @CsvSource(nullValues = "NULL", value = { "NULL, false", "invalid data, false", "2007-??-??, false", + "2024-??-??, false", "2007-01-01, true", "2007-12-02, true", "2007-12-03, false", "2007-12-04, false", + "2024-02-08, false" }) + void isCurrentVersionReleased(final String releaseDate, final boolean expectedReleaseState) { + final ChangesFile changesFile = ChangesFile.builder().releaseDate(releaseDate).build(); + when(changesFileIOMock.read(PROJECT_DIR.resolve("doc/changes/changes_1.2.3.md"))).thenReturn(changesFile); + assertThat("release date '" + releaseDate + "' is considered as " + (expectedReleaseState ? "" : "not ") + + "released", testee().isCurrentVersionReleased(), is(expectedReleaseState)); + } + + @Test + void incrementProjectVersionFailsForInconsistentVersionInPom() { + final Model pomModel = new Model(); + pomModel.setVersion("1.2.2"); + when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel); + final ProjectVersionIncrementor testee = testee(configWithoutJarArtifact()); + + final IllegalStateException exception = assertThrows(IllegalStateException.class, + testee::incrementProjectVersion); + assertThat(exception.getMessage(), startsWith( + "E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom 'ProjectDir/pom.xml', expected '1.2.3'.")); + } + + @ParameterizedTest + @CsvSource({ "0.0.0, 0.0.1", "0.1.1, 0.1.2", "1.2.1, 1.2.2", "9.9.9, 9.9.10", "1.2.99, 1.2.100", + "99.34.12345, 99.34.12346" }) + void incrementProjectVersion(final String currentVersion, final String expectedNextVersion) { + final Model pomModel = new Model(); + pomModel.setVersion(currentVersion); + when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel); + final String newVersion = testee(configWithoutJarArtifact(), currentVersion).incrementProjectVersion(); + assertAll(() -> assertThat(newVersion, equalTo(expectedNextVersion)), + () -> assertThat(pomModel.getVersion(), equalTo(newVersion))); + verify(pomFileIOMock).writePom(same(pomModel), eq(POM_PATH)); + } + + @Test + void incrementProjectVersionWithJarArtifactTriesToUpdateReferences() { + final Model pomModel = new Model(); + pomModel.setVersion(CURRENT_PROJECT_VERSION); + when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel); + final ProjectVersionIncrementor testee = testee(configWithJarArtifact()); + // This fails because the project dir does not exist when we try to run reference checker. + final IllegalStateException exception = assertThrows(IllegalStateException.class, + testee::incrementProjectVersion); + assertThat(exception.getMessage(), startsWith( + "E-PK-CORE-125: Error executing command 'mvn --batch-mode artifact-reference-checker:unify'.")); + } + + private ProjectVersionIncrementor testee() { + return testee(null); + } + + private ProjectVersionIncrementor testee(final ProjectKeeperConfig config) { + return testee(config, CURRENT_PROJECT_VERSION); + } + + private ProjectVersionIncrementor testee(final ProjectKeeperConfig config, final String currentProjectVersion) { + return new ProjectVersionIncrementor(config, loggerMock, PROJECT_DIR, currentProjectVersion, changesFileIOMock, + pomFileIOMock, fixedClock); + } + + private ProjectKeeperConfig configWithJarArtifact() { + return ProjectKeeperConfig.builder() + .sources(List.of(Source.builder().modules(Set.of(ProjectKeeperModule.JAR_ARTIFACT)).build())).build(); + } + + private ProjectKeeperConfig configWithoutJarArtifact() { + return ProjectKeeperConfig.builder().sources(List.of(Source.builder().modules(Set.of()).build())).build(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java index 7bffedf2..e3b32bf5 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java @@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.Mockito.mock; -import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,7 +15,6 @@ import org.apache.maven.model.Model; import org.apache.maven.model.Parent; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -115,33 +113,29 @@ private void runFix(final ParentPomRef parentPomRef) { } @Test - void testMissingVersion() throws IOException { + void testMissingVersion() { getTestModel().withVersion(null).writeAsPomToProject(this.tempDir); assertThat(runValidator(null), hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*")); } @Test - void testMissingVersionButParentPomRef() throws IOException, XmlPullParserException { + void testMissingVersionButParentPomRef() { getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir); runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null)); - try (final FileReader reader = new FileReader(this.tempDir.resolve("pk_generated_parent.pom").toFile())) { - final Model pom = new MavenXpp3Reader().read(reader); - assertThat(pom.getVersion(), equalTo("1.2.3")); - } + final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom")); + assertThat(pom.getVersion(), equalTo("1.2.3")); } @Test - void testMissingVersionButFromParent() throws IOException, XmlPullParserException { + void testMissingVersionButFromParent() { getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir); assertThat(runValidator(null), not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*"))); } - private Model readModel(final Path projectDir) throws XmlPullParserException, IOException { - try (final FileReader fileReader = new FileReader(projectDir.toFile())) { - return new MavenXpp3Reader().read(fileReader); - } + private Model readModel(final Path projectDir) { + return new PomFileIO().readPom(projectDir); } @Test @@ -279,4 +273,4 @@ void testValidAfterFix() throws IOException { assertThat(result, empty()); } -} \ No newline at end of file +} From e47066671d9fdd5e72d5673e3c9f1cf0a1eede6f Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 07:27:25 +0100 Subject: [PATCH 67/78] Use command executor --- .../JavaProjectCrawlerRunner.java | 11 ++--- .../dependencyupdate/DependencyUpdater.java | 14 ++++-- .../ProjectVersionIncrementor.java | 13 +++-- .../analyze/generic/CommandExecutor.java | 19 +++++-- .../analyze/generic/MavenProcessBuilder.java | 28 ++++++++--- .../analyze/generic/ProcessResult.java | 38 ++++++++++++++ .../sources/analyze/generic/ShellCommand.java | 30 +++++++++++- .../analyze/generic/SimpleProcess.java | 9 ++++ .../sources/analyze/golang/GoBinary.java | 2 +- .../analyze/golang/GolangServices.java | 10 ++-- .../sources/analyze/npm/NpmServices.java | 2 +- .../DependencyUpdaterTest.java | 49 +++++++++++++++++++ .../ProjectVersionIncrementorTest.java | 26 +++++++--- .../sources/analyze/golang/GoBinaryTest.java | 4 +- .../sources/analyze/npm/NpmServicesTest.java | 28 ++++++----- 15 files changed, 226 insertions(+), 57 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java index 18dcf1ed..b419defa 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java @@ -8,8 +8,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder; -import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; -import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; +import com.exasol.projectkeeper.sources.analyze.generic.*; /** * Runs the maven plugin goal on the current repository and returns the parsed result. @@ -43,9 +42,8 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) { private String runCrawlerPlugin(final Path... pomFiles) { final MavenProcessBuilder builder = buildMavenCommand(pomFiles); - final SimpleProcess process = builder.startSimpleProcess(); - process.waitUntilFinished(Duration.ofSeconds(90)); - return new ResponseCoder().decodeResponse(process.getOutputStreamContent()); + final ProcessResult result = new CommandExecutor().execute(builder.buildCommand()); + return new ResponseCoder().decodeResponse(result.getOutputStreamContent()); } private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { @@ -60,7 +58,8 @@ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { * comparing dependencies). */ "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true") - .workingDir(null); + .workingDir(null) // + .timeout(Duration.ofSeconds(90)); if (this.mvnRepositoryOverride != null) { builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index aec19dd7..224d0cb6 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -7,7 +7,7 @@ import com.exasol.projectkeeper.Logger; import com.exasol.projectkeeper.ProjectKeeper; import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; -import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; +import com.exasol.projectkeeper.sources.analyze.generic.*; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; @@ -24,10 +24,12 @@ public class DependencyUpdater { private final ChangesFileIO changesFileIO; private final String currentProjectVersion; private final ChangesFileUpdater changesFileUpdater; + private final CommandExecutor commandExecutor; DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir, final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor, - final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater) { + final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater, + final CommandExecutor commandExecutor) { this.projectKeeper = projectKeeper; this.logger = logger; this.projectDir = projectDir; @@ -35,6 +37,7 @@ public class DependencyUpdater { this.projectVersionIncrementor = projectVersionIncrementor; this.changesFileIO = changesFileIO; this.changesFileUpdater = changesFileUpdater; + this.commandExecutor = commandExecutor; } /** @@ -51,7 +54,7 @@ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final final Logger logger, final Path projectDir, final String currentProjectVersion) { return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion, new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(), - new ChangesFileUpdater()); + new ChangesFileUpdater(), new CommandExecutor()); } /** @@ -89,8 +92,9 @@ private void updateDependencyVersions() { } private void runMaven(final String mavenGoal) { - MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir).startSimpleProcess() - .waitUntilFinished(MAVEN_COMMAND_TIMEOUT); + final ShellCommand command = MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir) + .timeout(MAVEN_COMMAND_TIMEOUT).buildCommand(); + commandExecutor.execute(command); } private void runProjectKeeperFix() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index a9013644..3fe8ac8b 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -12,7 +12,7 @@ import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.Logger; import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; -import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; +import com.exasol.projectkeeper.sources.analyze.generic.*; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; import com.exasol.projectkeeper.validators.pom.PomFileIO; @@ -27,21 +27,23 @@ class ProjectVersionIncrementor { private final Path projectDir; private final Logger logger; private final PomFileIO pomFileIO; + private final CommandExecutor commandExecutor; ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion) { this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), new PomFileIO(), - Clock.systemUTC()); + new CommandExecutor(), Clock.systemUTC()); } ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion, final ChangesFileIO changesFileIO, final PomFileIO pomFileIO, - final Clock clock) { + final CommandExecutor commandExecutor, final Clock clock) { this.config = config; this.logger = logger; this.projectDir = projectDir; this.changesFileIO = changesFileIO; this.pomFileIO = pomFileIO; + this.commandExecutor = commandExecutor; this.clock = clock; this.currentProjectVersion = Objects.requireNonNull(currentProjectVersion, "currentProjectVersion"); } @@ -94,8 +96,9 @@ private boolean usesReferenceCheckerPlugin() { private void updateReferences() { logger.info("Unify artifact references"); - MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify").workingDir(projectDir) - .startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30)); + final ShellCommand command = MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify") + .workingDir(projectDir).timeout(Duration.ofSeconds(30)).buildCommand(); + commandExecutor.execute(command); } private String incrementVersion(final Model pom) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java index c6410a73..bd8f3aea 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java @@ -8,16 +8,27 @@ public class CommandExecutor { /** - * Executes the specified {@link ShellCommand} + * Executes the specified {@link ShellCommand}. * * @param sc command to execute * @param workingDirectory directory to run the execution in - * @return standard output of the command + * @return standard and error output of the command * @throws IllegalStateException if execution fails. */ - public String execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException { + public ProcessResult execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException { final SimpleProcess process = SimpleProcess.start(workingDirectory, sc.commandline()); process.waitUntilFinished(sc.timeout()); - return process.getOutputStreamContent(); + return process.getResult(); + } + + /** + * Executes the specified {@link ShellCommand}. + * + * @param sc command to execute + * @return standard and error output of the command + * @throws IllegalStateException if execution fails. + */ + public ProcessResult execute(final ShellCommand sc) throws IllegalStateException { + return execute(sc, sc.workingDir().orElse(null)); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java index 56a0cf28..0e002cbb 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -3,6 +3,7 @@ import static java.util.Arrays.asList; import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -13,8 +14,9 @@ * This class allows building and starting a {@code mvn} command. */ public class MavenProcessBuilder { - private final List command = new ArrayList<>(); + private final List args = new ArrayList<>(); private Path workingDir = null; + private Duration timeout = null; private MavenProcessBuilder() { // Use create() method @@ -27,7 +29,6 @@ private MavenProcessBuilder() { */ public static MavenProcessBuilder create() { final MavenProcessBuilder builder = new MavenProcessBuilder(); - builder.addArgument(getMavenExecutable()); builder.addArgument("--batch-mode"); return builder; } @@ -39,7 +40,7 @@ public static MavenProcessBuilder create() { * @return {@code this} for fluent programming */ public MavenProcessBuilder addArguments(final String... arguments) { - command.addAll(asList(arguments)); + args.addAll(asList(arguments)); return this; } @@ -50,7 +51,7 @@ public MavenProcessBuilder addArguments(final String... arguments) { * @return {@code this} for fluent programming */ public MavenProcessBuilder addArgument(final String argument) { - command.add(argument); + args.add(argument); return this; } @@ -66,12 +67,23 @@ public MavenProcessBuilder workingDir(final Path workingDir) { } /** - * Build the command and run it. + * Set the timeout for running the process. * - * @return the running {@link SimpleProcess} + * @param timeout process timeout + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder timeout(final Duration timeout) { + this.timeout = timeout; + return this; + } + + /** + * Build a {@link ShellCommand} that can be started with {@link CommandExecutor}. + * + * @return the built command */ - public SimpleProcess startSimpleProcess() { - return SimpleProcess.start(workingDir, command); + public ShellCommand buildCommand() { + return ShellCommand.builder().command(getMavenExecutable()).args(this.args).timeout(this.timeout).build(); } private static String getMavenExecutable() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java new file mode 100644 index 00000000..baf30819 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java @@ -0,0 +1,38 @@ +package com.exasol.projectkeeper.sources.analyze.generic; + +/** + * Result of executing a process. + */ +public class ProcessResult { + private final String outputStreamContent; + private final String errorStreamContent; + + /** + * Create a new process result. + * + * @param outputStreamContent output stream content + * @param errorStreamContent error stream content + */ + public ProcessResult(final String outputStreamContent, final String errorStreamContent) { + this.outputStreamContent = outputStreamContent; + this.errorStreamContent = errorStreamContent; + } + + /** + * Content of the output stream. + * + * @return output stream + */ + public String getOutputStreamContent() { + return outputStreamContent; + } + + /** + * Content of the error stream. + * + * @return error stream + */ + public String getErrorStreamContent() { + return errorStreamContent; + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java index 076d1488..c69471d8 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java @@ -1,5 +1,6 @@ package com.exasol.projectkeeper.sources.analyze.generic; +import java.nio.file.Path; import java.time.Duration; import java.util.*; import java.util.logging.Logger; @@ -22,6 +23,7 @@ public static Builder builder() { private Duration timeout; private String mainCommand; private String subCommand; + private Path workingDir = null; private final List options = new ArrayList<>(); /** @@ -52,6 +54,15 @@ public Duration timeout() { return this.timeout; } + /** + * Working directory for the process. + * + * @return working dir + */ + public Optional workingDir() { + return Optional.ofNullable(this.workingDir); + } + /** * Builder for a new instance of {@link ShellCommand}. */ @@ -67,6 +78,15 @@ public Builder timeout(final Duration timeout) { return this; } + /** + * @param workingDir optional working directory for the process + * @return this for fluent programming + */ + public Builder workingDir(final Path workingDir) { + this.shellCommand.workingDir = workingDir; + return this; + } + /** * @param command name of the command to execute. On Windows platform probably with a suffix like ".exe" or * ".cmd", see {@link OsCheck#suffix} @@ -94,7 +114,15 @@ public Builder command(final String main, final String sub) { * @return this for fluent programming */ public Builder args(final String... value) { - this.shellCommand.options.addAll(Arrays.asList(value)); + return this.args(Arrays.asList(value)); + } + + /** + * @param value additional options and arguments to the command + * @return this for fluent programming + */ + public Builder args(final List value) { + this.shellCommand.options.addAll(value); return this; } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java index cf1903a3..a07fe90c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java @@ -129,6 +129,15 @@ public String getErrorStreamContent() { } } + /** + * Get the process result containing output and error stream content. + * + * @return result + */ + public ProcessResult getResult() { + return new ProcessResult(getOutputStreamContent(), getErrorStreamContent()); + } + private void waitForExecutionFinished(final Duration executionTimeout) { try { if (!this.process.waitFor(executionTimeout.toMillis(), TimeUnit.MILLISECONDS)) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java index 40f22564..b4c8caa7 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java @@ -63,7 +63,7 @@ public GoBinary install() { .args("install", this.moduleName) // .build(); try { - this.executor.execute(shellCommand, null); + this.executor.execute(shellCommand); } catch (final IllegalStateException exception) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-161") .message("Error installing go binary {{binary}}.", this.binaryName).toString(), exception); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java index 443814d3..aad86426 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java @@ -78,9 +78,9 @@ private String retrieveLicenses(final Path absoluteSourcePath, final String modu .timeout(EXECUTION_TIMEOUT) // .command(goLicenses.command()) // .args("csv", module) // - .build(); + .workingDir(absoluteSourcePath).build(); try { - return this.executor.execute(shellCommand, absoluteSourcePath); + return this.executor.execute(shellCommand).getOutputStreamContent(); } catch (final RuntimeException exception) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CORE-142") @@ -100,8 +100,9 @@ Path getModuleDir(final Path absoluteSourcePath, final String moduleName) { .timeout(Duration.ofSeconds(3)) // .command(GoBinary.GO.command()) // .args("list", "-m", "-f", "{{.Dir}}", moduleName) // + .workingDir(absoluteSourcePath) // .build(); - final String output = this.executor.execute(shellCommand, absoluteSourcePath).trim(); + final String output = this.executor.execute(shellCommand).getOutputStreamContent().trim(); if (output.isEmpty()) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-160") .message("Did not get directory for module {{module name}}.", moduleName).ticketMitigation() @@ -226,7 +227,8 @@ void installDependencies(final Path projectPath) { .timeout(Duration.ofMinutes(2)) // .command(GoBinary.GO.command()) // .args("get", "-t", "./...") // + .workingDir(projectPath) // .build(); - this.executor.execute(sc, projectPath); + this.executor.execute(sc); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java index 1128a165..ac1d9755 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java @@ -72,7 +72,7 @@ JsonObject getLicenses(final Path folder) { private JsonObject getJsonOutput(final ShellCommand cmd, final Path workingDir) { fetchDependencies(workingDir); - final String stdout = this.executor.execute(cmd, workingDir); + final String stdout = this.executor.execute(cmd, workingDir).getOutputStreamContent(); return JsonIo.read(new StringReader(stdout)); } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java new file mode 100644 index 00000000..27090fdd --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java @@ -0,0 +1,49 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.projectkeeper.Logger; +import com.exasol.projectkeeper.ProjectKeeper; +import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; + +@ExtendWith(MockitoExtension.class) +class DependencyUpdaterTest { + + private static final Path PROJECT_DIR = Path.of("ProjectDir"); + private static final String CURRENT_PROJECT_VERSION = "1.2.3"; + @Mock + private ProjectKeeper projectKeeperMock; + @Mock + private Logger loggerMock; + @Mock + private ProjectVersionIncrementor projectVersionIncrementorMock; + @Mock + private ChangesFileIO changesFileIOMock; + @Mock + private ChangesFileUpdater changesFileUpdaterMock; + @Mock + private CommandExecutor commandExecutorMock; + + @Test + void updateDependencies() { + // assertUpdate(); + } + + private DependencyUpdater testee() { + return new DependencyUpdater(projectKeeperMock, loggerMock, PROJECT_DIR, CURRENT_PROJECT_VERSION, + projectVersionIncrementorMock, changesFileIOMock, changesFileUpdaterMock, commandExecutorMock); + } + + private void assertUpdate() { + assertThat(testee().updateDependencies(), is(true)); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java index c41de2c0..5a9432ec 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java @@ -19,11 +19,14 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import com.exasol.projectkeeper.Logger; import com.exasol.projectkeeper.shared.config.*; +import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor; +import com.exasol.projectkeeper.sources.analyze.generic.ShellCommand; import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; import com.exasol.projectkeeper.validators.pom.PomFileIO; @@ -43,6 +46,8 @@ class ProjectVersionIncrementorTest { private ChangesFileIO changesFileIOMock; @Mock private PomFileIO pomFileIOMock; + @Mock + private CommandExecutor commandExecutorMock; @ParameterizedTest @CsvSource(nullValues = "NULL", value = { "NULL, false", "invalid data, false", "2007-??-??, false", @@ -82,16 +87,21 @@ void incrementProjectVersion(final String currentVersion, final String expectedN } @Test - void incrementProjectVersionWithJarArtifactTriesToUpdateReferences() { + void incrementProjectVersionWithJarArtifactUpdatesReferences() { final Model pomModel = new Model(); pomModel.setVersion(CURRENT_PROJECT_VERSION); when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel); - final ProjectVersionIncrementor testee = testee(configWithJarArtifact()); - // This fails because the project dir does not exist when we try to run reference checker. - final IllegalStateException exception = assertThrows(IllegalStateException.class, - testee::incrementProjectVersion); - assertThat(exception.getMessage(), startsWith( - "E-PK-CORE-125: Error executing command 'mvn --batch-mode artifact-reference-checker:unify'.")); + final String newVersion = testee(configWithJarArtifact(), CURRENT_PROJECT_VERSION).incrementProjectVersion(); + assertAll(() -> assertThat(newVersion, equalTo("1.2.4")), + () -> assertThat(pomModel.getVersion(), equalTo(newVersion)), + () -> assertThat(getExecutedCommand().commandline(), contains(startsWith("mvn"), + equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify")))); + } + + private ShellCommand getExecutedCommand() { + final ArgumentCaptor arg = ArgumentCaptor.forClass(ShellCommand.class); + verify(commandExecutorMock).execute(arg.capture()); + return arg.getValue(); } private ProjectVersionIncrementor testee() { @@ -104,7 +114,7 @@ private ProjectVersionIncrementor testee(final ProjectKeeperConfig config) { private ProjectVersionIncrementor testee(final ProjectKeeperConfig config, final String currentProjectVersion) { return new ProjectVersionIncrementor(config, loggerMock, PROJECT_DIR, currentProjectVersion, changesFileIOMock, - pomFileIOMock, fixedClock); + pomFileIOMock, commandExecutorMock, fixedClock); } private ProjectKeeperConfig configWithJarArtifact() { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java index 94cb90a8..5a47f174 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java @@ -46,7 +46,7 @@ void goItself() { @Test void installFailure() { - when(this.executor.execute(any(), any())).thenThrow(new IllegalStateException("bla bla")); + when(this.executor.execute(any())).thenThrow(new IllegalStateException("bla bla")); final GoBinary testee = testee(); final Exception e = assertThrows(IllegalStateException.class, () -> testee.install()); assertThat(e.getMessage(), Matchers.startsWith("E-PK-CORE-161: Error installing go binary")); @@ -56,7 +56,7 @@ void installFailure() { @Test void installSuccess() { testee().install(); - verify(this.executor).execute(any(), any()); + verify(this.executor).execute(any()); } @Test diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java index d892d412..b6270772 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java @@ -22,8 +22,7 @@ import com.exasol.projectkeeper.shared.dependencies.ProjectDependencies; import com.exasol.projectkeeper.shared.repository.GitRepository; import com.exasol.projectkeeper.shared.repository.TaggedCommit; -import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor; -import com.exasol.projectkeeper.sources.analyze.generic.GitService; +import com.exasol.projectkeeper.sources.analyze.generic.*; @ExtendWith(MockitoExtension.class) class NpmServicesTest { @@ -40,9 +39,10 @@ class NpmServicesTest { @Test void getDependencies() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); - when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(TestData.LICENSES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); + when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(new ProcessResult(TestData.LICENSES, null)); final PackageJson current = TestData.samplePackageJson(); assertThat(testee().getDependencies(current), Matchers.isA(ProjectDependencies.class)); } @@ -68,8 +68,9 @@ void previousNotFound() throws FileNotFoundException { @Test void dependenciesFetchedOnlyOnceForWorkingDir() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); final NpmServices testee = testee(); final Path workingDir = Path.of("testing-working-dir"); testee.listDependencies(workingDir); @@ -79,8 +80,9 @@ void dependenciesFetchedOnlyOnceForWorkingDir() { @Test void dependenciesFetchedForEachWorkingDir() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); final NpmServices testee = testee(); final Path workingDir1 = Path.of("testing-working-dir1"); final Path workingDir2 = Path.of("testing-working-dir2"); @@ -92,7 +94,7 @@ void dependenciesFetchedForEachWorkingDir() { @Test void fetchDependenciesSucceeds() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); assertDoesNotThrow(() -> testee().fetchDependencies(Path.of("testing-working-dir1"))); } @@ -101,8 +103,10 @@ void fetchDependenciesFailsWithIllegalStateException() { when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenThrow(IllegalStateException.class); final NpmServices testee = testee(); final Path workingDir = Path.of("testing-working-dir1"); - final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.fetchDependencies(workingDir)); - assertThat(exception.getMessage(), equalTo("E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'.")); + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> testee.fetchDependencies(workingDir)); + assertThat(exception.getMessage(), equalTo( + "E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'.")); } private PackageJson currentPackageJson(final Path relative) { From 8e7d22b9ce2dcbf1b2ecd06129c41fe7f375d549 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 08:54:47 +0100 Subject: [PATCH 68/78] Add assertion for maven command --- .../sources/analyze/generic/MavenProcessBuilder.java | 6 +++++- .../ProjectVersionIncrementorTest.java | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java index 0e002cbb..f630a03c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -83,7 +83,11 @@ public MavenProcessBuilder timeout(final Duration timeout) { * @return the built command */ public ShellCommand buildCommand() { - return ShellCommand.builder().command(getMavenExecutable()).args(this.args).timeout(this.timeout).build(); + return ShellCommand.builder().command(getMavenExecutable()) // + .args(this.args) // + .timeout(this.timeout) // + .workingDir(workingDir) // + .build(); } private static String getMavenExecutable() { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java index 5a9432ec..caac26e4 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java @@ -93,9 +93,14 @@ void incrementProjectVersionWithJarArtifactUpdatesReferences() { when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel); final String newVersion = testee(configWithJarArtifact(), CURRENT_PROJECT_VERSION).incrementProjectVersion(); assertAll(() -> assertThat(newVersion, equalTo("1.2.4")), - () -> assertThat(pomModel.getVersion(), equalTo(newVersion)), - () -> assertThat(getExecutedCommand().commandline(), contains(startsWith("mvn"), - equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify")))); + () -> assertThat(pomModel.getVersion(), equalTo(newVersion)), () -> assertMavenExecuted()); + } + + private void assertMavenExecuted(final String... mavenArguments) { + final ShellCommand command = getExecutedCommand(); + assertThat(command.workingDir().get(), equalTo(PROJECT_DIR)); + assertThat(command.commandline(), + contains(startsWith("mvn"), equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify"))); } private ShellCommand getExecutedCommand() { From aa9f7f345309de3bfb1d3fd394608ec5916b0511 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 11:24:42 +0100 Subject: [PATCH 69/78] Fix test for windows --- .../dependencyupdate/ProjectVersionIncrementorTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java index caac26e4..28d3ad5c 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java @@ -69,8 +69,9 @@ void incrementProjectVersionFailsForInconsistentVersionInPom() { final IllegalStateException exception = assertThrows(IllegalStateException.class, testee::incrementProjectVersion); - assertThat(exception.getMessage(), startsWith( - "E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom 'ProjectDir/pom.xml', expected '1.2.3'.")); + assertThat(exception.getMessage(), + startsWith("E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom '" + POM_PATH + + "', expected '1.2.3'.")); } @ParameterizedTest From e5e4a4d98c15399eacf4e8c3cd22e6af8919c488 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 14:15:09 +0100 Subject: [PATCH 70/78] Refactor command executor --- ...nProjectWithProjectKeeperPluginWriter.java | 10 ++-- .../JavaProjectCrawlerRunner.java | 11 ++-- .../sources/analyze/MavenSourceAnalyzer.java | 13 +---- .../analyze/generic/CommandExecutor.java | 19 +++++-- .../analyze/generic/MavenProcessBuilder.java | 32 +++++++++--- .../analyze/generic/ProcessResult.java | 38 ++++++++++++++ .../sources/analyze/generic/ShellCommand.java | 30 ++++++++++- .../analyze/generic/SimpleProcess.java | 9 ++++ .../sources/analyze/golang/GoBinary.java | 2 +- .../analyze/golang/GolangServices.java | 10 ++-- .../sources/analyze/npm/NpmServices.java | 2 +- .../validators/changesfile/ChangesFile.java | 2 +- .../validators/pom/PomFileIO.java | 52 +++++++++++++++++++ .../JavaProjectCrawlerRunnerIT.java | 9 ++-- .../sources/analyze/golang/GoBinaryTest.java | 4 +- .../sources/analyze/npm/NpmServicesTest.java | 28 +++++----- .../validators/pom/PomFileValidatorTest.java | 22 +++----- 17 files changed, 215 insertions(+), 78 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java index 11953af5..0cb66aef 100644 --- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java +++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java @@ -1,13 +1,13 @@ package com.exasol.projectkeeper.plugin; -import java.io.*; import java.nio.file.Path; import java.util.List; import org.apache.maven.model.*; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.codehaus.plexus.util.xml.Xpp3Dom; +import com.exasol.projectkeeper.validators.pom.PomFileIO; + public class MvnProjectWithProjectKeeperPluginWriter { public static final String PROJECT_ARTIFACT_ID = "my-test-project"; public static final String PROJECT_VERSION = "0.1.0"; @@ -26,11 +26,7 @@ public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion public void writeAsPomToProject(final Path projectDir) { final Path path = projectDir.resolve("pom.xml"); - try (final FileWriter fileWriter = new FileWriter(path.toFile())) { - new MavenXpp3Writer().write(fileWriter, this.model); - } catch (final IOException exception) { - throw new UncheckedIOException("Failed writing POM to file " + path, exception); - } + new PomFileIO().writePom(model, path); } public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId, diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java index 18dcf1ed..b419defa 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java @@ -8,8 +8,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder; -import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder; -import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess; +import com.exasol.projectkeeper.sources.analyze.generic.*; /** * Runs the maven plugin goal on the current repository and returns the parsed result. @@ -43,9 +42,8 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) { private String runCrawlerPlugin(final Path... pomFiles) { final MavenProcessBuilder builder = buildMavenCommand(pomFiles); - final SimpleProcess process = builder.startSimpleProcess(); - process.waitUntilFinished(Duration.ofSeconds(90)); - return new ResponseCoder().decodeResponse(process.getOutputStreamContent()); + final ProcessResult result = new CommandExecutor().execute(builder.buildCommand()); + return new ResponseCoder().decodeResponse(result.getOutputStreamContent()); } private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { @@ -60,7 +58,8 @@ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) { * comparing dependencies). */ "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true") - .workingDir(null); + .workingDir(null) // + .timeout(Duration.ofSeconds(90)); if (this.mvnRepositoryOverride != null) { builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java index f02e8ff9..1f550b76 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java @@ -3,7 +3,6 @@ import static com.exasol.projectkeeper.shared.config.SourceType.MAVEN; import static java.util.Collections.emptyMap; -import java.io.FileInputStream; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.List; @@ -11,7 +10,6 @@ import java.util.stream.Collectors; import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import com.exasol.errorreporting.ExaError; import com.exasol.projectkeeper.JavaProjectCrawlerRunner; @@ -19,6 +17,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject; import com.exasol.projectkeeper.sources.AnalyzedMavenSource; import com.exasol.projectkeeper.sources.AnalyzedSource; +import com.exasol.projectkeeper.validators.pom.PomFileIO; /** * This class analyzes Java Maven projects. @@ -106,14 +105,6 @@ private CrawledMavenProject getCrawlResultForProject(final Source source, } private Model readMavenModel(final Source source) { - try (final FileInputStream fileInputStream = new FileInputStream(source.getPath().toFile())) { - return new MavenXpp3Reader().read(fileInputStream); - } catch (final Exception exception) { - // Catch Exception instead of org.codehaus.plexus.util.xml.pull.XmlPullParserException helps avoid adding - // runtime dependency org.codehaus.plexus:plexus-utils - throw new IllegalStateException( - ExaError.messageBuilder("E-PK-CORE-94").message("Failed to analyze maven source.").toString(), - exception); - } + return new PomFileIO().readPom(source.getPath()); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java index c6410a73..bd8f3aea 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java @@ -8,16 +8,27 @@ public class CommandExecutor { /** - * Executes the specified {@link ShellCommand} + * Executes the specified {@link ShellCommand}. * * @param sc command to execute * @param workingDirectory directory to run the execution in - * @return standard output of the command + * @return standard and error output of the command * @throws IllegalStateException if execution fails. */ - public String execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException { + public ProcessResult execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException { final SimpleProcess process = SimpleProcess.start(workingDirectory, sc.commandline()); process.waitUntilFinished(sc.timeout()); - return process.getOutputStreamContent(); + return process.getResult(); + } + + /** + * Executes the specified {@link ShellCommand}. + * + * @param sc command to execute + * @return standard and error output of the command + * @throws IllegalStateException if execution fails. + */ + public ProcessResult execute(final ShellCommand sc) throws IllegalStateException { + return execute(sc, sc.workingDir().orElse(null)); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java index b8252558..5dfd7877 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java @@ -3,6 +3,7 @@ import static java.util.Arrays.asList; import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -12,8 +13,9 @@ * This class allows building and starting a {@code mvn} command. */ public class MavenProcessBuilder { - private final List command = new ArrayList<>(); + private final List args = new ArrayList<>(); private Path workingDir = null; + private Duration timeout = null; private MavenProcessBuilder() { // Use create() method @@ -26,7 +28,6 @@ private MavenProcessBuilder() { */ public static MavenProcessBuilder create() { final MavenProcessBuilder builder = new MavenProcessBuilder(); - builder.addArgument(getMavenExecutable()); builder.addArgument("--batch-mode"); return builder; } @@ -38,7 +39,7 @@ public static MavenProcessBuilder create() { * @return {@code this} for fluent programming */ public MavenProcessBuilder addArguments(final String... arguments) { - command.addAll(asList(arguments)); + args.addAll(asList(arguments)); return this; } @@ -49,7 +50,7 @@ public MavenProcessBuilder addArguments(final String... arguments) { * @return {@code this} for fluent programming */ public MavenProcessBuilder addArgument(final String argument) { - command.add(argument); + args.add(argument); return this; } @@ -65,12 +66,27 @@ public MavenProcessBuilder workingDir(final Path workingDir) { } /** - * Build the command and run it. + * Set the timeout for running the process. * - * @return the running {@link SimpleProcess} + * @param timeout process timeout + * @return {@code this} for fluent programming + */ + public MavenProcessBuilder timeout(final Duration timeout) { + this.timeout = timeout; + return this; + } + + /** + * Build a {@link ShellCommand} that can be started with {@link CommandExecutor}. + * + * @return the built command */ - public SimpleProcess startSimpleProcess() { - return SimpleProcess.start(workingDir, command); + public ShellCommand buildCommand() { + return ShellCommand.builder().command(getMavenExecutable()) // + .args(this.args) // + .timeout(this.timeout) // + .workingDir(workingDir) // + .build(); } private static String getMavenExecutable() { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java new file mode 100644 index 00000000..baf30819 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java @@ -0,0 +1,38 @@ +package com.exasol.projectkeeper.sources.analyze.generic; + +/** + * Result of executing a process. + */ +public class ProcessResult { + private final String outputStreamContent; + private final String errorStreamContent; + + /** + * Create a new process result. + * + * @param outputStreamContent output stream content + * @param errorStreamContent error stream content + */ + public ProcessResult(final String outputStreamContent, final String errorStreamContent) { + this.outputStreamContent = outputStreamContent; + this.errorStreamContent = errorStreamContent; + } + + /** + * Content of the output stream. + * + * @return output stream + */ + public String getOutputStreamContent() { + return outputStreamContent; + } + + /** + * Content of the error stream. + * + * @return error stream + */ + public String getErrorStreamContent() { + return errorStreamContent; + } +} diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java index 076d1488..c69471d8 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java @@ -1,5 +1,6 @@ package com.exasol.projectkeeper.sources.analyze.generic; +import java.nio.file.Path; import java.time.Duration; import java.util.*; import java.util.logging.Logger; @@ -22,6 +23,7 @@ public static Builder builder() { private Duration timeout; private String mainCommand; private String subCommand; + private Path workingDir = null; private final List options = new ArrayList<>(); /** @@ -52,6 +54,15 @@ public Duration timeout() { return this.timeout; } + /** + * Working directory for the process. + * + * @return working dir + */ + public Optional workingDir() { + return Optional.ofNullable(this.workingDir); + } + /** * Builder for a new instance of {@link ShellCommand}. */ @@ -67,6 +78,15 @@ public Builder timeout(final Duration timeout) { return this; } + /** + * @param workingDir optional working directory for the process + * @return this for fluent programming + */ + public Builder workingDir(final Path workingDir) { + this.shellCommand.workingDir = workingDir; + return this; + } + /** * @param command name of the command to execute. On Windows platform probably with a suffix like ".exe" or * ".cmd", see {@link OsCheck#suffix} @@ -94,7 +114,15 @@ public Builder command(final String main, final String sub) { * @return this for fluent programming */ public Builder args(final String... value) { - this.shellCommand.options.addAll(Arrays.asList(value)); + return this.args(Arrays.asList(value)); + } + + /** + * @param value additional options and arguments to the command + * @return this for fluent programming + */ + public Builder args(final List value) { + this.shellCommand.options.addAll(value); return this; } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java index cf1903a3..a07fe90c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java @@ -129,6 +129,15 @@ public String getErrorStreamContent() { } } + /** + * Get the process result containing output and error stream content. + * + * @return result + */ + public ProcessResult getResult() { + return new ProcessResult(getOutputStreamContent(), getErrorStreamContent()); + } + private void waitForExecutionFinished(final Duration executionTimeout) { try { if (!this.process.waitFor(executionTimeout.toMillis(), TimeUnit.MILLISECONDS)) { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java index 40f22564..b4c8caa7 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java @@ -63,7 +63,7 @@ public GoBinary install() { .args("install", this.moduleName) // .build(); try { - this.executor.execute(shellCommand, null); + this.executor.execute(shellCommand); } catch (final IllegalStateException exception) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-161") .message("Error installing go binary {{binary}}.", this.binaryName).toString(), exception); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java index 443814d3..aad86426 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java @@ -78,9 +78,9 @@ private String retrieveLicenses(final Path absoluteSourcePath, final String modu .timeout(EXECUTION_TIMEOUT) // .command(goLicenses.command()) // .args("csv", module) // - .build(); + .workingDir(absoluteSourcePath).build(); try { - return this.executor.execute(shellCommand, absoluteSourcePath); + return this.executor.execute(shellCommand).getOutputStreamContent(); } catch (final RuntimeException exception) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CORE-142") @@ -100,8 +100,9 @@ Path getModuleDir(final Path absoluteSourcePath, final String moduleName) { .timeout(Duration.ofSeconds(3)) // .command(GoBinary.GO.command()) // .args("list", "-m", "-f", "{{.Dir}}", moduleName) // + .workingDir(absoluteSourcePath) // .build(); - final String output = this.executor.execute(shellCommand, absoluteSourcePath).trim(); + final String output = this.executor.execute(shellCommand).getOutputStreamContent().trim(); if (output.isEmpty()) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-160") .message("Did not get directory for module {{module name}}.", moduleName).ticketMitigation() @@ -226,7 +227,8 @@ void installDependencies(final Path projectPath) { .timeout(Duration.ofMinutes(2)) // .command(GoBinary.GO.command()) // .args("get", "-t", "./...") // + .workingDir(projectPath) // .build(); - this.executor.execute(sc, projectPath); + this.executor.execute(sc); } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java index 1128a165..ac1d9755 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java @@ -72,7 +72,7 @@ JsonObject getLicenses(final Path folder) { private JsonObject getJsonOutput(final ShellCommand cmd, final Path workingDir) { fetchDependencies(workingDir); - final String stdout = this.executor.execute(cmd, workingDir); + final String stdout = this.executor.execute(cmd, workingDir).getOutputStreamContent(); return JsonIo.read(new StringReader(stdout)); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index c2e02c54..05a08ca0 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -109,7 +109,7 @@ public String getCodeName() { */ public Optional getParsedReleaseDate() { try { - return Optional.of(LocalDate.parse(this.getReleaseDate())); + return Optional.ofNullable(this.getReleaseDate()).map(LocalDate::parse); } catch (final DateTimeParseException exception) { return Optional.empty(); } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java new file mode 100644 index 00000000..9560b2fb --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java @@ -0,0 +1,52 @@ +package com.exasol.projectkeeper.validators.pom; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import com.exasol.errorreporting.ExaError; + +/** + * This class reads and writes POM files. + */ +public class PomFileIO { + + private static final MavenXpp3Writer WRITER = new MavenXpp3Writer(); + private static final MavenXpp3Reader READER = new MavenXpp3Reader(); + + /** + * Read the given file and parse it as a POM file. + * + * @param path path to read + * @return parsed POM model + */ + public Model readPom(final Path path) { + try { + return READER.read(Files.newBufferedReader(path)); + } catch (IOException | XmlPullParserException exception) { + throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172") + .message("Failed to read pom {{pom file path}}", path).toString(), exception); + } + } + + /** + * Write a POM model to a file + * + * @param model the POM model to write + * @param path the path to write + */ + public void writePom(final Model model, final Path path) { + try { + WRITER.write(Files.newOutputStream(path), model); + } catch (final IOException exception) { + throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173") + .message("Failed to write pom {{pom file path}}", path).toString(), exception); + } + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java index ea11a2c7..0432ec36 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java @@ -6,12 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.FileWriter; import java.io.IOException; import java.nio.file.Path; import java.util.List; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.hamcrest.Matchers; @@ -26,6 +24,7 @@ import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject; import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult; import com.exasol.projectkeeper.test.TestMavenModel; +import com.exasol.projectkeeper.validators.pom.PomFileIO; @Tag("integration") class JavaProjectCrawlerRunnerIT { @@ -83,11 +82,9 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString()))); } - private void writePomFile(final Path pomFile) throws IOException { + private void writePomFile(final Path pomFile) { final TestMavenModel model = new TestMavenModel(); model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION); - try (final FileWriter fileWriter = new FileWriter(pomFile.toFile())) { - new MavenXpp3Writer().write(fileWriter, model); - } + new PomFileIO().writePom(model, pomFile); } } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java index 94cb90a8..5a47f174 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java @@ -46,7 +46,7 @@ void goItself() { @Test void installFailure() { - when(this.executor.execute(any(), any())).thenThrow(new IllegalStateException("bla bla")); + when(this.executor.execute(any())).thenThrow(new IllegalStateException("bla bla")); final GoBinary testee = testee(); final Exception e = assertThrows(IllegalStateException.class, () -> testee.install()); assertThat(e.getMessage(), Matchers.startsWith("E-PK-CORE-161: Error installing go binary")); @@ -56,7 +56,7 @@ void installFailure() { @Test void installSuccess() { testee().install(); - verify(this.executor).execute(any(), any()); + verify(this.executor).execute(any()); } @Test diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java index d892d412..b6270772 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java @@ -22,8 +22,7 @@ import com.exasol.projectkeeper.shared.dependencies.ProjectDependencies; import com.exasol.projectkeeper.shared.repository.GitRepository; import com.exasol.projectkeeper.shared.repository.TaggedCommit; -import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor; -import com.exasol.projectkeeper.sources.analyze.generic.GitService; +import com.exasol.projectkeeper.sources.analyze.generic.*; @ExtendWith(MockitoExtension.class) class NpmServicesTest { @@ -40,9 +39,10 @@ class NpmServicesTest { @Test void getDependencies() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); - when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(TestData.LICENSES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); + when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(new ProcessResult(TestData.LICENSES, null)); final PackageJson current = TestData.samplePackageJson(); assertThat(testee().getDependencies(current), Matchers.isA(ProjectDependencies.class)); } @@ -68,8 +68,9 @@ void previousNotFound() throws FileNotFoundException { @Test void dependenciesFetchedOnlyOnceForWorkingDir() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); final NpmServices testee = testee(); final Path workingDir = Path.of("testing-working-dir"); testee.listDependencies(workingDir); @@ -79,8 +80,9 @@ void dependenciesFetchedOnlyOnceForWorkingDir() { @Test void dependenciesFetchedForEachWorkingDir() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); - when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); + when(this.executor.execute(eq(LIST_DEPENDENCIES), any())) + .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null)); final NpmServices testee = testee(); final Path workingDir1 = Path.of("testing-working-dir1"); final Path workingDir2 = Path.of("testing-working-dir2"); @@ -92,7 +94,7 @@ void dependenciesFetchedForEachWorkingDir() { @Test void fetchDependenciesSucceeds() { - when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(""); + when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null)); assertDoesNotThrow(() -> testee().fetchDependencies(Path.of("testing-working-dir1"))); } @@ -101,8 +103,10 @@ void fetchDependenciesFailsWithIllegalStateException() { when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenThrow(IllegalStateException.class); final NpmServices testee = testee(); final Path workingDir = Path.of("testing-working-dir1"); - final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.fetchDependencies(workingDir)); - assertThat(exception.getMessage(), equalTo("E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'.")); + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> testee.fetchDependencies(workingDir)); + assertThat(exception.getMessage(), equalTo( + "E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'.")); } private PackageJson currentPackageJson(final Path relative) { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java index 7bffedf2..e3b32bf5 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java @@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.Mockito.mock; -import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,7 +15,6 @@ import org.apache.maven.model.Model; import org.apache.maven.model.Parent; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -115,33 +113,29 @@ private void runFix(final ParentPomRef parentPomRef) { } @Test - void testMissingVersion() throws IOException { + void testMissingVersion() { getTestModel().withVersion(null).writeAsPomToProject(this.tempDir); assertThat(runValidator(null), hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*")); } @Test - void testMissingVersionButParentPomRef() throws IOException, XmlPullParserException { + void testMissingVersionButParentPomRef() { getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir); runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null)); - try (final FileReader reader = new FileReader(this.tempDir.resolve("pk_generated_parent.pom").toFile())) { - final Model pom = new MavenXpp3Reader().read(reader); - assertThat(pom.getVersion(), equalTo("1.2.3")); - } + final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom")); + assertThat(pom.getVersion(), equalTo("1.2.3")); } @Test - void testMissingVersionButFromParent() throws IOException, XmlPullParserException { + void testMissingVersionButFromParent() { getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir); assertThat(runValidator(null), not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*"))); } - private Model readModel(final Path projectDir) throws XmlPullParserException, IOException { - try (final FileReader fileReader = new FileReader(projectDir.toFile())) { - return new MavenXpp3Reader().read(fileReader); - } + private Model readModel(final Path projectDir) { + return new PomFileIO().readPom(projectDir); } @Test @@ -279,4 +273,4 @@ void testValidAfterFix() throws IOException { assertThat(result, empty()); } -} \ No newline at end of file +} From d348f15de879691b4cc57523d8f99d260628cee7 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 14:37:18 +0100 Subject: [PATCH 71/78] Add unit tests --- .../analyze/generic/ProcessResult.java | 31 +++++++++- .../validators/pom/PomFileIO.java | 2 +- .../validators/pom/io/PomFileReader.java | 5 +- .../validators/pom/io/PomFileWriter.java | 5 +- .../analyze/generic/ProcessResultTest.java | 19 ++++++ .../validators/pom/PomFileIOTest.java | 60 +++++++++++++++++++ 6 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java index baf30819..598ea333 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java @@ -1,9 +1,11 @@ package com.exasol.projectkeeper.sources.analyze.generic; +import java.util.Objects; + /** * Result of executing a process. */ -public class ProcessResult { +public final class ProcessResult { private final String outputStreamContent; private final String errorStreamContent; @@ -35,4 +37,31 @@ public String getOutputStreamContent() { public String getErrorStreamContent() { return errorStreamContent; } + + @Override + public int hashCode() { + return Objects.hash(outputStreamContent, errorStreamContent); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ProcessResult other = (ProcessResult) obj; + return Objects.equals(outputStreamContent, other.outputStreamContent) + && Objects.equals(errorStreamContent, other.errorStreamContent); + } + + @Override + public String toString() { + return "ProcessResult [outputStreamContent=" + outputStreamContent + ", errorStreamContent=" + + errorStreamContent + "]"; + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java index 9560b2fb..97a400be 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java @@ -13,7 +13,7 @@ import com.exasol.errorreporting.ExaError; /** - * This class reads and writes POM files. + * This class reads and writes POM files using the Maven POM {@link Model} class. */ public class PomFileIO { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java index 970ae9b2..dda099bd 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java @@ -11,9 +11,12 @@ import org.xml.sax.SAXException; import com.exasol.errorreporting.ExaError; +import com.exasol.projectkeeper.validators.pom.PomFileIO; /** - * This class implements reading a POM file. + * This class implements reading a POM file as an XML document. + *

+ * Use {@link PomFileIO} if you need the Maven POM model. */ public class PomFileReader { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java index 60cb3d4b..dfe56b12 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java @@ -12,9 +12,12 @@ import org.w3c.dom.Document; import com.exasol.errorreporting.ExaError; +import com.exasol.projectkeeper.validators.pom.PomFileIO; /** - * This class implements write access to a pom file. + * This class implements write access to a POM file as an XML document. + *

+ * Use {@link PomFileIO} if you need the Maven POM model. */ public class PomFileWriter { diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java new file mode 100644 index 00000000..460a4932 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java @@ -0,0 +1,19 @@ +package com.exasol.projectkeeper.sources.analyze.generic; + +import org.junit.jupiter.api.Test; + +import com.jparams.verifier.tostring.ToStringVerifier; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ProcessResultTest { + @Test + void testEqualsContract() { + EqualsVerifier.forClass(ProcessResult.class).verify(); + } + + @Test + void testToString() { + ToStringVerifier.forClass(ProcessResult.class).verify(); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java new file mode 100644 index 00000000..7a219b6e --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java @@ -0,0 +1,60 @@ +package com.exasol.projectkeeper.validators.pom; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.maven.model.Model; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class PomFileIOTest { + + @TempDir + Path tempDir; + + @Test + void write() throws IOException { + final Path file = tempDir.resolve("pom.xml"); + final Model model = new Model(); + model.setArtifactId("dummy-artifact"); + testee().writePom(model, file); + assertThat(Files.readString(file), allOf(startsWith(""), + containsString("dummy-artifact"), endsWith("\n"))); + } + + @Test + void writeFails() throws IOException { + final Path file = tempDir.resolve("non-existing-dir").resolve("pom.xml"); + final Model model = new Model(); + final PomFileIO testee = testee(); + final UncheckedIOException exception = assertThrows(UncheckedIOException.class, + () -> testee.writePom(model, file)); + assertThat(exception.getMessage(), startsWith("E-PK-CORE-173: Failed to write pom")); + } + + @Test + void read() throws IOException { + final Path file = Path.of("pom.xml"); + final Model pom = testee().readPom(file); + assertThat(pom.getArtifactId(), equalTo("project-keeper-core")); + } + + @Test + void readFails() throws IOException { + final Path file = tempDir.resolve("pom.xml"); + final PomFileIO testee = testee(); + final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.readPom(file)); + assertThat(exception.getMessage(), startsWith("E-PK-CORE-172: Failed to read pom")); + } + + private PomFileIO testee() { + return new PomFileIO(); + } + +} From 029b56b51b7b8d8860aea7dca350665724698193 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 14:41:14 +0100 Subject: [PATCH 72/78] Add comments --- .../com/exasol/projectkeeper/validators/pom/PomFileIO.java | 3 +++ .../exasol/projectkeeper/validators/pom/io/PomFileReader.java | 3 +-- .../exasol/projectkeeper/validators/pom/io/PomFileWriter.java | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java index 97a400be..fb8cbdc6 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java @@ -14,6 +14,9 @@ /** * This class reads and writes POM files using the Maven POM {@link Model} class. + *

+ * Use {@link com.exasol.projectkeeper.validators.pom.io.PomFileReader} or + * {@link com.exasol.projectkeeper.validators.pom.io.PomFileWriter} if you want to read/write POM files as XML. */ public class PomFileIO { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java index dda099bd..5ff34b46 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java @@ -11,12 +11,11 @@ import org.xml.sax.SAXException; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.pom.PomFileIO; /** * This class implements reading a POM file as an XML document. *

- * Use {@link PomFileIO} if you need the Maven POM model. + * Use {@link com.exasol.projectkeeper.validators.pom.PomFileIO} if you need the Maven POM model. */ public class PomFileReader { diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java index dfe56b12..9073739c 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java @@ -12,12 +12,11 @@ import org.w3c.dom.Document; import com.exasol.errorreporting.ExaError; -import com.exasol.projectkeeper.validators.pom.PomFileIO; /** * This class implements write access to a POM file as an XML document. *

- * Use {@link PomFileIO} if you need the Maven POM model. + * Use {@link com.exasol.projectkeeper.validators.pom.PomFileIO} if you need the Maven POM model. */ public class PomFileWriter { From 82080464fa20dd96078433dc9ae8bc607ddacf21 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 8 Feb 2024 14:43:32 +0100 Subject: [PATCH 73/78] Code cleanup --- .../projectkeeper/validators/pom/PomFileValidatorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java index e3b32bf5..15de0da9 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java @@ -123,7 +123,7 @@ void testMissingVersion() { void testMissingVersionButParentPomRef() { getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir); runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null)); - final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom")); + final Model pom = readModel(this.tempDir.resolve("pk_generated_parent.pom")); assertThat(pom.getVersion(), equalTo("1.2.3")); } @@ -134,8 +134,8 @@ void testMissingVersionButFromParent() { not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*"))); } - private Model readModel(final Path projectDir) { - return new PomFileIO().readPom(projectDir); + private Model readModel(final Path file) { + return new PomFileIO().readPom(file); } @Test From 83701de5dcfebd1571bf8e19b259c559d93ceaf0 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 9 Feb 2024 08:22:42 +0100 Subject: [PATCH 74/78] Add unit tests --- .../dependencyupdate/ChangesFileUpdater.java | 31 +++++- .../dependencyupdate/DependencyUpdater.java | 26 ++--- .../ProjectVersionIncrementor.java | 9 ++ .../VulnerabilityInfoProvider.java | 9 ++ .../DependencyUpdaterTest.java | 102 +++++++++++++++--- 5 files changed, 144 insertions(+), 33 deletions(-) create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java index 63637e06..b7ab0979 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java @@ -1,12 +1,41 @@ package com.exasol.projectkeeper.dependencyupdate; +import java.nio.file.Path; + import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; +/** + * This class updates the the changesfile (e.g. {@code doc/changes/changes_1.2.0.md} for a given version, adding + * information about fixed vulnerabilities in dependencies. + */ class ChangesFileUpdater { - ChangesFile update(final ChangesFile changesFile) { + private final ChangesFileIO changesFileIO; + private final Path projectDir; + private final VulnerabilityInfoProvider vulnerabilityInfoProvider; + + ChangesFileUpdater(final VulnerabilityInfoProvider vulnerabilityInfoProvider, final ChangesFileIO changesFileIO, + final Path projectDir) { + this.vulnerabilityInfoProvider = vulnerabilityInfoProvider; + this.changesFileIO = changesFileIO; + this.projectDir = projectDir; + } + + void updateChanges(final String version) { + final Path changesFilePath = getChangesFilePath(version); + final ChangesFile changesFile = changesFileIO.read(changesFilePath); + final ChangesFile updatedChanges = update(changesFile); + changesFileIO.write(updatedChanges, changesFilePath); + } + + private ChangesFile update(final ChangesFile changesFile) { final Builder builder = changesFile.toBuilder(); // Changes file will be updated in the next PR return builder.build(); } + + private Path getChangesFilePath(final String version) { + return projectDir.resolve(ChangesFile.getPathForVersion(version)); + } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java index 224d0cb6..c4ce4335 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java @@ -8,7 +8,6 @@ import com.exasol.projectkeeper.ProjectKeeper; import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig; import com.exasol.projectkeeper.sources.analyze.generic.*; -import com.exasol.projectkeeper.validators.changesfile.ChangesFile; import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; /** @@ -21,21 +20,18 @@ public class DependencyUpdater { private final Logger logger; private final Path projectDir; private final ProjectVersionIncrementor projectVersionIncrementor; - private final ChangesFileIO changesFileIO; private final String currentProjectVersion; private final ChangesFileUpdater changesFileUpdater; private final CommandExecutor commandExecutor; DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir, final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor, - final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater, - final CommandExecutor commandExecutor) { + final ChangesFileUpdater changesFileUpdater, final CommandExecutor commandExecutor) { this.projectKeeper = projectKeeper; this.logger = logger; this.projectDir = projectDir; this.currentProjectVersion = currentProjectVersion; this.projectVersionIncrementor = projectVersionIncrementor; - this.changesFileIO = changesFileIO; this.changesFileUpdater = changesFileUpdater; this.commandExecutor = commandExecutor; } @@ -53,8 +49,9 @@ public class DependencyUpdater { public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config, final Logger logger, final Path projectDir, final String currentProjectVersion) { return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion, - new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(), - new ChangesFileUpdater(), new CommandExecutor()); + new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), + new ChangesFileUpdater(new VulnerabilityInfoProvider(), new ChangesFileIO(), projectDir), + new CommandExecutor()); } /** @@ -72,7 +69,7 @@ public boolean updateDependencies() { final String version = incrementProjectVersion(); updateDependencyVersions(); runProjectKeeperFix(); - updateChangelog(version); + changesFileUpdater.updateChanges(version); return true; } @@ -98,22 +95,11 @@ private void runMaven(final String mavenGoal) { } private void runProjectKeeperFix() { - logger.info("Running project-keeper fix"); + logger.info("Running project-keeper fix..."); if (!projectKeeper.fix()) { throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-177") .message("Running project-keeper fix failed, see errors above.") .mitigation("Fix findings and try again.").toString()); } } - - private void updateChangelog(final String version) { - final Path changesFilePath = getChangesFilePath(version); - final ChangesFile changesFile = changesFileIO.read(changesFilePath); - final ChangesFile updatedChanges = changesFileUpdater.update(changesFile); - changesFileIO.write(updatedChanges, changesFilePath); - } - - private Path getChangesFilePath(final String version) { - return projectDir.resolve(ChangesFile.getPathForVersion(version)); - } } diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java index 3fe8ac8b..86ddf113 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java @@ -18,6 +18,9 @@ import com.exasol.projectkeeper.validators.pom.PomFileIO; import com.vdurmont.semver4j.Semver; +/** + * This class can increment the project's version. + */ class ProjectVersionIncrementor { private static final ZoneId UTC_ZONE = ZoneId.of("UTC"); private final ProjectKeeperConfig config; @@ -75,6 +78,12 @@ private LocalDate today() { return LocalDate.ofInstant(clock.instant(), UTC_ZONE); } + /** + * Increment the project's patch version. If the project produces a JAR (i.e. uses the {@code JAR_ARTIFACT} module), + * it runs its {@code artifact-reference-checker:unify} goal to update references to the JAR file. + * + * @return the new, incremented version + */ String incrementProjectVersion() { final Path path = getPomPath(); final Model pom = pomFileIO.readPom(path); diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java new file mode 100644 index 00000000..345062a1 --- /dev/null +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java @@ -0,0 +1,9 @@ +package com.exasol.projectkeeper.dependencyupdate; + +/** + * This class provides access to information about vulnerabilities in dependencies that are potentially fixed by + * updating dependency versions. + */ +class VulnerabilityInfoProvider { + // Will be implemented in next PR +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java index 27090fdd..73f25455 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java @@ -1,49 +1,127 @@ package com.exasol.projectkeeper.dependencyupdate; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; import java.nio.file.Path; +import java.util.List; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.exasol.projectkeeper.Logger; -import com.exasol.projectkeeper.ProjectKeeper; +import com.exasol.projectkeeper.*; import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor; -import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; +import com.exasol.projectkeeper.sources.analyze.generic.ShellCommand; @ExtendWith(MockitoExtension.class) class DependencyUpdaterTest { private static final Path PROJECT_DIR = Path.of("ProjectDir"); private static final String CURRENT_PROJECT_VERSION = "1.2.3"; + private static final String NEXT_PROJECT_VERSION = "1.2.4"; @Mock private ProjectKeeper projectKeeperMock; @Mock - private Logger loggerMock; - @Mock private ProjectVersionIncrementor projectVersionIncrementorMock; @Mock - private ChangesFileIO changesFileIOMock; - @Mock private ChangesFileUpdater changesFileUpdaterMock; @Mock private CommandExecutor commandExecutorMock; @Test - void updateDependencies() { - // assertUpdate(); + void updateDependenciesIncrementsVersionIfRequired() { + when(projectKeeperMock.fix()).thenReturn(true); + when(projectVersionIncrementorMock.isCurrentVersionReleased()).thenReturn(true); + when(projectVersionIncrementorMock.incrementProjectVersion()).thenReturn(NEXT_PROJECT_VERSION); + assertUpdate(); + verify(projectVersionIncrementorMock).incrementProjectVersion(); + } + + @Test + void updateDependenciesDoesNotIncrementsVersionIfNotRequired() { + when(projectKeeperMock.fix()).thenReturn(true); + when(projectVersionIncrementorMock.isCurrentVersionReleased()).thenReturn(false); + assertUpdate(); + verify(projectVersionIncrementorMock, never()).incrementProjectVersion(); + } + + @Test + void updateDependenciesPKFixFails() { + when(projectKeeperMock.fix()).thenReturn(false); + final DependencyUpdater testee = testee(); + final IllegalStateException exception = assertThrows(IllegalStateException.class, testee::updateDependencies); + assertThat(exception.getMessage(), equalTo( + "E-PK-CORE-177: Running project-keeper fix failed, see errors above. Fix findings and try again.")); + } + + @Test + void updateDependenciesPKFixSucceeds() { + when(projectKeeperMock.fix()).thenReturn(true); + assertUpdate(); + verify(projectKeeperMock).fix(); + } + + @Test + void updateDependenciesRunsVersionsPlugin() { + when(projectKeeperMock.fix()).thenReturn(true); + assertUpdate(); + final List commands = verifyCommandExecuted(); + final ShellCommand useLatestVersion = commands.get(0); + final ShellCommand updateProperties = commands.get(1); + assertThat(useLatestVersion.workingDir().get(), equalTo(PROJECT_DIR)); + assertThat(updateProperties.workingDir().get(), equalTo(PROJECT_DIR)); + final String mavenExecutable = "mvn" + OsCheck.suffix(".cmd"); + assertThat(useLatestVersion.commandline(), + Matchers.contains(mavenExecutable, "--batch-mode", "versions:use-latest-releases")); + assertThat(updateProperties.commandline(), + Matchers.contains(mavenExecutable, "--batch-mode", "versions:update-properties")); + } + + @Test + void updateDependenciesUpdatesChangesFile() { + when(projectKeeperMock.fix()).thenReturn(true); + assertUpdate(); + verify(changesFileUpdaterMock).updateChanges(CURRENT_PROJECT_VERSION); + } + + private List verifyCommandExecuted() { + final ArgumentCaptor arg = ArgumentCaptor.forClass(ShellCommand.class); + verify(commandExecutorMock, times(2)).execute(arg.capture()); + assertThat(arg.getAllValues(), hasSize(2)); + return arg.getAllValues(); } private DependencyUpdater testee() { - return new DependencyUpdater(projectKeeperMock, loggerMock, PROJECT_DIR, CURRENT_PROJECT_VERSION, - projectVersionIncrementorMock, changesFileIOMock, changesFileUpdaterMock, commandExecutorMock); + return new DependencyUpdater(projectKeeperMock, new PrintLogger(), PROJECT_DIR, CURRENT_PROJECT_VERSION, + projectVersionIncrementorMock, changesFileUpdaterMock, commandExecutorMock); } private void assertUpdate() { assertThat(testee().updateDependencies(), is(true)); } + + static class PrintLogger implements Logger { + + @Override + public void info(final String message) { + System.out.println(message); + } + + @Override + public void warn(final String message) { + System.out.println(message); + } + + @Override + public void error(final String message) { + System.out.println(message); + } + + } } From a25e3558dff6322bb8b9a230e9b7d52aa67de529 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 9 Feb 2024 12:23:14 +0100 Subject: [PATCH 75/78] Improve test coverage --- parent-pom/pom.xml | 6 ++ project-keeper/pom.xml | 5 ++ .../exasol/projectkeeper/ProjectKeeper.java | 2 +- .../validators/changesfile/ChangesFile.java | 13 +++-- .../projectkeeper/ProjectKeeperTest.java | 35 ++++++++++++ .../ChangesFileUpdaterTest.java | 55 +++++++++++++++++++ 6 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdaterTest.java diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml index a0ee2850..c7340981 100644 --- a/parent-pom/pom.xml +++ b/parent-pom/pom.xml @@ -202,6 +202,12 @@ 1.2.0 test + + org.junit-pioneer + junit-pioneer + 2.2.0 + test + nl.jqno.equalsverifier equalsverifier diff --git a/project-keeper/pom.xml b/project-keeper/pom.xml index 08f81c72..1a18ef16 100644 --- a/project-keeper/pom.xml +++ b/project-keeper/pom.xml @@ -97,6 +97,11 @@ to-string-verifier test + + org.junit-pioneer + junit-pioneer + test + org.slf4j diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java index 6f9f1cdd..e17eba8d 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java @@ -61,7 +61,7 @@ public static ProjectKeeper createProjectKeeper(final Logger logger, final Path return new ProjectKeeper(logger, projectDir, mvnRepo, readConfig(projectDir), getOwnVersion()); } - private static String getOwnVersion() { + static String getOwnVersion() { final String packageVersion = ProjectKeeper.class.getPackage().getImplementationVersion(); if (packageVersion != null) { return packageVersion; diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java index 05a08ca0..bc4a5f0f 100644 --- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java +++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java @@ -60,9 +60,14 @@ public static Builder builder() { * @return a preconfigured builder */ public Builder toBuilder() { - return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString()) - .releaseDate(this.releaseDate).codeName(this.codeName).summary(this.summarySection) - .sections(List.copyOf(this.sections)).dependencyChangeSection(this.dependencyChangeSection); + return builder() // + .projectName(this.projectName) + .projectVersion(this.projectVersion != null ? this.projectVersion.toString() : null) + .releaseDate(this.releaseDate) // + .codeName(this.codeName) // + .summary(this.summarySection) // + .sections(List.copyOf(this.sections)) // + .dependencyChangeSection(this.dependencyChangeSection); } /** @@ -208,7 +213,7 @@ public Builder projectName(final String projectName) { * @return self for fluent programming */ public Builder projectVersion(final String projectVersion) { - this.projectVersion = new Semver(projectVersion); + this.projectVersion = projectVersion != null ? new Semver(projectVersion) : null; return this; } diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java new file mode 100644 index 00000000..c4009ed8 --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java @@ -0,0 +1,35 @@ +package com.exasol.projectkeeper; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junitpioneer.jupiter.ClearSystemProperty; +import org.junitpioneer.jupiter.SetSystemProperty; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ProjectKeeperTest { + + @Mock + private Logger loggerMock; + + @Test + void createProjectKeeper() { + assertThat(ProjectKeeper.createProjectKeeper(null, null, null), not(nullValue())); + } + + @Test + @ClearSystemProperty(key = "com.exasol.projectkeeper.ownVersion") + void getOwnVersionWithoutSystemProperty() { + assertThat(ProjectKeeper.getOwnVersion(), equalTo("(unknownVersion)")); + } + + @Test + @SetSystemProperty(key = "com.exasol.projectkeeper.ownVersion", value = "version") + void getOwnVersionWithSystemProperty() { + assertThat(ProjectKeeper.getOwnVersion(), equalTo("version")); + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdaterTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdaterTest.java new file mode 100644 index 00000000..860be44b --- /dev/null +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdaterTest.java @@ -0,0 +1,55 @@ +package com.exasol.projectkeeper.dependencyupdate; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.projectkeeper.validators.changesfile.ChangesFile; +import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO; + +@ExtendWith(MockitoExtension.class) +class ChangesFileUpdaterTest { + + private static final String VERSION = "1.2.3"; + private static final Path PROJECT_DIR = Path.of("projectDir"); + private static final Path CHANGES_FILE = PROJECT_DIR.resolve("doc/changes/").resolve("changes_" + VERSION + ".md"); + @Mock + VulnerabilityInfoProvider vulnerabilityInfoProviderMock; + @Mock + ChangesFileIO changesFileIOMock; + + @Test + void updateChangesFileWritesChangesFile() { + assertChangesUpdated(ChangesFile.builder().build()); + } + + private ChangesFile assertChangesUpdated(final ChangesFile inputChangesFile) { + when(changesFileIOMock.read(CHANGES_FILE)).thenReturn(inputChangesFile); + testee().updateChanges(VERSION); + final ChangesFile updatedChangesFile = verifyChangesFileWritten(); + assertAll(() -> assertThat(updatedChangesFile, not(nullValue())), + () -> assertThat(updatedChangesFile, not(sameInstance(inputChangesFile)))); + return updatedChangesFile; + } + + private ChangesFile verifyChangesFileWritten() { + final ArgumentCaptor arg = ArgumentCaptor.forClass(ChangesFile.class); + verify(changesFileIOMock).write(arg.capture(), eq(CHANGES_FILE)); + return arg.getValue(); + } + + private ChangesFileUpdater testee() { + return new ChangesFileUpdater(vulnerabilityInfoProviderMock, changesFileIOMock, PROJECT_DIR); + } +} From 24b62bd89b5c62c6b97572e37a2920cd2734e310 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 9 Feb 2024 12:28:12 +0100 Subject: [PATCH 76/78] Run PK fix --- dependencies.md | 66 ++++++++++--------- doc/changes/changes_4.0.0.md | 1 + .../projectkeeper/ProjectKeeperTest.java | 7 +- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/dependencies.md b/dependencies.md index c623cd8e..75c41e0a 100644 --- a/dependencies.md +++ b/dependencies.md @@ -76,6 +76,7 @@ | [Maven Plugin Integration Testing][54] | [MIT License][55] | | [EqualsVerifier \| release normal jar][15] | [Apache License, Version 2.0][16] | | [to-string-verifier][17] | [MIT License][18] | +| [junit-pioneer][56] | [Eclipse Public License v2.0][11] | | [SLF4J JDK14 Binding][21] | [MIT License][18] | ### Runtime Dependencies @@ -90,7 +91,7 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | @@ -103,7 +104,7 @@ | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -147,15 +148,15 @@ | [Maven Surefire Plugin][30] | [Apache-2.0][16] | | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | -| [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | -| [Artifact reference checker and unifier][59] | [MIT License][60] | +| [Apache Maven Assembly Plugin][59] | [Apache-2.0][16] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | +| [Artifact reference checker and unifier][60] | [MIT License][61] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -167,9 +168,9 @@ | Dependency | License | | ----------------------------------------- | --------------------- | | [Project Keeper Core][45] | [The MIT License][46] | -| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | -| [Maven Plugin API][62] | [Apache-2.0][16] | -| [Maven Core][63] | [Apache-2.0][16] | +| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][16] | +| [Maven Plugin API][63] | [Apache-2.0][16] | +| [Maven Core][64] | [Apache-2.0][16] | | [error-reporting-java][7] | [MIT License][8] | ### Test Dependencies @@ -184,7 +185,7 @@ | [mockito-core][19] | [MIT][20] | | [Maven Plugin Integration Testing][54] | [MIT License][55] | | [SLF4J JDK14 Binding][21] | [MIT License][18] | -| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | +| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][41] | ### Plugin Dependencies @@ -192,22 +193,22 @@ | ------------------------------------------------------- | --------------------------------- | | [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] | | [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | +| [Maven Plugin Plugin][66] | [Apache-2.0][16] | | [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] | | [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] | | [Maven Flatten Plugin][27] | [Apache Software Licenese][16] | | [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | | [Maven Surefire Plugin][30] | [Apache-2.0][16] | | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] | +| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [Apache Maven Dependency Plugin][67] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -219,12 +220,12 @@ | Dependency | License | | ----------------------------------------- | ---------------------------------------------- | | [Project Keeper shared model classes][45] | [The MIT License][46] | -| [Maven Plugin Tools Java Annotations][61] | [Apache-2.0][16] | -| [Maven Plugin API][62] | [Apache-2.0][16] | +| [Maven Plugin Tools Java Annotations][62] | [Apache-2.0][16] | +| [Maven Plugin API][63] | [Apache-2.0][16] | | [error-reporting-java][7] | [MIT License][8] | | [JGit - Core][9] | Eclipse Distribution License (New BSD License) | | [semver4j][49] | [The MIT License][18] | -| [Maven Core][63] | [Apache-2.0][16] | +| [Maven Core][64] | [Apache-2.0][16] | ### Test Dependencies @@ -239,7 +240,7 @@ | [mockito-core][19] | [MIT][20] | | [mockito-junit-jupiter][19] | [MIT][20] | | [Maven Plugin Integration Testing][54] | [MIT License][55] | -| [JaCoCo :: Agent][64] | [Eclipse Public License 2.0][41] | +| [JaCoCo :: Agent][65] | [Eclipse Public License 2.0][41] | ### Plugin Dependencies @@ -253,15 +254,15 @@ | [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] | | [Maven Surefire Plugin][30] | [Apache-2.0][16] | | [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] | -| [Maven Plugin Plugin][65] | [Apache-2.0][16] | +| [Maven Plugin Plugin][66] | [Apache-2.0][16] | | [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] | | [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] | | [Apache Maven GPG Plugin][35] | [Apache-2.0][16] | | [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] | | [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] | | [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] | -| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] | -| [Maven Failsafe Plugin][57] | [Apache-2.0][16] | +| [Apache Maven Dependency Plugin][67] | [Apache-2.0][16] | +| [Maven Failsafe Plugin][58] | [Apache-2.0][16] | | [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] | | [error-code-crawler-maven-plugin][42] | [MIT License][43] | | [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] | @@ -350,14 +351,15 @@ [53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE [54]: https://github.com/exasol/maven-plugin-integration-testing/ [55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE -[56]: https://maven.apache.org/plugins/maven-jar-plugin/ -[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/ -[58]: https://maven.apache.org/plugins/maven-assembly-plugin/ -[59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ -[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE -[61]: https://maven.apache.org/plugin-tools/maven-plugin-annotations -[62]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ -[63]: https://maven.apache.org/ref/3.9.6/maven-core/ -[64]: https://www.eclemma.org/jacoco/index.html -[65]: https://maven.apache.org/plugin-tools/maven-plugin-plugin -[66]: https://maven.apache.org/plugins/maven-dependency-plugin/ +[56]: https://junit-pioneer.org/ +[57]: https://maven.apache.org/plugins/maven-jar-plugin/ +[58]: https://maven.apache.org/surefire/maven-failsafe-plugin/ +[59]: https://maven.apache.org/plugins/maven-assembly-plugin/ +[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ +[61]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE +[62]: https://maven.apache.org/plugin-tools/maven-plugin-annotations +[63]: https://maven.apache.org/ref/3.9.6/maven-plugin-api/ +[64]: https://maven.apache.org/ref/3.9.6/maven-core/ +[65]: https://www.eclemma.org/jacoco/index.html +[66]: https://maven.apache.org/plugin-tools/maven-plugin-plugin +[67]: https://maven.apache.org/plugins/maven-dependency-plugin/ diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md index bee44ffd..7204f7d9 100644 --- a/doc/changes/changes_4.0.0.md +++ b/doc/changes/changes_4.0.0.md @@ -40,6 +40,7 @@ Code name: Automatic Security Updates * Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0` * Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6` +* Added `org.junit-pioneer:junit-pioneer:2.2.0` * Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2` * Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2` * Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0` diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java index c4009ed8..97ef4e3e 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java @@ -1,7 +1,7 @@ package com.exasol.projectkeeper; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalTo; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,11 +16,6 @@ class ProjectKeeperTest { @Mock private Logger loggerMock; - @Test - void createProjectKeeper() { - assertThat(ProjectKeeper.createProjectKeeper(null, null, null), not(nullValue())); - } - @Test @ClearSystemProperty(key = "com.exasol.projectkeeper.ownVersion") void getOwnVersionWithoutSystemProperty() { From 340dad576d25efd18299ec70e17431c0e82ce10d Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 22 Feb 2024 12:25:22 +0100 Subject: [PATCH 77/78] Implement review findings --- .../cli/ProjectKeeperLauncher.java | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java index 8e4c344a..a54d8c8b 100644 --- a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java +++ b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.nio.file.Path; import java.util.Arrays; +import java.util.Map; import java.util.logging.*; import com.exasol.errorreporting.ExaError; @@ -19,7 +20,12 @@ public class ProjectKeeperLauncher { private static final Logger LOGGER = Logger.getLogger(ProjectKeeperLauncher.class.getName()); private static final String GOAL_VERIFY = "verify"; private static final String GOAL_FIX = "fix"; - private static final String GOAL_UPGRADE_DEPENDENCIES = "update-dependencies"; + private static final String GOAL_UPDATE_DEPENDENCIES = "update-dependencies"; + private static final Map ACCEPT_GOALS = Map.of( // + GOAL_VERIFY, ProjectKeeper::verify, // + GOAL_FIX, ProjectKeeper::fix, // + GOAL_UPDATE_DEPENDENCIES, ProjectKeeper::updateDependencies // + ); private final Path currentWorkingDir; @@ -61,21 +67,8 @@ void start(final String[] args) { private void runProjectKeeper(final String goal) { final ProjectKeeper projectKeeper = createProjectKeeper(); - final boolean success; - switch (goal) { - case GOAL_FIX: - success = projectKeeper.fix(); - break; - case GOAL_VERIFY: - success = projectKeeper.verify(); - break; - case GOAL_UPGRADE_DEPENDENCIES: - success = projectKeeper.updateDependencies(); - break; - default: - success = false; - break; - } + final ProjectKeeperGoal method = getProjectKeeperGoal(goal); + final boolean success = method.execute(projectKeeper); if (!success) { throw new IllegalStateException( ExaError.messageBuilder("E-PK-CLI-1").message("Failed to run project keeper {{goal}}", goal) @@ -83,17 +76,27 @@ private void runProjectKeeper(final String goal) { } } + private ProjectKeeperGoal getProjectKeeperGoal(final String goal) { + final ProjectKeeperGoal failure = pk -> { + LOGGER.warning(() -> ExaError.messageBuilder("goal").message("Goal {{goal}} not supported.", goal) + .mitigation("Use one of the supported goals: {{supported goals}}", ACCEPT_GOALS.keySet()) + .toString()); + return false; + }; + return ACCEPT_GOALS.getOrDefault(goal, failure); + } + private ProjectKeeper createProjectKeeper() { return ProjectKeeper.createProjectKeeper(new JULLogger(), this.currentWorkingDir, null); } private void verifyCommandLineArguments(final String[] args) { if ((args == null) || (args.length != 1) || !(GOAL_FIX.equals(args[0]) || GOAL_VERIFY.equals(args[0]) - || GOAL_UPGRADE_DEPENDENCIES.equals(args[0]))) { + || GOAL_UPDATE_DEPENDENCIES.equals(args[0]))) { throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CLI-2") .message("Got no or invalid command line argument {{arguments}}.", Arrays.toString(args)) .mitigation("Please only specify arguments '" + GOAL_VERIFY + "', '" + GOAL_FIX + "' or '" - + GOAL_UPGRADE_DEPENDENCIES + "'.") + + GOAL_UPDATE_DEPENDENCIES + "'.") .toString()); } } @@ -114,4 +117,9 @@ public void error(final String message) { LOGGER.severe(message); } } + + @FunctionalInterface + private interface ProjectKeeperGoal { + boolean execute(ProjectKeeper projectKeeper); + } } From 6f7f870bbbff4112a06f8dede28de830d375c903 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Thu, 22 Feb 2024 14:51:56 +0100 Subject: [PATCH 78/78] Fix error code --- project-keeper-cli/error_code_config.yml | 2 +- .../com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project-keeper-cli/error_code_config.yml b/project-keeper-cli/error_code_config.yml index c6f74982..7df60e7b 100644 --- a/project-keeper-cli/error_code_config.yml +++ b/project-keeper-cli/error_code_config.yml @@ -2,4 +2,4 @@ error-tags: PK-CLI: packages: - com.exasol.projectkeeper.cli - highest-index: 4 \ No newline at end of file + highest-index: 5 diff --git a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java index a54d8c8b..242ae2bc 100644 --- a/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java +++ b/project-keeper-cli/src/main/java/com/exasol/projectkeeper/cli/ProjectKeeperLauncher.java @@ -78,7 +78,7 @@ private void runProjectKeeper(final String goal) { private ProjectKeeperGoal getProjectKeeperGoal(final String goal) { final ProjectKeeperGoal failure = pk -> { - LOGGER.warning(() -> ExaError.messageBuilder("goal").message("Goal {{goal}} not supported.", goal) + LOGGER.warning(() -> ExaError.messageBuilder("E-PK-CLI-5").message("Goal {{goal}} not supported.", goal) .mitigation("Use one of the supported goals: {{supported goals}}", ACCEPT_GOALS.keySet()) .toString()); return false;