Hamster
🐀 A Bot toolkit for github that supports OAuth, Events, API, Custom Commands and Check Runs.
Install / Use
/learn @Clivern/HamsterREADME
Documentation
Config & Run The Application
Hamster uses Go Modules to manage dependencies. First Create a dist config file.
$ cp config.json config.dist.json
Then add your app_mode, app_port, app_log_level, github_token, github_webhook_secret, repository_author and repository_name
{
"app_mode": "prod",
"app_port": "8080",
"app_log_level": "info",
"github_token": "...",
"github_webhook_secret": "...",
"repository_author": "Clivern",
"repository_name": "Hamster",
"app_domain": "example.com",
"github_app_client_id": "..",
"github_app_redirect_uri": "..",
"github_app_allow_signup": "true",
"github_app_scope": "..",
"github_app_client_secret": ".."
}
You can config app_domain and the rest of github app configs github_app_* in case you need a github app not a personal bot.
Add a new webhook from Settings > Webhooks, Set the Payload URL to be https://hamster.com/listen, Content type as JSON and Add Your Webhook Secret.
And then run the application
$ go build hamster.go
$ ./hamster
// OR
$ go run hamster.go
Also running hamster with docker still an option. Just don't forget to update GithubToken, GithubWebhookSecret, RepositoryAuthor and RepositoryName inside docker-compose.yml file. Then run the following stuff
$ docker-compose build
$ docker-compose up -d
Customize the Default Event Listeners
Anytime github call hamster listen endpoint, there will be a callback that get called with incoming data. For example when you get a status change call from github, the StatusListener(status event.Status) will get called. So do whatever you need inside this callback.
any event: any time listen endpoint get a call, the following callback get called.
// plugin/base.go
// Any Action
func RawListener(raw event.Raw) (bool, error) {
logger.Info("Raw event listener fired!")
return true, nil
}
status event: any time a Repository has a status update from the API, The following callback get called.
// plugin/base.go
// Status Action
func StatusListener(status event.Status) (bool, error) {
logger.Info("Status event listener fired!")
return true, nil
}
watch event: any time a User stars a Repository.
// plugin/base.go
// Watch Action
func WatchListener(watch event.Watch) (bool, error) {
logger.Info("Watch event listener fired!")
return true, nil
}
issues event: any time an Issue is assigned, unassigned, labeled, unlabeled, opened, edited, milestoned, demilestoned, closed, or reopened.
// plugin/base.go
// Issue Action
func IssuesListener(issues event.Issues) (bool, error) {
logger.Info("Issues event listener fired!")
return true, nil
}
issue_comment event: any time a comment on an issue is created, edited, or deleted.
// plugin/base.go
// Issue Comment Action
func IssueCommentListener(issueComment event.IssueComment) (bool, error) {
logger.Info("IssueComment event listener fired!")
return true, nil
}
push event: Any Git push to a Repository, including editing tags or branches. Commits via API actions that update references are also counted. This is the default event.
// plugin/base.go
// Push Action
func PushListener(push event.Push) (bool, error) {
logger.Info("Push event listener fired!")
return true, nil
}
create event: Any time a Branch or Tag is created.
// plugin/base.go
// Create Action
func CreateListener(create event.Create) (bool, error) {
logger.Info("Create event listener fired!")
return true, nil
}
label event: Any time a Label is created, edited, or deleted.
// plugin/base.go
// Label Action
func LabelListener(label event.Label) (bool, error) {
logger.Info("Label event listener fired!")
return true, nil
}
delete event: Any time a branch or tag is deleted.
// plugin/base.go
// Delete Action
func DeleteListener(delete event.Delete) (bool, error) {
logger.Info("Delete event listener fired!")
return true, nil
}
milestone event: Any time a Milestone is created, closed, opened, edited, or deleted.
// plugin/base.go
// Milestone Action
func MilestoneListener(milestone event.Milestone) (bool, error) {
logger.Info("Milestone event listener fired!")
return true, nil
}
pull_request event: Any time a pull request is assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened, or synchronized (updated due to a new push in the branch that the pull request is tracking). Also any time a pull request review is requested, or a review request is removed.
// plugin/base.go
// Pull Request Action
func PullRequestListener(pullRequest event.PullRequest) (bool, error) {
logger.Info("PullRequest event listener fired!")
return true, nil
}
pull_request_review event: Any time a pull request review is submitted, edited, or dismissed.
// plugin/base.go
// Pull Request Review Action
func PullRequestReviewListener(pullRequestReview event.PullRequestReview) (bool, error) {
logger.Info("PullRequestReview event listener fired!")
return true, nil
}
pull_request_review_comment event: Any time a comment on a pull request's unified diff is created, edited, or deleted (in the Files Changed tab).
// plugin/base.go
// Pull Request Review Comment Action
func PullRequestReviewCommentListener(pullRequestReviewComment event.PullRequestReviewComment) (bool, error) {
logger.Info("PullRequestReviewComment event listener fired!")
return true, nil
}
All current supported events and the future events will be available on plugin/base.go. Also it is handy to add aditional callbacks so each event can have any number of callbacks.
Also please check the latest github webhooks guide.
Build Custom Commands
In order to build an interactive bot, you will need to listen to a pre-defined commands that once your repo users type on an issue or a comment, your application get notified. Github don't support this by default but it is still possible to achieve this manually.
First you need to define you command and the callback on internal/app/controller/listener.go, exactly like the test command:
// The default test command for issue comments
commands.RegisterIssueCommentAction("test", plugin.IssueCommentTestCommandListener)
//The new run command for issue comments
commands.RegisterIssueCommentAction("run", plugin.IssueCommentRunCommandListener)
// The default test command for issues
commands.RegisterIssuesAction("test", plugin.IssuesTestCommandListener)
//The new run command for issues
commands.RegisterIssuesAction("run", plugin.IssuesRunCommandListener)
Then define the callbacks on plugin/base.go same as test commands callbacks:
// Test Command Callbacks
// Test Command Listener for Issues
func IssuesTestCommandListener(command event.Command, issues event.Issues) (bool, error) {
logger.Info("IssuesTestCommandListener event listener fired!")
return true, nil
}
// Test Command Listener for Issues Comments
func IssueCommentTestCommandListener(command event.Command, issue_comment event.IssueComment) (bool, error) {
logger.Info("IssueCommentTestCommandListener event listener fired!")
return true, nil
}
// Run Command Callbacks
// Run Command Listener for Issues
func IssuesRunCommandListener(command event.Command, issues event.Issues) (bool, error) {
logger.Info("IssuesTestCommandListener event listener fired!")
return true, nil
}
// Run Command Listener for Issues Comments
func IssueCommentRunCommandListener(command event.Command, issue_comment event.IssueComment) (bool, error) {
logger.Info("IssueCommentTestCommandListener event listener fired!")
return true, nil
}
Now if you create a new issue or issue comment, the related callbacks will get notified with command object:
/test
/test{option1}
/test{option1,option2}
/test{option1,option2,option3}
/run
/run{option1}
/run{option1,option2}
/run{option1,option2,option3}
The command object will be
event.Command{Name=test, Parameters=[]}
event.Command{Name=test, Parameters=[option1]}
event.Command{Name=test, Parameters=[option1 option2]}
event.Command{Name=test, Parameters=[option1 option2 option3]}
event.Command{Name=run, Parameters=[]}
event.Command{Name=run, Parameters=[option1]}
event.Command{Name=run, Parameters=[option1 option2]}
event.Command{Name=run, Parameters=[option1 option2 option3]}
Create a Github Comment
// for more info https://developer.github.com/v3/issues/comments/#create-a-comment
import (
"github.com/clivern/hamster/internal/app/pkg/
