snapshot of https://github.com/ueberdosis/tiptap.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped
This commit is contained in:
128
.github/scripts/__tests__/resolve-publish-config.test.mjs
vendored
Normal file
128
.github/scripts/__tests__/resolve-publish-config.test.mjs
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
import { describe, it, before, after } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync, writeFileSync, mkdtempSync, rmSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { resolveConfig } from '../resolve-publish-config.mjs'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const ACTUAL_CONFIG_PATH = join(__dirname, '..', '..', 'publish-config.json')
|
||||
|
||||
let tmpDir
|
||||
let configPath
|
||||
|
||||
before(() => {
|
||||
tmpDir = mkdtempSync(join(tmpdir(), 'publish-config-test-'))
|
||||
configPath = join(tmpDir, 'publish-config.json')
|
||||
})
|
||||
|
||||
after(() => {
|
||||
rmSync(tmpDir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
function writeConfig(data) {
|
||||
writeFileSync(configPath, JSON.stringify(data, null, 2))
|
||||
}
|
||||
|
||||
describe('real publish-config.json', () => {
|
||||
let actualConfig
|
||||
|
||||
before(() => {
|
||||
const raw = readFileSync(ACTUAL_CONFIG_PATH, 'utf8')
|
||||
actualConfig = JSON.parse(raw)
|
||||
})
|
||||
|
||||
it('is valid JSON and contains a branches object', () => {
|
||||
assert.ok(actualConfig.branches, 'missing branches object')
|
||||
assert.ok(typeof actualConfig.branches === 'object', 'branches must be an object')
|
||||
})
|
||||
|
||||
it('has at least one configured branch', () => {
|
||||
const names = Object.keys(actualConfig.branches)
|
||||
assert.ok(names.length > 0, 'publish-config.json has no branches configured')
|
||||
})
|
||||
|
||||
it('every branch entry has all required string fields', () => {
|
||||
const required = ['distTag', 'label', 'title', 'commit']
|
||||
for (const [name, entry] of Object.entries(actualConfig.branches)) {
|
||||
for (const field of required) {
|
||||
assert.ok(
|
||||
entry[field] && typeof entry[field] === 'string',
|
||||
`Branch "${name}" is missing required string field "${field}"`,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('resolves each configured branch through the resolver', () => {
|
||||
for (const name of Object.keys(actualConfig.branches)) {
|
||||
const result = resolveConfig(name, ACTUAL_CONFIG_PATH)
|
||||
assert.equal(result.configured, true, `Branch "${name}" should resolve as configured`)
|
||||
assert.equal(result.distTag, actualConfig.branches[name].distTag)
|
||||
assert.equal(result.label, actualConfig.branches[name].label)
|
||||
assert.equal(result.title, actualConfig.branches[name].title)
|
||||
assert.equal(result.commit, actualConfig.branches[name].commit)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('unknown branches', () => {
|
||||
it('returns configured=false for a branch with no entry', () => {
|
||||
writeConfig({
|
||||
branches: { known: { distTag: 'x', label: 'stable', title: 'T', commit: 'c' } },
|
||||
})
|
||||
const result = resolveConfig('unknown', configPath)
|
||||
assert.equal(result.configured, false)
|
||||
})
|
||||
|
||||
it('does not match partial branch names', () => {
|
||||
writeConfig({
|
||||
branches: { main: { distTag: 'x', label: 'stable', title: 'T', commit: 'c' } },
|
||||
})
|
||||
const result = resolveConfig('main-foo', configPath)
|
||||
assert.equal(result.configured, false)
|
||||
})
|
||||
|
||||
it('returns only configured=false for an unknown branch', () => {
|
||||
writeConfig({ branches: {} })
|
||||
const result = resolveConfig('anything', configPath)
|
||||
assert.deepEqual(result, { configured: false })
|
||||
})
|
||||
})
|
||||
|
||||
describe('validation errors', () => {
|
||||
it('fails when a required field is missing', () => {
|
||||
writeConfig({ branches: { main: { distTag: 'latest', label: 'stable' } } })
|
||||
assert.throws(() => resolveConfig('main', configPath), /missing required/i)
|
||||
})
|
||||
|
||||
it('fails when a required field is not a string', () => {
|
||||
writeConfig({
|
||||
branches: { main: { distTag: 'latest', label: 123, title: null, commit: 'ok' } },
|
||||
})
|
||||
assert.throws(() => resolveConfig('main', configPath), /missing required/i)
|
||||
})
|
||||
|
||||
it('fails when config has no branches object', () => {
|
||||
writeConfig({})
|
||||
assert.throws(() => resolveConfig('main', configPath), /branches/)
|
||||
})
|
||||
|
||||
it('fails when branches is an array instead of an object', () => {
|
||||
writeConfig({ branches: [] })
|
||||
assert.throws(() => resolveConfig('any', configPath), /branches/)
|
||||
})
|
||||
|
||||
it('fails when config file is malformed JSON', () => {
|
||||
writeFileSync(configPath, 'not-json')
|
||||
assert.throws(() => resolveConfig('main', configPath), /Failed to read or parse/)
|
||||
})
|
||||
|
||||
it('fails when config file does not exist', () => {
|
||||
assert.throws(
|
||||
() => resolveConfig('main', join(tmpDir, 'nonexistent.json')),
|
||||
/Failed to read or parse/,
|
||||
)
|
||||
})
|
||||
})
|
||||
103
.github/scripts/resolve-publish-config.mjs
vendored
Normal file
103
.github/scripts/resolve-publish-config.mjs
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join, dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const DEFAULT_CONFIG_PATH = join(__dirname, '..', 'publish-config.json')
|
||||
const REQUIRED_FIELDS = ['distTag', 'label', 'title', 'commit']
|
||||
|
||||
/** @typedef {{ distTag: string, label: string, title: string, commit: string }} BranchEntry */
|
||||
|
||||
/**
|
||||
* Reads and parses the publish config JSON file.
|
||||
* @param {string} configPath
|
||||
* @returns {object}
|
||||
*/
|
||||
function readConfig(configPath) {
|
||||
try {
|
||||
return JSON.parse(readFileSync(configPath, 'utf8'))
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to read or parse ${configPath}: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the config has a "branches" object.
|
||||
* @param {object} config
|
||||
*/
|
||||
function requireBranchesObject(config) {
|
||||
if (!config.branches || typeof config.branches !== 'object' || Array.isArray(config.branches)) {
|
||||
throw new Error('publish-config.json must contain a "branches" object')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a branch entry has all required string fields.
|
||||
* @param {string} branch
|
||||
* @param {BranchEntry} entry
|
||||
*/
|
||||
function requireValidEntry(branch, entry) {
|
||||
for (const field of REQUIRED_FIELDS) {
|
||||
if (!entry[field] || typeof entry[field] !== 'string') {
|
||||
throw new Error(
|
||||
`Branch "${branch}" is missing required string field "${field}" in publish-config.json`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a branch in the publish config and returns its release settings.
|
||||
*
|
||||
* @param {string} branch - Branch name to look up (exact match).
|
||||
* @param {string} [configPath] - Path to publish-config.json. Defaults to the
|
||||
* canonical location next to the scripts directory.
|
||||
* @returns {{ configured: false } | { configured: true, distTag: string, label: string, title: string, commit: string }}
|
||||
* @throws {Error} When the config cannot be read/parsed or a required field is missing.
|
||||
*/
|
||||
export function resolveConfig(branch, configPath = DEFAULT_CONFIG_PATH) {
|
||||
const config = readConfig(configPath)
|
||||
requireBranchesObject(config)
|
||||
|
||||
const entry = config.branches[branch]
|
||||
if (!entry) {
|
||||
return { configured: false }
|
||||
}
|
||||
|
||||
requireValidEntry(branch, entry)
|
||||
|
||||
return {
|
||||
configured: true,
|
||||
distTag: entry.distTag,
|
||||
label: entry.label,
|
||||
title: entry.title,
|
||||
commit: entry.commit,
|
||||
}
|
||||
}
|
||||
|
||||
// ── CLI entry point ───────────────────────────────────────────
|
||||
// When run as `node resolve-publish-config.mjs <branch>`, emits
|
||||
// key=value lines suitable for GitHub Actions step outputs.
|
||||
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
const branch = process.argv[2]
|
||||
if (!branch) {
|
||||
console.error('Usage: node resolve-publish-config.mjs <branch-name> [config-path]')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const configPath = process.argv[3] || DEFAULT_CONFIG_PATH
|
||||
|
||||
try {
|
||||
const result = resolveConfig(branch, configPath)
|
||||
for (const [key, value] of Object.entries(result)) {
|
||||
// Convert camelCase to snake_case for GitHub Actions output keys
|
||||
const actionsKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
|
||||
console.log(`${actionsKey}=${value}`)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.message)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user