-
Notifications
You must be signed in to change notification settings - Fork 0
CI CD Setup
This page covers how to configure CircleCI in any QQQ ecosystem repository using the qqq-orb. The orb handles version calculation, building, testing, artifact publishing, and GitHub release creation automatically based on which branch you push to.
Before configuring a repo, ensure these are in place:
Your CircleCI organization must have these contexts configured:
| Context | Secrets | Used by |
|---|---|---|
qqq-maven-registry-credentials |
MAVEN_USERNAME, MAVEN_PASSWORD, GPG_PRIVATE_KEY_B64, GPG_KEYNAME, GPG_PASSPHRASE
|
All Maven projects |
qqq-security-credentials |
(same as above, plus optional scanner tokens) | Security scan jobs |
build-qqq-sample-app |
(project-specific env vars) | Projects that build with sample data |
Individual secrets:
-
GITHUB_TOKEN: Set as a project environment variable in CircleCI. Used bypublish_github_releaseto create GitHub Releases on production and hotfix builds. -
NPM_TOKEN: Required for Node.js package publishing (set in project or context).
- The repo follows GitFlow branching with
developas the default branch. - For Maven projects:
pom.xmluses<revision>X.Y.Z-SNAPSHOT</revision>for version management. - For Node projects:
package.jsonhas a standardversionfield. - The repo is followed in CircleCI (Settings > Projects > Set Up Project).
The orb maps each GitFlow branch type to a specific CI behavior:
| Trigger | Orb Job | What Happens | Artifact Published |
|---|---|---|---|
Push to feature/*
|
mvn_test_only |
Build + test, no publish | None |
Push to develop
|
mvn_publish (snapshot) |
Build + test + deploy |
X.Y.Z-SNAPSHOT to Maven Central |
Push to release/X.Y
|
mvn_publish (release_candidate) |
Build + test + deploy |
X.Y.0-RC.N to Maven Central |
Push vX.Y.Z tag |
mvn_publish (release) |
Build + test + deploy + GitHub Release |
X.Y.Z to Maven Central |
Push to hotfix/*
|
mvn_publish (hotfix) |
Build + test + deploy + GitHub Release |
X.Y.Z+1 to Maven Central |
The branch_type parameter tells the orb which version strategy to use. The orb's calculate_version.sh script reads the current pom.xml version and branch name, then calculates the correct next version automatically.
This is the most common configuration. Copy this into .circleci/config.yml:
version: 2.1
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.5
workflows:
test_only:
jobs:
- qqq-orb/mvn_test_only:
context: [qqq-maven-registry-credentials]
filters:
branches:
ignore: /(develop|main|release\/.*|hotfix\/.*|integration.*)/
tags:
only: []
publish_snapshot:
jobs:
- qqq-orb/mvn_publish:
context: [qqq-maven-registry-credentials]
branch_type: snapshot
filters:
branches:
only: [develop]
publish_release_candidate:
jobs:
- qqq-orb/mvn_publish:
context: [qqq-maven-registry-credentials]
branch_type: release_candidate
filters:
branches:
only: [/release\/.*/]
publish_release:
jobs:
- qqq-orb/mvn_publish:
context: [qqq-maven-registry-credentials]
branch_type: release
filters:
branches:
ignore: /.*/
tags:
only: [/v.*/]
publish_hotfix_release:
jobs:
- qqq-orb/mvn_publish:
context: [qqq-maven-registry-credentials]
branch_type: hotfix
filters:
branches:
only: [/hotfix\/.*/]
# Optional: feature branch publishing for cross-repo testing
# Trigger with: git tag publish-my-feature && git push origin publish-my-feature
#publish_feature:
# jobs:
# - qqq-orb/mvn_publish:
# context: [qqq-maven-registry-credentials]
# branch_type: feature
# filters:
# branches:
# only: [feature/.*]
# tags:
# only: [/publish.*/]Note on publish_release filters: The branches: ignore: /.*/ ensures this workflow only runs when a vX.Y.Z tag is pushed, not on the branch merge itself. This is important because calculate_version.sh reads the git tag to determine the release version. See Finalizing a Production Release for the correct tag workflow.
For repos that publish to NPM:
version: 2.1
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.5
workflows:
test_only:
jobs:
- qqq-orb/node_test_only:
context: [qqq-maven-registry-credentials]
filters:
branches:
ignore: /(develop|main|release\/.*|hotfix\/.*|integration.*)/
tags:
only: []
publish_snapshot:
jobs:
- qqq-orb/node_publish:
context: [qqq-maven-registry-credentials]
branch_type: snapshot
filters:
branches:
only: [develop]
publish_release_candidate:
jobs:
- qqq-orb/node_publish:
context: [qqq-maven-registry-credentials]
branch_type: release_candidate
filters:
branches:
only: [/release\/.*/]
publish_release:
jobs:
- qqq-orb/node_publish:
context: [qqq-maven-registry-credentials]
branch_type: release
filters:
branches:
ignore: /.*/
tags:
only: [/v.*/]
publish_hotfix_release:
jobs:
- qqq-orb/node_publish:
context: [qqq-maven-registry-credentials]
branch_type: hotfix
filters:
branches:
only: [/hotfix\/.*/]For repos that build a Node.js frontend and package it into a Maven JAR:
version: 2.1
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.5
workflows:
test_only:
jobs:
- qqq-orb/mvn_frontend_test_only:
context: [qqq-maven-registry-credentials]
filters:
branches:
ignore: /(develop|main|release\/.*|hotfix\/.*)/
tags:
only: []
publish_snapshot:
jobs:
- qqq-orb/mvn_frontend_publish:
context: [qqq-maven-registry-credentials]
branch_type: snapshot
filters:
branches:
only: [develop]
publish_release_candidate:
jobs:
- qqq-orb/mvn_frontend_publish:
context: [qqq-maven-registry-credentials]
branch_type: release_candidate
filters:
branches:
only: [/release\/.*/]
publish_release:
jobs:
- qqq-orb/mvn_frontend_publish:
context: [qqq-maven-registry-credentials]
branch_type: release
filters:
branches:
ignore: /.*/
tags:
only: [/v.*/]
publish_hotfix_release:
jobs:
- qqq-orb/mvn_frontend_publish:
context: [qqq-maven-registry-credentials]
branch_type: hotfix
filters:
branches:
only: [/hotfix\/.*/]For deployed applications that need CI but do NOT publish to NPM:
version: 2.1
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.5
workflows:
test_only:
jobs:
- qqq-orb/node_app_test_only:
filters:
branches:
ignore: /(develop|main|release\/.*|hotfix\/.*|integration.*)/
tags:
only: []
publish_snapshot:
jobs:
- qqq-orb/node_app_build:
filters:
branches:
only: [develop]
publish_release_candidate:
jobs:
- qqq-orb/node_app_build:
filters:
branches:
only: [/release\/.*/]
publish_release:
jobs:
- qqq-orb/node_app_build:
filters:
branches:
ignore: /.*/
tags:
only: [/v.*/]
publish_hotfix_release:
jobs:
- qqq-orb/node_app_build:
filters:
branches:
only: [/hotfix\/.*/]To add Playwright e2e tests after the build:
publish_snapshot:
jobs:
- qqq-orb/node_app_build:
name: build
filters:
branches:
only: [develop]
- qqq-orb/node_app_e2e:
requires: [build]
filters:
branches:
only: [develop]# Create feature branch from develop
git checkout develop && git pull
git checkout -b feature/add-new-widget
# Make changes, commit, push
git add .
git commit -m "feat(widget): add configurable chart widget"
git push origin feature/add-new-widgetWhat CI does: Runs mvn_test_only (or node_test_only / node_app_test_only). Builds and tests your code. No artifacts are published. If tests fail, the CI check on your PR will be red.
# Merge your feature PR into develop (via GitHub PR)
# CI triggers automatically on the develop pushWhat CI does: Runs mvn_publish with branch_type: snapshot. Calculates a X.Y.Z-SNAPSHOT version, builds, tests, and publishes to Maven Central's snapshot repository (or NPM with --tag snapshot). Other repos can depend on this SNAPSHOT for integration testing.
# 1. Ensure develop is green and all scope is merged
git checkout develop && git pull
# 2. Create the release branch
git checkout -b release/1.5
git push origin release/1.5What CI does: Runs mvn_publish with branch_type: release_candidate. Calculates 1.5.0-RC.1, builds, tests, and publishes the RC to Maven Central. Each subsequent push to the release branch increments the RC number (RC.2, RC.3, etc.).
Testing the RC:
<!-- In a downstream project's pom.xml -->
<dependency>
<groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-backend-core</artifactId>
<version>1.5.0-RC.1</version>
</dependency>Fixing issues on the release branch:
git checkout release/1.5
git commit -m "fix: resolve null pointer in query filter"
git push origin release/1.5
# CI automatically creates RC.2# 1. Merge the release branch into main
git checkout main && git pull
git merge release/1.5
# 2. Create the version tag and push everything
git tag v1.5.0
git push origin main v1.5.0
# 3. Merge back into develop so it gets any RC fixes
git checkout develop && git pull
git merge release/1.5
git push origin develop
# 4. Clean up the release branch
git branch -d release/1.5
git push origin --delete release/1.5What CI does: The v1.5.0 tag push triggers the publish_release workflow. The orb's calculate_version.sh reads the tag, sets pom.xml to 1.5.0, builds, tests, deploys to Maven Central, and creates a GitHub Release with auto-generated notes.
Important: The tag must be created before pushing, because the publish_release workflow is triggered by the tag push (not the branch push). The calculate_version.sh script reads the tag name to determine the release version.
# 1. Branch from main
git checkout main && git pull
git checkout -b hotfix/1.5.1
# 2. Fix the issue, push to trigger CI on the hotfix branch
git commit -m "fix: critical auth token validation bypass"
git push origin hotfix/1.5.1
# CI builds and publishes 1.5.1 to Maven Central
# 3. When verified, merge to main and tag
git checkout main && git merge hotfix/1.5.1
git tag v1.5.1
git push origin main v1.5.1
# Tag push triggers publish_release -> creates GitHub Release
# 4. Merge back to develop
git checkout develop && git merge hotfix/1.5.1
git push origin develop
# 5. Clean up
git branch -d hotfix/1.5.1
git push origin --delete hotfix/1.5.1What CI does: The hotfix branch push triggers mvn_publish with branch_type: hotfix, which bumps the patch version (1.5.0 -> 1.5.1), builds, tests, and publishes. The v1.5.1 tag push later triggers publish_release, which creates the GitHub Release.
For testing unreleased features in downstream projects. Requires the publish_feature workflow in your config (commented out by default in the templates above -- uncomment it to enable).
# Tag the feature branch commit with a publish- prefix
git tag publish-my-feature
git push origin publish-my-featureWhat CI does: Runs mvn_publish with branch_type: feature. Creates a version like 1.5.0-my-feature-abc1234-SNAPSHOT that downstream projects can temporarily depend on. The version commit is skipped for feature branches (versions are ephemeral).
The orb's calculate_version.sh automatically determines the version from the branch name and current pom.xml:
| Branch | Input Version (pom.xml) | Output Version | Logic |
|---|---|---|---|
develop |
1.5.0-SNAPSHOT |
1.5.0-SNAPSHOT (no change) |
Keeps current SNAPSHOT |
develop (after release merge) |
1.5.0-RC.3 |
1.6.0-SNAPSHOT |
Detects RC/stable version, bumps minor |
release/1.5 (first push) |
1.5.0-SNAPSHOT |
1.5.0-RC.1 |
Creates first RC |
release/1.5 (subsequent push) |
1.5.0-RC.1 |
1.5.0-RC.2 |
Increments RC number |
main (tagged v1.5.0) |
1.5.0-RC.3 |
1.5.0 |
Reads version from git tag |
hotfix/* |
1.5.0 |
1.5.1 |
Bumps patch |
feature/new-widget |
1.5.0-SNAPSHOT |
1.5.0-new-widget-abc1234-SNAPSHOT |
Appends feature name + commit hash |
You never need to manually edit versions. The orb handles it.
Default is Java 21. To use Java 17:
- qqq-orb/mvn_publish:
java_version: "17"
branch_type: snapshot- qqq-orb/node_publish:
node_version: "20"
branch_type: snapshotFor the main qqq repo, enable API compatibility checks:
- qqq-orb/mvn_test_only:
check_middleware_api_versions: trueAdd a security scan workflow (typically on develop only):
security_scan:
jobs:
- qqq-orb/security_scan:
context: [qqq-maven-registry-credentials, qqq-security-credentials]
filters:
branches:
only: [develop]- qqq-orb/static_analysis:
context: [qqq-maven-registry-credentials]When a new orb version is released, update the version in your .circleci/config.yml:
orbs:
qqq-orb: kingsrook/qqq-orb@0.6.5 # Update this versionYou can also pin to a major version to get automatic patches:
orbs:
qqq-orb: kingsrook/qqq-orb@0.6Or use the development snapshot for testing unreleased orb changes:
orbs:
qqq-orb: kingsrook/qqq-orb@dev:snapshotImportant: CircleCI resolves the orb version at pipeline creation time. If you rerun a pipeline, it uses the orb version from the original run. To pick up a new orb version, you must trigger a new pipeline (push a commit or use the CircleCI API).
- Check that the
contextincludes all required secrets. - Verify the orb version in your config supports the features you're using.
- Ensure
pom.xmluses<revision>for version management.
- Confirm your branch name matches GitFlow conventions exactly (
release/X.Y, notrelease/X.Y.Z). - Check that existing git tags follow
vX.Y.Zformat. - The script reads
CIRCLE_BRANCHin CI -- verify it's set correctly in your CircleCI dashboard.
-
GITHUB_TOKENmust be set as a project environment variable. - GitHub Releases are only created for
releaseandhotfixbranch types, not for snapshots or RCs.
- You must trigger a new pipeline (new commit or API trigger). Reruns use the old orb version.
- Release Flow - End-to-end release workflow
- Branching & Versioning - Branch strategy and SemVer
- Multi-Repo Workflow - Coordinating releases across repos