Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrate to ESM #542

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
'use strict'

const express = require('express')
const bodyParser = require('body-parser')
const bunyanMiddleware = require('bunyan-middleware')
const AsyncEventEmitter = require('events-async')
import express from 'express'
import bodyParser from 'body-parser'
import bunyanMiddleware from 'bunyan-middleware'
import AsyncEventEmitter from 'events-async'

const logger = require('./lib/logger')
const authMiddleware = require('./lib/auth-middleware')
import logger from './lib/logger.js'
import authMiddleware from './lib/auth-middleware.js'
import githubEvents from './lib/github-events.js'
import jenkinsEvents from './lib/jenkins-events.js'

const captureRaw = (req, res, buffer) => { req.raw = buffer }

const app = express()
const events = new AsyncEventEmitter()
export const app = express()
export const events = new AsyncEventEmitter()

const logsDir = process.env.LOGS_DIR || ''

Expand All @@ -29,12 +31,10 @@ app.use(bunyanMiddleware({
obscureHeaders: ['x-hub-signature']
}))

require('./lib/github-events')(app, events)
require('./lib/jenkins-events')(app, events)
githubEvents(app, events)
jenkinsEvents(app, events)

app.use(function logUnhandledErrors (err, req, res, next) {
logger.error(err, 'Unhandled error while responding to incoming HTTP request')
res.status(500).end()
})

module.exports = { app, events }
10 changes: 3 additions & 7 deletions lib/auth-middleware.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
'use strict'

/**
* Routes using this middleware gets HTTP basic authentication.
* There's only support for *one* username and password combination,
* which is set in the $LOGIN_CREDENTIALS environment variable
* in the follow format: "username:password"
*/

const auth = require('basic-auth')

const pkg = require('../package')
import auth from 'basic-auth'

const [username, password] = (process.env.LOGIN_CREDENTIALS || '').split(':')

