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

Initial commits #1

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open

Initial commits #1

wants to merge 15 commits into from

Conversation

pyokagan
Copy link
Collaborator

No description provided.

@pyokagan pyokagan force-pushed the initial branch 17 times, most recently from ea01b44 to 4bc199a Compare June 14, 2017 16:39
pyokagan added 13 commits June 15, 2017 15:08
All cool projects need to have a GitHub bot, so let's create our own.

We'll use nodejs for the project since it can be easily deployed to
Heroku, and we'll use Typescript in order to make working with
Javascript more bearable[1].

We are also using the oss-generic Typescript coding guidelines, so let's
setup tslint and editorconfig with the relevant rules to ensure that our
code adheres to those guidelines.

We will be using Heroku to host our bot, so let's add a Procfile as
well, and document setup instructions in the README.adoc.

[1] For more information on what makes Typescript better than plain
    Javascript, search for "Typescript rocks" or "Javascript sucks" on
    the internet.
The typescript compiler generates source maps for us, however node does
not recognize them. As a result, we get error stack traces pointing to
the generated .js files rather than the source .ts files:

    /se-edu-bot/dist/server.js:3
        throw new Error('Some error');
        ^

    Error: Some error
        at Object.<anonymous> (/se-edu-bot/dist/server.js:3:11)
        ...

This makes finding the exact line where the error occured in the source
.ts files harder than it should be.

As such, let's use the source-map-support package, which teaches node to
use source maps to replace the paths and line numbers of source-mapped
files with their original paths and line numbers. Using this package, we
get error stack traces like this instead:

    /se-edu-bot/server.ts:5
        throw new Error('Some error');
              ^
    Error: Some error
        at Object.<anonymous> (/se-edu-bot/server.ts:5:11)
        ...
We are going to be using environment variables to configure the bot, to
store settings which do not belong in version control. Environment
variables are used for configuration because they are strongly supported
by Heroku.

However, working with environment variables during development can be
kind of unwieldy, as we will either need to set them up one by one on
the command line every time we wish to develop se-edu-bot, or modify our
system settings.

It would be nice if we had a file where we could just dump all our
environment variables inside, and server.ts would automatically pick
them up when it runs.

Fortunately, there is a popular package in the nodejs world called
"dotenv" which does just that. It will load environment variables from
the ".env" file in the project root when called to do so. Let's use
that.
We'll need to implement a web server to respond to GitHub webhook
events.

As a step towards that goal, let's implement a simple web server using
Koa[1] that responds with "Hello world!".

Koa is used due to the simplicity of its core concepts (every middleware
is a function that returns a promise).

In later commits, we will be building on top of this web server code to
fully flesh out se-edu-bot's behavior, including responding to GitHub
webhook events.

[1] https://github.com/koajs/koa
Tests are always good, as they can help weed out bugs and prevent
regressions.

While we don't specifically require our code to be well tested, it is
still good to have a testing framework available at hand so that
developers can implement tests when they want to.

Let's use mocha[1] as the testing framework, and mocha-typescript[2] to
make it pleasant to use in typescript. Set mocha up such that all
*.spec.ts files are automatically run as tests. As an example of how to
implement tests, write tests for server.ts as well.

[1] https://mochajs.org/
[2] https://github.com/pana-cc/mocha-typescript
In order for se-edu-bot to be useful it will need to be aware of events
which occur on GitHub. (e.g. it will need to be aware of when PRs are
merged so that it can post comments to thank authors for their hard
work).

GitHub uses webhooks[1] to notify se-edu-bot of events that we are
interested in. To receive these events, let's implement a webhook
endpoint at /webhook.

As an example of how to implement support for a webhook event type,
let's also implement support for the "ping"[2] event.

[1] https://developer.github.com/webhooks/
[2] https://developer.github.com/webhooks/#ping-event
We envision that se-edu-bot in the future will perform a large variety
of tasks, and as such will have complex code implementing its behavior
as well.

To manage this eventual complexity, let's implement a modular
architecture for defining the behavior of the bot, called "logic". Each
module, which we shall call a "logic component", will implement one
aspect of the bot's behavior. By composing logic components together, we
can then implement complex bot behaviors while managing code complexity.

As an example of a logic component, we also implement and use
LogWebhookLogic, which will log to console all webhook payloads received
by our web server.
Making unauthenticated GitHub API requests is simple enough that any
user-friendly http client library such as request[1] should do the
trick. On the other hand, making authenticated requests are tricky, yet
in future commits we will need to use them since we will need to do
things which requires authorization (e.g. posting a comment as the bot)
in order for se-edu-bot to be useful.

As such, let's implement support for making authenticated GitHub API
requests via our lib/github library. Requests can be authenticated by
App via JWT[2] or authorized by access token (users[3] and
installations[4]).

[1] https://github.com/request/request
[2] https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/#authenticating-as-a-github-app
[3] https://developer.github.com/v3/#authentication
[4] https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/#authenticating-as-an-installation
While logic components can receive GitHub webhook events, they can't
really act on them as they do not have access to the GitHub API.

Give logic components access to the GitHub API by passing them a
RequestApi object which is authorized with the installation of the
GitHub App on the se-edu organization. This is implemented by
implementing two Koa middlewares, koaGhAppApi() and
koaGhInstallationApi(). The former installs a RequestApi on the koa
context which is authorized with the GitHub App, while the latter
installs a RequestApi on the koa context which is authorized with the
installation access token.
Thank them for their hard work. Hopefully they will come back again.
Logs are useful for debugging errors in production. While heroku does
have logs, only people who have access to the heroku app can access
them. Heroku does allow adding collaborators to an app who can then
access the logs as well, however collaborators also have access to other
sensitive operations such as deleting the app or adding or removing paid
addons.

