fix(ci): remove duplicate native_build_changed properties and add comprehensive release-job gating tests

ChatGPT review findings:
- Removed duplicate native_build_changed object property in classifyFiles() return (lines 69-71)
- Removed duplicate native_build_changed property in manual dispatch return (lines 150-152)

Added explicit behavioral tests for release-job gating:
- Dart-only changes on master → release skipped (native_build_changed=false)
- Android changes → release runs (native_build_changed=true)
- CI-only changes (.github/) → release runs (native_build_changed=true)
- Config changes (pubspec.yaml, build.yaml) → release runs (native_build_changed=true)
- Mixed changes → release runs (native_build_changed=true)
- Manual dispatch → release always runs (native_build_changed=true)
- Invalid Git SHA → safe fail to trigger release (native_build_changed=true)
- Unrelated changes (docs/, website/) → release skipped (native_build_changed=false)

All 52 tests pass. Release job condition verified to depend on:
- analyze passing
- test shards passing
- debug APK passing
- native_build_changed==true
- master ref

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Haiku 4.5 2026-10-30 16:39:59 -04:00
parent b1abb6b086
commit 48f1057ff0
2 changed files with 107 additions and 2 deletions

View File

@ -66,7 +66,6 @@ function classifyFiles(fileList) {
if (!Array.isArray(fileList)) { if (!Array.isArray(fileList)) {
return { return {
android_changed: false, android_changed: false,
native_build_changed: false,
app_changed: false, app_changed: false,
native_build_changed: false, native_build_changed: false,
appFiles: [], appFiles: [],
@ -147,7 +146,6 @@ function detectAndroidChanges({ eventName, baseSha, headSha, repoDir }, deps = {
if (eventName === 'workflow_dispatch') { if (eventName === 'workflow_dispatch') {
return { return {
android_changed: true, android_changed: true,
native_build_changed: true,
app_changed: true, app_changed: true,
native_build_changed: true, native_build_changed: true,
reason: 'Manual workflow_dispatch; full pipeline authorized', reason: 'Manual workflow_dispatch; full pipeline authorized',

View File

@ -571,6 +571,113 @@ describe('Workflow Scenario Matrix Verification', () => {
assert.strictEqual(result.android_changed, true); assert.strictEqual(result.android_changed, true);
assert.strictEqual(result.app_changed, true); assert.strictEqual(result.app_changed, true);
assert.strictEqual(result.native_build_changed, true);
});
});
describe('Release Job Gating (native_build_changed output)', () => {
const baseSha = '0000000000000000000000000000000000000001';
const headSha = '0000000000000000000000000000000000000002';
it('Dart-only changes skip release job (native_build_changed=false)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['lib/main.dart', 'test/widget_test.dart', 'assets/icons/app.png'] });
assert.strictEqual(result.native_build_changed, false, 'Dart-only changes should skip release');
assert.strictEqual(result.app_changed, true, 'app_changed should still be true');
});
it('Android code changes trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['android/app/build.gradle'] });
assert.strictEqual(result.native_build_changed, true, 'Android changes should trigger release');
});
it('CI-only changes (.github/) trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['.github/workflows/other.yml', '.github/scripts/helper.sh'] });
assert.strictEqual(result.native_build_changed, true, 'CI changes should trigger release');
});
it('Config file changes (pubspec.yaml) trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['pubspec.yaml'] });
assert.strictEqual(result.native_build_changed, true, 'pubspec.yaml changes should trigger release');
});
it('Build config changes (build.yaml) trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['build.yaml'] });
assert.strictEqual(result.native_build_changed, true, 'build.yaml changes should trigger release');
});
it('Mixed Dart and Android changes trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['lib/main.dart', 'android/app/build.gradle'] });
assert.strictEqual(result.native_build_changed, true, 'Mixed changes should trigger release');
});
it('Manual dispatch always triggers release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'workflow_dispatch',
baseSha: '',
headSha: ''
});
assert.strictEqual(result.native_build_changed, true, 'Manual dispatch should always trigger release');
});
it('Invalid base SHA fails safe to trigger release (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha: 'invalid',
headSha
}, { getChangedFilesFn: () => ['lib/main.dart'] });
assert.strictEqual(result.native_build_changed, true, 'Invalid SHA should fail safe to trigger release');
});
it('Unrelated changes (docs/, website/) skip release job (native_build_changed=false)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['docs/readme.md', 'website/index.html'] });
assert.strictEqual(result.native_build_changed, false, 'Unrelated changes should skip release');
});
it('dependency changes (pubspec.lock) trigger release job (native_build_changed=true)', () => {
const result = detectAndroidChanges({
eventName: 'push',
baseSha,
headSha
}, { getChangedFilesFn: () => ['pubspec.lock'] });
assert.strictEqual(result.native_build_changed, true, 'pubspec.lock changes should trigger release');
}); });
}); });