diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml new file mode 100644 index 0000000..becfcb3 --- /dev/null +++ b/.github/workflows/pr-validation.yml @@ -0,0 +1,48 @@ +name: Pull request validation + +on: + pull_request: + branches: + - main + types: + - opened + - edited + - synchronize + +jobs: + pr-validation: + runs-on: ubuntu-latest + + steps: + - name: PR title validation + uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + docs + refactor + chore + fix + feat + breaking + requireScope: false + subjectPattern: ^[A-Z].+$ + subjectPatternError: | + The subject "{subject}" found in the pull request title "{title}" + doesn't match the configured pattern. Please ensure that the subject + starts with an uppercase character. + wip: false + + - name: Checkout the repository + uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Execute unit-testing + run: mvn clean test \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..67d8013 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,83 @@ +name: Release a new version + +on: + pull_request: + types: + - closed + branches: + - main + +jobs: + release: + if: github.event.pull_request.merged == true + + runs-on: ubuntu-latest + + outputs: + new_release_published: ${{ steps.semantic.outputs.new_release_published }} + new_release_version: ${{ steps.semantic.outputs.new_release_version }} + + steps: + # + # Checkout the source code. + # + - name: Checkout the source code + uses: actions/checkout@v3 + with: + token: ${{ secrets.GIT_PAT }} + + # + # Calculation of the new version (dry-run). + # + - name: Calculation of the new version (dry-run) + uses: cycjimmy/semantic-release-action@v3 + id: semantic + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + semantic_version: 19 + branch: main + extra_plugins: | + @semantic-release/release-notes-generator@10.0.3 + @semantic-release/git@10.0.1 + dry_run: true + + # + # Setup the JDK. + # + - name: Setup the JDK + if: steps.semantic.outputs.new_release_published == 'true' + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + # + # Update of pom.xml with the new version + Git add + commit + push of the updated pom.xml. + # + - name: Update of pom.xml with the new version + Git add + commit + push of the updated pom.xml + if: steps.semantic.outputs.new_release_published == 'true' + run: | + mvn versions:set -DnewVersion=${{ steps.semantic.outputs.new_release_version }} + git config user.name "GitHub Workflow" + git config user.email "<>" + git add pom.xml + git commit -m "pom.xml updated with new version ${{ steps.semantic.outputs.new_release_version }}" + git push origin main + + # + # Calculation of the new version (again) with tagging + releasing + etc. + # + - name: Calculation of the new version (again) with tagging + releasing + etc + if: steps.semantic.outputs.new_release_published == 'true' + uses: cycjimmy/semantic-release-action@v3 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + semantic_version: 19 + branch: main + extra_plugins: | + @semantic-release/release-notes-generator@10.0.3 + @semantic-release/git@10.0.1 + dry_run: false \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..20031e7 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,23 @@ +{ + "branches": [ + "main" + ], + "ci": false, + "tagFormat": "${version}", + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "angular", + "releaseRules": [ + { + "type": "breaking", + "release": "major" + } + ] + } + ], + "@semantic-release/release-notes-generator", + "@semantic-release/github" + ] +} diff --git a/src/main/java/it/gov/pagopa/swclient/mil/ErrorCode.java b/src/main/java/it/gov/pagopa/swclient/mil/ErrorCode.java index a94edb5..55bdf9f 100644 --- a/src/main/java/it/gov/pagopa/swclient/mil/ErrorCode.java +++ b/src/main/java/it/gov/pagopa/swclient/mil/ErrorCode.java @@ -26,6 +26,9 @@ public final class ErrorCode { public static final String TERMINAL_ID_MUST_NOT_BE_NULL = MODULE_ID + "000009"; public static final String TERMINAL_ID_MUST_MATCH_REGEXP = MODULE_ID + "00000A"; + + public static final String MERCHANT_ID_MUST_NOT_BE_NULL_FOR_POS = MODULE_ID + "00000B"; + public static final String MERCHANT_ID_MUST_MATCH_REGEXP = MODULE_ID + "00000C"; private ErrorCode() { } diff --git a/src/main/java/it/gov/pagopa/swclient/mil/bean/CommonHeader.java b/src/main/java/it/gov/pagopa/swclient/mil/bean/CommonHeader.java index 19d905b..defd6f2 100644 --- a/src/main/java/it/gov/pagopa/swclient/mil/bean/CommonHeader.java +++ b/src/main/java/it/gov/pagopa/swclient/mil/bean/CommonHeader.java @@ -11,12 +11,14 @@ import javax.ws.rs.HeaderParam; import it.gov.pagopa.swclient.mil.ErrorCode; +import it.gov.pagopa.swclient.mil.validation.constraints.MerchantIdNotNullForPos; /** * Common header attributes * * @author Antonio Tarricone */ +@MerchantIdNotNullForPos(message = "[" + ErrorCode.MERCHANT_ID_MUST_NOT_BE_NULL_FOR_POS + "] If Channel equals to POS, MerchantId must not be null") public class CommonHeader { /* * Request ID @@ -51,11 +53,18 @@ public class CommonHeader { private String channel; /* - * ID of the terminal originating the transaction. It must be unique per acquirer and channel. + * Merchant ID originating the transaction. If Channel equals to POS, MerchantId must not be null. + */ + @HeaderParam("MerchantId") + @Pattern(regexp = "^[0-9a-zA-Z]{4,8}$", message = "[" + ErrorCode.MERCHANT_ID_MUST_MATCH_REGEXP + "] MerchantId must match \"{regexp}\"") + private String merchantId; + + /* + * ID of the terminal originating the transaction. It must be unique per acquirer, channel and merchant if present. */ @HeaderParam("TerminalId") @NotNull(message = "[" + ErrorCode.TERMINAL_ID_MUST_NOT_BE_NULL + "] TerminalId must not be null") - @Pattern(regexp = "^[0-9a-zA-Z]{8}$", message = "[" + ErrorCode.TERMINAL_ID_MUST_MATCH_REGEXP + "] TerminalId must match \"{regexp}\"") + @Pattern(regexp = "^[0-9a-zA-Z]{4,8}$", message = "[" + ErrorCode.TERMINAL_ID_MUST_MATCH_REGEXP + "] TerminalId must match \"{regexp}\"") private String terminalId; /** @@ -113,6 +122,20 @@ public String getChannel() { public void setChannel(String channel) { this.channel = channel; } + + /** + * @return the merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * @param merchantId the merchantId to set + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } /** * @return the terminalId @@ -131,7 +154,7 @@ public void setTerminalId(String terminalId) { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("CommonHeader [requestId=").append(requestId).append(", version=").append(version).append(", acquirerId=").append(acquirerId).append(", channel=").append(channel).append(", terminalId=").append(terminalId).append("]"); + builder.append("CommonHeader [requestId=").append(requestId).append(", version=").append(version).append(", acquirerId=").append(acquirerId).append(", channel=").append(channel).append(", merchantId=").append(merchantId).append(", terminalId=").append(terminalId).append("]"); return builder.toString(); } } diff --git a/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPos.java b/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPos.java new file mode 100644 index 0000000..49b67d1 --- /dev/null +++ b/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPos.java @@ -0,0 +1,31 @@ +/* + * MerchantIdNotNullForPos.java + * + * 20 gen 2023 + */ +package it.gov.pagopa.swclient.mil.validation.constraints; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +/** + * If Channel equals to POS, the MerchantId must not be null. + * + * @author Antonio Tarricone + */ +@Documented +@Retention(RUNTIME) +@Target(TYPE) +@Constraint(validatedBy = { MerchantIdNotNullForPosValidator.class }) +public @interface MerchantIdNotNullForPos { + String message() default ""; + Class[] groups() default {}; + Class[] payload() default {}; +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPosValidator.java b/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPosValidator.java new file mode 100644 index 0000000..744b37b --- /dev/null +++ b/src/main/java/it/gov/pagopa/swclient/mil/validation/constraints/MerchantIdNotNullForPosValidator.java @@ -0,0 +1,25 @@ +/* + * MerchantIdNotNullForPosValidator.java + * + * 20 gen 2023 + */ +package it.gov.pagopa.swclient.mil.validation.constraints; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import it.gov.pagopa.swclient.mil.bean.CommonHeader; + +/** + * If Channel equals to POS, the MerchantId must not be null. + * + * @author Antonio Tarricone + */ +public class MerchantIdNotNullForPosValidator implements ConstraintValidator { + @Override + public boolean isValid(CommonHeader commonHeader, ConstraintValidatorContext context) { + String channel = commonHeader.getChannel(); + String merchantId = commonHeader.getMerchantId(); + return !(channel != null && channel.equals("POS") && merchantId == null); + } +}