Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sunekochhansen authored Aug 3, 2023
0 parents commit a1e1e0c
Show file tree
Hide file tree
Showing 66 changed files with 2,589 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10

- package-ecosystem: "maven"
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
8 changes: 8 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
changelog:
exclude:
authors:
- kitautomation
categories:
- title: Changes
labels:
- "*"
104 changes: 104 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: CICD

on:
push:
branches: [ main ]
tags:
- 'v*.*.*'

jobs:
build:
runs-on: ubuntu-latest

steps:
# Set docker image names.
- name: Setup env variables
run: |
echo "DOCKER_SERVICE=kvalitetsit/kithugs" >> $GITHUB_ENV
echo "DOCKER_DOCUMENTATION=kvalitetsit/kithugs-documentation" >> $GITHUB_ENV
# Checkout source code
- uses: actions/checkout@v3

# Fail if DOCKER_SERVICE is kithugs and repo is not kithugs. This step can be deleted once
- name: Initial build
run: ./build/failOnFirstBuild.sh

# Cache maven stuff
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# if below step is skipped this build is a tag build. Can be used for skipping other steps.
- name: Is Tag Build
id: tag
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/}

# Login to docker hub using secrets in GitHub.
- name: Login to docker
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}

- name: Build and test
run: ./build/build.sh

- name: Tag service dev docker image
run: ./build/docker-tag.sh ${{ env.DOCKER_SERVICE }}:latest ${{ env.DOCKER_SERVICE }}:dev

- name: Push service dev docker image
run: ./build/docker-push.sh ${{ env.DOCKER_SERVICE }}:dev

- name: Tag service git id docker image
run: ./build/docker-tag.sh ${{ env.DOCKER_SERVICE }}:latest ${{ env.DOCKER_SERVICE }}:${{ github.sha }}

- name: Push service git id docker image.
run: ./build/docker-push.sh ${{ env.DOCKER_SERVICE }}:${{ github.sha }}

- name: Tag documentation dev docker image
run: ./build/docker-tag.sh ${{ env.DOCKER_DOCUMENTATION }}:latest ${{ env.DOCKER_DOCUMENTATION }}:dev

- name: Push documentation dev docker image
run: ./build/docker-push.sh ${{ env.DOCKER_DOCUMENTATION }}:dev

- name: Tag documentation git id docker image
run: ./build/docker-tag.sh ${{ env.DOCKER_DOCUMENTATION }}:latest ${{ env.DOCKER_DOCUMENTATION }}:${{ github.sha }}

- name: Push documentation git id docker image.
run: ./build/docker-push.sh ${{ env.DOCKER_DOCUMENTATION }}:${{ github.sha }}

- name: Push latest service docker image
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-push.sh ${{ env.DOCKER_SERVICE }}:latest

- name: Tag version service docker image
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-tag.sh ${{ env.DOCKER_SERVICE }}:latest ${{ env.DOCKER_SERVICE }}:${{ steps.tag.outputs.VERSION }}

- name: Push version service docker image.
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-push.sh ${{ env.DOCKER_SERVICE }}:${{ steps.tag.outputs.VERSION }}

- name: Push latest documentation docker image
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-push.sh ${{ env.DOCKER_DOCUMENTATION }}:latest

- name: Tag version documentation docker image
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-tag.sh ${{ env.DOCKER_DOCUMENTATION }}:latest ${{ env.DOCKER_DOCUMENTATION }}:${{ steps.tag.outputs.VERSION }}

- name: Push version documentation docker image.
if: ${{ steps.tag.conclusion != 'skipped' }}
run: ./build/docker-push.sh ${{ env.DOCKER_DOCUMENTATION }}:${{ steps.tag.outputs.VERSION }}

- name: Create Release Notes
uses: softprops/action-gh-release@v1
if: ${{ steps.tag.conclusion != 'skipped' }}
with:
generate_release_notes: true
28 changes: 28 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Dependabot auto-merge
on: pull_request

permissions:
pull-requests: write
contents: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'KvalitetsIT/kithugs' }}
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/[email protected]
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Approve PR
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Enable Auto-Merge
if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
42 changes: 42 additions & 0 deletions .github/workflows/pr_ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Pull Request CI

on:
pull_request: ~

jobs:
pr_build:
runs-on: ubuntu-latest

steps:
# Checkout source code
- uses: actions/checkout@v3

# Cache maven stuff
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build and test
run: ./build/build.sh

