From badd1f8bace18887fd56948d0f364ea1e1314f89 Mon Sep 17 00:00:00 2001 From: Andrea Ferracci Date: Fri, 20 Dec 2024 12:12:12 +0100 Subject: [PATCH] Initial commit --- .devops/code-review-pipelines.yml | 64 ++++ .devops/deploy-pipelines-aks.yml | 223 +++++++++++++ .devops/deploy-pipelines-standard.yml | 298 ++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 36 +++ .github/auto_assign.yml | 3 + .github/release.yml | 18 ++ .github/workflows/anchore.yml | 54 ++++ .github/workflows/assignee.yml | 26 ++ .github/workflows/check_metadata_pr.yml | 35 ++ .github/workflows/deploy.yml | 58 ++++ .github/workflows/sonar_analysis.yml | 28 ++ .gitignore | 39 +++ .java-version | 1 + .pre-commit-config.yaml | 11 + CODEOWNERS | 3 + Dockerfile | 22 ++ LICENSE | 21 ++ README.md | 42 +++ helm/.helmignore | 23 ++ helm/Chart.lock | 6 + helm/Chart.yaml | 10 + helm/values-dev.yaml | 73 +++++ helm/values-prod.yaml | 73 +++++ helm/values-uat.yaml | 73 +++++ host.json | 26 ++ local.settings.json.example | 6 + pom.xml | 273 ++++++++++++++++ .../java/it/gov/pagopa/project/Example.java | 41 +++ src/main/resources/application.properties | 1 + .../it/gov/pagopa/project/ExampleTest.java | 51 +++ 30 files changed, 1638 insertions(+) create mode 100644 .devops/code-review-pipelines.yml create mode 100644 .devops/deploy-pipelines-aks.yml create mode 100644 .devops/deploy-pipelines-standard.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/auto_assign.yml create mode 100644 .github/release.yml create mode 100644 .github/workflows/anchore.yml create mode 100644 .github/workflows/assignee.yml create mode 100644 .github/workflows/check_metadata_pr.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/sonar_analysis.yml create mode 100644 .gitignore create mode 100644 .java-version create mode 100644 .pre-commit-config.yaml create mode 100644 CODEOWNERS create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 helm/.helmignore create mode 100644 helm/Chart.lock create mode 100644 helm/Chart.yaml create mode 100644 helm/values-dev.yaml create mode 100644 helm/values-prod.yaml create mode 100644 helm/values-uat.yaml create mode 100644 host.json create mode 100644 local.settings.json.example create mode 100644 pom.xml create mode 100644 src/main/java/it/gov/pagopa/project/Example.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/it/gov/pagopa/project/ExampleTest.java diff --git a/.devops/code-review-pipelines.yml b/.devops/code-review-pipelines.yml new file mode 100644 index 0000000..1ddfe59 --- /dev/null +++ b/.devops/code-review-pipelines.yml @@ -0,0 +1,64 @@ +# Maven +# Build your Java project and run tests with Apache Maven. +# Add steps that analyze code, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/java + +# Automatically triggered on PR +# https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#pr-trigger +trigger: + - main +pr: + - main + +pool: + vmImage: 'ubuntu-latest' + +variables: + MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository + MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)' + +steps: + - task: Cache@2 + inputs: + key: 'maven | "$(Agent.OS)" | pom.xml' + restoreKeys: | + maven | "$(Agent.OS)" + maven + path: $(MAVEN_CACHE_FOLDER) + displayName: Cache Maven local repo + + - task: SonarCloudPrepare@1 + displayName: 'Prepare SonarCloud analysis configuration' + inputs: + SonarCloud: '$(SONARCLOUD_SERVICE_CONN)' + organization: '$(SONARCLOUD_ORG)' + scannerMode: Other + extraProperties: | + sonar.projectKey=$(SONARCLOUD_PROJECT_KEY) + sonar.projectName=$(SONARCLOUD_PROJECT_NAME) + sonar.coverage.exclusions=**/config/*,**/*Mock*,**/model/**,**/entity/* + sonar.cpd.exclusions=**/model/**,**/entity/* + + + - task: Maven@3 + displayName: 'Run Junit Test' + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' + mavenVersionOption: 'Default' + mavenAuthenticateFeed: false + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + publishJUnitResults: true + testResultsFiles: '**/surefire-reports/TEST-*.xml' + goals: 'clean verify' + sonarQubeRunAnalysis: true + codeCoverageToolOption: 'JaCoCo' + effectivePomSkip: false + isJacocoCoverageReportXML: true + sqMavenPluginVersionChoice: 'latest' + + - task: SonarCloudPublish@1 + displayName: 'Publish SonarCloud results on build summary' + inputs: + pollingTimeoutSec: '300' diff --git a/.devops/deploy-pipelines-aks.yml b/.devops/deploy-pipelines-aks.yml new file mode 100644 index 0000000..8bf1700 --- /dev/null +++ b/.devops/deploy-pipelines-aks.yml @@ -0,0 +1,223 @@ +# Only manual triggers +trigger: none +pr: none + +pool: + vmImage: 'ubuntu-22.04' + +parameters: + - name: ENV + displayName: Target Environment + type: string + default: dev + values: + - dev + - uat + - prod + - name: SEMVER + displayName: "When packing a release, define the version bump to apply. Use only buildNumber or skip for manual deployment" + type: string + values: + - major + - minor + - patch + - buildNumber + - skip + default: skip + - name: "FORCE_REPLACE_DOCKER_IMAGE" + displayName: "Force the existing docker image to be replaced" + type: boolean + default: False + values: + - False + - True + - name: TEST + displayName: Run integration/smoke tests + type: boolean + default: true + +variables: + imageRepository: '$(IMAGE_REPOSITORY_NAME)' + nameSpace: '$(K8S_NAMESPACE)' + + ${{ if eq(parameters['ENV'], 'dev') }}: + dockerRegistryServiceConnection: $(DEV_CONTAINER_REGISTRY_SERVICE_CONN) + dockerRegistryFqdn: $(DEV_CONTAINER_NAMESPACE) + kubernetesServiceConnection: '$(DEV_KUBERNETES_SERVICE_CONN)' + poolImage: 'pagopa-dev-linux' + appInsightsServiceConn: "$(TF_APPINSIGHTS_SERVICE_CONN_DEV)" + appInsightsResourceId: "$(TF_APPINSIGHTS_RESOURCE_ID_DEV)" + ${{ if eq(parameters['ENV'], 'uat') }}: + dockerRegistryServiceConnection: $(UAT_CONTAINER_REGISTRY_SERVICE_CONN) + dockerRegistryFqdn: $(UAT_CONTAINER_NAMESPACE) + kubernetesServiceConnection: '$(UAT_KUBERNETES_SERVICE_CONN)' + poolImage: 'pagopa-uat-linux' + appInsightsServiceConn: "$(TF_APPINSIGHTS_SERVICE_CONN_UAT)" + appInsightsResourceId: "$(TF_APPINSIGHTS_RESOURCE_ID_UAT)" + ${{ if eq(parameters['ENV'], 'prod') }}: + dockerRegistryServiceConnection: $(PROD_CONTAINER_REGISTRY_SERVICE_CONN) + dockerRegistryFqdn: $(PROD_CONTAINER_NAMESPACE) + kubernetesServiceConnection: '$(PROD_KUBERNETES_SERVICE_CONN)' + poolImage: 'pagopa-prod-linux' + appInsightsServiceConn: "$(TF_APPINSIGHTS_SERVICE_CONN_PROD)" + appInsightsResourceId: "$(TF_APPINSIGHTS_RESOURCE_ID_PROD)" + + ${{ if eq(variables['Build.SourceBranchName'], 'merge') }}: + sourceBranch: "main" # force to main branch + ${{ if ne(variables['Build.SourceBranchName'], 'merge') }}: + sourceBranch: ${{ variables['Build.SourceBranchName'] }} + + + +resources: + repositories: + - repository: pagopaCommons + type: github + name: pagopa/azure-pipeline-templates + ref: refs/tags/v2.10.1 + endpoint: 'io-azure-devops-github-ro' + +stages: + + # Create a release on GitHub + - stage: Release + jobs: + - job: make_release + steps: + - checkout: self + clean: true + persistCredentials: true + + - ${{ if ne(parameters.SEMVER, 'skip') }}: + - template: templates/maven-github-release/template.yaml@pagopaCommons + parameters: + release_branch: $(sourceBranch) + gitEmail: $(GIT_EMAIL) + gitUsername: $(GIT_USERNAME) + gitHubConnection: $(GITHUB_CONNECTION) + ${{ if ne(parameters.SEMVER, 'skip') }}: + semver: '${{ parameters.SEMVER }}' + ${{ if eq(parameters.SEMVER, 'skip') }}: + semver: 'buildNumber' # this case is impossible due to main condition, but it is necessary to work property + + - template: templates/maven-github-current-version/template.yaml@pagopaCommons + + # Build and Push Docker Image + - stage: Build + dependsOn: Release + variables: + current_version: $[ stageDependencies.Release.make_release.outputs['current_version.value'] ] + jobs: + - job: "build" + steps: + - checkout: self + persistCredentials: true + + - script: | + git checkout $(sourceBranch) + displayName: Checkout and update branch + + - template: templates/docker-release/template.yaml@pagopaCommons + parameters: + CONTAINER_REGISTRY_SERVICE_CONN: $(dockerRegistryServiceConnection) + CONTAINER_REGISTRY_FQDN: $(dockerRegistryFqdn) + DOCKER_IMAGE_NAME: $(imageRepository) + DOCKER_IMAGE_TAG: $(current_version) + FORCE_REPLACE_DOCKER_IMAGE: ${{ parameters.FORCE_REPLACE_DOCKER_IMAGE }} + +# # Testing the docker image +# - stage: Smoke_Test +# dependsOn: +# - Build +# condition: and(succeeded(), eq('${{ parameters.TEST }}', 'true')) +# jobs: +# - job: smoke_tests +# steps: +# - checkout: self +# persistCredentials: true +# +# - script: | +# git checkout $(sourceBranch) +# displayName: Checkout and update branch +# +# - task: Docker@2 +# displayName: "Docker login" +# inputs: +# containerRegistry: "$(dockerRegistryServiceConnection)" +# command: "login" +# +# - task: Bash@3 +# displayName: 'Run Smoke Tests' +# inputs: +# targetType: 'inline' +# script: | +# cd ./integration-test +# sh run_integration_test.sh +# env: +# containerRegistry: $(dockerRegistryFqdn) + + # Deploy on K8s with Helm + - stage: Deploy +# condition: not(failed('Smoke_Test')) + dependsOn: + - Release + - Build +# - Smoke_Test + variables: + deploy_version: $[ stageDependencies.Release.make_release.outputs['current_version.value'] ] + jobs: + - deployment: "deploy" + pool: + name: $(poolImage) + environment: ${{ parameters['ENV'] }} + strategy: + runOnce: + deploy: + steps: + - checkout: self + persistCredentials: true + + - script: | + git checkout $(sourceBranch) + displayName: Checkout and update branch + + - template: templates/helm-microservice-chart-setup/template.yaml@pagopaCommons + parameters: + DEPLOY_VERSION: $(deploy_version) + + - template: templates/helm-microservice-chart-deploy/template.yaml@pagopaCommons + parameters: + DO_DEPLOY: true + ENV: ${{ parameters['ENV'] }} + KUBERNETES_SERVICE_CONN: ${{ variables.kubernetesServiceConnection }} + NAMESPACE: $(nameSpace) + APP_NAME: $(imageRepository) + VALUE_FILE: "helm/values-${{ parameters['ENV'] }}.yaml" + DEPLOY_VERSION: $(deploy_version) + APPINSIGHTS_SERVICE_CONN: ${{ variables.appInsightsServiceConn }} + APPINSIGHTS_RESOURCE_ID: ${{ variables.appInsightsResourceId }} + + + # Run Tests +# - stage: Integration_Test +# dependsOn: +# - Deploy +# condition: and(succeeded(), eq('${{ parameters.TEST }}', 'true')) +# jobs: +# - job: integration_tests +# steps: +# - checkout: self +# persistCredentials: true +# +# - script: | +# git checkout $(sourceBranch) +# displayName: Checkout and update branch +# +# - task: Bash@3 +# displayName: 'Run Integration Tests' +# inputs: +# targetType: 'inline' +# script: | +# cd ./integration-test/src +# yarn install +# yarn test:${{ parameters.ENV }} diff --git a/.devops/deploy-pipelines-standard.yml b/.devops/deploy-pipelines-standard.yml new file mode 100644 index 0000000..e134ac5 --- /dev/null +++ b/.devops/deploy-pipelines-standard.yml @@ -0,0 +1,298 @@ +parameters: + - name: ENV + displayName: Target Environment + type: string + default: dev + values: + - dev + - uat + - prod + - name: SEMVER + displayName: "When packing a release, define the version bump to apply. Use only buildNumber or skip for manual deployment" + type: string + values: + - major + - minor + - patch + - buildNumber + - skip + default: skip + - name: TEST + displayName: Run tests + type: boolean + default: false + +variables: + ${{ if eq(parameters['ENV'], 'dev') }}: + AZURE_SUBSCRIPTION: $(DEV_AZURE_SUBSCRIPTION) + RESOURCE_GROUP: $(DEV_WEB_APP_RESOURCE_GROUP_NAME) + APP_NAME: $(DEV_WEB_APP_NAME) + STAGE: "d" + dockerRegistryServiceConnection: $(DEV_CONTAINER_REGISTRY) + dockerNamespace: $(DEV_CONTAINER_NAMESPACE) + + ${{ if eq(parameters['ENV'], 'uat') }}: + AZURE_SUBSCRIPTION: $(UAT_AZURE_SUBSCRIPTION) + RESOURCE_GROUP: $(UAT_WEB_APP_RESOURCE_GROUP_NAME) + APP_NAME: $(UAT_WEB_APP_NAME) + STAGE: "u" + dockerRegistryServiceConnection: $(UAT_CONTAINER_REGISTRY) + dockerNamespace: $(UAT_CONTAINER_NAMESPACE) + + ${{ if eq(parameters['ENV'], 'prod') }}: + AZURE_SUBSCRIPTION: $(PROD_AZURE_SUBSCRIPTION) + RESOURCE_GROUP: $(PROD_WEB_APP_RESOURCE_GROUP_NAME) + APP_NAME: $(PROD_WEB_APP_NAME) + STAGE: "p" + dockerRegistryServiceConnection: $(PROD_CONTAINER_REGISTRY) + dockerNamespace: $(PROD_CONTAINER_NAMESPACE) + + ${{ if eq(variables['Build.SourceBranchName'], 'merge') }}: + SOURCE_BRANCH: "main" # force to main branch + ${{ if ne(variables['Build.SourceBranchName'], 'merge') }}: + SOURCE_BRANCH: ${{ variables['Build.SourceBranchName'] }} + + + + MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository + MAVEN_OPTS: "-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)" + title: "" + sha: "" + tag: "" + +# Only manual triggers +trigger: none +pr: none + +pool: + vmImage: ubuntu-latest + +stages: + + # Create a release on GitHub + - stage: release_service + condition: ne('${{ parameters.SEMVER }}', 'skip') + pool: + vmImage: "ubuntu-latest" + jobs: + - job: releaseService + steps: + - checkout: self + clean: true + persistCredentials: true + + - script: | + git checkout $(SOURCE_BRANCH) + + - script: | + git config --global user.name "$(GIT_USERNAME)" + git config --global user.email "$(GIT_EMAIL)" + + - template: azure-templates/maven-versioning.yml + parameters: + semver: "${{ parameters.SEMVER }}" + + - task: Bash@3 + name: pomversion + inputs: + targetType: "inline" + script: | + version=$(mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "##vso[task.setvariable variable=next;isOutput=true]$version" + failOnStderr: true + + - script: | + git add pom.xml + git commit -m "Bump version [skip ci]" + git push origin $(SOURCE_BRANCH) + + + - script: | + HEAD_SHA=$(git rev-parse HEAD) + TAG="$(pomversion.next)" + TITLE="Release $(pomversion.next)" + echo "##vso[task.setvariable variable=title]$TITLE" + echo "##vso[task.setvariable variable=sha]$HEAD_SHA" + echo "##vso[task.setvariable variable=tag]$TAG" + + - script: | + echo $(tag) + echo $(title) + echo $(sha) + + + # create new release + - task: GitHubRelease@0 + inputs: + gitHubConnection: $(GITHUB_CONNECTION) + repositoryName: $(Build.Repository.Name) + action: create + target: $(sha) + tagSource: manual + tag: $(tag) + title: $(title) + addChangelog: true + + # Deploy on Azure + - stage: deploy + condition: not(failed('releaseService')) + pool: + vmImage: "ubuntu-latest" + jobs: + - job: deployJava + steps: + + - script: | + echo ${{variables['Build.SourceBranchName']}} + echo $(SOURCE_BRANCH) + echo $(TEST) + + - checkout: self + clean: true + persistCredentials: true + submodules: true + + - script: | + echo "Checkout on $(SOURCE_BRANCH)" + git checkout $(SOURCE_BRANCH) + displayName: Checkout on source branch + + # - task: Bash@3 + # name: application_properties + # inputs: + # targetType: "inline" + # script: | + # cp src/main/resources/application-azure-$(STAGE).properties src/main/resources/application.properties + # cat src/main/resources/application.properties + # failOnStderr: true + + - task: Cache@2 + inputs: + key: 'maven | "$(Agent.OS)" | pom.xml' + restoreKeys: | + maven | "$(Agent.OS)" + maven + path: $(MAVEN_CACHE_FOLDER) + displayName: Set Maven Cache + + - task: Bash@3 + # When the maven task is installed, mvn can be used in a script + name: pomversion + inputs: + targetType: "inline" + script: | + version=$(mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "##vso[task.setvariable variable=next;isOutput=true]$version" + failOnStderr: true + + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + publishJUnitResults: false + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + mavenVersionOption: 'Default' + mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' + mavenAuthenticateFeed: false + effectivePomSkip: false + sonarQubeRunAnalysis: false + + - task: Docker@2 + displayName: Build and push an image to container registry + inputs: + containerRegistry: '$(dockerRegistryServiceConnection)' + repository: '$(IMAGE_REPOSITORY)' + command: 'buildAndPush' + tags: | + $(Build.BuildId) + latest + $(pomversion.next) + + # deploy project-fn + - task: AzureFunctionAppContainer@1 + displayName: Deploy Function App [DEV] + inputs: + azureSubscription: $(AZURE_SUBSCRIPTION) + appName: "${{variables.DEV_WEB_APP_NAME}}-fn-project" + imageName: "${{variables.DEV_CONTAINER_NAMESPACE}}/project:$(Build.BuildId)" + slotName: production + + - script: | + echo "##vso[task.setvariable variable=version;isOutput=true]$(pomversion.next)" + name: dockerTag + + + # Run test + - stage: test + # run this stage only if 'test' is enabled + condition: and(not(failed('deployJava')), eq('${{ parameters.TEST }}', 'true')) + pool: + vmImage: "ubuntu-latest" + jobs: + # is needed to wait for startup of application + - job: waitStartup + pool: Server + steps: + - task: Delay@1 + inputs: + delayForMinutes: '10' + + # - job: integrationTests + # dependsOn: waitStartup + # steps: + # - script: | + # git checkout $(SOURCE_BRANCH) + + # - script: | + # yarn global add newman + # displayName: 'newman installation' + + # - script: | + # newman run api-test/Project.postman_collection.json --environment=api-test/Azure.postman_environment.json --reporters cli,junit --reporter-junit-export Results/api-config-TEST.xml --verbose + # displayName: 'Run api test' + # continueOnError: false + + # - task: PublishTestResults@2 + # condition: always() + # inputs: + # testResultsFormat: 'JUnit' + # testResultsFiles: '**/*-TEST.xml' + # searchFolder: '$(System.DefaultWorkingDirectory)' + + - job: deployUAT + dependsOn: integrationTests + variables: + version: $[ stageDependencies.deploy.deployJava.outputs['dockerTag.version'] ] + steps: + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + publishJUnitResults: false + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + mavenVersionOption: 'Default' + mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' + mavenAuthenticateFeed: false + effectivePomSkip: false + sonarQubeRunAnalysis: false + + - task: Docker@2 + displayName: Build and push an image to UAT container registry + inputs: + containerRegistry: '$(UAT_CONTAINER_REGISTRY)' + repository: '$(IMAGE_REPOSITORY)' + command: 'buildAndPush' + tags: | + $(Build.BuildId) + latest + $(version) + + # deploy project-fn + - task: AzureFunctionAppContainer@1 + displayName: Deploy Function App [UAT] + condition: in('${{ parameters.ENV }}', 'uat') + inputs: + azureSubscription: $(AZURE_SUBSCRIPTION) + appName: "${{variables.UAT_WEB_APP_NAME}}-fn-project}" + imageName: "${{variables.UAT_CONTAINER_NAMESPACE}}/project:$(Build.BuildId)" + slotName: production \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..6ceafec --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,36 @@ + + + + + +#### List of Changes + + + +#### Motivation and Context + + + +#### How Has This Been Tested? + + + + + +#### Screenshots (if appropriate): + +#### Types of changes + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) + +#### Checklist: + + + + +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. \ No newline at end of file diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000..2e0bbe2 --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,3 @@ +addAssignees: author + +runOnDraft: true diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..9cbf0b9 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,18 @@ +# release.yml + +changelog: + exclude: + labels: + - ignore-for-release + authors: + - pagopa-github-bot + categories: + - title: Breaking Changes 🛠 + labels: + - breaking-change + - title: Exciting New Features 🎉 + labels: + - enhancement + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/anchore.yml b/.github/workflows/anchore.yml new file mode 100644 index 0000000..802f626 --- /dev/null +++ b/.github/workflows/anchore.yml @@ -0,0 +1,54 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, builds an image, performs a container image +# vulnerability scan with Anchore's Grype tool, and integrates the results with GitHub Advanced Security +# code scanning feature. For more information on the Anchore scan action usage +# and parameters, see https://github.com/anchore/scan-action. For more +# information on Anchore's container image scanning tool Grype, see +# https://github.com/anchore/grype +name: Anchore Container Scan + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '00 07 * * *' + +permissions: + contents: read + +env: + DOCKERFILE: Dockerfile + +jobs: + Anchore-Build-Scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + runs-on: ubuntu-latest + steps: + - name: Checkout the code + uses: actions/checkout@v3 + + - name: Build the Docker image + run: docker build . --file ${{ env.DOCKERFILE }} --tag localbuild/testimage:latest + + - name: Run the Anchore scan action itself with GitHub Advanced Security code scanning integration enabled + uses: anchore/scan-action@v3 + with: + image: "localbuild/testimage:latest" + acs-report-enable: true + fail-build: true + severity-cutoff: "high" + - name: Upload Anchore Scan Report + uses: github/codeql-action/upload-sarif@v2 + if: always() + with: + sarif_file: results.sarif diff --git a/.github/workflows/assignee.yml b/.github/workflows/assignee.yml new file mode 100644 index 0000000..0611917 --- /dev/null +++ b/.github/workflows/assignee.yml @@ -0,0 +1,26 @@ +name: Auto Assign + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + pull_request_target: + branches: + - main + types: [ opened, reopened ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Assign Me + # You may pin to the exact commit or the version. + uses: kentaro-m/auto-assign-action@v1.2.1 + with: + configuration-path: '.github/auto_assign.yml' diff --git a/.github/workflows/check_metadata_pr.yml b/.github/workflows/check_metadata_pr.yml new file mode 100644 index 0000000..c687c53 --- /dev/null +++ b/.github/workflows/check_metadata_pr.yml @@ -0,0 +1,35 @@ +name: Check PR + +# Controls when the workflow will run +on: + pull_request_target: + branches: + - main + types: [ opened, labeled, unlabeled, reopened ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + name: Check Labels + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + + - name: Verify PR Labels + uses: jesusvasquez333/verify-pr-label-action@v1.4.0 + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + valid-labels: 'bug, enhancement, breaking-change, ignore-for-release' + pull-request-number: '${{ github.event.pull_request.number }}' + + - name: Label Check + if: ${{ !contains(github.event.pull_request.labels.*.name, 'breaking-change') && !contains(github.event.pull_request.labels.*.name, 'enhancement') && !contains(github.event.pull_request.labels.*.name, 'bug') && !contains(github.event.pull_request.labels.*.name, 'ignore-for-release') }} + uses: actions/github-script@v3 + with: + script: | + core.setFailed('Missing required labels') diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..4f4091b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,58 @@ +name: Auto Deploy + +# Controls when the workflow will run +on: + pull_request: + branches: + - main + types: [ closed ] + + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + if: ${{ github.event.pull_request.merged }} + name: Call Azure Build Pipeline + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + + # default skip bump versioning + - name: Set as default skip bump versioning + run: | + echo "SEMVER=skip" >> $GITHUB_ENV + + - name: Set major + run: | + echo "SEMVER=major" >> $GITHUB_ENV + if: ${{ contains(github.event.pull_request.labels.*.name, 'breaking-change') }} + + - name: Set minor + run: | + echo "SEMVER=minor" >> $GITHUB_ENV + if: ${{ contains(github.event.pull_request.labels.*.name, 'enhancement') }} + + - name: Set patch + run: | + echo "SEMVER=patch" >> $GITHUB_ENV + if: ${{ contains(github.event.pull_request.labels.*.name, 'bug') }} + + - name: Set skip + run: | + echo "SEMVER=skip" >> $GITHUB_ENV + if: ${{ contains(github.event.pull_request.labels.*.name, 'ignore-for-release') }} + + - name: Azure Pipelines Action - Jversion + uses: jacopocarlini/azure-pipelines@v1.3 + with: + azure-devops-project-url: https://dev.azure.com/pagopaspa/pagoPA-projects + azure-pipeline-name: 'pagopa-function-template.deploy' + azure-devops-token: ${{ secrets.AZURE_DEVOPS_TOKEN }} + azure-template-parameters: '{"ENV": "dev", "SEMVER": "${{env.SEMVER}}", "TEST": "true"}' + azure-pipeline-variables: '{"system.debug": "true"}' + diff --git a/.github/workflows/sonar_analysis.yml b/.github/workflows/sonar_analysis.yml new file mode 100644 index 0000000..8003cbf --- /dev/null +++ b/.github/workflows/sonar_analysis.yml @@ -0,0 +1,28 @@ +name: Sonar Analysis + +# Controls when the workflow will run +on: + push: + branches: + - main + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + name: Call Azure Build Pipeline + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Azure Pipelines Action - Jversion + uses: jacopocarlini/azure-pipelines@v1.3 + with: + azure-devops-project-url: https://dev.azure.com/pagopaspa/pagoPA-projects + azure-pipeline-name: 'pagopa-function-templat.code-review' + azure-devops-token: ${{ secrets.AZURE_DEVOPS_TOKEN }} + azure-pipeline-variables: '{"system.debug": "true"}' + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab23ace --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# Build output +target/ +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# IDE +.idea/ +*.iml +.settings/ +.project +.classpath +.vscode/ + +# macOS +.DS_Store + +# Azure Functions +local.settings.json +bin/ +obj/ diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +11 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0d2e1f8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +# 1. `pip install pre-commit` +# 2. `pre-commit install` +# 3. set GITGUARDIAN_API_KEY in your develop environment (get an api key here: https://dashboard.gitguardian.com/workspace/230910/settings/personal/personal-access-tokens) +# more info https://docs.gitguardian.com/internal-repositories-monitoring/integrations/git_hooks/pre_commit +repos: + - repo: https://github.com/gitguardian/ggshield + rev: v1.11.0 + hooks: + - id: ggshield + language_version: python3 + stages: [ commit ] diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..e514c2f --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +# see https://help.github.com/en/articles/about-code-owners#example-of-a-codeowners-file + +* @pagopa/pagopa-tech diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dd42d12 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +ARG JAVA_VERSION=11 +# This image additionally contains function core tools – useful when using custom extensions +FROM mcr.microsoft.com/azure-functions/java:3.0-java$JAVA_VERSION-build AS installer-env + +COPY . /src/java-function-app +RUN cd /src/java-function-app && \ + mkdir -p /home/site/wwwroot && \ + mvn clean package -Dmaven.test.skip=true && \ + cd ./target/azure-functions/ && \ + cd $(ls -d */|head -n 1) && \ + cp -a . /home/site/wwwroot + +# This image is ssh enabled +#FROM mcr.microsoft.com/azure-functions/java:3.0-java$JAVA_VERSION-appservice +# This image isn't ssh enabled +FROM mcr.microsoft.com/azure-functions/java:3.0-java$JAVA_VERSION + +ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ + AzureFunctionsJobHost__Logging__Console__IsEnabled=true + +EXPOSE 80 +COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a442c4a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 PagoPA SpA + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f6354b --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# pagoPA Functions template + +Java template to create an Azure Function. + +## Function examples +There is an example of a Http Trigger function. + +--- + +## Run locally with Docker +`docker build -t pagopa-functions-template .` + +`docker run -p 8999:80 pagopa-functions-template` + +### Test +`curl http://localhost:8999/example` + +## Run locally with Maven + +`mvn clean package` + +`mvn azure-functions:run` + +### Test +`curl http://localhost:7071/example` + +--- + + +## TODO +Once cloned the repo, you should: +- to deploy on standard Azure service: + - rename `deploy-pipelines-standard.yml` to `deploy-pipelines.yml` + - remove `helm` folder +- to deploy on Kubernetes: + - rename `deploy-pipelines-aks.yml` to `deploy-pipelines.yml` + - customize `helm` configuration +- configure the following GitHub action in `.github` folder: + - `deploy.yml` + - `sonar_analysis.yml` + +Configure the SonarCloud project :point_right: [guide](https://pagopa.atlassian.net/wiki/spaces/DEVOPS/pages/147193860/SonarCloud+experimental). \ No newline at end of file diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/Chart.lock b/helm/Chart.lock new file mode 100644 index 0000000..ec10db3 --- /dev/null +++ b/helm/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: microservice-chart + repository: https://pagopa.github.io/aks-microservice-chart-blueprint + version: 1.21.0 +digest: sha256:e3deccb7ac0b5d85af0c726f28316ebe7a3795cbf54522330c33474b0bae309a +generated: "2022-10-06T17:44:35.49088+02:00" diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..b69df2e --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +name: pagopa-functions-template +description: Microservice description +type: application +version: 0.0.1 +appVersion: 0.0.1 +dependencies: + - name: microservice-chart + version: 1.21.0 + repository: "https://pagopa.github.io/aks-microservice-chart-blueprint" diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml new file mode 100644 index 0000000..a39b257 --- /dev/null +++ b/helm/values-dev.yaml @@ -0,0 +1,73 @@ +microservice-chart: + namespace: "" # TODO + nameOverride: "" + fullnameOverride: "" + image: + repository: pagopadcommonacr.azurecr.io/pagopa # TODO + tag: "0.0.1" + pullPolicy: Always + # https://github.com/Azure/azure-functions-host/blob/dev/src/WebJobs.Script.WebHost/Controllers/HostController.cs + livenessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + deployment: + create: true + service: + create: true + type: ClusterIP + port: 80 + ingress: + create: true + host: "weudev..internal.dev.platform.pagopa.it" # TODO + path: /pagopa--service/(.*) # TODO + serviceAccount: + create: false + annotations: {} + name: "" + podAnnotations: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault + securityContext: + allowPrivilegeEscalation: false + resources: + requests: + memory: "512Mi" + cpu: "0.25" + limits: + memory: "512Mi" + cpu: "0.25" + autoscaling: + enable: true + minReplica: 3 + maxReplica: 10 + pollingInterval: 10 # seconds + cooldownPeriod: 50 # seconds + triggers: + - type: cpu + metadata: + # Required + type: Utilization # Allowed types are 'Utilization' or 'AverageValue' + value: "75" + envConfig: + WEBSITE_SITE_NAME: "pagopa" # required to show cloud role name in application insights # TODO + FUNCTIONS_WORKER_RUNTIME: "java" + envSecret: + APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string' # TODO set in kv + keyvault: + name: "pagopa-d--kv" # TODO + tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml new file mode 100644 index 0000000..83842f0 --- /dev/null +++ b/helm/values-prod.yaml @@ -0,0 +1,73 @@ +microservice-chart: + namespace: "" # TODO + nameOverride: "" + fullnameOverride: "" + image: + repository: pagopapcommonacr.azurecr.io/pagopa # TODO + tag: "0.0.1" + pullPolicy: Always + # https://github.com/Azure/azure-functions-host/blob/dev/src/WebJobs.Script.WebHost/Controllers/HostController.cs + livenessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + deployment: + create: true + service: + create: true + type: ClusterIP + port: 80 + ingress: + create: true + host: "weuprod..internal.platform.pagopa.it" # TODO + path: /pagopa--service/(.*) # TODO + serviceAccount: + create: false + annotations: {} + name: "" + podAnnotations: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault + securityContext: + allowPrivilegeEscalation: false + resources: + requests: + memory: "512Mi" + cpu: "0.25" + limits: + memory: "512Mi" + cpu: "0.25" + autoscaling: + enable: true + minReplica: 3 + maxReplica: 10 + pollingInterval: 10 # seconds + cooldownPeriod: 50 # seconds + triggers: + - type: cpu + metadata: + # Required + type: Utilization # Allowed types are 'Utilization' or 'AverageValue' + value: "75" + envConfig: + WEBSITE_SITE_NAME: "pagopa" # required to show cloud role name in application insights # TODO + FUNCTIONS_WORKER_RUNTIME: "java" + envSecret: + APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string' # TODO set in kv + keyvault: + name: "pagopa-p--kv" # TODO + tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml new file mode 100644 index 0000000..1a380e5 --- /dev/null +++ b/helm/values-uat.yaml @@ -0,0 +1,73 @@ +microservice-chart: + namespace: "" # TODO + nameOverride: "" + fullnameOverride: "" + image: + repository: pagopaucommonacr.azurecr.io/pagopa # TODO + tag: "0.0.1" + pullPolicy: Always + # https://github.com/Azure/azure-functions-host/blob/dev/src/WebJobs.Script.WebHost/Controllers/HostController.cs + livenessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /info + port: 80 + initialDelaySeconds: 60 + failureThreshold: 6 + periodSeconds: 10 + deployment: + create: true + service: + create: true + type: ClusterIP + port: 80 + ingress: + create: true + host: "weuuat..internal.uat.platform.pagopa.it" # TODO + path: /pagopa--service/(.*) # TODO + serviceAccount: + create: false + annotations: {} + name: "" + podAnnotations: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault + securityContext: + allowPrivilegeEscalation: false + resources: + requests: + memory: "512Mi" + cpu: "0.25" + limits: + memory: "512Mi" + cpu: "0.25" + autoscaling: + enable: true + minReplica: 3 + maxReplica: 10 + pollingInterval: 10 # seconds + cooldownPeriod: 50 # seconds + triggers: + - type: cpu + metadata: + # Required + type: Utilization # Allowed types are 'Utilization' or 'AverageValue' + value: "75" + envConfig: + WEBSITE_SITE_NAME: "pagopa" # required to show cloud role name in application insights # TODO + FUNCTIONS_WORKER_RUNTIME: "java" + envSecret: + APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string' # TODO set in kv + keyvault: + name: "pagopa-u--kv" # TODO + tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/host.json b/host.json new file mode 100644 index 0000000..c627a64 --- /dev/null +++ b/host.json @@ -0,0 +1,26 @@ +{ + "version": "2.0", + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[2.*, 3.0.0)" + }, + "extensions": { + "http": { + "routePrefix": "" + } + }, + "logging": { + "fileLoggingMode": "always", + "logLevel": { + "default": "Information", + "Host.Results": "Error", + "Function": "Information", + "Host.Aggregator": "Trace" + }, + "applicationInsights": { + "samplingSettings": { + "isEnabled": false + } + } +} +} diff --git a/local.settings.json.example b/local.settings.json.example new file mode 100644 index 0000000..87c20b1 --- /dev/null +++ b/local.settings.json.example @@ -0,0 +1,6 @@ +{ + "IsEncrypted": false, + "Values": { + "FUNCTIONS_WORKER_RUNTIME": "java", + } + } diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1f35088 --- /dev/null +++ b/pom.xml @@ -0,0 +1,273 @@ + + + 4.0.0 + + it.gov.pagopa.project + example-function + 0.0.1 + jar + + Azure Custom Fn + + + UTF-8 + 11 + 1.15.0 + 1.4.2 + com.microsoft.azure-20220215182005862 + 3.15.3.Final + + + + + + org.modelmapper + modelmapper + 3.0.0 + + + com.microsoft.azure.functions + azure-functions-java-library + ${azure.functions.java.library.version} + + + + + + + org.junit.jupiter + junit-jupiter + 5.8.2 + test + + + + org.mockito + mockito-core + 4.3.1 + test + + + org.mockito + mockito-junit-jupiter + 4.3.1 + test + + + + + com.sun.xml.ws + jaxws-ri + 2.3.3 + pom + + + + javax.xml.ws + jaxws-api + 2.3.1 + + + + com.sun.xml.bind + jaxb-core + 2.3.0.1 + + + + com.sun.xml.bind + jaxb-impl + 2.3.1 + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + + + org.jboss.resteasy + resteasy-jaxb-provider + 6.0.0.Final + + + + + + + + com.fasterxml.jackson.core + jackson-core + 2.13.1 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.2.1 + + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.1 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.13.1 + + + + + + + org.projectlombok + lombok + 1.18.20 + provided + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + com.microsoft.azure + azure-functions-maven-plugin + ${azure.functions.maven.plugin.version} + + + ${functionAppName} + + + FUNCTIONS_EXTENSION_VERSION + ~3 + + + java-functions-group + java-functions-app-service-plan + westus + + windows + 11 + + + + + package-functions + + package + + + + + + + maven-clean-plugin + 3.1.0 + + + + obj + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.7 + + + **/config/* + + + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + + + org.junit.platform + junit-platform-surefire-provider + 1.0.1 + + + org.junit.jupiter + junit-jupiter-engine + 5.0.3 + + + + + ${argLine} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + add-source + generate-sources + + add-source + + + + target/generated + + + + + + + + diff --git a/src/main/java/it/gov/pagopa/project/Example.java b/src/main/java/it/gov/pagopa/project/Example.java new file mode 100644 index 0000000..f063da4 --- /dev/null +++ b/src/main/java/it/gov/pagopa/project/Example.java @@ -0,0 +1,41 @@ +package it.gov.pagopa.project; + +import com.microsoft.azure.functions.*; +import com.microsoft.azure.functions.annotation.AuthorizationLevel; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.HttpTrigger; + +import javax.ws.rs.core.MediaType; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Azure Functions with Azure Queue trigger. + */ +public class Example { + + /** + * This function will be invoked when a Http Trigger occurs + */ + @FunctionName("ExampleFunction") + public HttpResponseMessage run ( + @HttpTrigger( + name = "ExampleTrigger", + methods = {HttpMethod.GET}, + route = "example", + authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, + final ExecutionContext context) { + + Logger logger = context.getLogger(); + + String message = String.format("it.gov.pagopa.project.Example function called at: %s", LocalDateTime.now()); + logger.log(Level.INFO, () -> message); + + return request.createResponseBuilder(HttpStatus.OK) + .header("Content-Type", MediaType.TEXT_PLAIN) + .body(message) + .build(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/src/test/java/it/gov/pagopa/project/ExampleTest.java b/src/test/java/it/gov/pagopa/project/ExampleTest.java new file mode 100644 index 0000000..f2ca314 --- /dev/null +++ b/src/test/java/it/gov/pagopa/project/ExampleTest.java @@ -0,0 +1,51 @@ +package it.gov.pagopa.project; + +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.HttpStatus; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ExampleTest { + + @Spy + Example function; + + @Mock + ExecutionContext context; + + @Test + void runOk() { + // test precondition + Logger logger = Logger.getLogger("example-test-logger"); + when(context.getLogger()).thenReturn(logger); + + final HttpResponseMessage.Builder builder = mock(HttpResponseMessage.Builder.class); + HttpRequestMessage> request = mock(HttpRequestMessage.class); + + doReturn(builder).when(request).createResponseBuilder(any(HttpStatus.class)); + doReturn(builder).when(builder).header(anyString(), anyString()); + doReturn(builder).when(builder).body(anyString()); + + HttpResponseMessage responseMock = mock(HttpResponseMessage.class); + doReturn(HttpStatus.OK).when(responseMock).getStatus(); + doReturn(responseMock).when(builder).build(); + + // test execution + HttpResponseMessage response = function.run(request, context); + + // test assertion + assertEquals(HttpStatus.OK, response.getStatus()); + } +}