├── .env ├── infrastructure ├── aat.tfvars ├── demo.tfvars ├── output.tf ├── prod.tfvars ├── .terraform-version ├── main.tf ├── state.tf ├── variables.tf └── README.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── charts └── rpe-spring-boot-template │ ├── values.preview.template.yaml │ ├── values.aat.template.yaml │ ├── templates │ └── NOTES.txt │ ├── Chart.yaml │ ├── .helmignore │ └── values.yaml ├── .github ├── ISSUE_TEMPLATE.md ├── renovate.json ├── CODEOWNERS ├── workflows │ ├── publish-openapi.yaml │ ├── ci.yml │ └── codeql.yml ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── CONTRIBUTING.md ├── Dockerfile ├── .gitignore ├── src ├── test │ └── java │ │ └── uk │ │ └── gov │ │ └── hmcts │ │ └── reform │ │ └── rsecheck │ │ └── DemoUnitTest.java ├── main │ ├── java │ │ └── uk │ │ │ └── gov │ │ │ └── hmcts │ │ │ └── reform │ │ │ └── demo │ │ │ ├── Application.java │ │ │ ├── controllers │ │ │ └── RootController.java │ │ │ └── config │ │ │ └── OpenAPIConfiguration.java │ └── resources │ │ └── application.yaml ├── integrationTest │ └── java │ │ └── uk │ │ └── gov │ │ └── hmcts │ │ └── reform │ │ └── demo │ │ ├── controllers │ │ └── GetWelcomeTest.java │ │ └── openapi │ │ └── OpenAPIPublisherTest.java ├── smokeTest │ └── java │ │ └── uk │ │ └── gov │ │ └── hmcts │ │ └── reform │ │ └── demo │ │ └── controllers │ │ └── SampleSmokeTest.java └── functionalTest │ └── java │ └── uk │ └── gov │ └── hmcts │ └── reform │ └── demo │ └── controllers │ └── SampleFunctionalTest.java ├── Jenkinsfile_nightly ├── Jenkinsfile_template ├── lib └── applicationinsights.json ├── config └── owasp │ └── suppressions.xml ├── .editorconfig ├── docker-compose.yml ├── LICENSE ├── catalog-info.yaml ├── bin ├── run-in-docker.sh └── init.sh ├── gradlew.bat ├── README.md └── gradlew /.env: -------------------------------------------------------------------------------- 1 | SERVER_PORT=4550 2 | -------------------------------------------------------------------------------- /infrastructure/aat.tfvars: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infrastructure/demo.tfvars: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infrastructure/output.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infrastructure/prod.tfvars: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infrastructure/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.12.0 2 | -------------------------------------------------------------------------------- /infrastructure/main.tf: -------------------------------------------------------------------------------- 1 | provider "azurerm" { 2 | features {} 3 | } 4 | -------------------------------------------------------------------------------- /infrastructure/state.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "azurerm" {} 3 | } 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmcts/spring-boot-template/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/values.preview.template.yaml: -------------------------------------------------------------------------------- 1 | java: 2 | # Don't modify below here 3 | image: ${IMAGE_NAME} 4 | ingressHost: ${SERVICE_FQDN} 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What would you like to change? 2 | 3 | ### How do you think that would improve the project? 4 | 5 | ### If this entry is related to a bug, please provide the steps to reproduce it 6 | -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/values.aat.template.yaml: -------------------------------------------------------------------------------- 1 | # Don't modify this file, it is only needed for the pipeline to set the image and ingressHost 2 | java: 3 | image: ${IMAGE_NAME} 4 | ingressHost: ${SERVICE_FQDN} 5 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>hmcts/.github:renovate-config", 5 | "local>hmcts/.github//renovate/automerge-all" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @hmcts/platform-operations @hmcts/developer-enablement 2 | 3 | # Ignore files updated by Renovate 4 | gradle/wrapper/gradle-wrapper.properties 5 | Dockerfile 6 | build.gradle 7 | charts/**/Chart.yaml 8 | .github/workflows/*.yaml 9 | -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}. 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To learn more about the release, try: 6 | 7 | $ helm status {{ .Release.Name }} 8 | $ helm get {{ .Release.Name }} 9 | -------------------------------------------------------------------------------- /infrastructure/variables.tf: -------------------------------------------------------------------------------- 1 | variable "product" {} 2 | 3 | variable "component" {} 4 | 5 | variable "location" { 6 | default = "UK South" 7 | } 8 | 9 | variable "env" {} 10 | 11 | variable "subscription" {} 12 | 13 | variable "common_tags" { 14 | type = map(string) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # renovate: datasource=github-releases depName=microsoft/ApplicationInsights-Java 2 | ARG APP_INSIGHTS_AGENT_VERSION=3.7.6 3 | FROM hmctspublic.azurecr.io/base/java:21-distroless 4 | 5 | COPY lib/applicationinsights.json /opt/app/ 6 | COPY build/libs/spring-boot-template.jar /opt/app/ 7 | 8 | EXPOSE 4550 9 | CMD [ "spring-boot-template.jar" ] 10 | -------------------------------------------------------------------------------- /infrastructure/README.md: -------------------------------------------------------------------------------- 1 | # App infrastructure 2 | 3 | Add any application specific infrastructure to the terraform files in this folder 4 | 5 | This could be things like: 6 | * a database 7 | * redis 8 | * vault 9 | * application insights 10 | 11 | If you don't need any application infrastructure here, you can delete the whole folder (it will speed up your Jenkins build) 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | *.class 5 | bin/main/application.yaml 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | /out 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | .DS_Store 23 | 24 | applicationinsights-agent-*.jar 25 | *.log 26 | -------------------------------------------------------------------------------- /src/test/java/uk/gov/hmcts/reform/rsecheck/DemoUnitTest.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.rsecheck; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | 7 | class DemoUnitTest { 8 | 9 | @Test 10 | void exampleOfTest() { 11 | assertTrue(System.currentTimeMillis() > 0, "Example of Unit Test"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Jenkinsfile_nightly: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | properties([ 4 | // H allow predefined but random minute see https://en.wikipedia.org/wiki/Cron#Non-standard_characters 5 | pipelineTriggers([cron('H 07 * * 1-5')]) 6 | ]) 7 | 8 | @Library("Infrastructure") 9 | 10 | def type = "java" 11 | def product = "rpe" 12 | def component = "spring-boot-template" 13 | 14 | withNightlyPipeline(type, product, component) {} 15 | -------------------------------------------------------------------------------- /Jenkinsfile_template: -------------------------------------------------------------------------------- 1 | #!groovy 2 | // If this is new microservice built on the template and you want it to run in Jenkins, you 3 | // will need to follow these steps: https://hmcts.github.io/cloud-native-platform/new-component/github-repo.html 4 | 5 | @Library("Infrastructure") 6 | 7 | def type = "java" 8 | def product = "rpe" 9 | def component = "demo" 10 | 11 | withPipeline(type, product, component) {} 12 | -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: "1.0" 3 | description: A Helm chart for spring-boot-template App 4 | name: rpe-spring-boot-template 5 | home: https://github.com/hmcts/spring-boot-template 6 | version: 0.0.18 7 | maintainers: 8 | - name: HMCTS rpe team 9 | dependencies: 10 | - name: java 11 | version: 5.3.0 12 | repository: 'oci://hmctspublic.azurecr.io/helm' 13 | -------------------------------------------------------------------------------- /.github/workflows/publish-openapi.yaml: -------------------------------------------------------------------------------- 1 | name: Publish OpenAPI specs 2 | on: 3 | push: 4 | branches: 5 | - "master" 6 | 7 | jobs: 8 | publish-openapi: 9 | uses: hmcts/workflow-publish-openapi-spec/.github/workflows/publish-openapi.yml@v1 10 | secrets: 11 | SWAGGER_PUBLISHER_API_TOKEN: ${{ secrets.SWAGGER_PUBLISHER_API_TOKEN }} 12 | with: 13 | test_to_run: 'uk.gov.hmcts.reform.demo.openapi.OpenAPIPublisherTest' 14 | java_version: 17 15 | -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | .vscode/ 23 | -------------------------------------------------------------------------------- /src/main/java/uk/gov/hmcts/reform/demo/Application.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | @SuppressWarnings("HideUtilityClassConstructor") // Spring needs a constructor, its not a utility class 8 | public class Application { 9 | 10 | public static void main(final String[] args) { 11 | SpringApplication.run(Application.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "connectionString": "${file:/mnt/secrets/rpe/app-insights-connection-string}", 3 | "role": { 4 | "name": "rpe-demo" 5 | }, 6 | "sampling": { 7 | "overrides": [ 8 | { 9 | "telemetryType": "request", 10 | "attributes": [ 11 | { 12 | "key": "http.url", 13 | "value": "https?://[^/]+/health.*", 14 | "matchType": "regexp" 15 | } 16 | ], 17 | "percentage": 1 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Template CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-java@v4 17 | with: 18 | distribution: 'temurin' # See 'Supported distributions' for available options 19 | java-version: '17' 20 | cache: 'gradle' 21 | - name: Build 22 | run: ./gradlew check 23 | -------------------------------------------------------------------------------- /charts/rpe-spring-boot-template/values.yaml: -------------------------------------------------------------------------------- 1 | java: 2 | applicationPort: 4550 3 | image: 'hmctspublic.azurecr.io/rpe/spring-boot-template:latest' 4 | ingressHost: rpe-spring-boot-template-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal 5 | aadIdentityName: rpe 6 | # Uncomment once the vault containing the app insights key has been set up 7 | # keyVaults: 8 | # rpe: 9 | # secrets: 10 | # - name: AppInsightsInstrumentationKey 11 | # alias: azure.application-insights.instrumentation-key 12 | environment: 13 | -------------------------------------------------------------------------------- /config/owasp/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | False Positive 6 | 7 | 8 | ^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$ 9 | CVE-2023-35116 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 120 12 | 13 | [*.java] 14 | indent_size = 4 15 | ij_continuation_indent_size = 4 16 | ij_java_align_multiline_parameters = true 17 | ij_java_align_multiline_parameters_in_calls = true 18 | ij_java_call_parameters_new_line_after_left_paren = true 19 | ij_java_call_parameters_right_paren_on_new_line = true 20 | ij_java_call_parameters_wrap = on_every_item 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Before creating a pull request make sure that:** 2 | 3 | - [ ] commit messages are meaningful and follow good commit message guidelines 4 | - [ ] README and other documentation has been updated / added (if needed) 5 | - [ ] tests have been updated / new tests has been added (if needed) 6 | 7 | Please remove this line and everything above and fill the following sections: 8 | 9 | 10 | ### JIRA link (if applicable) ### 11 | 12 | 13 | 14 | ### Change description ### 15 | 16 | 17 | 18 | **Does this PR introduce a breaking change?** (check one with "x") 19 | 20 | ``` 21 | [ ] Yes 22 | [ ] No 23 | ``` 24 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | spring-boot-template: 5 | build: 6 | context: . 7 | args: 8 | - http_proxy 9 | - https_proxy 10 | - no_proxy 11 | image: hmctspublic.azurecr.io/spring-boot/template 12 | environment: 13 | # these environment variables are used by java-logging library 14 | - ROOT_APPENDER 15 | - JSON_CONSOLE_PRETTY_PRINT 16 | - ROOT_LOGGING_LEVEL 17 | - REFORM_SERVICE_TYPE 18 | - REFORM_SERVICE_NAME 19 | - REFORM_TEAM 20 | - REFORM_ENVIRONMENT 21 | - LOGBACK_DATE_FORMAT 22 | - LOGBACK_REQUIRE_THREAD 23 | - LOGBACK_REQUIRE_ALERT_LEVEL=false 24 | - LOGBACK_REQUIRE_ERROR_CODE=false 25 | ports: 26 | - $SERVER_PORT:$SERVER_PORT 27 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 7 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 4 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - dependencies 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: > 18 | This issue is being closed automatically as it was stale 19 | -------------------------------------------------------------------------------- /src/main/java/uk/gov/hmcts/reform/demo/controllers/RootController.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.controllers; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import static org.springframework.http.ResponseEntity.ok; 8 | 9 | /** 10 | * Default endpoints per application. 11 | */ 12 | @RestController 13 | public class RootController { 14 | 15 | /** 16 | * Root GET endpoint. 17 | * 18 | *

