This is a Github Flow boilerplate project using Quarkus GraalVM native image. The whole CICD process deploying to Heroku is already setup so the development can just get started.
- CICD Workflows in place
- How to Github Flow
- Release
- Load Tests
- Integration Tests
- Sonar
- Wrapping up developer responsabilities
- Heroku DEV environment
- Database
- Api docs
- Quarkus
- Continuous Deployment
Github Actions is the CICD tool for this project. Under the directory .github/worflows
4 workflows are defined:
cron.yml
-> runs periodically (cron expression). For now, two stages running locust load tests against TEST environment and updating SonarCloud dashboard will take place.master.yml
-> full CICD, executed each time code gets merged into master. Stages: native image build / deploy to Heroku / run integration tests.pullrequest.yml
-> each time a PR is created, runs unitary teststag.yml
-> whenever a git tag (v*) is created, this workflow creates a release in Github (https://github.com/javieraviles/quarkus-github-flow/releases)
Project workflows are displayed in the repo Actions section.
- Create a feature branch from master
- Send a pull request with your proposed changes to kick off a discussion against master
- Make changes on your branch as needed. Your pull request will update automatically
- Merge the pull request once the branch is ready to be merged
- Tidy up your branches using the delete button in the pull request or on the branches page.
Checkout Github Guides for a nice and more detailed explanation on this topic.
Master branch will always be stable, as only ready branches will be merged into it. Still, not every commit from master will be a release. A git tag shall be created on master specific commits each time a new release is to be released, following a semantic versioning with v
prefix (i.e. v1.1.0
).
Once the tag has been created, the tag.yml
workflow will get triggered, publishing a github release in the repository.
As load testing tool, Locust is the one this project will be using. Opensource, mature and super powerful. The load tests can be found under the directory /loadtests
, containing an environment specific configuration file within config
dir.
As part of the cron workflow, load tests will get executed against TEST periodically.
Whenever a new endpoint is created, or a new developed feature is to affect load tests, is the responsability of the developer to update load tests accordingly.
The chosen tool here is Postman due to the simplicity and universality of it.
Under the directory /integrationtests
the test collection can be found. Within env
an environment specific file is created so the collection can be reused.
The idea is every developer should update and execute the collection locally when new features are developed and a PR is created.
Thanks to Newman the collection can also be directly executed from the CLI. In this project, every time new code is pushed to master the tests are executed against TEST environment, currently running on Heroku.
SonarCloud is free for opensource projects, so you can register there with your github account and link it to a project. Then you have mainly two options, either SonarCloud takes care of pulling from your project whenever there are changes or PRs, or you push it from your CI (previously setting your properties in the pom.xml
) performing a mvn verify sonar:sonar
.
The Dashboard in this project will then get updated with the latest quality status whenever cron.yml
worflow is executed, using master branch.
Therefore, notice the following piece of code in the pom.xml
:
```
<sonar.projectKey>javieraviles_quarkus-github-flow</sonar.projectKey>
<sonar.organization>quarkus-github-flow</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.login>214f06333c5b7090128e9144a144da8bc2439ab6</sonar.login>
```
Even though the dashboard will always represent the quality status of master, is the responsability of every developer in the project not to worsen the technical debt of the project when a new feature is introduced. Some IDEs also allow you to bind the sonar project in SonarCloud to your local project so you check whether you are introducing some new code smells based on project rules.
- Code within a feature branch starting from latest master
- Whenever is ready, create a Pull Request against develop and tell another developer to check it out and start a discussion
- Make sure your branch passes all unit tests and every piece of code you introduced contains its own unit test
- Make sure integration tests still work. Introduce some if needed.
- Make sure the technial debt in Sonar is the same or better when your code is merged.
As mentioned before, master.yml
pipeline will deploy to a DEV heroku environment every time new features are merged into master branch using a push
mechanism.
A so called Add-on
is already active in Heroku, making a PostgreSQL
database hosted in AWS available through a connection string provided as DATABASE_URL
environment variable.
Additionally, a Dyno
is also created in Heroku so the platform knows how to bootstrap our docker image every time it gets deplyed, configured with the command web ./application -Dquarkus.http.host\=0.0.0.0
.
Other than that, when the pipeline pushes to Heroku, the application downtime (startup time) will be around 50ms thanks to the GraalVM native image.
For testing purposes an H2 database will be used (notice the %test prefix in application properties
that only apply to mvn test). Once deployed, the application will use a PostgreSQL in Heroku. Connection details will get overriden as environment variables will replace some application properties
(notice the ${PORT:8080} annotation, this will get a default value of 8080
unless a PORT
environment variables is set, in which case its value will override the 8080
).
As version control for database, the selected tool is flyway
. Schema migrations will take place automatically on application startup when new flyway scripts are created at src/main/resources/db/migration
following the appropriate annotation.
Both OpenAPI and Swagger-UI are available.
This project uses Quarkus, the Supersonic Subatomic Java Framework.
If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
You can run your application in dev mode that enables live coding using:
./mvnw quarkus:dev
The application can be packaged using ./mvnw package
.
It produces the quarkus-github-flow-1.0.0-SNAPSHOT-runner.jar
file in the /target
directory.
Be aware that it’s not an über-jar as the dependencies are copied into the target/lib
directory.
The application is now runnable using java -jar target/quarkus-github-flow-1.0.0-SNAPSHOT-runner.jar
.
You can create a native executable using: ./mvnw package -Pnative
.
Or, if you don't have GraalVM installed, you can run the native executable build in a container using: ./mvnw package -Pnative -Dquarkus.native.container-build=true
.
You can then execute your native executable with: ./target/quarkus-github-flow-1.0.0-SNAPSHOT-runner
If you want to learn more about building native executables, please consult https://quarkus.io/guides/building-native-image.
So the whole project is fine and the DEV environment looks very comfy and so, BUT, what if a real production deployment completely automated is needed, with zero downtime and a serious strategy?
Well, that's the reason why I'm adding this section here.
A very convenient strategy is the so called BlueGreenDeployment.
For our scenario we will have two exact replicas of the production environment, blue and green (active and inactive). New deployments will be performed over the green (inactive) environment (where the router is not pointing to at the moment), and ensure with our integration and load tests from pipeline that the new deployment is working correctly. Then, the swap can be performed (router points now to green, becoming the active one).
Both rollback and stability should be fine following this pattern.
Your PROD environments can be created at Heroku in the same way you did for DEV. Deployment can be automated editing the tag.yaml
workflow including the same heroku deployment stages master.yaml
is using but for the prod release. Afterwards, you should include also the postman integration tests and locust load tests to ensure environment stability.
Now the end clients will not call Heroku prod environments directly, but using the router url. This router can be implemented using NGINX web server. Both the configuration and the swap script NGINX would use can be found at bluegreendeployment
directory.
This is a very brief description to just give an insight of how this could be done, but don't hesitate to read further or contact me for more details about this specific approach.