diff --git a/.gitignore b/.gitignore index 15a54625..28f2a316 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules .env *.pem +test-payload.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0a7cebb..53364693 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,3 +20,19 @@ Ideas not as issues yet: - If the bot has an open pull request, don't open another one? - How do we handle failure modes? - Should we switch to typescript? + + + +### Testing serverless locally +`yarn add serverless-dotenv-plugin` + +in `serverless.yml` plugins add: +`- serverless-dotenv-plugin` + + +Create file test-file.json with payload +``` +curl -vX POST http://localhost:3000/ -d @test-payload.json \ +--header "Content-Type: application/json" \ +--header "X-GitHub-Event: issue_comment" +``` diff --git a/serverless.yml b/serverless.yml index 70440997..864b15af 100644 --- a/serverless.yml +++ b/serverless.yml @@ -7,14 +7,14 @@ plugins: custom: stage: ${opt:stage, self:provider.stage} appId: - dev: '23178' + dev: '23544' prod: '23186' botName: - dev: 'AllContributorsDev' + dev: 'AllContributorsDevBot' prod: 'AllContributorsBot' logLevel: dev: debug - prod: debug # TODO change to info soon + prod: info sentryDsn: dev: '' prod: 'https://e950ab524cde4682a740c218c15a461d@sentry.io/1366866' @@ -28,7 +28,7 @@ provider: environment: BOT_NAME: ${self:custom.botName.${self:custom.stage}} APP_ID: ${self:custom.appId.${self:custom.stage}} - DEBUG_LEVEL: ${self:custom.logLevel.${self:custom.stage}} + LOG_LEVEL: ${self:custom.logLevel.${self:custom.stage}} SENTRY_DSN: ${self:custom.sentryDsn.${self:custom.stage}} DISABLE_STATS: true INSTALLATION_TOKEN_TTL: 3540 diff --git a/src/handler.js b/src/handler.js index 0f00c8fd..a2e3e3aa 100644 --- a/src/handler.js +++ b/src/handler.js @@ -1,3 +1,5 @@ -const { serverless } = require('@probot/serverless-lambda') +// TODO: put back on release of: https://github.com/probot/serverless-lambda/pull/13/files +// const { serverless } = require('@probot/serverless-lambda') +const { serverless } = require('serverless-lambda') const appFn = require('./') module.exports.probot = serverless(appFn) diff --git a/src/serverless-lambda.js b/src/serverless-lambda.js new file mode 100644 index 00000000..cea8c15f --- /dev/null +++ b/src/serverless-lambda.js @@ -0,0 +1,84 @@ +// TODO: get off of fork once https://github.com/probot/serverless-lambda/pull/13/files is released + +const { createProbot } = require('probot') +const { resolve } = require('probot/lib/resolver') +const { findPrivateKey } = require('probot/lib/private-key') + +let probot + +const loadProbot = appFn => { + probot = + probot || + createProbot({ + id: process.env.APP_ID, + secret: process.env.WEBHOOK_SECRET, + cert: findPrivateKey(), + }) + + if (typeof appFn === 'string') { + appFn = resolve(appFn) + } + + if (process.env.SENTRY_DSN) { + probot.load(require('probot/lib/apps/sentry')) + } + probot.load(appFn) + + return probot +} + +module.exports.serverless = appFn => { + return async (event, context) => { + // Otherwise let's listen handle the payload + probot = probot || loadProbot(appFn) + + // Ends function immediately after callback + context.callbackWaitsForEmptyEventLoop = false + + // Determine incoming webhook event type + const e = + event.headers['x-github-event'] || event.headers['X-GitHub-Event'] + + // Convert the payload to an Object if API Gateway stringifies it + event.body = + typeof event.body === 'string' ? JSON.parse(event.body) : event.body + + const { info: logInfo, error: logError } = probot.apps[0].log + + // Do the thing + logInfo( + `Received event ${e}${ + event.body.action ? `.${event.body.action}` : '' + }`, + ) + if (event) { + try { + await probot.receive({ + name: e, + payload: event.body, + }) + const res = { + statusCode: 200, + body: JSON.stringify({ + message: `Received ${e}.${event.body.action}`, + }), + } + return context.done(null, res) + } catch (err) { + logError(err) + return context.done(null, { + statusCode: 500, + body: JSON.stringify(err), + }) + } + } else { + logError({ event, context }) + context.done(null, 'unknown error') + } + logInfo('Nothing to do.') + return context.done(null, { + statusCode: 200, + body: 'Nothing to do.', + }) + } +}