Compare commits

..
Author SHA1 Message Date
james.maesandCodex 0c32b55bb5 ci: use central source scanning
Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 11:39:05 -05:00
james.maesandCodex ee2e0d28c4 ci: adopt central orb 0.7.12 and stable gates (#9)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 08:52:26 -05:00
james.maesandCodex 37dc9db970 ci: centralize rc release completion in qqq orb (#8)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 02:24:11 -05:00
james.maesandCodex de6c0a7887 ci: adopt shared orb 0.7.11 (#7)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 00:59:01 -05:00
james.maes 44914c1731 Merge pull request #6 from QRun-IO/feature/central-ci
ci: adopt shared QQQ orb 0.7.4
2026-10-20 19:30:39 -05:00
james.maesandCodex 4843cad35a ci: adopt central QQQ orb 0.7.4
Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 19:26:42 -05:00
james.maes c5b842faca Merge pull request #5 from QRun-IO/ci/release-rc-secrets-inherit
ci(release-rc): pass secrets so the shared workflow can sign the RC tag
2026-10-16 08:04:01 -05:00
james.maesandClaude Opus 5.5 9a46e9428d ci(release-rc): pass secrets to the shared workflow so it can sign the RC tag
QRun-IO/.github#2 adds a tag-and-release job that signs vX with the
QRUN_TAG_SIGNING_KEY secret after Maven Central confirms the artifact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:19:43 -05:00
james.maes d0bda4fc97 Merge pull request #4 from QRun-IO/fix/develop-snapshot-version
build: develop on 0.1.0-SNAPSHOT; version test reads the build
2026-10-15 14:33:56 -05:00
james.maesandClaude Opus 5.5 a7ad7e2c9f build: develop carries 0.1.0-SNAPSHOT; version test reads the build
The release orb computes the RC on release/0.1. The producer test no longer
asserts a version literal; the version comes from the filtered
qbit-cluster.properties (and equals qbit.artifactVersion when set).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:23:07 -05:00
james.maes 376a66d2fb Merge pull request #3 from QRun-IO/feature/qqq-rc14
build: QQQ 4.1.0-RC.14
2026-10-15 14:11:13 -05:00
james.maesandClaude Opus 5.5 a10a31b695 build: QQQ 4.1.0-RC.14 (ships the cluster APIs)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:04:48 -05:00
james.maes 3ea2debd6b Merge pull request #2 from QRun-IO/feature/widget-four-columns
fix(widget): cluster nodes table in four columns
2026-10-15 12:25:14 -05:00
james.maesandClaude Opus 5.5 21f22bb926 fix(widget): cluster nodes table in four columns
Where the node runs and its version fold into the Node column, so the table
stays readable at every width (hosts gate widgets at four columns).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:24:56 -05:00
9 changed files with 141 additions and 53 deletions

No files matched your search

+11 -28
View File
@@ -1,31 +1,14 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/reference/configuration-reference/
version: 2.1
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#jobs-overview & https://circleci.com/docs/reference/configuration-reference/#jobs
jobs:
say-hello:
# Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub.
# See: https://circleci.com/docs/guides/execution-managed/executor-intro/ & https://circleci.com/docs/reference/configuration-reference/#executor-job
docker:
# Specify the version you desire here
# See: https://circleci.com/developer/images/image/cimg/base
- image: cimg/base:current
# Add steps to the job
# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#steps-overview & https://circleci.com/docs/reference/configuration-reference/#steps
steps:
# Checkout the code as the first step.
- checkout
- run:
name: "Say hello"
command: "echo Hello, World!"
# Orchestrate jobs using workflows
# See: https://circleci.com/docs/guides/orchestrate/workflows/ & https://circleci.com/docs/reference/configuration-reference/#workflows
setup: true
orbs:
qqq-orb: kingsrook/qqq-orb@0.7.12
workflows:
say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow.
# Inside the workflow, you define the jobs you want to run.
setup:
jobs:
- say-hello
- qqq-orb/generate_pipeline:
orb_version: 0.7.12
filters:
branches:
ignore: automation/qbit-rc-pending
tags:
only: /^v\d+\.\d+\.\d+$/
+23
View File
@@ -0,0 +1,23 @@
name: CodeQL
'on':
push:
branches:
- main
- develop
- release/**
- hotfix/**
pull_request: {}
schedule:
- cron: 41 16 * * 0
workflow_dispatch: {}
permissions:
contents: read
actions: read
security-events: write
packages: read
concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
analyze:
uses: QRun-IO/qqq-orb/.github/workflows/qbit-codeql.yml@c288a8864fe9054f68410e1d78f5863aea4c4d22
+62 -13
View File
@@ -1,25 +1,74 @@
# Cut the next release candidate (QRun-IO/qqq docs/QRUN-QBIT-REPO-STANDARD.md, C6):
# run this workflow by hand, or merge a develop PR labelled `release:rc`. It merges develop into
# the release line and the release/* push runs CircleCI publish_release_candidate.
name: Release candidate
on:
'on':
workflow_dispatch:
inputs:
dry_run:
description: Print the plan without merging or creating branches
description: Plan a cut without changing release state
type: boolean
default: false
finalize:
description: Retry finalization of an existing cut; do not cut another RC
type: boolean
default: false
recover:
description: Recover the same published RC after a deployment timeout; never
reupload
type: boolean
default: false
circle_build:
description: Original Circle publisher build number (recovery only)
type: string
default: ''
merge_sha:
description: Existing cut merge_sha (finalize retry only)
type: string
default: ''
bump_sha:
description: Existing cut bump_sha (finalize retry only)
type: string
default: ''
branch:
description: Existing cut branch (finalize retry only)
type: string
default: ''
version:
description: Existing cut version (finalize retry only)
type: string
default: ''
pull_request:
types: [closed]
branches: [develop]
types:
- closed
branches:
- develop
repository_dispatch:
types:
- qbit-rc-published
permissions:
contents: write
actions: read
checks: read
jobs:
release-rc:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release:rc'))
uses: QRun-IO/.github/.github/workflows/qbit-release-rc.yml@main
if: github.event_name == 'workflow_dispatch' || github.event_name == 'repository_dispatch'
|| (github.event_name == 'pull_request' && github.event.pull_request.merged
== true && github.event.pull_request.base.ref == 'develop' && contains(github.event.pull_request.labels.*.name,
'release:rc'))
uses: QRun-IO/qqq-orb/.github/workflows/qbit-release-rc.yml@cc30f599e63c8e41629c99d23395bac1adb8bc44
with:
dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false
}}
finalize: ${{ github.event_name == 'repository_dispatch' || (github.event_name
== 'workflow_dispatch' && inputs.finalize) }}
recover: ${{ github.event_name == 'workflow_dispatch' && inputs.recover || false
}}
circle_build: ${{ github.event_name == 'workflow_dispatch' && inputs.circle_build
|| '' }}
merge_sha: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.merge_sha
|| inputs.merge_sha || '' }}
bump_sha: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.bump_sha
|| inputs.bump_sha || '' }}
branch: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch
|| inputs.branch || '' }}
version: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.version
|| inputs.version || '' }}
secrets: inherit
+16
View File
@@ -0,0 +1,16 @@
profile: qbit
orb_version: 0.7.12
default_branch: develop
java_version: '21'
browsers: true
api_checks: false
docs_only: false
release_on_main: false
release_tag_policy: stable
test_branch_policy: non-release
publish:
snapshot: true
release_candidate: true
release: true
asciidoc: false
release_completion: true
+1 -1
View File
@@ -25,7 +25,7 @@ section E (summary in [docs/DESIGN.md](docs/DESIGN.md)).
<dependency>
<groupId>com.kingsrook.qbits</groupId>
<artifactId>qbit-cluster</artifactId>
<version>0.1.0-RC.1</version>
<version>0.1.0-RC.1</version><!-- first release; see GitHub releases for the latest -->
</dependency>
```
+2 -2
View File
@@ -18,7 +18,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<revision>0.1.0-RC.1</revision>
<revision>0.1.0-SNAPSHOT</revision>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<jacoco.version>0.8.15</jacoco.version>
@@ -211,7 +211,7 @@
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<qqq.snapshot.version>4.1.0-SNAPSHOT</qqq.snapshot.version>
<qqq.snapshot.version>4.1.0-RC.14</qqq.snapshot.version>
</properties>
<dependencyManagement>
<dependencies>
@@ -67,8 +67,6 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
static final String NODE = "node";
static final String STATUS = "status";
static final String HEARTBEAT = "heartbeat";
static final String WHERE = "where";
static final String VERSION = "version";
@@ -96,7 +94,7 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
}
TableData table = new TableData(null, List.of(
column("Role", ROLE), column("Node", NODE), column("Status", STATUS), column("Last heartbeat", HEARTBEAT), column("Where", WHERE), column("Version", VERSION)), rows)
column("Role", ROLE), column("Node", NODE), column("Status", STATUS), column("Last heartbeat", HEARTBEAT)), rows)
.withNoRowsFoundHTML("No nodes are running. A node appears here once it starts with the Cluster qbit.")
.withRowsPerPage(50)
.withHidePaginationDropdown(true);
@@ -112,17 +110,29 @@ public class ClusterNodesWidgetRenderer extends AbstractWidgetRenderer
{
Map<String, Object> row = new LinkedHashMap<>();
row.put(ROLE, roleLabel(role));
row.put(NODE, node.getValueString(ClusterTables.NODE_ID));
row.put(NODE, nodeText(node));
row.put(STATUS, statusText(node));
row.put(HEARTBEAT, age(node.getValueInstant(ClusterTables.HEARTBEAT_AT), now));
row.put(WHERE, Stream.of(node.getValueString(ClusterTables.K8S_NODE_NAME), node.getValueString(ClusterTables.ZONE), node.getValueString(ClusterTables.DEPLOYMENT))
.filter(StringUtils::hasContent).collect(Collectors.joining(", ")));
row.put(VERSION, node.getValueString(ClusterTables.VERSION) == null ? "" : node.getValueString(ClusterTables.VERSION));
return (row);
}
/*******************************************************************************
** The node id, with where it runs and its version folded in (four columns
** keep the table readable at every width): "web-7f9 (k8s-2, website-backend, 0.1.110)".
*******************************************************************************/
static String nodeText(QRecord node)
{
String details = Stream.of(node.getValueString(ClusterTables.K8S_NODE_NAME), node.getValueString(ClusterTables.ZONE), node.getValueString(ClusterTables.DEPLOYMENT),
node.getValueString(ClusterTables.VERSION))
.filter(StringUtils::hasContent).collect(Collectors.joining(", "));
String nodeId = node.getValueString(ClusterTables.NODE_ID);
return (details.isEmpty() ? nodeId : nodeId + " (" + details + ")");
}
/*******************************************************************************
** "Up", "Draining", "Up, drain requested", "Lost".
*******************************************************************************/
@@ -89,7 +89,14 @@ class ClusterQBitProducerTest extends BaseClusterTest
assertThat(QAlertTypeMetaData.of(qInstance, ClusterAlerts.NODE_LOST)).isNotNull();
assertThat(HealthChecksMetaData.ofOrWithNew(qInstance).getChecks()).anyMatch(check -> ClusterHeartbeatHealthCheck.NAME.equals(check.getName()));
assertThat(qInstance.getRuntimeServices()).extracting(reference -> reference.getName()).containsOnlyOnce(ClusterRuntimeService.class.getName());
assertThat(ClusterQBitProducer.version()).isEqualTo("0.1.0-RC.1");
////////////////////////////////////////////////////////////////////
// the version comes from the build (filtered qbit-cluster.properties) //
////////////////////////////////////////////////////////////////////
assertThat(ClusterQBitProducer.version()).matches("[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9.]+)?");
if(System.getProperty("qbit.artifactVersion") != null)
{
assertThat(ClusterQBitProducer.version()).isEqualTo(System.getProperty("qbit.artifactVersion"));
}
}
@@ -118,7 +118,7 @@ class ClusterSettingsWidgetHealthTest extends BaseClusterTest
assertThat(rows.get(0).get("heartbeat")).isEqualTo("5 hours ago");
assertThat(rows.get(2).get("status")).isEqualTo("Up, drain requested");
assertThat(rows.get(3).get("heartbeat")).isEqualTo("3 minutes ago");
assertThat(table.getColumns()).hasSize(6);
assertThat(table.getColumns()).as("four columns: readable at every width").hasSize(4);
assertThat(lost).isNotNull();
assertThat(ClusterNodesWidgetRenderer.class).isNotNull();