This is a simple Sales Manager Java App that stores sales items in a table presented in a web app.
This demo repo is designed to help understand some of CI/CD (Continuous Integration/Continuous Delivery) principles and best practices.
Java (Spring Boot framework) with MVC (Model View Controller) and OOP (Object Oriented Programming) design patterns. Backend Database is PostreSQL 10.4 (but can be used with other versions).
CI/CD Pipeline GitHub Actions as the main CI/CD pipeline orchestrator
Tools used to optimize the pipeline (See the .github/workflows/ci.yml
.github/workflows/cd.yml
for more detailed configuration).
CI - Continuous Integration
- Caching Dependencies to Speed Up Workflows
- Reusing Docker Layer Caching from pervious docker builds with action-docker-layer-caching or build-push-action actions.
- Using the Metrix Strategy to run unit tests in parallel to scale-out resources and reduce significant testing time.
- Using the Split Test Action to help splitting tests by previous testing time runs or line count (or other strategies) across multiple runners.
- GitHub Advanced Security - Code Scanning using the CodeQL analysis to scan for vulnerabilities.
- Liquibase Quality Checks - To help enforce Database schema changes best practices set by your DBA team, including naming conventions, grants & revokes, rollback scripts and security risks.
CD - Continuous Delivery/Deployment
- Using Environments with an approval step review prior to deployments
- Using the azure/login action to leverage the OIDC (OpenID Connect) functionality for the benefit of to exchange short-lived tokens directly with Azure cloud provider prior to deployment
- Running a Canary or Blue-Green deployments in an AKS (Azure Kubernetes) Cluster.
stateDiagram
state Developer-Workflow {
Commits --> PR: Developers Commit new changes in a Pull Request
PR --> Build: Security Scans, Build & Unit Test Suite
}
state Continuous-Integration {
state GitHub-Advanced-Security {
Build --> PR: Feedback of failed tests - back to dev
Build --> JunitTests: Storing Artifacts
JunitTests --> Publish: If CI passes, \nmerging to main branch \nand publishing Containerised\n App to GitHub\n Container Registry
state Parallel-Testing {
JunitTests --> JunitTest1: Each test runs in \na containerized environment
JunitTests --> JunitTest2
JunitTests --> JunitTest3
JunitTests --> JunitTest4
JunitTests --> JunitTest5
JunitTests --> JunitTest..N
}
}
}
state Continuous-Delivery {
Publish --> SystemTesting: Pulling Image from GHCR
SystemTesting --> IntegrationTesting: [staging]
IntegrationTesting --> AccepetanceTesting: [staging]
}
AccepetanceTesting --> Deploy: Login with OpenID Connect and \nDeploy the app to K8s
Deploy --> [ProdInstance1]: Blue
Deploy --> [ProdInstance2]: Green
Maven is used as the project management for Building and Testing the application. To build the application, you can run:
mvn clean package
It will generate a JAR file in the target
folder with the following format salesmanager-x.x.x-SNAPSHOT.jar
.
To run the application, you can deploy the JAR file. For example:
java -jar target/salesmanager-0.0.6-SNAPSHOT.jar
For easy demos without the need to stand up a Postgres database, a lightweight local H2 database (PostgreSQL Mode) is setup by default in the src/main/resources/application.properties
file.
You can run the ./build_and_run_app.sh
helper shell script and interact with the web app on localhost:8086
.
You can easily use a GitHub codespaces with this repository. To set up your codespace, simply go to this repo main page --> Click Code --> Codespaces '+'.
- In order to run the workflow, you will need to fork this repo.
- Then, make sure to save the following environment variables in your repository secrets so you can successfully run the Database schema mirgations scripts (using Liquibase as the schema migration tool) on application startup and when running the tests.
Repository Secrets
LIQUIBASE_COMMAND_URL
LIQUIBASE_COMMAND_USERNAME
LIQUIBASE_COMMAND_PASSWORD
If you are going to use the same dockerised service container in the CI job for dev, then the default values should be:
LIQUIBASE_COMMAND_URL
= jdbc:postgresql://postgres:5432/postgres
LIQUIBASE_COMMAND_USERNAME
= postgres
LIQUIBASE_COMMAND_PASSWORD
= postgres
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true}} }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release