To allow us to access the logs without needing to become a heroku app
collaborator, let's implement our own logging system. We can then access
the logs via the /logs endpoint.

Note, however, that *anyone* can access the logs, which is dangerous
since the logs may contain sensitive info. However, this is no
implemented yet since we do not have an authentication system. In future
commits, when the authentication system has been implemented, we can
then tweak the implementation such that only se-edu organization members
can access the logs.
Pagination[1] is a pretty common thing in the GitHub API. To make it
easy for our code to handle pagination, let's implement a forEachPage()
helper function.

[1] https://developer.github.com/v3/#pagination
Some functionality of se-edu-bot that we wish to implement in the future
requires se-edu-bot to be aware of the user's identity.

For GitHub Apps which is what se-edu-bot is using, this requires us to
identify users via OAuth[1], which in turn requires us to implement
OAuth endpoints. We will also need to use cookies to keep track of the
user's session so we can persistently identify the user.

[1] https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/identifying-users-for-github-apps/
The bot's logs are accessible to everyone at the /logs endpoint. This is
dangerous because the logs may contain sensitive info.

Fix this by only allowing se-edu organization members to view the logs.

Note that our access control doesn't actually check if the current user
is a member of se-edu, but rather whether the user has access to the
se-edu-bot installation in the se-edu organization. This should be
equivalent.
@CanIHasReview-bot
Copy link

v1

@pyokagan submitted v1 for review.

(📚 Archive)

Checkout this PR version locally
git fetch https://github.com/se-edu/se-edu-bot.git refs/pr/1/1/head:BRANCHNAME

where BRANCHNAME is the name of the local branch you wish to fetch this PR to.

@pyokagan
Copy link
Collaborator Author

@yamgent Can help me run through the README and see if the Heroku installation instructions work. (Install to wang-leng-org)

Copy link
Collaborator Author

@pyokagan pyokagan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[1/14]

Initial commit

All cool projects need to have a GitHub bot, so let's create our own.

We'll use nodejs for the project since it can be easily deployed to
Heroku, and we'll use Typescript in order to make working with
Javascript more bearable[1].

We are also using the oss-generic Typescript coding guidelines, so let's
setup tslint and editorconfig with the relevant rules to ensure that our
code adheres to those guidelines.

We will be using Heroku to host our bot, so let's add a Procfile as
well, and document setup instructions in the README.adoc.

It's probably better to format all of these paragraphs as bullet points.

Also need to mention the .travis.yml.

It would also be good if the README.adoc has a "Background reading" section which links to topics that developers need to know when working on this code base.


=== Prerequisites

. Node `7.9.0` or later.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to specify required npm version as well.


. Node `7.9.0` or later.
. An editor with Typescript language service support is strongly recommended.
(e.g. https://code.visualstudio.com/[VS Code])
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a Recommended editors section.

Note that for VSCode, the editorconfig plugin must be installed for it to respect .editorconfig files.

Copy link
Collaborator Author

@pyokagan pyokagan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[2/14]

server: add source-map-support

The typescript compiler generates source maps for us, however node does
not recognize them. As a result, we get error stack traces pointing to
the generated .js files rather than the source .ts files:

    /se-edu-bot/dist/server.js:3
        throw new Error('Some error');
        ^

    Error: Some error
        at Object.<anonymous> (/se-edu-bot/dist/server.js:3:11)
        ...

This makes finding the exact line where the error occured in the source
.ts files harder than it should be.

occured -> occurred

As such, let's use the source-map-support package, which teaches node to

Need to give the package URL.

use source maps to replace the paths and line numbers of source-mapped
files with their original paths and line numbers. Using this package, we
get error stack traces like this instead:

    /se-edu-bot/server.ts:5
        throw new Error('Some error');
              ^
    Error: Some error
        at Object.<anonymous> (/se-edu-bot/server.ts:5:11)
        ...

Copy link
Collaborator Author

@pyokagan pyokagan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[3/14]

server: implement support for ".env" files

We are going to be using environment variables to configure the bot, to
store settings which do not belong in version control. Environment
variables are used for configuration because they are strongly supported
by Heroku.

However, working with environment variables during development can be
kind of unwieldy, as we will either need to set them up one by one on
the command line every time we wish to develop se-edu-bot, or modify our
system settings.

It would be nice if we had a file where we could just dump all our
environment variables inside, and server.ts would automatically pick
them up when it runs.

Fortunately, there is a popular package in the nodejs world called
"dotenv" which does just that. It will load environment variables from
the ".env" file in the project root when called to do so. Let's use
that.

Looks okay to me. Just need to add a link to the dotenv package in the commit message.

Copy link
Collaborator Author

@pyokagan pyokagan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[4/14]

 server: implement "Hello world!" web server

README.adoc Outdated
`PROXY`::
(Required) Set to `true` if se-edu-bot is served behind a reverse proxy (e.g. ngrok or heroku).
Given that we host se-edu-bot on heroku and use ngrok for development,
this should usually be set to `true`.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, given that for both development and production this should be set to true, we shouldn't even need this environment variable in the first place?

README.adoc Outdated
@@ -129,6 +129,17 @@ Below is a guide for setting up the Heroku application from scratch should there

== Environment variables

`PROXY`::
(Required) Set to `true` if se-edu-bot is served behind a reverse proxy (e.g. ngrok or heroku).
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required, but optional. Defaults to false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants