Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .cz.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
name = "cz_conventional_commits"
tag_format = "v$version"
version_scheme = "semver"
version = "2.0.0-rc.8"
version = "3.0.0-rc.1"
update_changelog_on_bump = true
27 changes: 27 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
* text=auto
*.java text eol=lf
*.gradle text eol=lf
*.md text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.jar binary
*.zip binary

# Keep release source archives self-contained and free of local artifacts.
*.zip export-ignore
build/** export-ignore
**/build/** export-ignore
.gradle/** export-ignore
**/.gradle/** export-ignore
__MACOSX/** export-ignore
**/__MACOSX/** export-ignore
._* export-ignore
**/._* export-ignore
.DS_Store export-ignore
**/.DS_Store export-ignore
*.jfr export-ignore
*.hprof export-ignore
hs_err_pid*.log export-ignore
replay_pid*.log export-ignore
98 changes: 77 additions & 21 deletions .github/scripts/prepare-rc-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { execFileSync } = require('node:child_process');
const fs = require('node:fs');

const CZ_TOML = '.cz.toml';
const CANONICAL_EVIDENCE = 'docs/releases/3.0.0-rc.1-evidence.json';
const MAIN_REF = process.env.RC_BASE_REF || 'origin/main';
const VALID_BUMPS = new Set(['major', 'minor', 'patch']);

Expand All @@ -20,14 +21,15 @@ function readVersion(content) {
}

function parseVersion(version) {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-rc\.\d+)?$/);
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-rc\.(\d+))?$/);
if (!match) {
throw new Error(`Unsupported version format: ${version}`);
}
return {
major: Number(match[1]),
minor: Number(match[2]),
patch: Number(match[3]),
rc: match[4] == null ? null : Number(match[4]),
};
}

Expand Down Expand Up @@ -98,24 +100,78 @@ function versionFromRef(ref) {
return parseVersion(readVersion(content));
}

const currentContent = fs.readFileSync(CZ_TOML, 'utf8');
const baseVersion = versionFromRef(MAIN_REF);
const messages = commitMessagesSince(MAIN_REF);
const bump = bumpFromMessages(messages);
const targetBase = formatVersion(increment(baseVersion, bump));
const nextVersion = `${targetBase}-rc.${latestRc(targetBase) + 1}`;

const nextContent = currentContent.replace(
/^version\s*=\s*"[^"]+"/m,
`version = "${nextVersion}"`,
);
fs.writeFileSync(CZ_TOML, nextContent);

console.log(`Base ref: ${MAIN_REF}`);
console.log(`Base version: ${formatVersion(baseVersion)}`);
console.log(`Aggregate bump: ${bump}`);
console.log(`Next RC version: ${nextVersion}`);

if (process.env.GITHUB_OUTPUT) {
fs.appendFileSync(process.env.GITHUB_OUTPUT, `version=${nextVersion}\n`);
function nextVersionForCurrentRc(currentVersion, latestTaggedRc) {
const parsed = parseVersion(currentVersion);
if (parsed.rc == null) {
throw new Error(`Version is not an RC: ${currentVersion}`);
}
const nextRc = Math.max(parsed.rc, latestTaggedRc + 1);
return `${formatVersion(parsed)}-rc.${nextRc}`;
}

function evidenceRelease(content) {
const evidence = JSON.parse(content);
if (typeof evidence.release !== 'string' || evidence.release.length === 0) {
throw new Error(`Canonical evidence is missing a release: ${CANONICAL_EVIDENCE}`);
}
return evidence.release;
}

function assertEvidenceRelease(preparedVersion, content) {
const canonicalRelease = evidenceRelease(content);
if (canonicalRelease !== preparedVersion) {
throw new Error(
`Prepared RC ${preparedVersion} does not match canonical evidence release ${canonicalRelease}`,
);
}
}

function prepareRcRelease() {
const currentContent = fs.readFileSync(CZ_TOML, 'utf8');
const currentVersion = readVersion(currentContent);
const current = parseVersion(currentVersion);
let nextVersion;

if (current.rc != null) {
const targetBase = formatVersion(current);
nextVersion = nextVersionForCurrentRc(currentVersion, latestRc(targetBase));
console.log(`Current RC series: ${targetBase}`);
} else {
const baseVersion = versionFromRef(MAIN_REF);
const messages = commitMessagesSince(MAIN_REF);
const bump = bumpFromMessages(messages);
const targetBase = formatVersion(increment(baseVersion, bump));
nextVersion = `${targetBase}-rc.${latestRc(targetBase) + 1}`;
console.log(`Base ref: ${MAIN_REF}`);
console.log(`Base version: ${formatVersion(baseVersion)}`);
console.log(`Aggregate bump: ${bump}`);
}

assertEvidenceRelease(
nextVersion,
fs.readFileSync(CANONICAL_EVIDENCE, 'utf8'),
);

const nextContent = currentContent.replace(
/^version\s*=\s*"[^"]+"/m,
`version = "${nextVersion}"`,
);
fs.writeFileSync(CZ_TOML, nextContent);

console.log(`Next RC version: ${nextVersion}`);

if (process.env.GITHUB_OUTPUT) {
fs.appendFileSync(process.env.GITHUB_OUTPUT, `version=${nextVersion}\n`);
}
}

if (require.main === module) {
prepareRcRelease();
}

module.exports = {
assertEvidenceRelease,
evidenceRelease,
nextVersionForCurrentRc,
parseVersion,
};
55 changes: 55 additions & 0 deletions .github/scripts/prepare-rc-release.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const assert = require('node:assert/strict');
const test = require('node:test');

