text: const { getConfig } = require('./lib/config')
  const { isTriggerableReference } = require('./lib/triggerable-reference')
  const {
    findReleases,
    generateReleaseInfo,
    createRelease,
    updateRelease,
  } = require('./lib/releases')
  const { findCommitsWithAssociatedPullRequests } = require('./lib/commits')
  const { sortPullRequests } = require('./lib/sort-pull-requests')
  const log = require('./lib/log')
  const core = require('@actions/core')
  const { runnerIsActions } = require('./lib/utils')
  const ignore = require('ignore')
  
  module.exports = (app, { getRouter }) => {
    const event = runnerIsActions() ? '*' : 'push'
  
    if (!runnerIsActions() && typeof getRouter === 'function') {
      getRouter().get('/healthz', (req, res) => {
        res.status(200).json({ status: 'pass' })
      })
    }
  
    app.on(
      [
        'pull_request.opened',
        'pull_request.reopened',
        'pull_request.synchronize',
      ],
      async (context) => {
        const { disableAutolabeler } = getInput()
  
        const config = await getConfig({
          context,
          configName: core.getInput('config-name'),
        })
  
        if (config === null || disableAutolabeler) return
  
        let issue = {
          ...context.issue({ pull_number: context.payload.pull_request.number }),
        }
        const changedFiles = await context.octokit.paginate(
          context.octokit.pulls.listFiles.endpoint.merge(issue),
          (res) => res.data.map((file) => file.filename)
        )
        const labels = new Set()
  
        for (const autolabel of config['autolabeler']) {
          let found = false
          // check modified files
          if (!found && autolabel.files.length > 0) {
            const matcher = ignore().add(autolabel.files)
            if (changedFiles.find((file) => matcher.ignores(file))) {
              labels.add(autolabel.label)
              found = true
              log({
                context,
                message: `Found label for files: '${autolabel.label}'`,
              })
            }
          }
          // check branch names
          if (!found && autolabel.branch.length > 0) {
            for (const matcher of autolabel.branch) {
              if (context.payload.pull_request.head.ref.match(matcher)) {
                labels.add(autolabel.label)
                found = true
                log({
                  context,
                  message: `Found label for branch: '${autolabel.label}'`,
                })
                break
              }
            }
          }
          // check pr title
          if (!found && autolabel.title.length > 0) {
            for (const matcher of autolabel.title) {
              if (context.payload.pull_request.title.match(matcher)) {
                labels.add(autolabel.label)
                found = true
                log({
                  context,
                  message: `Found label for title: '${autolabel.label}'`,
                })
                break
              }
            }
          }
          // check pr body
          if (!found && autolabel.body.length > 0) {
            for (const matcher of autolabel.body) {
              if (context.payload.pull_request.body.match(matcher)) {
                labels.add(autolabel.label)
                found = true
                log({
                  context,
                  message: `Found label for body: '${autolabel.label}'`,
                })
                break
              }
            }
          }
        }
  
        const labelsToAdd = Array.from(labels)
        if (labelsToAdd.length > 0) {
          let labelIssue = {
            ...context.issue({
              issue_number: context.payload.pull_request.number,
              labels: labelsToAdd,
            }),
          }
          await context.octokit.issues.addLabels(labelIssue)
          if (runnerIsActions()) {
            core.setOutput('number', context.payload.pull_request.number)
            core.setOutput('labels', labelsToAdd.join(','))
          }
          return
        }
      }
    )
  
    app.on(event, async (context) => {
      const {
        shouldDraft,
        configName,
        version,
        tag,
        name,
        disableReleaser,
      } = getInput()
  
      const config = await getConfig({
        context,
        configName,
      })
  
      const { isPreRelease } = getInput({ config })
  
      if (config === null || disableReleaser) return
  
      // GitHub Actions merge payloads slightly differ, in that their ref points
      // to the PR branch instead of refs/heads/master
      const ref = process.env['GITHUB_REF'] || context.payload.ref
      const commitish = config['commitish'] || ''
  
      if (!isTriggerableReference({ ref, context, config })) {
        return
      }
  
      const { draftRelease, lastRelease } = await findReleases({
        commitish,
        context,
        config,
      })
      const {
        commits,
        pullRequests: mergedPullRequests,
      } = await findCommitsWithAssociatedPullRequests({
        context,
        commitish,
        lastRelease,
        config,
      })
  
      const sortedMergedPullRequests = sortPullRequests(
        mergedPullRequests,
        config['sort-by'],
        config['sort-direction']
      )
  
      const releaseInfo = generateReleaseInfo({
        commits,
        config,
        lastRelease,
        mergedPullRequests: sortedMergedPullRequests,
        version,
        tag,
        name,
        isPreRelease,
        shouldDraft,
      })
  
      let createOrUpdateReleaseResponse
      if (!draftRelease) {
        log({ context, message: 'Creating new release' })
        createOrUpdateReleaseResponse = await createRelease({
          context,
          releaseInfo,
          config,
        })
      } else {
        log({ context, message: 'Updating existing release' })
        createOrUpdateReleaseResponse = await updateRelease({
          context,
          draftRelease,
          releaseInfo,
          config,
        })
      }
  
      if (runnerIsActions()) {
        setActionOutput(createOrUpdateReleaseResponse, releaseInfo)
      }
    })
  }
  
  function getInput({ config } = {}) {
    // Returns all the inputs that doesn't need a merge with the config file
    if (!config) {
      return {
        shouldDraft: core.getInput('publish').toLowerCase() !== 'true',
        configName: core.getInput('config-name'),
        version: core.getInput('version') || undefined,
        tag: core.getInput('tag') || undefined,
        name: core.getInput('name') || undefined,
        disableReleaser:
          core.getInput('disable-releaser').toLowerCase() === 'true',
        disableAutolabeler:
          core.getInput('disable-autolabeler').toLowerCase() === 'true',
      }
    }
  
    // Merges the config file with the input
    // the input takes precedence, because it's more easy to change at runtime
    const preRelease = core.getInput('prerelease').toLowerCase()
    return {
      isPreRelease: preRelease === 'true' || (!preRelease && config.prerelease),
    }
  }
  
  function setActionOutput(releaseResponse, { body }) {
    const {
      data: {
        id: releaseId,
        html_url: htmlUrl,
        upload_url: uploadUrl,
        tag_name: tagName,
        name: name,
      },
    } = releaseResponse
    if (releaseId && Number.isInteger(releaseId))
      core.setOutput('id', releaseId.toString())
    if (htmlUrl) core.setOutput('html_url', htmlUrl)
    if (uploadUrl) core.setOutput('upload_url', uploadUrl)
    if (tagName) core.setOutput('tag_name', tagName)
    if (name) core.setOutput('name', name)
    core.setOutput('body', body)
  }
  