Ctrl K
ComunidadGuías…

scripts/generate-forgejo-workflows.cjs

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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
  })