const {
assertEvidenceRelease,
evidenceRelease,
nextVersionForCurrentRc,
parseVersion,
} = require('./prepare-rc-release.js');

test('parses stable and RC versions', () => {
assert.deepEqual(parseVersion('3.0.0'), {
major: 3,
minor: 0,
patch: 0,
rc: null,
});
assert.deepEqual(parseVersion('3.0.0-rc.12'), {
major: 3,
minor: 0,
patch: 0,
rc: 12,
});
});

test('keeps an intentional RC when its tag does not exist yet', () => {
assert.equal(nextVersionForCurrentRc('3.0.0-rc.1', 0), '3.0.0-rc.1');
});

test('advances an RC after the current tag exists', () => {
assert.equal(nextVersionForCurrentRc('3.0.0-rc.1', 1), '3.0.0-rc.2');
assert.equal(nextVersionForCurrentRc('3.0.0-rc.1', 8), '3.0.0-rc.9');
});

test('reads the release bound by canonical evidence', () => {
assert.equal(evidenceRelease('{"release":"3.0.0-rc.1"}'), '3.0.0-rc.1');
assert.throws(
() => evidenceRelease('{}'),
/Canonical evidence is missing a release/,
);
});

test('rejects a prepared RC that differs from canonical evidence', () => {
assert.doesNotThrow(() => assertEvidenceRelease(
'3.0.0-rc.1',
'{"release":"3.0.0-rc.1"}',
));
assert.throws(
() => assertEvidenceRelease(
'2.0.0-rc.9',
'{"release":"3.0.0-rc.1"}',
),
/Prepared RC 2\.0\.0-rc\.9 does not match canonical evidence release 3\.0\.0-rc\.1/,
);
});
117 changes: 56 additions & 61 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,80 @@ on:
push:
branches:
- main
- 'cursor/*'
- 'feature/*'
- 'fix/*'
- 'hotfix/*'
- 'release/*'
- next
- 'feature/**'
- 'fix/**'
- 'hotfix/**'
- 'release/**'
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: coordination-build-${{ github.ref }}
cancel-in-progress: true

jobs:
CoreJava8:
verify:
name: Java ${{ matrix.test-java }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
test-java: ['17', '21']
env:
CI: true
defaults:
run:
working-directory: blue-coordination-java
steps:
- uses: actions/checkout@v4

- name: Check out blue-quickjs
- name: Check out Coordination
uses: actions/checkout@v4
with:
repository: bluecontract/blue-quickjs
path: blue-quickjs
submodules: recursive
path: blue-coordination-java
fetch-depth: 0

- name: Set up Java 8 test runtime
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'corretto'

- name: Set up JDK 25
uses: actions/setup-java@v3
with:
java-version: '25'
distribution: 'corretto'
- name: Configure Gradle user home
run: echo "GRADLE_USER_HOME=$RUNNER_TEMP/coordination-gradle-${{ matrix.test-java }}" >> "$GITHUB_ENV"

- name: Set up pnpm
uses: pnpm/action-setup@v4
- name: Set up test JDK
uses: actions/setup-java@v4
with:
version: 9.8.0
run_install: false
distribution: temurin
java-version: ${{ matrix.test-java }}

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version-file: 'blue-quickjs/.nvmrc'
cache: 'pnpm'
cache-dependency-path: 'blue-quickjs/pnpm-lock.yaml'
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v4

- name: Cache emsdk
uses: actions/cache@v4
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
with:
path: blue-quickjs/tools/emsdk
key: emsdk-${{ runner.os }}-${{ hashFiles('blue-quickjs/tools/scripts/emsdk-version.txt') }}

- name: Install blue-quickjs dependencies
run: pnpm install --frozen-lockfile
working-directory: blue-quickjs

- name: Install emsdk
run: bash tools/scripts/setup-emsdk.sh
working-directory: blue-quickjs
cache-read-only: ${{ github.ref != 'refs/heads/main' }}

- name: Build blue-quickjs runtime
run: pnpm exec nx build quickjs-runtime
working-directory: blue-quickjs
- name: Verify release-version selection
run: node --test .github/scripts/prepare-rc-release.test.js

- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Verify published dependency availability
run: >-
./gradlew --no-daemon dependencyPreflight
-PblueDependencyMode=published-artifact

- name: Execute Java 8 core build
run: ./gradlew :clean :build -Dblue.quickjs.root="$GITHUB_WORKSPACE/blue-quickjs"
- name: Run clean RC verification
run: >-
./gradlew --no-daemon clean releaseCheck

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid gating every CI build on interim RC evidence

This workflow runs releaseCheck on every push/PR, but the committed canonical evidence is still INTERIM/PENDING_VERIFICATION with publicRcReady: BLOCKED and candidateCommit: null. releaseCheck rejects those values, so every build in this workflow will fail before tests can pass until final evidence is committed. Use a non-final verification task here or commit final PASS evidence before wiring releaseCheck into normal CI.

Useful? React with 👍 / 👎.

-PblueDependencyMode=published-artifact
-PtestJavaVersion=${{ matrix.test-java }}

- name: Archive test results
- name: Archive verification evidence
uses: actions/upload-artifact@v4
if: always()
with:
name: core-java8-test-results
path: build/reports

- name: Archive libs
uses: actions/upload-artifact@v4
with:
name: core-java8-libs
path: build/libs
name: coordination-java-${{ matrix.test-java }}-evidence
path: |
blue-coordination-java/build/libs/**
blue-coordination-java/build/publications/**
blue-coordination-java/build/reports/**
blue-coordination-java/build/test-results/**
blue-coordination-java/build/staging-deploy/**
Loading
Loading