module.exports = function authMiddleware (req, res, next) {
export default function authMiddleware (req, res, next) {
const user = auth(req)

if (user === undefined || user.name !== username || user.pass !== password) {
res.statusCode = 401
res.setHeader('WWW-Authenticate', `Basic realm="${pkg.name}"`)
res.setHeader('WWW-Authenticate', 'Basic realm="nodejs-github-bot"')
res.end('Unauthorized')
} else {
next()
Expand Down
1 change: 0 additions & 1 deletion lib/bot-username.js

This file was deleted.

6 changes: 2 additions & 4 deletions lib/github-client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict'

const { Octokit } = require('@octokit/rest')
import { Octokit } from '@octokit/rest'

const githubClient = new Octokit({
auth: process.env.GITHUB_TOKEN || 'invalid-placeholder-token',
Expand All @@ -10,4 +8,4 @@ const githubClient = new Octokit({
}
})

module.exports = githubClient
export default githubClient
6 changes: 2 additions & 4 deletions lib/github-comment.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
'use strict'

/* eslint-disable camelcase */

const githubClient = require('./github-client')
import githubClient from './github-client.js'

exports.createPrComment = async function createPrComment ({ owner, repo, issue_number, logger }, body) {
export async function createPrComment ({ owner, repo, issue_number, logger }, body) {
try {
await githubClient.issues.createComment({
owner,
Expand Down
8 changes: 5 additions & 3 deletions lib/github-events.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const debug = require('debug')('github-events')
import debugLib from 'debug'

const githubSecret = require('./github-secret')
import * as githubSecret from './github-secret.js'

module.exports = (app, events) => {
const debug = debugLib('github-events')

export default (app, events) => {
app.post('/hooks/github', async (req, res) => {
const event = req.headers['x-github-event']
if (!event) {
Expand Down
4 changes: 2 additions & 2 deletions lib/github-secret.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const crypto = require('crypto')
import crypto from 'node:crypto'

const secret = process.env.GITHUB_WEBHOOK_SECRET || 'hush-hush'

Expand All @@ -7,7 +7,7 @@ function sign (data) {
return 'sha1=' + crypto.createHmac('sha1', secret).update(buffer).digest('hex')
}

exports.isValid = function isValid (req) {
export function isValid (req) {
const signature = req.headers['x-hub-signature']
return signature && signature === sign(req.raw)
}
8 changes: 4 additions & 4 deletions lib/jenkins-events.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'
import debugLib from 'debug'

const pushJenkinsUpdate = require('../lib/push-jenkins-update')
import * as pushJenkinsUpdate from './push-jenkins-update.js'

const debug = require('debug')('jenkins-events')
const debug = debugLib('jenkins-events')
const enabledRepos = process.env.JENKINS_ENABLED_REPOS
? process.env.JENKINS_ENABLED_REPOS.split(',')
: ['citgm', 'http-parser', 'node', 'node-auto-test']
Expand All @@ -25,7 +25,7 @@ function isRelatedToPullRequest (gitRef) {
return gitRef.includes('/pull/')
}

module.exports = (app, events) => {
export default (app, events) => {
app.post('/:repo/jenkins/:event', async (req, res) => {
const isValid = pushJenkinsUpdate.validate(req.body)
const repo = req.params.repo
Expand Down
7 changes: 3 additions & 4 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict'
import path from 'node:path'

const path = require('path')
const bunyan = require('bunyan')
import bunyan from 'bunyan'

const isRunningTests = process.env.npm_lifecycle_event === 'test'
const stdoutLevel = isRunningTests ? 'FATAL' : process.env.LOG_LEVEL || 'INFO'
Expand All @@ -26,7 +25,7 @@ if (logsDir) {
})
}

module.exports = bunyan.createLogger({
export default bunyan.createLogger({
name: 'bot',
streams
})
10 changes: 2 additions & 8 deletions lib/node-owners.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use static'
import { matchPattern, parse } from 'codeowners-utils'

const { parse, matchPattern } = require('codeowners-utils')

class Owners {
export class Owners {
constructor (ownersDefinitions) {
this._ownersDefinitions = ownersDefinitions
}
Expand All @@ -24,7 +22,3 @@ class Owners {
return ownersForPaths.filter((v, i) => ownersForPaths.indexOf(v) === i).sort()
}
}

module.exports = {
Owners
}
23 changes: 10 additions & 13 deletions lib/node-repo.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
'use strict'

/* eslint-disable camelcase */

const https = require('https')
const Aigle = require('aigle')
import https from 'node:https'

import Aigle from 'aigle'

const githubClient = require('./github-client')
const { createPrComment } = require('./github-comment')
const { Owners } = require('./node-owners')
import githubClient from './github-client.js'
import { createPrComment } from './github-comment.js'
import { Owners } from './node-owners.js'

const fiveSeconds = 5 * 1000

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))

async function removeLabelFromPR (options, label) {
export async function removeLabelFromPR (options, label) {
// no need to request github if we didn't resolve a label
if (!label) {
return
Expand Down Expand Up @@ -41,7 +40,7 @@ async function removeLabelFromPR (options, label) {
return label
}

function getBotPrLabels (options, cb) {
export function getBotPrLabels (options, cb) {
githubClient.issues.listEvents({
owner: options.owner,
repo: options.repo,
Expand Down Expand Up @@ -184,11 +183,9 @@ async function pingOwners (options, owners) {
options.logger.debug('Owners pinged successfully')
}

exports.getBotPrLabels = getBotPrLabels
exports.removeLabelFromPR = removeLabelFromPR
exports.resolveOwnersThenPingPr = deferredResolveOwnersThenPingPr
export { deferredResolveOwnersThenPingPr as resolveOwnersThenPingPr }

// exposed for testability
exports._testExports = {
export const _testExports = {
pingOwners, getCodeOwnersFile, getCodeOwnersUrl, getDefaultBranch, listFiles, getCommentForOwners
}
19 changes: 6 additions & 13 deletions lib/push-jenkins-update.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
'use strict'
import githubClient from './github-client.js'
import { createPrComment } from './github-comment.js'

const githubClient = require('./github-client')
const { createPrComment } = require('./github-comment')

function pushStarted (options, build, cb) {
export function pushStarted (options, build, cb) {
const pr = findPrInRef(build.ref)

// create unique logger which is easily traceable for every subsequent log statement
Expand Down Expand Up @@ -47,7 +45,7 @@ function pushStarted (options, build, cb) {
})
}

function pushEnded (options, build, cb) {
export function pushEnded (options, build, cb) {
const pr = findPrInRef(build.ref)

// create unique logger which is easily traceable for every subsequent log statement
Expand Down Expand Up @@ -77,7 +75,7 @@ function findPrInRef (gitRef) {
return parseInt(gitRef.split('/')[2], 10)
}

async function findLatestCommitInPr (options) {
export async function findLatestCommitInPr (options) {
const paginateOptions = githubClient.pulls.listCommits.endpoint.merge({
owner: options.owner,
repo: options.repo,
Expand Down Expand Up @@ -112,12 +110,7 @@ async function createGhStatus (options, logger) {
logger.info('Jenkins / Github PR status updated')
}

function validate (payload) {
export function validate (payload) {
const isString = (param) => typeof (payload[param]) === 'string'
return ['identifier', 'status', 'message', 'commit', 'url'].every(isString)
}

exports.validate = validate
exports.pushStarted = pushStarted
exports.pushEnded = pushEnded
exports.findLatestCommitInPr = findLatestCommitInPr
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"name": "nodejs-github-bot",
"version": "1.0.0-beta1",
"description": "Node.js GitHub Bot",
"type": "module",
"scripts": {
"start": "node server.js | bunyan -o short",
"test": "STATUS=0; tap --allow-incomplete-coverage test/**/*.test.js || STATUS=$?; standard || STATUS=$?; exit $STATUS",
"test:watch": "nodemon -q -x 'npm test'"
},
"engines": {
"node": ">= 20.0.0"
"node": ">= 20.11.0"
},
"private": true,
"license": "MIT",
Expand Down
6 changes: 2 additions & 4 deletions scripts/event-relay.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict'

const githubClient = require('../lib/github-client')
import githubClient from '../lib/github-client.js'

async function handleJenkinsRelay (event) {
const { owner, repo, identifier } = event
Expand All @@ -20,6 +18,6 @@ async function handleJenkinsRelay (event) {
}
}

module.exports = function (_, event) {
export default function (_, event) {
event.on('jenkins', handleJenkinsRelay)
}
6 changes: 2 additions & 4 deletions scripts/jenkins-status.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict'

const pushJenkinsUpdate = require('../lib/push-jenkins-update')
import * as pushJenkinsUpdate from '../lib/push-jenkins-update.js'

function handleJenkinsStart (event) {
const { repo, owner } = event
Expand Down Expand Up @@ -30,7 +28,7 @@ function handleJenkinsStop (event) {
})
}

module.exports = function (_, event) {
export default function (_, event) {
event.on('jenkins.start', handleJenkinsStart)
event.on('jenkins.end', handleJenkinsStop)
}
8 changes: 4 additions & 4 deletions scripts/node-ping-owners.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use strict'
import debugLib from 'debug'

const debug = require('debug')('node_ping_owners')
import * as nodeRepo from '../lib/node-repo.js'

const nodeRepo = require('../lib/node-repo')
const debug = debugLib('node_ping_owners')

module.exports = function (app, events) {
export default function (app, events) {
events.on('pull_request.opened', handlePrCreated)
}

Expand Down
4 changes: 1 addition & 3 deletions scripts/ping.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict'

module.exports = function (app) {
export default function (app) {
app.get('/ping', (req, res) => {
res.end('pong')
})
Expand Down
18 changes: 9 additions & 9 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
'use strict'
import 'dotenv/config'

require('dotenv').config({ silent: true })

const { globSync } = require('glob')
const logger = require('./lib/logger')
import { globSync } from 'glob'
import logger from './lib/logger.js'
import { app, events } from './app.js'

const port = process.env.PORT || 3000
const scriptsToLoad = process.env.SCRIPTS || './scripts/**/*.js'
const { app, events } = require('./app')

// load all the files in the scripts folder
globSync(scriptsToLoad, { dotRelative: true }).forEach((file) => {
const files = globSync(scriptsToLoad, { dotRelative: true })
for (const file of files) {
logger.info('Loading:', file)
require(file)(app, events)
})
const { default: extend } = await import(file)
extend(app, events)
}

app.listen(port, () => {
logger.info('Listening on port', port)
Expand Down
Loading