- name: Upload Jacoco coverage report
uses: actions/upload-artifact@v3
with:
name: jacoco-report
path: testreport/target/site/jacoco-aggregate/

- name: Save PR number
run: |
mkdir -p ./pr
echo ${{ github.event.number }} > ./pr/NR
- uses: actions/upload-artifact@v3
with:
name: pr
path: |
pr/
testreport/target/site/jacoco-aggregate/jacoco.csv
63 changes: 63 additions & 0 deletions .github/workflows/pr_ci_coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Update coverage

on:
workflow_run:
workflows: ["Pull Request CI"]
types:
- completed

jobs:
coverage:
runs-on: ubuntu-latest
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
- name: 'Download artifact'
uses: actions/github-script@v6
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr"
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
- run: unzip pr.zip

- name: Generate Jacoco Badge
id: jacoco
uses: cicirello/[email protected]
with:
jacoco-csv-file: testreport/target/site/jacoco-aggregate/jacoco.csv

- name: Log coverage percentage
run: |
echo "coverage = ${{ steps.jacoco.outputs.coverage }}"
# - name: Update coverage badge
# run: ./build/badge-update.sh

- name: 'Comment on PR with code coverage'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
var fs = require('fs');
var issue_number = Number(fs.readFileSync('./pr/NR'));
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: 'Code coverage after this PR: ' + ${{ steps.jacoco.outputs.coverage }}
});
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# maven target folder
target

# IntelliJ stuff
*.iml
.idea

# Eclipse stuff
.project
.settings/
.classpath
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 KvalitetsIT

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.
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
![Build Status](https://github.com/KvalitetsIT/kithugs/workflows/CICD/badge.svg)
# kithugs

Template repository showing how to be a good Java Spring Boot citizen in a k8s cluster.

## A good citizen

Below is a set of recommendations for being a good service. The recommendations are not tied to a specific language or
framework.

1. Configuration through environment variables.
2. Expose readiness endpoint
3. Expose endpoint that Prometheus can scrape
4. Be stateless
5. Support multiple instances
6. Always be in a releasable state
7. Automate build and deployment.

Some of above recommendations are heavily inspired by [https://12factor.net/](https://12factor.net/). It is recommended
read [https://12factor.net/](https://12factor.net/) for more inspiration and further details. Some points go
further than just being a good service and also touches areas like operations.

## Getting started

Run `./setup.sh GIT_REPOSITORY_NAME`.

Above does a search/replace in relevant files.

## Endpoints

### Service

The service is listening for connections on port 8080.

Spring boot actuator is listening for connections on port 8081. This is used as prometheus scrape endpoint and health monitoring.

Prometheus scrape endpoint: `http://localhost:8081/actuator/prometheus`
Health URL that can be used for readiness probe: `http://localhost:8081/actuator/health`

### Documentation

Documentation of the API is build as a separate Docker image. Documentation is build using Swagger. The documentation
image is post-fixed with `-documentation`. The file `documentation/docker/compose/docker-compose.yml` contains a setup
that starts both the service and documentation image. The documentation can be accessed at `http://localhost/test`
and the service can be called through the Swagger UI.

In the docker-compose setup is also an example on how to set custom endpoints for the Swagger documentation service.

## Dependency updates

Out of the box we use GitHub Actions as our CI/CD platform and that can also handle dependency updates. We utilize
GitHubs [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates)
to create PR's with dependency updates. Further we have a job that automatically approves and merges dependencies. By
default, it is only enabled in the template repository. You can enable this by removing ` && github.repository == 'KvalitetsIT/kithugs'`
from [dependabot-auto-merge.yml](.github/workflows/dependabot-auto-merge.yml). Before enabling it please consider below.

- If no branch protection rule is configured dependency udpates that fails the automatic build and test will get merged.
- You will not have a chance to review the changes in the dependency updates before it gets merged.
- Enable auto-merge must be enabled in the repository.

## Configuration

| Environment variable | Description | Required |
|----------------------|------------------------------------------------------------------------------------------------------|----------|
| JDBC_URL | JDBC connection URL | Yes |
| JDBC_USER | JDBC user | Yes |
| JDBC_PASS | JDBC password | Yes |
| LOG_LEVEL | Log Level for applikation log. Defaults to INFO. | No |
| LOG_LEVEL_FRAMEWORK | Log level for framework. Defaults to INFO. | No |
| CORRELATION_ID | HTTP header to take correlation id from. Used to correlate log messages. Defaults to "x-request-id". | No |
Loading

0 comments on commit a1e1e0c

Please sign in to comment.