Skip to content

Commit

Permalink
refactor: migrate to ESM (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
targos authored Jul 30, 2024
1 parent 7764e9e commit 4a14a01
Show file tree
Hide file tree
Showing 26 changed files with 113 additions and 148 deletions.
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

0 comments on commit 4a14a01

Please sign in to comment.