OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git-deploy / lib / config.js

137 lines · javascript ref:
/**
 * DeployConfig — Per-repo deploy configuration stored in Hyperbee
 *
 * Config fields per repo:
 *   enabled: boolean
 *   channel: string (target channel/branch)
 *   mode: 'git' | 'legacy'
 *   autoRelease: boolean
 *   autoSeed: boolean
 *   autoDeploy: boolean (trigger deploy on push)
 *   configuredAt: timestamp
 */

export class DeployConfig {
  constructor (bee) {
    this._bee = bee
  }

  async get (repoName) {
    const entry = await this._bee.get(`deploy-config:${repoName}`)
    return entry ? entry.value : null
  }

  async set (repoName, config) {
    const existing = await this.get(repoName) || {}
    const merged = {
      ...existing,
      ...config,
      repoName,
      configuredAt: Date.now()
    }
    await this._bee.put(`deploy-config:${repoName}`, merged)
    return merged
  }

  async delete (repoName) {
    await this._bee.del(`deploy-config:${repoName}`)
  }

  async list () {
    const configs = []
    for await (const entry of this._bee.createReadStream({
      gt: 'deploy-config:', lt: 'deploy-config:\xff'
    })) {
      configs.push(entry.value)
    }
    return configs
  }

  async isEnabled (repoName) {
    const config = await this.get(repoName)
    return config ? config.enabled === true : false
  }

  async shouldAutoDeploy (repoName) {
    const config = await this.get(repoName)
    return config ? config.autoDeploy === true : false
  }
}

/**
 * DeployLog — Deploy history per repo stored in Hyperbee
 *
 * Each entry: { timestamp, status, commitHash, duration, error?, message? }
 */
export class DeployLog {
  constructor (bee) {
    this._bee = bee
  }

  async append (repoName, entry) {
    const key = `deploy-log:${repoName}:${Date.now()}`
    await this._bee.put(key, {
      ...entry,
      repoName,
      timestamp: Date.now()
    })
  }

  async getLog (repoName, limit = 20) {
    const entries = []
    for await (const entry of this._bee.createReadStream({
      gt: `deploy-log:${repoName}:`, lt: `deploy-log:${repoName}:\xff`,
      reverse: true, limit
    })) {
      entries.push(entry.value)
    }
    return entries
  }

  async getLatest (repoName) {
    for await (const entry of this._bee.createReadStream({
      gt: `deploy-log:${repoName}:`, lt: `deploy-log:${repoName}:\xff`,
      reverse: true, limit: 1
    })) {
      return entry.value
    }
    return null
  }

  async clear (repoName) {
    const keys = []
    for await (const entry of this._bee.createReadStream({
      gt: `deploy-log:${repoName}:`, lt: `deploy-log:${repoName}:\xff`
    })) {
      keys.push(entry.key)
    }
    for (const key of keys) await this._bee.del(key)
  }
}

/**
 * getDeployStatus — assemble status from config + log
 */
export async function getDeployStatus (config, log, repoName) {
  const cfg = await config.get(repoName)
  const latest = await log.getLatest(repoName)

  return {
    repoName,
    configured: !!cfg,
    enabled: cfg?.enabled || false,
    mode: cfg?.mode || 'git',
    channel: cfg?.channel || 'release',
    autoDeploy: cfg?.autoDeploy || false,
    autoRelease: cfg?.autoRelease || false,
    autoSeed: cfg?.autoSeed || false,
    lastDeploy: latest ? {
      timestamp: latest.timestamp,
      status: latest.status,
      commitHash: latest.commitHash,
      duration: latest.duration,
      error: latest.error || null
    } : null
  }
}