mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-30 19:00:57 +08:00
fix(release): derive video suite paths from version (#2384)
Co-authored-by: jan <jan@w-saxs001.local>
This commit is contained in:
parent
9896644dab
commit
73895b5d05
@ -5,9 +5,7 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { spawnSync } = require('child_process');
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
const RELEASE = '2.0.0-rc.1';
|
|
||||||
const SCHEMA_VERSION = 'ecc.release-video-suite.v1';
|
const SCHEMA_VERSION = 'ecc.release-video-suite.v1';
|
||||||
const VIDEO_MANIFEST_PATH = `docs/releases/${RELEASE}/video-suite-production.md`;
|
|
||||||
const HYPERGROWTH_DOC_PATH = 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md';
|
const HYPERGROWTH_DOC_PATH = 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md';
|
||||||
|
|
||||||
const REQUIRED_DOC_MARKERS = [
|
const REQUIRED_DOC_MARKERS = [
|
||||||
@ -320,7 +318,7 @@ function usage() {
|
|||||||
console.log([
|
console.log([
|
||||||
'Usage: node scripts/release-video-suite.js [options]',
|
'Usage: node scripts/release-video-suite.js [options]',
|
||||||
'',
|
'',
|
||||||
'Validates the ECC 2.0 release video production lane without committing raw media paths.',
|
'Validates the ECC 2.0 release video production lane for the package.json release version without committing raw media paths.',
|
||||||
'',
|
'',
|
||||||
'Options:',
|
'Options:',
|
||||||
' --format <text|json> Output format (default: text)',
|
' --format <text|json> Output format (default: text)',
|
||||||
@ -455,6 +453,28 @@ function safeParseJson(text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRelease(packageJson, options = {}) {
|
||||||
|
if (typeof options.release === 'string' && options.release.trim()) {
|
||||||
|
return options.release.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof packageJson.version === 'string' ? packageJson.version.trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function releaseDirFor(release) {
|
||||||
|
return `docs/releases/${release}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function releasePathsFor(release) {
|
||||||
|
const releaseDir = releaseDirFor(release);
|
||||||
|
|
||||||
|
return {
|
||||||
|
videoManifestPath: `${releaseDir}/video-suite-production.md`,
|
||||||
|
previewManifestPath: `${releaseDir}/preview-pack-manifest.md`,
|
||||||
|
launchChecklistPath: `${releaseDir}/launch-checklist.md`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function lineNumberForIndex(text, index) {
|
function lineNumberForIndex(text, index) {
|
||||||
return text.slice(0, index).split('\n').length;
|
return text.slice(0, index).split('\n').length;
|
||||||
}
|
}
|
||||||
@ -841,17 +861,19 @@ function buildReport(options = {}) {
|
|||||||
const suiteRoot = options.suiteRoot ? path.resolve(options.suiteRoot) : '';
|
const suiteRoot = options.suiteRoot ? path.resolve(options.suiteRoot) : '';
|
||||||
const skipProbe = Boolean(options.skipProbe);
|
const skipProbe = Boolean(options.skipProbe);
|
||||||
const packageJson = safeParseJson(readText(rootDir, 'package.json')) || {};
|
const packageJson = safeParseJson(readText(rootDir, 'package.json')) || {};
|
||||||
|
const release = resolveRelease(packageJson, options);
|
||||||
|
const releasePaths = releasePathsFor(release);
|
||||||
const packageScripts = packageJson.scripts || {};
|
const packageScripts = packageJson.scripts || {};
|
||||||
const packageFiles = Array.isArray(packageJson.files) ? packageJson.files : [];
|
const packageFiles = Array.isArray(packageJson.files) ? packageJson.files : [];
|
||||||
const manifest = readText(rootDir, VIDEO_MANIFEST_PATH);
|
const manifest = readText(rootDir, releasePaths.videoManifestPath);
|
||||||
const hypergrowth = readText(rootDir, HYPERGROWTH_DOC_PATH);
|
const hypergrowth = readText(rootDir, HYPERGROWTH_DOC_PATH);
|
||||||
|
|
||||||
const missingDocMarkers = REQUIRED_DOC_MARKERS.filter(marker => !manifest.includes(marker));
|
const missingDocMarkers = REQUIRED_DOC_MARKERS.filter(marker => !manifest.includes(marker));
|
||||||
const forbiddenPaths = scanForbiddenPaths(rootDir, [
|
const forbiddenPaths = scanForbiddenPaths(rootDir, [
|
||||||
VIDEO_MANIFEST_PATH,
|
releasePaths.videoManifestPath,
|
||||||
HYPERGROWTH_DOC_PATH,
|
HYPERGROWTH_DOC_PATH,
|
||||||
`docs/releases/${RELEASE}/preview-pack-manifest.md`,
|
releasePaths.previewManifestPath,
|
||||||
`docs/releases/${RELEASE}/launch-checklist.md`,
|
releasePaths.launchChecklistPath,
|
||||||
]);
|
]);
|
||||||
const sourceAssets = inspectSourceAssets(sourceRoot, skipProbe);
|
const sourceAssets = inspectSourceAssets(sourceRoot, skipProbe);
|
||||||
const suiteArtifacts = inspectSuiteArtifacts(suiteRoot, skipProbe);
|
const suiteArtifacts = inspectSuiteArtifacts(suiteRoot, skipProbe);
|
||||||
@ -875,7 +897,7 @@ function buildReport(options = {}) {
|
|||||||
'video-suite-manifest-present',
|
'video-suite-manifest-present',
|
||||||
manifest && missingDocMarkers.length === 0 ? 'pass' : 'fail',
|
manifest && missingDocMarkers.length === 0 ? 'pass' : 'fail',
|
||||||
manifest && missingDocMarkers.length === 0
|
manifest && missingDocMarkers.length === 0
|
||||||
? `${VIDEO_MANIFEST_PATH} includes the required production markers`
|
? `${releasePaths.videoManifestPath} includes the required production markers`
|
||||||
: `missing markers: ${missingDocMarkers.join(', ') || 'manifest file missing'}`,
|
: `missing markers: ${missingDocMarkers.join(', ') || 'manifest file missing'}`,
|
||||||
'Restore the video production manifest and required production markers.'
|
'Restore the video production manifest and required production markers.'
|
||||||
),
|
),
|
||||||
@ -960,7 +982,7 @@ function buildReport(options = {}) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
schema_version: SCHEMA_VERSION,
|
schema_version: SCHEMA_VERSION,
|
||||||
release: RELEASE,
|
release,
|
||||||
generatedAt: options.generatedAt || new Date().toISOString(),
|
generatedAt: options.generatedAt || new Date().toISOString(),
|
||||||
root: rootDir,
|
root: rootDir,
|
||||||
sourceRootConfigured: Boolean(sourceRoot),
|
sourceRootConfigured: Boolean(sourceRoot),
|
||||||
@ -1090,6 +1112,7 @@ module.exports = {
|
|||||||
REQUIRED_SOURCE_ASSETS,
|
REQUIRED_SOURCE_ASSETS,
|
||||||
REQUIRED_SUITE_ARTIFACTS,
|
REQUIRED_SUITE_ARTIFACTS,
|
||||||
buildReport,
|
buildReport,
|
||||||
|
releasePathsFor,
|
||||||
parseArgs,
|
parseArgs,
|
||||||
renderText,
|
renderText,
|
||||||
summarizeReport,
|
summarizeReport,
|
||||||
|
|||||||
@ -19,6 +19,13 @@ const {
|
|||||||
summarizeReport,
|
summarizeReport,
|
||||||
} = require(SCRIPT);
|
} = require(SCRIPT);
|
||||||
|
|
||||||
|
const CURRENT_RELEASE = require(path.join(__dirname, '..', '..', 'package.json')).version;
|
||||||
|
const RC_RELEASE = '2.0.0-rc.1';
|
||||||
|
|
||||||
|
function releaseDirFor(release) {
|
||||||
|
return `docs/releases/${release}`;
|
||||||
|
}
|
||||||
|
|
||||||
function createTempDir(prefix) {
|
function createTempDir(prefix) {
|
||||||
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
||||||
}
|
}
|
||||||
@ -33,16 +40,8 @@ function writeFile(rootDir, relativePath, content = 'fixture') {
|
|||||||
fs.writeFileSync(targetPath, content);
|
fs.writeFileSync(targetPath, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function seedRepo(rootDir, overrides = {}) {
|
function videoManifestContent(extra = '') {
|
||||||
const files = {
|
return [
|
||||||
'package.json': JSON.stringify({
|
|
||||||
name: 'ecc-universal',
|
|
||||||
files: ['scripts/release-video-suite.js'],
|
|
||||||
scripts: {
|
|
||||||
'release:video-suite': 'node scripts/release-video-suite.js',
|
|
||||||
},
|
|
||||||
}, null, 2),
|
|
||||||
'docs/releases/2.0.0-rc.1/video-suite-production.md': [
|
|
||||||
'# ECC 2.0 Video Suite Production Manifest',
|
'# ECC 2.0 Video Suite Production Manifest',
|
||||||
'ECC_VIDEO_SOURCE_ROOT',
|
'ECC_VIDEO_SOURCE_ROOT',
|
||||||
'ECC_VIDEO_RELEASE_SUITE_ROOT',
|
'ECC_VIDEO_RELEASE_SUITE_ROOT',
|
||||||
@ -51,13 +50,29 @@ function seedRepo(rootDir, overrides = {}) {
|
|||||||
'Self-Eval Gate',
|
'Self-Eval Gate',
|
||||||
'Do Not Publish If',
|
'Do Not Publish If',
|
||||||
'Do not commit raw footage, transcript JSON, or timeline exports',
|
'Do not commit raw footage, transcript JSON, or timeline exports',
|
||||||
].join('\n'),
|
extra,
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function seedRepo(rootDir, overrides = {}, options = {}) {
|
||||||
|
const release = options.release || CURRENT_RELEASE;
|
||||||
|
const releaseDir = releaseDirFor(release);
|
||||||
|
const files = {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
name: 'ecc-universal',
|
||||||
|
version: release,
|
||||||
|
files: ['scripts/release-video-suite.js'],
|
||||||
|
scripts: {
|
||||||
|
'release:video-suite': 'node scripts/release-video-suite.js',
|
||||||
|
},
|
||||||
|
}, null, 2),
|
||||||
|
[`${releaseDir}/video-suite-production.md`]: videoManifestContent(),
|
||||||
'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md': [
|
'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md': [
|
||||||
'Keep raw absolute paths out of public docs',
|
'Keep raw absolute paths out of public docs',
|
||||||
'Pick final video cuts, upload after approval, and attach public URLs',
|
'Pick final video cuts, upload after approval, and attach public URLs',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'docs/releases/2.0.0-rc.1/preview-pack-manifest.md': 'video-suite-production.md',
|
[`${releaseDir}/preview-pack-manifest.md`]: 'video-suite-production.md',
|
||||||
'docs/releases/2.0.0-rc.1/launch-checklist.md': 'release video suite',
|
[`${releaseDir}/launch-checklist.md`]: 'release video suite',
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [relativePath, content] of Object.entries({ ...files, ...overrides })) {
|
for (const [relativePath, content] of Object.entries({ ...files, ...overrides })) {
|
||||||
@ -171,6 +186,7 @@ function runTests() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(report.schema_version, 'ecc.release-video-suite.v1');
|
assert.strictEqual(report.schema_version, 'ecc.release-video-suite.v1');
|
||||||
|
assert.strictEqual(report.release, CURRENT_RELEASE);
|
||||||
assert.strictEqual(report.ready, true);
|
assert.strictEqual(report.ready, true);
|
||||||
assert.strictEqual(report.mediaPathsRedacted, true);
|
assert.strictEqual(report.mediaPathsRedacted, true);
|
||||||
assert.ok(report.checks.every(check => check.status === 'pass'));
|
assert.ok(report.checks.every(check => check.status === 'pass'));
|
||||||
@ -194,6 +210,33 @@ function runTests() {
|
|||||||
}
|
}
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (test('release override keeps rc.1 video fixtures testable', () => {
|
||||||
|
const rootDir = createTempDir('release-video-rc-');
|
||||||
|
const sourceRoot = createTempDir('release-video-source-');
|
||||||
|
const suiteRoot = createTempDir('release-video-suite-');
|
||||||
|
|
||||||
|
try {
|
||||||
|
seedRepo(rootDir, {}, { release: RC_RELEASE });
|
||||||
|
seedMedia(sourceRoot, suiteRoot);
|
||||||
|
|
||||||
|
const report = buildReport({
|
||||||
|
root: rootDir,
|
||||||
|
release: RC_RELEASE,
|
||||||
|
sourceRoot,
|
||||||
|
suiteRoot,
|
||||||
|
skipProbe: true,
|
||||||
|
generatedAt: '2026-05-19T00:00:00.000Z',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(report.release, RC_RELEASE);
|
||||||
|
assert.strictEqual(report.ready, true);
|
||||||
|
} finally {
|
||||||
|
cleanup(rootDir);
|
||||||
|
cleanup(sourceRoot);
|
||||||
|
cleanup(suiteRoot);
|
||||||
|
}
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
if (test('publish candidate videos require visual blank-frame QA', () => {
|
if (test('publish candidate videos require visual blank-frame QA', () => {
|
||||||
const publishVideos = REQUIRED_PUBLISH_CANDIDATES.filter(candidate => candidate.kind === 'video');
|
const publishVideos = REQUIRED_PUBLISH_CANDIDATES.filter(candidate => candidate.kind === 'video');
|
||||||
|
|
||||||
@ -231,18 +274,9 @@ function runTests() {
|
|||||||
const suiteRoot = createTempDir('release-video-suite-');
|
const suiteRoot = createTempDir('release-video-suite-');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const releaseDir = releaseDirFor(CURRENT_RELEASE);
|
||||||
seedRepo(rootDir, {
|
seedRepo(rootDir, {
|
||||||
'docs/releases/2.0.0-rc.1/video-suite-production.md': [
|
[`${releaseDir}/video-suite-production.md`]: videoManifestContent('/Users/affoon/private-media'),
|
||||||
'# ECC 2.0 Video Suite Production Manifest',
|
|
||||||
'ECC_VIDEO_SOURCE_ROOT',
|
|
||||||
'ECC_VIDEO_RELEASE_SUITE_ROOT',
|
|
||||||
'Primary launch video',
|
|
||||||
'video-use compatible workflow',
|
|
||||||
'Self-Eval Gate',
|
|
||||||
'Do Not Publish If',
|
|
||||||
'Do not commit raw footage, transcript JSON, or timeline exports',
|
|
||||||
'/Users/affoon/private-media',
|
|
||||||
].join('\n'),
|
|
||||||
});
|
});
|
||||||
seedMedia(sourceRoot, suiteRoot);
|
seedMedia(sourceRoot, suiteRoot);
|
||||||
|
|
||||||
@ -283,6 +317,7 @@ function runTests() {
|
|||||||
const parsed = JSON.parse(output);
|
const parsed = JSON.parse(output);
|
||||||
|
|
||||||
assert.strictEqual(parsed.ready, true);
|
assert.strictEqual(parsed.ready, true);
|
||||||
|
assert.strictEqual(parsed.release, CURRENT_RELEASE);
|
||||||
assert.strictEqual(parsed.sourceRootConfigured, true);
|
assert.strictEqual(parsed.sourceRootConfigured, true);
|
||||||
assert.strictEqual(parsed.suiteRootConfigured, true);
|
assert.strictEqual(parsed.suiteRootConfigured, true);
|
||||||
assert.strictEqual(parsed.sourceAssetSummary.present, REQUIRED_SOURCE_ASSETS.length);
|
assert.strictEqual(parsed.sourceAssetSummary.present, REQUIRED_SOURCE_ASSETS.length);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user