• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chrisns / repomanager / 15442251398

04 Jun 2025 12:26PM UTC coverage: 21.649%. Remained the same
15442251398

push

github

web-flow
fix: filter repos by promise status (#1364)

0 of 32 branches covered (0.0%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

21 of 65 relevant lines covered (32.31%)

0.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.65
/handler.js
1
const YAML = require('yaml')
1✔
2
const fs = require('fs')
1✔
3

4
const { Octokit } = require('@octokit/rest')
1✔
5
const { createPullRequest } = require('octokit-plugin-create-pull-request')
1✔
6
const { paginateRest } = require('@octokit/plugin-paginate-rest')
1✔
7

8
const MyOctokit = Octokit.plugin(createPullRequest).plugin(paginateRest)
1✔
9

10
const newOctokit = (installationId) => {
1✔
11
  const auth = {
×
12
    appId: process.env.APP_ID,
13
    privateKey: process.env.CERT
14
  }
15
  if (installationId) auth.installationId = installationId
×
16
  return new MyOctokit({
×
17
    authStrategy: require('@octokit/auth-app').createAppAuth,
18
    auth
19
  })
20
}
21

22
const cron = async () => {
1✔
23
  const octokit = newOctokit(0)
×
24
  const installations = await octokit.paginate(octokit.apps.listInstallations)
×
25

26
  const repos = await Promise.allSettled(
×
27
    installations.map(async (inst) => {
28
      const octokit = newOctokit(inst.id)
×
29
      return octokit
×
30
        .paginate(octokit.apps.listReposAccessibleToInstallation, inst.id)
31
        .then((repos) =>
32
          repos.filter(
×
33
            (repo) =>
34
              repo.fork === false &&
×
35
              repo.disabled === false &&
36
              repo.archived === false
37
          )
38
        )
39
        .then(async (repos) =>
40
          Promise.allSettled(
×
41
            repos.map(async (repo) => {
42
              return {
×
43
                ...repo,
44
                installationId: inst.id,
45
                octokit,
46
                desiredConfig: await getRepoConfig(
47
                  repo.name,
48
                  repo.owner.login,
49
                  octokit
50
                )
51
              }
52
            })
53
          )
54
        )
55
    })
56
  )
57
  const newrepos = []
×
58
  repos.forEach((install) => {
×
59
    if (install.status === 'fulfilled')
×
60
      install.value.forEach((repo) => {
×
NEW
61
        if (repo.status === 'fulfilled') newrepos.push(repo.value)
×
62
      })
63
  })
64
  await Promise.allSettled(newrepos.map(applyConfig))
×
65
}
66

67
const applyConfig = async (repo) => {
1✔
68
  const octokit = repo.octokit
×
69
  console.info(`applying config to ${repo.owner.login}/${repo.name}`)
×
70

71
  if (repo.desiredConfig.vulnerabilityAlerts === true) {
×
72
    await octokit.repos.enableVulnerabilityAlerts({
×
73
      owner: repo.owner.login,
74
      repo: repo.name
75
    })
76
  } else if (repo.desiredConfig.vulnerabilityAlerts === false) {
×
77
    octokit.repos.disableVulnerabilityAlerts({
×
78
      owner: repo.owner.login,
79
      repo: repo.name
80
    })
81
  }
82

83
  if (repo.desiredConfig.automatedSecurityFixes === true) {
×
84
    await octokit.repos.enableAutomatedSecurityFixes({
×
85
      owner: repo.owner.login,
86
      repo: repo.name
87
    })
88
  } else if (repo.desiredConfig.automatedSecurityFixes === false) {
×
89
    octokit.repos.disableAutomatedSecurityFixes({
×
90
      owner: repo.owner.login,
91
      repo: repo.name
92
    })
93
  }
94

95
  if (
×
96
    repo.desiredConfig.branchProtection &&
×
97
    repo.private === false &&
98
    repo.default_branch
99
  ) {
100
    const branchProtectionConfig = await Promise.allSettled(
×
101
      repo.desiredConfig.branchProtection.map(async (a) => {
102
        return {
×
103
          owner: repo.owner.login,
104
          repo: repo.name,
105
          ...a,
106
          branch:
107
            a.branch === '__DEFAULT_BRANCH__' ? repo.default_branch : a.branch,
×
108
          required_status_checks:
109
            a.required_status_checks.contexts === 'ALL'
×
110
              ? await (async () => {
111
                  try {
×
112
                    a.required_status_checks.contexts = Array.from(
×
113
                      new Set(
114
                        (
115
                          await octokit.checks.listForRef({
116
                            owner: repo.owner.login,
117
                            repo: repo.name,
118
                            ref: `refs/heads/${
119
                              a.branch === '__DEFAULT_BRANCH__'
×
120
                                ? repo.default_branch
121
                                : a.branch
122
                            }`
123
                          })
124
                        ).data.check_runs.map((check) => check.name)
×
125
                      )
126
                    )
127
                  } catch (error) {
128
                    a.required_status_checks.contexts = []
×
129
                  }
130
                  return a.required_status_checks
×
131
                })(a.required_status_checks)
132
              : a.required_status_checks
133
        }
134
      })
135
    )
136
    console.log(branchProtectionConfig[0])
×
137
    await Promise.allSettled(
×
138
      branchProtectionConfig.map(octokit.repos.updateBranchProtection)
139
    )
140
  }
141
  if (repo.desiredConfig.repo) {
×
142
    await octokit.repos.update({
×
143
      owner: repo.owner.login,
144
      repo: repo.name,
145
      ...repo.desiredConfig.repo
146
    })
147
  }
148

149
  if (repo.desiredConfig.files !== false) {
×
150
    try {
×
151
      await octokit.createPullRequest({
×
152
        owner: repo.owner.login,
153
        repo: repo.name,
154
        title: 'Update templated files',
155
        body: '',
156
        createWhenEmpty: false,
157
        head: 'repomanager_files',
158
        changes: [
159
          {
160
            files: repo.desiredConfig.files,
161
            emptyCommit: false,
162
            commit: 'Update templated files'
163
          }
164
        ]
165
      })
166
    } catch (error) {
167
      console.error(
×
168
        `${repo.full_name}: could not template file PR`,
169
        error.message
170
      )
171
    }
172
  }
173
}
174

175
const getRepoConfig = async (repo, owner, octokit) => {
1✔
176
  let configFromRepo = {}
3✔
177
  let configFromOwner = {}
3✔
178

179
  try {
3✔
180
    configFromRepo = YAML.parse(
3✔
181
      Buffer.from(
182
        (
183
          await octokit.repos.getContent({
184
            owner,
185
            repo,
186
            path: '.github/repo-config.yml'
187
          })
188
        ).data.content,
189
        'base64'
190
      ).toString()
191
    )
192
  } catch (error) {
193
    console.info(`${owner}/${repo}: could not get .github/repo-config.yml`)
2✔
194
  }
195

196
  try {
3✔
197
    configFromOwner = YAML.parse(
3✔
198
      Buffer.from(
199
        (
200
          await octokit.repos.getContent({
201
            owner,
202
            repo: '.github',
203
            path: 'repo-config.yml'
204
          })
205
        ).data.content,
206
        'base64'
207
      ).toString()
208
    )
209
  } catch (error) {
210
    console.warn(`${owner}/.github: could not get .github/repo-config.yml`)
1✔
211
  }
212

213
  const baseConfig = YAML.parse(
3✔
214
    fs.readFileSync('./base-repo-config.yml').toString()
215
  )
216
  return { ...baseConfig, ...configFromOwner, ...configFromRepo }
3✔
217
}
218

219
module.exports = {
1✔
220
  cron,
221
  getRepoConfig,
222
  applyConfig,
223
  newOctokit,
224
  MyOctokit
225
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc