scripts/generate-forgejo-workflows.cjs
Rama master · réplica de lectura del repositorio original.
const fs = require('node:fs')
const path = require('node:path')
const yaml = require('js-yaml')
const prettier = require('prettier')
const template = 'projects/start-sdk/docs/package-template'
const upstream = 'Start9Labs/start-technologies/'
const artifactHost = 'https://data.forgejo.org/forgejo'
const header =
'# Generated by scripts/generate-forgejo-workflows.cjs; edit the GitHub sources instead.\n'
function generatedPaths(root) {
return ['.forgejo', `${template}/.forgejo`].flatMap(directory => {
const absolute = path.join(root, directory)
if (!fs.existsSync(absolute)) return []
return fs
.readdirSync(absolute, { recursive: true })
.filter(
file =>
/\.ya?ml$/.test(file) &&
fs.readFileSync(path.join(absolute, file), 'utf8').startsWith(header),
)
.map(file => `${directory}/${file}`)
})
}
async function generate(root) {
const outputs = new Map()
const visited = new Set()
const config = JSON.parse(
fs.readFileSync(path.join(root, '.prettierrc.json'), 'utf8'),
)
const readYaml = file =>
yaml.load(fs.readFileSync(path.join(root, file), 'utf8'))
function portUses(uses) {
const prefix = `${upstream}.github/`
if (uses.startsWith(prefix) && uses.endsWith('@master')) {
const source = uses.slice(upstream.length, -'@master'.length)
const manifest = source.startsWith('.github/workflows/')
? source
: `${source}/action.yml`
const document = readYaml(manifest)
if (document.jobs || document.runs.steps?.some(step => step.uses)) {
portFile(manifest, manifest.replace('.github/', '.forgejo/'))
return `https://github.com/${upstream}${source.replace('.github/', '.forgejo/')}@master`
}
}
if (uses.startsWith('actions/upload-artifact@'))
return `${artifactHost}/upload-artifact@v4`
if (uses.startsWith('actions/download-artifact@'))
return `${artifactHost}/download-artifact@v4`
return uses.startsWith('https://') ||
uses.startsWith('./') ||
uses.startsWith('docker://')
? uses
: `https://github.com/${uses}`
}
function portStep(step, job) {
if (!step.uses) return
if (step.uses === `${upstream}.github/actions/upload-each@master`) {
step.name = 'Upload s9pks'
step.uses = `${artifactHost}/upload-artifact@v4`
const { pattern, ...options } = step.with
step.with = {
...options,
name: job.strategy?.matrix
? "s9pks-${{ matrix.target || 'default' }}"
: 's9pks',
path: pattern,
}
} else if (step.uses.startsWith('softprops/action-gh-release@')) {
step.name = 'Create Forgejo release'
step.uses = `https://github.com/${upstream}.github/actions/forgejo-release@master`
step.with.token = '${{ github.token }}'
} else {
step.uses = portUses(step.uses)
}
}
function portFile(source, destination) {
if (visited.has(destination)) return
visited.add(destination)
const document = readYaml(source)
for (const job of Object.values(document.jobs || {})) {
job['runs-on'] = 'ubuntu-latest'
if (job.uses) job.uses = portUses(job.uses)
for (const step of job.steps || []) portStep(step, job)
}
for (const step of document.runs?.steps || []) portStep(step, {})
outputs.set(destination, document)
}
for (const filename of fs
.readdirSync(path.join(root, template, '.github/workflows'))
.sort()) {
if (/\.ya?ml$/.test(filename)) {
portFile(
`${template}/.github/workflows/${filename}`,
`${template}/.forgejo/workflows/${filename}`,
)
}
}
for (const [destination, document] of outputs) {
const text =
header +
yaml.dump(document, { lineWidth: -1, noRefs: true, quotingType: "'" })
outputs.set(
destination,
await prettier.format(text, { ...config, parser: 'yaml' }),
)
}
return outputs
}
async function main() {
const root = path.resolve(__dirname, '..')
const outputs = await generate(root)
const check = process.argv.includes('--check')
for (const file of generatedPaths(root).filter(file => !outputs.has(file))) {
if (check)
throw new Error(`${file} is obsolete; regenerate Forgejo workflows`)
fs.unlinkSync(path.join(root, file))
}
for (const [destination, text] of outputs) {
const file = path.join(root, destination)
if (check) {
if (!fs.existsSync(file) || fs.readFileSync(file, 'utf8') !== text) {
throw new Error(
`${destination} is stale; run node scripts/generate-forgejo-workflows.cjs`,
)
}
} else {
fs.mkdirSync(path.dirname(file), { recursive: true })
fs.writeFileSync(file, text)
}
}
console.log(
`${check ? 'Checked' : 'Generated'} ${outputs.size} Forgejo workflows/actions`,
)
}
module.exports = { generate, generatedPaths }
if (require.main === module)
main().catch(error => {
console.error(error)
process.exitCode = 1
})