Skip to content

Instantly share code, notes, and snippets.

@muesli
Created February 18, 2017 16:36
Show Gist options
  • Save muesli/7a4eeec66f32456d6f4bddc14c84d3c8 to your computer and use it in GitHub Desktop.
Save muesli/7a4eeec66f32456d6f4bddc14c84d3c8 to your computer and use it in GitHub Desktop.
GitHubBee
/*
* Copyright (C) 2014-2017 Christian Muehlhaeuser
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Nicolas Martin <[email protected]>
*/
// Package githubbee is a Bee that can interface with GitHub
package githubbee
import (
"encoding/json"
"fmt"
"github.com/google/go-github/github"
"github.com/muesli/beehive/bees"
)
func (mod *GithubBee) handlePushEvent(event *github.Event) {
var b github.PushEvent
json.Unmarshal(*event.RawPayload, &b)
ev := bees.Event{
Bee: mod.Name(),
Name: "push",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "url",
Type: "url",
Value: fmt.Sprintf("https://github.com/%s/compare/%s...%s", *event.Repo.Name, (*b.Before)[0:12], (*b.Head)[0:12]),
},
{
Name: "event_id",
Type: "string",
Value: *event.ID,
},
},
}
mod.eventChan <- ev
for _, commit := range b.Commits {
ev := bees.Event{
Bee: mod.Name(),
Name: "commit",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *commit.Author.Name,
},
{
Name: "url",
Type: "url",
Value: fmt.Sprintf("https://github.com/%s/commit/%s", *event.Repo.Name, (*commit.SHA)[0:12]),
},
{
Name: "id",
Type: "string",
Value: (*commit.SHA)[0:12],
},
{
Name: "message",
Type: "string",
Value: *commit.Message,
},
},
}
mod.eventChan <- ev
}
}
func (mod *GithubBee) handleWatchEvent(event *github.Event) {
var b github.WatchEvent
json.Unmarshal(*event.RawPayload, &b)
ev := bees.Event{
Bee: mod.Name(),
Name: "star",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "event_id",
Type: "string",
Value: *event.ID,
},
},
}
mod.eventChan <- ev
}
func (mod *GithubBee) handleForkEvent(event *github.Event) {
var b github.ForkEvent
json.Unmarshal(*event.RawPayload, &b)
ev := bees.Event{
Bee: mod.Name(),
Name: "fork",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "event_id",
Type: "string",
Value: *event.ID,
},
},
}
mod.eventChan <- ev
}
func (mod *GithubBee) handleIssuesEvent(event *github.Event) {
var b github.IssuesEvent
json.Unmarshal(*event.RawPayload, &b)
switch *b.Action {
case "opened":
ev := bees.Event{
Bee: mod.Name(),
Name: "issue_open",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "id",
Type: "int",
Value: *b.Issue.Number,
},
{
Name: "url",
Type: "url",
Value: *b.Issue.HTMLURL,
},
{
Name: "title",
Type: "string",
Value: *b.Issue.Title,
},
{
Name: "text",
Type: "string",
Value: *b.Issue.Body,
},
},
}
mod.eventChan <- ev
default:
mod.LogErrorf("Unhandled issues event: %s", *b.Action)
}
}
func (mod *GithubBee) handleIssueCommentEvent(event *github.Event) {
var b github.IssueCommentEvent
json.Unmarshal(*event.RawPayload, &b)
switch *b.Action {
case "created":
ev := bees.Event{
Bee: mod.Name(),
Name: "issue_comment",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "id",
Type: "int",
Value: *b.Issue.Number,
},
{
Name: "url",
Type: "url",
Value: *b.Comment.HTMLURL,
},
{
Name: "text",
Type: "string",
Value: *b.Comment.Body,
},
},
}
mod.eventChan <- ev
default:
mod.LogErrorf("Unhandled issue comment event: %s", *b.Action)
}
}
func (mod *GithubBee) handlePullRequestEvent(event *github.Event) {
var b github.PullRequestEvent
json.Unmarshal(*event.RawPayload, &b)
var t string
switch *b.Action {
case "closed":
t = "close"
fallthrough
case "opened":
if t == "" {
t = "open"
}
ev := bees.Event{
Bee: mod.Name(),
Name: "pullrequest_" + t,
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "id",
Type: "int",
Value: *b.PullRequest.Number,
},
{
Name: "url",
Type: "url",
Value: *b.PullRequest.HTMLURL,
},
{
Name: "title",
Type: "string",
Value: *b.PullRequest.Title,
},
{
Name: "text",
Type: "string",
Value: *b.PullRequest.Body,
},
},
}
mod.eventChan <- ev
default:
mod.LogErrorf("Unhandled pullrequest event: %s", *b.Action)
}
}
func (mod *GithubBee) handlePullRequestReviewCommentEvent(event *github.Event) {
var b github.PullRequestReviewCommentEvent
json.Unmarshal(*event.RawPayload, &b)
switch *b.Action {
case "created":
ev := bees.Event{
Bee: mod.Name(),
Name: "pullrequest_review_comment",
Options: []bees.Placeholder{
{
Name: "public",
Type: "bool",
Value: *event.Public,
},
{
Name: "repo",
Type: "string",
Value: *event.Repo.Name,
},
{
Name: "repo_url",
Type: "url",
Value: "https://github.com/" + *event.Repo.Name,
},
{
Name: "username",
Type: "string",
Value: *event.Actor.Login,
},
{
Name: "id",
Type: "int",
Value: *b.PullRequest.Number,
},
{
Name: "url",
Type: "url",
Value: *b.Comment.HTMLURL,
},
{
Name: "text",
Type: "string",
Value: *b.Comment.Body,
},
},
}
mod.eventChan <- ev
default:
mod.LogErrorf("Unhandled issue comment event: %s", *b.Action)
}
}
/*
* Copyright (C) 2014-2017 Christian Muehlhaeuser
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Nicolas Martin <[email protected]>
*/
// Package githubbee is a Bee that can interface with GitHub
package githubbee
import (
"time"
"github.com/google/go-github/github"
"golang.org/x/oauth2"
"github.com/muesli/beehive/bees"
)
// GithubBee is a Bee that can interface with GitHub
type GithubBee struct {
bees.Bee
eventChan chan bees.Event
client *github.Client
accessToken string
}
// Action triggers the actions passed to it.
func (mod *GithubBee) Action(action bees.Action) []bees.Placeholder {
outs := []bees.Placeholder{}
switch action.Name {
case "follow":
var user string
action.Options.Bind("username", &user)
if _, err := mod.client.Users.Follow(user); err != nil {
mod.LogErrorf("Failed to follow user: %v", err)
}
case "unfollow":
var user string
action.Options.Bind("username", &user)
if _, err := mod.client.Users.Unfollow(user); err != nil {
mod.LogErrorf("Failed to follow user: %v", err)
}
case "star":
var user string
var repo string
action.Options.Bind("username", &user)
action.Options.Bind("repository", &repo)
if _, err := mod.client.Activity.Star(user, repo); err != nil {
mod.LogErrorf("Failed to star repository %v", err)
}
case "unstar":
var user string
var repo string
action.Options.Bind("username", &user)
action.Options.Bind("repository", &repo)
if _, err := mod.client.Activity.Unstar(user, repo); err != nil {
mod.LogErrorf("Failed to unstar repository %v", err)
}
default:
panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
}
return outs
}
// Run executes the Bee's event loop.
func (mod *GithubBee) Run(eventChan chan bees.Event) {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: mod.accessToken},
)
tc := oauth2.NewClient(oauth2.NoContext, ts)
mod.eventChan = eventChan
mod.client = github.NewClient(tc)
since := time.Now()
timeout := time.Duration(time.Second * 10)
for {
select {
case <-mod.SigChan:
return
case <-time.After(timeout):
mod.getRepositoryEvents("muesli", "beehive", since)
}
since = time.Now()
timeout = time.Duration(time.Minute)
}
}
func (mod *GithubBee) getRepositoryEvents(owner, repo string, since time.Time) {
for page := 0; page < 10; page++ {
opts := &github.ListOptions{
Page: page,
}
events, _, err := mod.client.Activity.ListRepositoryEvents(owner, repo, opts)
if err != nil {
mod.LogErrorf("Failed to fetch events: %v", err)
return
}
for _, v := range events {
if since.After(*v.CreatedAt) {
return
}
switch *v.Type {
case "PushEvent":
mod.handlePushEvent(v)
case "WatchEvent":
mod.handleWatchEvent(v)
case "ForkEvent":
mod.handleForkEvent(v)
case "IssuesEvent":
mod.handleIssuesEvent(v)
case "IssueCommentEvent":
mod.handleIssueCommentEvent(v)
case "PullRequestEvent":
mod.handlePullRequestEvent(v)
case "PullRequestReviewCommentEvent":
mod.handlePullRequestReviewCommentEvent(v)
default:
mod.LogErrorf("Unhandled event: %s", *v.Type)
}
}
}
}
func (mod *GithubBee) getNotifications() {
opts := &github.NotificationListOptions{
All: true,
// Participating: true,
ListOptions: github.ListOptions{
PerPage: 10,
},
}
notif, _, err := mod.client.Activity.ListNotifications(opts)
if err != nil {
mod.LogErrorf("Failed to fetch notifications: %v", err)
}
for _, v := range notif {
ev := bees.Event{
Bee: mod.Name(),
Name: "notification",
Options: []bees.Placeholder{
{
Name: "subject_title",
Type: "string",
Value: *v.Subject.Title,
},
{
Name: "subject_type",
Type: "string",
Value: *v.Subject.Type,
},
{
Name: "subject_url",
Type: "url",
Value: *v.Subject.URL,
},
{
Name: "reason",
Type: "string",
Value: *v.Reason,
},
{
Name: "id",
Type: "string",
Value: *v.ID,
},
{
Name: "url",
Type: "url",
Value: *v.URL,
},
},
}
mod.eventChan <- ev
}
}
// ReloadOptions parses the config options and initializes the Bee.
func (mod *GithubBee) ReloadOptions(options bees.BeeOptions) {
mod.SetOptions(options)
options.Bind("accesstoken", &mod.accessToken)
}
/*
* Copyright (C) 2014-2017 Christian Muehlhaeuser
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Nicolas Martin <[email protected]>
*/
// Package githubbee is a Bee that can interface with github
package githubbee
import (
"github.com/muesli/beehive/bees"
)
// GithubBeeFactory is a factory for GithubBees
type GithubBeeFactory struct {
bees.BeeFactory
}
// New returns a new Bee instance configured with the supplied options.
func (factory *GithubBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface {
bee := GithubBee{
Bee: bees.NewBee(name, factory.ID(), description, options),
}
bee.ReloadOptions(options)
return &bee
}
// ID returns the ID of this Bee.
func (factory *GithubBeeFactory) ID() string {
return "githubbee"
}
// Name returns the name of this Bee.
func (factory *GithubBeeFactory) Name() string {
return "Github"
}
// Description returns the desciption of this Bee.
func (factory *GithubBeeFactory) Description() string {
// TODO: Specify 'stuff'
return "Do stuff on Github"
}
// Image returns the filename of an image for this Bee.
func (factory *GithubBeeFactory) Image() string {
return factory.ID() + ".png" // TODO: Add picture
}
// LogoColor returns ther preferred logo background color (used by the admin interface).
func (factory *GithubBeeFactory) LogoColor() string {
return "#E6E6FA" // TODO: Find fitting color
}
// Options returns the options available to configure this Bee.
func (factory *GithubBeeFactory) Options() []bees.BeeOptionDescriptor {
opts := []bees.BeeOptionDescriptor{
{
Name: "accesstoken",
Description: "Your github access token",
Type: "string",
Mandatory: true,
},
}
return opts
}
// Events describes the available events provided by this Bee.
func (factory *GithubBeeFactory) Events() []bees.EventDescriptor {
events := []bees.EventDescriptor{
{
Namespace: factory.Name(),
Name: "push",
Description: "Commits were pushed to a repository",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that something was pushed to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that pushed the commits",
Type: "string",
},
{
Name: "url",
Description: "URL to the diff-view of the changes",
Type: "url",
},
{
Name: "id",
Description: "ID of the GitHub event",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "commit",
Description: "New commit in a repository",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that something was committed to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that authored the commit",
Type: "string",
},
{
Name: "url",
Description: "URL to the diff-view of the commit",
Type: "url",
},
{
Name: "id",
Description: "ID of the commit",
Type: "string",
},
{
Name: "message",
Description: "Commit message",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "star",
Description: "Someone starred a repository",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that was starred",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that starred the repository",
Type: "string",
},
{
Name: "id",
Description: "ID of the GitHub event",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "fork",
Description: "Someone forked a repository",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that was forked",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that forked the repository",
Type: "string",
},
{
Name: "id",
Description: "ID of the GitHub event",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "issue_open",
Description: "An issue was opened",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the issue belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that created the issue",
Type: "string",
},
{
Name: "url",
Description: "URL to the issue on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the issue",
Type: "int",
},
{
Name: "title",
Description: "Issue title",
Type: "string",
},
{
Name: "text",
Description: "Issue text",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "issue_close",
Description: "An issue was closed",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the issue belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that closed the issue",
Type: "string",
},
{
Name: "url",
Description: "URL to the issue on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the issue",
Type: "int",
},
{
Name: "title",
Description: "Issue title",
Type: "string",
},
{
Name: "text",
Description: "Issue text",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "issue_comment",
Description: "An issue was commented on",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the issue belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that commented on the issue",
Type: "string",
},
{
Name: "url",
Description: "URL to the comment on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the issue",
Type: "int",
},
{
Name: "text",
Description: "Issue text",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "pullrequest_open",
Description: "A Pull Request was created",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the Pull Request belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that opened the Pull Request",
Type: "string",
},
{
Name: "url",
Description: "URL to the Pull Request on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the Pull Request",
Type: "int",
},
{
Name: "title",
Description: "Pull Request title",
Type: "string",
},
{
Name: "text",
Description: "Pull Request text",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "pullrequest_close",
Description: "A Pull Request was closed",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the Pull Request belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that closed the Pull Request",
Type: "string",
},
{
Name: "url",
Description: "URL to the Pull Request on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the Pull Request",
Type: "int",
},
{
Name: "title",
Description: "Pull Request title",
Type: "string",
},
{
Name: "text",
Description: "Pull Request text",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "pullrequest_review_comment",
Description: "A Pull Request commit was commented on",
Options: []bees.PlaceholderDescriptor{
{
Name: "public",
Description: "Indicates whether this was a public activity",
Type: "string",
},
{
Name: "repo",
Description: "The repository that the Pull Request belongs to",
Type: "string",
},
{
Name: "repo_url",
Description: "The repository's URL",
Type: "url",
},
{
Name: "username",
Description: "Username that commented on the Pull Request commit",
Type: "string",
},
{
Name: "url",
Description: "URL to the comment on GitHub",
Type: "url",
},
{
Name: "id",
Description: "ID of the Pull Request",
Type: "int",
},
{
Name: "text",
Description: "Review text",
Type: "string",
},
},
},
}
return events
}
// Actions describes the available actions provided by this Bee.
func (factory *GithubBeeFactory) Actions() []bees.ActionDescriptor {
actions := []bees.ActionDescriptor{
{
Namespace: factory.Name(),
Name: "follow",
Description: "Follow a user on Github",
Options: []bees.PlaceholderDescriptor{
{
Name: "username",
Description: "Username on github to follow",
Type: "string",
Mandatory: true,
},
},
},
{
Namespace: factory.Name(),
Name: "unfollow",
Description: "Unfollow a user on Github",
Options: []bees.PlaceholderDescriptor{
{
Name: "username",
Description: "Username on github to unfollow",
Type: "string",
Mandatory: true,
},
},
},
{
Namespace: factory.Name(),
Name: "star",
Description: "Star a repository on Github",
Options: []bees.PlaceholderDescriptor{
{
Name: "username",
Description: "Username the repository belongs to",
Type: "string",
Mandatory: true,
},
{
Name: "repo",
Description: "Repository to star",
Type: "string",
Mandatory: true,
},
},
},
{
Namespace: factory.Name(),
Name: "unstar",
Description: "Unstar a repository on Github",
Options: []bees.PlaceholderDescriptor{
{
Name: "username",
Description: "Username the repository belongs to",
Type: "string",
Mandatory: true,
},
{
Name: "repo",
Description: "Repository to unstar",
Type: "string",
Mandatory: true,
},
},
},
}
return actions
}
func init() {
f := GithubBeeFactory{}
bees.RegisterFactory(&f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment