Skip to content

Commit

Permalink
Use classes to better handle tests
Browse files Browse the repository at this point in the history
Because of recent changes from the Octokit library (relying on Node internal fetch), we can't use `nock` anymore during tests. We must now pass a custom `fetch` to the Octokit class to mock request.
To do that, we can no longer only use `handler` with all the code inside it, but use classes. It's also more clean :)
  • Loading branch information
j0k3r committed Oct 6, 2023
1 parent 2ff17e8 commit 1607075
Show file tree
Hide file tree
Showing 10 changed files with 926 additions and 1,057 deletions.
67 changes: 67 additions & 0 deletions functions/classes/ExtensionHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import got from 'got'
import parse from 'diffparser'
import { Handler } from './Handler'

export class ExtensionHandler extends Handler {
constructor(githubToken, namespace, fetch = null) {
super(githubToken, fetch)

this.namespace = namespace
}

async handle(body, callback) {
let response = this.validateEvent(body)

if (response !== true) {
return callback(null, response)
}

console.log(`Working on repo ${body.repository.full_name} for PR #${body.pull_request.number}`)

Check warning on line 19 in functions/classes/ExtensionHandler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

const payload = {
success: {
state: 'success',
description: 'passed',
context: `${this.namespace} - File extension check`,
},
failure: {
state: 'failure',
description: 'failed',
context: `${this.namespace} - File extension check`,
},
}

let diffResponse
try {
diffResponse = await got(body.pull_request.diff_url)
} catch (e) {
console.log(e.message)

Check warning on line 38 in functions/classes/ExtensionHandler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

return callback(null, {
statusCode: 500,
body: e.message,
})
}

const validation = parse(diffResponse.body).every((diff) => {
// we don't need to validate deleted file
if (diff.deleted === true) {
return true
}

if (/\.txt$/.test(diff.to) === false) {
payload.failure.description = `Fail: "${diff.to}" has not a txt extension`

console.log(`Fail: "${diff.to}" has not a txt extension`)

Check warning on line 55 in functions/classes/ExtensionHandler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

return false
}

return true
})

response = await this.updateStatus(body, validation ? payload.success : payload.failure)

return callback(null, response)
}
}
91 changes: 91 additions & 0 deletions functions/classes/Handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Octokit } from '@octokit/rest'

export class Handler {
constructor(githubToken, fetch = null) {
const options = {
auth: githubToken,
}

if (fetch) {
options.request = {
fetch,
}
}

this.githubClient = new Octokit(options)
}

// eslint-disable-next-line class-methods-use-this
validateEvent(body) {
// when creating the webhook
if (body && 'hook' in body) {
try {
if (!body.hook.events.includes('pull_request')) {
throw new Error(`This webhook needs the "${'pull_request'}" event. Please tick it.`)
}

let message

if ('organization' in body) {
message = `Hello ${body.sender.login}, the webhook is now enabled for the organization ${body.organization.login}, enjoy!`
} else {
message = `Hello ${body.sender.login}, the webhook is now enabled for ${body.repository.full_name}, enjoy!`
}

console.log(message)

Check warning on line 35 in functions/classes/Handler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

return {
statusCode: 200,
body: message,
}
} catch (e) {
console.log(e.message)

Check warning on line 42 in functions/classes/Handler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

return {
statusCode: 500,
body: e.message,
}
}
}

if (!(body && 'pull_request' in body)) {
return {
statusCode: 500,
body: 'Event is not a Pull Request',
}
}

return true
}

/**
* Update the GitHub PR Status with the given payload
*
* @param object body JSON body from GitHub event
* @param object payload Object to update PR (keys: status, description, context)
*
* @return string reponse
*/
async updateStatus(body, payload) {
try {
await this.githubClient.rest.repos.createCommitStatus({
owner: body.repository.owner.login,
repo: body.repository.name,
sha: body.pull_request.head.sha,
...payload,
})

return {
statusCode: 204,
body: `Process finished with state: ${payload.state}`,
}
} catch (e) {
console.error(e)

return {
statusCode: 500,
body: `Process finished with error: ${e.message}`,
}
}
}
}
37 changes: 37 additions & 0 deletions functions/classes/WeblateHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Handler } from './Handler'

export class WeblateHandler extends Handler {
async handle(body, callback) {
const response = this.validateEvent(body)

if (response !== true) {
return callback(null, response)
}

console.log(`Working on repo ${body.repository.full_name} for PR #${body.pull_request.number}`)

Check warning on line 11 in functions/classes/WeblateHandler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

if (body.pull_request.user.login !== 'weblate' || body.sender.login !== 'weblate') {
return callback(null, {
statusCode: 204,
body: 'PR is not from Weblate',
})
}

const owner = body.repository.owner.login
const repo = body.repository.name

await this.githubClient.request(
`POST /repos/${owner}/${repo}/issues/${body.pull_request.number}/labels`,
{
labels: ['Translations'],
}
)

console.log('Labelled!')

Check warning on line 30 in functions/classes/WeblateHandler.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected console statement

return callback(null, {
statusCode: 204,
body: 'Process finished',
})
}
}
94 changes: 4 additions & 90 deletions functions/extension.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,7 @@
import got from 'got'
import parse from 'diffparser'
import { Octokit } from '@octokit/rest'
import { updateStatus, validateWebhook } from './utils/github'
import { ExtensionHandler } from './classes/ExtensionHandler'

export async function handler(event, context, callback) {
let response
const githubClient = new Octokit({ auth: process.env.GITHUB_TOKEN })

const body = JSON.parse(event.body)

// when creating the webhook
if (body && 'hook' in body) {
try {
const message = validateWebhook(body)

console.log(message)

response = {
statusCode: 200,
body: message,
}
} catch (e) {
console.log(e.message)

response = {
statusCode: 500,
body: e.message,
}
}

return callback(null, response)
}

if (!(body && 'pull_request' in body)) {
response = {
statusCode: 500,
body: 'Event is not a Pull Request',
}

return callback(null, response)
}

console.log(`Working on repo ${body.repository.full_name} for PR #${body.pull_request.number}`)

const payload = {
success: {
state: 'success',
description: 'passed',
context: `${process.env.NAMESPACE} - File extension check`,
},
failure: {
state: 'failure',
description: 'failed',
context: `${process.env.NAMESPACE} - File extension check`,
},
}
const extension = new ExtensionHandler(process.env.GITHUB_TOKEN, process.env.NAMESPACE)

let diffResponse
try {
diffResponse = await got(body.pull_request.diff_url)
} catch (e) {
console.log(e.message)

response = {
statusCode: 500,
body: e.message,
}

return callback(null, response)
}

const validation = parse(diffResponse.body).every((diff) => {
// we don't need to validate deleted file
if (diff.deleted === true) {
return true
}

if (/\.txt$/.test(diff.to) === false) {
payload.failure.description = `Fail: "${diff.to}" has not a txt extension`

console.log(`Fail: "${diff.to}" has not a txt extension`)

return false
}

return true
})

response = await updateStatus(githubClient, body, validation ? payload.success : payload.failure)

return callback(null, response)
export async function handler(event, context, callback) {
await extension.handle(JSON.parse(event.body), callback)
}
51 changes: 0 additions & 51 deletions functions/utils/github.js

This file was deleted.

Loading

0 comments on commit 1607075

Please sign in to comment.