Azure application service has a hidden feature of making requests to root endpoint when 19 | * "Always On" is turned on. 20 | * This is the endpoint to deal with that and therefore silence the unnecessary 404s as a response code. 21 | * 22 | * @return Welcome message from the service. 23 | */ 24 | @GetMapping("/") 25 | public ResponseEntity welcome() { 26 | return ok("Welcome to spring-boot-template"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/uk/gov/hmcts/reform/demo/config/OpenAPIConfiguration.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.config; 2 | 3 | import io.swagger.v3.oas.models.ExternalDocumentation; 4 | import io.swagger.v3.oas.models.OpenAPI; 5 | import io.swagger.v3.oas.models.info.Info; 6 | import io.swagger.v3.oas.models.info.License; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class OpenAPIConfiguration { 12 | 13 | @Bean 14 | public OpenAPI openAPI() { 15 | return new OpenAPI() 16 | .info(new Info().title("rpe demo") 17 | .description("rpe demo") 18 | .version("v0.0.1") 19 | .license(new License().name("MIT").url("https://opensource.org/licenses/MIT"))) 20 | .externalDocs(new ExternalDocumentation() 21 | .description("README") 22 | .url("https://github.com/hmcts/spring-boot-template")); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 HMCTS (HM Courts & Tribunals Service) 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /src/integrationTest/java/uk/gov/hmcts/reform/demo/controllers/GetWelcomeTest.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.controllers; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 7 | import org.springframework.test.web.servlet.MockMvc; 8 | import org.springframework.test.web.servlet.MvcResult; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 12 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 13 | 14 | @WebMvcTest 15 | class GetWelcomeTest { 16 | 17 | @Autowired 18 | private transient MockMvc mockMvc; 19 | 20 | @DisplayName("Should welcome upon root request with 200 response code") 21 | @Test 22 | void welcomeRootEndpoint() throws Exception { 23 | MvcResult response = mockMvc.perform(get("/")).andExpect(status().isOk()).andReturn(); 24 | 25 | assertThat(response.getResponse().getContentAsString()).startsWith("Welcome"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/smokeTest/java/uk/gov/hmcts/reform/demo/controllers/SampleSmokeTest.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.controllers; 2 | 3 | import io.restassured.RestAssured; 4 | import io.restassured.http.ContentType; 5 | import io.restassured.response.Response; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | import static io.restassured.RestAssured.given; 13 | 14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 15 | class SampleSmokeTest { 16 | @Value("${TEST_URL:http://localhost:4550}") 17 | private String testUrl; 18 | 19 | @BeforeEach 20 | public void setUp() { 21 | RestAssured.useRelaxedHTTPSValidation(); 22 | } 23 | 24 | @Test 25 | void smokeTest() { 26 | Response response = given() 27 | .baseUri(testUrl) 28 | .contentType(ContentType.JSON) 29 | .when() 30 | .get() 31 | .then() 32 | .extract().response(); 33 | 34 | Assertions.assertEquals(200, response.statusCode()); 35 | Assertions.assertTrue(response.asString().startsWith("Welcome")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/functionalTest/java/uk/gov/hmcts/reform/demo/controllers/SampleFunctionalTest.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.controllers; 2 | 3 | import io.restassured.RestAssured; 4 | import io.restassured.http.ContentType; 5 | import io.restassured.response.Response; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | import static io.restassured.RestAssured.given; 13 | 14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 15 | class SampleFunctionalTest { 16 | protected static final String CONTENT_TYPE_VALUE = "application/json"; 17 | 18 | @Value("${TEST_URL:http://localhost:8080}") 19 | private String testUrl; 20 | 21 | @BeforeEach 22 | public void setUp() { 23 | RestAssured.baseURI = testUrl; 24 | RestAssured.useRelaxedHTTPSValidation(); 25 | } 26 | 27 | @Test 28 | void functionalTest() { 29 | Response response = given() 30 | .contentType(ContentType.JSON) 31 | .when() 32 | .get() 33 | .then() 34 | .extract().response(); 35 | 36 | Assertions.assertEquals(200, response.statusCode()); 37 | Assertions.assertTrue(response.asString().startsWith("Welcome")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 4550 3 | shutdown: "graceful" 4 | 5 | # If you use a database then uncomment the `group:, readiness: and include: "db"` lines in the health probes and uncomment the datasource section 6 | management: 7 | endpoint: 8 | health: 9 | show-details: "always" 10 | # group: 11 | # readiness: 12 | # include: "db" 13 | endpoints: 14 | web: 15 | base-path: / 16 | exposure: 17 | include: health, info, prometheus 18 | 19 | springdoc: 20 | packagesToScan: uk.gov.hmcts.reform.demo.controllers 21 | writer-with-order-by-keys: true 22 | 23 | spring: 24 | config: 25 | import: "optional:configtree:/mnt/secrets/rpe/" 26 | application: 27 | name: Spring Boot Template 28 | # datasource: 29 | # driver-class-name: org.postgresql.Driver 30 | # url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}${DB_OPTIONS:} 31 | # username: ${DB_USER_NAME} 32 | # password: ${DB_PASSWORD} 33 | # properties: 34 | # charSet: UTF-8 35 | # hikari: 36 | # minimumIdle: 2 37 | # maximumPoolSize: 10 38 | # idleTimeout: 10000 39 | # poolName: {to-be-defined}HikariCP 40 | # maxLifetime: 7200000 41 | # connectionTimeout: 30000 42 | # jpa: 43 | # properties: 44 | # hibernate: 45 | # jdbc: 46 | # lob: 47 | # # silence the 'wall-of-text' - unnecessary exception throw about blob types 48 | # non_contextual_creation: true 49 | 50 | azure: 51 | application-insights: 52 | instrumentation-key: ${rpe.AppInsightsInstrumentationKey:00000000-0000-0000-0000-000000000000} 53 | -------------------------------------------------------------------------------- /src/integrationTest/java/uk/gov/hmcts/reform/demo/openapi/OpenAPIPublisherTest.java: -------------------------------------------------------------------------------- 1 | package uk.gov.hmcts.reform.demo.openapi; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit.jupiter.SpringExtension; 10 | import org.springframework.test.web.servlet.MockMvc; 11 | 12 | import java.io.OutputStream; 13 | import java.nio.file.Files; 14 | import java.nio.file.Paths; 15 | 16 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 17 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 18 | 19 | /** 20 | * Built-in feature which saves service's swagger specs in temporary directory. 21 | * Each CI run on master should automatically save and upload (if updated) documentation. 22 | */ 23 | @ExtendWith(SpringExtension.class) 24 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 25 | @AutoConfigureMockMvc 26 | class OpenAPIPublisherTest { 27 | 28 | @Autowired 29 | private MockMvc mvc; 30 | 31 | @DisplayName("Generate swagger documentation") 32 | @Test 33 | @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") 34 | void generateDocs() throws Exception { 35 | byte[] specs = mvc.perform(get("/v3/api-docs")) 36 | .andExpect(status().isOk()) 37 | .andReturn() 38 | .getResponse() 39 | .getContentAsByteArray(); 40 | 41 | try (OutputStream outputStream = Files.newOutputStream(Paths.get("/tmp/openapi-specs.json"))) { 42 | outputStream.write(specs); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | # The below YAML is a template for a Backstage catalog-info.yaml file. It should be updated to match the details of your service/component where applicable. 2 | # For further information on how to update this file to use other features of HMCTS Backstage, please see the HMCTS Backstage examples README: https://github.com/hmcts/backstage-hmcts-examples 3 | apiVersion: backstage.io/v1alpha1 4 | kind: Component 5 | metadata: 6 | name: "${{ values.product }}-${{ values.component }}" 7 | description: "${{ values.description }}" 8 | annotations: 9 | # This should match folder-name/job-name in Jenkins. 10 | jenkins.io/job-full-name: cft:HMCTS_${{ values.product }}/${{ values.destination.repo }} 11 | github.com/project-slug: '${{ values.destination.owner }}/${{ values.destination.repo }}' 12 | tags: 13 | - java 14 | links: 15 | - url: https://hmcts-reform.slack.com/app_redirect?channel=${{ values.slack_contact_channel }} 16 | title: ${{ values.slack_contact_channel }} on Slack 17 | icon: chat 18 | spec: 19 | type: service 20 | system: ${{ values.product }} 21 | lifecycle: experimental 22 | owner: ${{ values.owner }} 23 | 24 | # Uncomment the below once the project has an API file to link to 25 | #--- 26 | # 27 | #apiVersion: backstage.io/v1alpha1 28 | #kind: API 29 | #metadata: 30 | # name: "${{ values.description }}-api" 31 | # description: Update this description to describe the purpose of this API entity 32 | # annotations: 33 | # github.com/project-slug: '${{ values.destination.owner }}/${{ values.destination.repo }}' 34 | #spec: 35 | # type: openapi 36 | # lifecycle: experimental 37 | # owner: ${{ values.owner }} 38 | # system: ${{ values.product }} 39 | # apiProvidedBy: "${{ values.product }}-${{ values.component }}" 40 | # definition: 41 | # # Update the below to the raw URL of your OpenAPI spec 42 | # $text: https://raw.githubusercontent.com/hmcts/backstage-hmcts-examples/master/src/main/resources/openapi/testspec.yaml 43 | -------------------------------------------------------------------------------- /bin/run-in-docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | print_help() { 4 | echo "Script to run docker containers for Spring Boot Template API service 5 | 6 | Usage: 7 | 8 | ./run-in-docker.sh [OPTIONS] 9 | 10 | Options: 11 | --clean, -c Clean and install current state of source code 12 | --install, -i Install current state of source code 13 | --param PARAM=, -p PARAM= Parse script parameter 14 | --help, -h Print this help block 15 | 16 | Available parameters: 17 | 18 | " 19 | } 20 | 21 | # script execution flags 22 | GRADLE_CLEAN=false 23 | GRADLE_INSTALL=false 24 | 25 | # TODO custom environment variables application requires. 26 | # TODO also consider enlisting them in help string above ^ 27 | # TODO sample: DB_PASSWORD Defaults to 'dev' 28 | # environment variables 29 | #DB_PASSWORD=dev 30 | #S2S_URL=localhost 31 | #S2S_SECRET=secret 32 | 33 | execute_script() { 34 | cd $(dirname "$0")/.. 35 | 36 | if [ ${GRADLE_CLEAN} = true ] 37 | then 38 | echo "Clearing previous build.." 39 | ./gradlew clean 40 | fi 41 | 42 | if [ ${GRADLE_INSTALL} = true ] 43 | then 44 | echo "Assembling distribution.." 45 | ./gradlew assemble 46 | fi 47 | 48 | # echo "Assigning environment variables.." 49 | # 50 | # export DB_PASSWORD=${DB_PASSWORD} 51 | # export S2S_URL=${S2S_URL} 52 | # export S2S_SECRET=${S2S_SECRET} 53 | 54 | echo "Bringing up docker containers.." 55 | 56 | docker compose up 57 | } 58 | 59 | while true ; do 60 | case "$1" in 61 | -h|--help) print_help ; shift ; break ;; 62 | -c|--clean) GRADLE_CLEAN=true ; GRADLE_INSTALL=true ; shift ;; 63 | -i|--install) GRADLE_INSTALL=true ; shift ;; 64 | -p|--param) 65 | case "$2" in 66 | # DB_PASSWORD=*) DB_PASSWORD="${2#*=}" ; shift 2 ;; 67 | # S2S_URL=*) S2S_URL="${2#*=}" ; shift 2 ;; 68 | # S2S_SECRET=*) S2S_SECRET="${2#*=}" ; shift 2 ;; 69 | *) shift 2 ;; 70 | esac ;; 71 | *) execute_script ; break ;; 72 | esac 73 | done 74 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | We're happy to accept 3rd-party contributions. Please make sure you read this document before you do any work though, 4 | as we have some expectations related to the content and quality of change sets. 5 | 6 | ## What you should know about this application 7 | 8 | This project is a template Spring Boot application. It aims to speed up the creation of new Spring APIs in HMCTS 9 | projects, by serving as the initial setup of each API. 10 | 11 | ## Before contributing 12 | 13 | Any ideas on the user journeys and general service experience you may have **should be first consulted 14 | with us by submitting a new issue** to this repository. Ideas are always welcome, but if something is divergent or unrelated 15 | to what we're trying to achieve we won't be able to accept it. Please keep this in mind as we don't want to waste anybody's time. 16 | 17 | In the interest of creating a friendly collaboration environment, please read and adhere to an open source contributor's 18 | [code of conduct](http://contributor-covenant.org/version/1/4/). 19 | 20 | ## Making a contribution 21 | 22 | After your idea has been accepted you can implement it. We don't allow direct changes to the codebase from the public, 23 | they have to go through a review first. 24 | 25 | Here's what you should do: 26 | 1. [fork](https://help.github.com/articles/fork-a-repo/) this repository and clone it to your machine, 27 | 2. create a new branch for your change: 28 | * use the latest *master* to branch from, 29 | 3. implement the change in your branch: 30 | * if the change is non-trivial it's a good practice to split it into several logically independent units and deliver 31 | each one as a separate commit, 32 | * make sure the commit messages use proper language and accurately describe commit's content, e.g. *"Unify postcode lookup elements spacing"*. 33 | More information on good commit messages can be found [here](http://chris.beams.io/posts/git-commit/), 34 | 4. test if your feature works as expected and does not break any existing features, this may include implementing additional automated tests or amending existing ones, 35 | 5. push the change to your GitHub fork, 36 | 6. submit a [pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) to our repository: 37 | * ensure that the pull request and related GitHub issue reference each other. 38 | 39 | At this point the pull request will wait for someone from our team to review. It may be accepted straight away, 40 | or we may ask you to make some additional amendments before incorporating it into the main branch. 41 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '36 5 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | - uses: actions/setup-java@v4 58 | with: 59 | distribution: 'temurin' # See 'Supported distributions' for available options 60 | java-version: '17' 61 | 62 | 63 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 64 | # If this step fails, then you should remove it and run the build manually (see below) 65 | - name: Autobuild 66 | uses: github/codeql-action/autobuild@v3 67 | 68 | # ℹ️ Command-line programs to run using the OS shell. 69 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 70 | 71 | # If the Autobuild fails above, remove it and uncomment the following three lines. 72 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 73 | 74 | # - run: | 75 | # echo "Run, Build Application using script" 76 | # ./location_of_script_within_repo/buildscript.sh 77 | 78 | - name: Perform CodeQL Analysis 79 | uses: github/codeql-action/analyze@v3 80 | with: 81 | category: "/language:${{matrix.language}}" 82 | -------------------------------------------------------------------------------- /bin/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Script to initialise project by executing steps as follows: 4 | # - Replace port number 5 | # - Replace package `demo` 6 | # - Replace slug from `spring-boot-template` to one of two (first in first used): 7 | # - user input 8 | # - git config value of the root project. Value in use: `remote.origin.url` 9 | # - Clean-up README file from template related info 10 | # - Self-destruct 11 | 12 | read -p "Port number for new app: " port 13 | read -p "Replace \`demo\` package name with: " package 14 | read -p "Repo product: (It's first part of the git repo name. Often a team name) " product_name 15 | read -p "Repo component: (It's second part of git repo name. Application name) " component_name 16 | 17 | pushd $(dirname "$0")/.. > /dev/null 18 | 19 | slug="$product_name-$component_name" 20 | 21 | declare -a files_with_port=(.env Dockerfile README.md src/main/resources/application.yaml charts/rpe-spring-boot-template/values.yaml) 22 | declare -a files_with_slug=(build.gradle docker-compose.yml Dockerfile README.md ./infrastructure/main.tf ./src/main/java/uk/gov/hmcts/reform/demo/controllers/RootController.java charts/rpe-spring-boot-template/Chart.yaml) 23 | 24 | # Replace in CNP file 25 | for i in "Jenkinsfile_template" 26 | do 27 | perl -i -pe "s/rpe/$product_name/g" ${i} 28 | perl -i -pe "s/demo/$component_name/g" ${i} 29 | done 30 | 31 | # Replace image repo 32 | for i in "charts/rpe-spring-boot-template/values.yaml" 33 | do 34 | perl -i -pe "s/rpe/$product_name/g" ${i} 35 | perl -i -pe "s/spring-boot-template/$component_name/g" ${i} 36 | done 37 | 38 | # Remove "rpe-" prefix from chart name to prepare it for spring-boot-template slug replacement and update maintainer name 39 | for i in "charts/rpe-spring-boot-template/Chart.yaml" 40 | do 41 | perl -i -pe "s/rpe-//g" ${i} 42 | perl -i -pe "s/rpe/$product_name/g" ${i} 43 | done 44 | 45 | # Update mount config and packagesToScan 46 | for i in "src/main/resources/application.yaml" 47 | do 48 | perl -i -pe "s/rpe/$product_name/g" ${i} 49 | perl -i -pe "s/reform.demo/reform.$package/g" ${i} 50 | done 51 | 52 | # Update app insights 53 | for i in "lib/applicationinsights.json" 54 | do 55 | perl -i -pe "s/rpe/$product_name/g" ${i} 56 | perl -i -pe "s/demo/$component_name/g" ${i} 57 | done 58 | 59 | # Replace port number 60 | for i in ${files_with_port[@]} 61 | do 62 | perl -i -pe "s/4550/$port/g" ${i} 63 | done 64 | 65 | # Replace spring-boot-template slug 66 | for i in ${files_with_slug[@]} 67 | do 68 | perl -i -pe "s/spring-boot-template/$slug/g" ${i} 69 | done 70 | 71 | # Replace demo package in all files under ./src 72 | find ./src -type f -print0 | xargs -0 perl -i -pe "s/reform.demo/reform.$package/g" 73 | find ./.github/workflows -type f -print0 | xargs -0 perl -i -pe "s/reform.demo/reform.$package/g" 74 | perl -i -pe "s/reform.demo/reform.$package/g" build.gradle 75 | 76 | # Rename charts directory 77 | git mv charts/rpe-spring-boot-template charts/${slug} 78 | 79 | # Rename directory to provided package name 80 | git mv src/functionalTest/java/uk/gov/hmcts/reform/demo/ src/functionalTest/java/uk/gov/hmcts/reform/${package} 81 | git mv src/integrationTest/java/uk/gov/hmcts/reform/demo/ src/integrationTest/java/uk/gov/hmcts/reform/${package} 82 | git mv src/main/java/uk/gov/hmcts/reform/demo/ src/main/java/uk/gov/hmcts/reform/${package} 83 | git mv src/smokeTest/java/uk/gov/hmcts/reform/demo/ src/smokeTest/java/uk/gov/hmcts/reform/${package} 84 | 85 | # Rename CNP file 86 | git mv Jenkinsfile_template Jenkinsfile_CNP 87 | 88 | declare -a headers_to_delete=("Purpose" "What's inside" "Plugins" "Setup" "Hystrix") 89 | 90 | # Clean-up README file 91 | for i in "${headers_to_delete[@]}" 92 | do 93 | perl -0777 -i -p0e "s/## $i.+?\n(## )/\$1/s" README.md 94 | done 95 | 96 | # Rename title to slug 97 | perl -i -pe "s/.*\n/# $slug\n/g if 1 .. 1" README.md 98 | 99 | # Self-destruct 100 | rm bin/init.sh 101 | 102 | # Return to original directory 103 | popd > /dev/null 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot application template 2 | 3 | ## Purpose 4 | 5 | The purpose of this template is to speed up the creation of new Spring applications within HMCTS 6 | and help keep the same standards across multiple teams. If you need to create a new app, you can 7 | simply use this one as a starting point and build on top of it. 8 | 9 | ## What's inside 10 | 11 | The template is a working application with a minimal setup. It contains: 12 | * application skeleton 13 | * setup script to prepare project 14 | * common plugins and libraries 15 | * [HMCTS Java plugin](https://github.com/hmcts/gradle-java-plugin) 16 | * docker setup 17 | * automatically publishes API documentation to [hmcts/cnp-api-docs](https://github.com/hmcts/cnp-api-docs) 18 | * code quality tools already set up 19 | * MIT license and contribution information 20 | * Helm chart using chart-java. 21 | 22 | The application exposes health endpoint (http://localhost:4550/health) and metrics endpoint 23 | (http://localhost:4550/metrics). 24 | 25 | ## Plugins 26 | 27 | The template contains the following plugins: 28 | 29 | * HMCTS Java plugin 30 | 31 | Applies code analysis tools with HMCTS default settings. See the [project repository](https://github.com/hmcts/gradle-java-plugin) for details. 32 | 33 | Analysis tools include: 34 | 35 | * checkstyle 36 | 37 | https://docs.gradle.org/current/userguide/checkstyle_plugin.html 38 | 39 | Performs code style checks on Java source files using Checkstyle and generates reports from these checks. 40 | The checks are included in gradle's *check* task (you can run them by executing `./gradlew check` command). 41 | 42 | * org.owasp.dependencycheck 43 | 44 | https://jeremylong.github.io/DependencyCheck/dependency-check-gradle/index.html 45 | 46 | Provides monitoring of the project's dependent libraries and creating a report 47 | of known vulnerable components that are included in the build. To run it 48 | execute `gradle dependencyCheck` command. 49 | 50 | * jacoco 51 | 52 | https://docs.gradle.org/current/userguide/jacoco_plugin.html 53 | 54 | Provides code coverage metrics for Java code via integration with JaCoCo. 55 | You can create the report by running the following command: 56 | 57 | ```bash 58 | ./gradlew jacocoTestReport 59 | ``` 60 | 61 | The report will be created in build/reports subdirectory in your project directory. 62 | 63 | * io.spring.dependency-management 64 | 65 | https://github.com/spring-gradle-plugins/dependency-management-plugin 66 | 67 | Provides Maven-like dependency management. Allows you to declare dependency management 68 | using `dependency 'groupId:artifactId:version'` 69 | or `dependency group:'group', name:'name', version:version'`. 70 | 71 | * org.springframework.boot 72 | 73 | http://projects.spring.io/spring-boot/ 74 | 75 | Reduces the amount of work needed to create a Spring application 76 | 77 | 78 | * com.github.ben-manes.versions 79 | 80 | https://github.com/ben-manes/gradle-versions-plugin 81 | 82 | Provides a task to determine which dependencies have updates. Usage: 83 | 84 | ```bash 85 | ./gradlew dependencyUpdates -Drevision=release 86 | ``` 87 | 88 | ## Setup 89 | 90 | Located in `./bin/init.sh`. Simply run and follow the explanation how to execute it. 91 | 92 | ## Building and deploying the application 93 | 94 | ### Building the application 95 | 96 | The project uses [Gradle](https://gradle.org) as a build tool. It already contains 97 | `./gradlew` wrapper script, so there's no need to install gradle. 98 | 99 | To build the project execute the following command: 100 | 101 | ```bash 102 | ./gradlew build 103 | ``` 104 | 105 | ### Running the application 106 | 107 | Create the image of the application by executing the following command: 108 | 109 | ```bash 110 | ./gradlew assemble 111 | ``` 112 | 113 | Note: Docker Compose V2 is highly recommended for building and running the application. 114 | In the Compose V2 old `docker-compose` command is replaced with `docker compose`. 115 | 116 | Create docker image: 117 | 118 | ```bash 119 | docker compose build 120 | ``` 121 | 122 | Run the distribution (created in `build/install/spring-boot-template` directory) 123 | by executing the following command: 124 | 125 | ```bash 126 | docker compose up 127 | ``` 128 | 129 | This will start the API container exposing the application's port 130 | (set to `4550` in this template app). 131 | 132 | In order to test if the application is up, you can call its health endpoint: 133 | 134 | ```bash 135 | curl http://localhost:4550/health 136 | ``` 137 | 138 | You should get a response similar to this: 139 | 140 | ``` 141 | {"status":"UP","diskSpace":{"status":"UP","total":249644974080,"free":137188298752,"threshold":10485760}} 142 | ``` 143 | 144 | ### Alternative script to run application 145 | 146 | To skip all the setting up and building, just execute the following command: 147 | 148 | ```bash 149 | ./bin/run-in-docker.sh 150 | ``` 151 | 152 | For more information: 153 | 154 | ```bash 155 | ./bin/run-in-docker.sh -h 156 | ``` 157 | 158 | Script includes bare minimum environment variables necessary to start api instance. Whenever any variable is changed or any other script regarding docker image/container build, the suggested way to ensure all is cleaned up properly is by this command: 159 | 160 | ```bash 161 | docker compose rm 162 | ``` 163 | 164 | It clears stopped containers correctly. Might consider removing clutter of images too, especially the ones fiddled with: 165 | 166 | ```bash 167 | docker images 168 | 169 | docker image rm 170 | ``` 171 | 172 | There is no need to remove postgres and java or similar core images. 173 | 174 | ## License 175 | 176 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 177 | 178 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | --------------------------------------------------------------------------------