├── Procfile
├── assets
├── css
│ └── app.css
├── static
│ ├── favicon.ico
│ ├── images
│ │ └── phoenix.png
│ └── robots.txt
├── js
│ ├── app.js
│ └── socket.js
├── package.json
└── brunch-config.js
├── lib
├── dwylbot
│ └── repo.ex
├── dwylbot_web
│ ├── views
│ │ ├── page_view.ex
│ │ ├── layout_view.ex
│ │ ├── error_view.ex
│ │ └── error_helpers.ex
│ ├── controllers
│ │ ├── page_controller.ex
│ │ ├── processes
│ │ │ └── wait.ex
│ │ ├── event_controller.ex
│ │ ├── rules
│ │ │ ├── helpers.ex
│ │ │ ├── list_rules.ex
│ │ │ ├── rules.ex
│ │ │ ├── pr
│ │ │ │ ├── no_description.ex
│ │ │ │ ├── no_assignee_or_reviewer.ex
│ │ │ │ ├── merge_conflict.ex
│ │ │ │ ├── awaiting_review.ex
│ │ │ │ └── reviewer_but_no_assignee.ex
│ │ │ ├── issue
│ │ │ │ ├── noassignees.ex
│ │ │ │ ├── inprogress.ex
│ │ │ │ ├── no_description.ex
│ │ │ │ └── time_estimation.ex
│ │ │ └── status
│ │ │ │ └── travis_failure.ex
│ │ └── github_api
│ │ │ ├── in_memory.ex
│ │ │ └── http_client.ex
│ ├── router.ex
│ ├── gettext.ex
│ ├── templates
│ │ ├── page
│ │ │ └── index.html.eex
│ │ └── layout
│ │ │ └── app.html.eex
│ ├── channels
│ │ └── user_socket.ex
│ └── endpoint.ex
├── dwylbot.ex
└── dwylbot_web.ex
├── test
├── test_helper.exs
├── views
│ ├── page_view_test.exs
│ ├── layout_view_test.exs
│ └── error_view_test.exs
├── controllers
│ ├── page_controller_test.exs
│ └── event_controller_test.exs
├── support
│ ├── channel_case.ex
│ ├── conn_case.ex
│ └── data_case.ex
└── fixtures
│ ├── issue.json
│ ├── issue_pr.json
│ ├── issue_from_pr_failing.json
│ ├── issue_from_pr.json
│ ├── no_description.json
│ ├── dwylbot-test-bug-label.json
│ ├── dwylbot-test.json
│ ├── add_label.json
│ ├── inprogress.json
│ ├── in_progress.json
│ ├── multiple_labels.json
│ ├── unassigned_inprogress.json
│ ├── failing_test.json
│ ├── assignee.json
│ └── pull_request.json
├── elixir_buildpack.config
├── priv
├── repo
│ ├── migrations
│ │ └── 20170307213737_start.exs
│ └── seeds.exs
└── gettext
│ ├── en
│ └── LC_MESSAGES
│ │ └── errors.po
│ └── errors.pot
├── coveralls.json
├── .travis.yml
├── doc
├── deploy_heroku.md
└── github_authentication.md
├── config
├── test.exs
├── config.exs
├── dev.exs
└── prod.exs
├── .gitignore
├── mix.exs
├── .credo.exs
└── mix.lock
/Procfile:
--------------------------------------------------------------------------------
1 | web: MIX_ENV=prod mix phx.server
2 |
--------------------------------------------------------------------------------
/assets/css/app.css:
--------------------------------------------------------------------------------
1 | /* This file is for your main application css. */
--------------------------------------------------------------------------------
/assets/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/dwylbot/HEAD/assets/static/favicon.ico
--------------------------------------------------------------------------------
/lib/dwylbot/repo.ex:
--------------------------------------------------------------------------------
1 | defmodule Dwylbot.Repo do
2 | use Ecto.Repo, otp_app: :dwylbot
3 | end
4 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/views/page_view.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.PageView do
2 | use DwylbotWeb, :view
3 | end
4 |
--------------------------------------------------------------------------------
/test/test_helper.exs:
--------------------------------------------------------------------------------
1 | ExUnit.start
2 |
3 | Ecto.Adapters.SQL.Sandbox.mode(Dwylbot.Repo, :manual)
4 |
5 |
--------------------------------------------------------------------------------
/assets/static/images/phoenix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/dwylbot/HEAD/assets/static/images/phoenix.png
--------------------------------------------------------------------------------
/lib/dwylbot_web/views/layout_view.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.LayoutView do
2 | use DwylbotWeb, :view
3 | end
4 |
--------------------------------------------------------------------------------
/elixir_buildpack.config:
--------------------------------------------------------------------------------
1 | erlang_version=20.1
2 | elixir_version=1.5.0
3 | always_rebuild=false
4 | runtime_path=/app
5 |
--------------------------------------------------------------------------------
/test/views/page_view_test.exs:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.PageViewTest do
2 | use DwylbotWeb.ConnCase, async: true
3 | end
4 |
--------------------------------------------------------------------------------
/test/views/layout_view_test.exs:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.LayoutViewTest do
2 | use DwylbotWeb.ConnCase, async: true
3 | end
4 |
--------------------------------------------------------------------------------
/priv/repo/migrations/20170307213737_start.exs:
--------------------------------------------------------------------------------
1 | defmodule Dwylbot.Repo.Migrations.Start do
2 | use Ecto.Migration
3 |
4 | def change do
5 |
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/assets/static/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/test/controllers/page_controller_test.exs:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.PageControllerTest do
2 | use DwylbotWeb.ConnCase
3 |
4 | test "GET /", %{conn: conn} do
5 | conn = get conn, "/"
6 | assert html_response(conn, 200) =~ "Welcome to dwylbot"
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/page_controller.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.PageController do
2 | use DwylbotWeb, :controller
3 |
4 | def index(conn, _params) do
5 | user = conn.assigns[:current_user]
6 | app_name = System.get_env("GITHUB_APP_NAME")
7 | render conn, "index.html", current_user: user, app_name: app_name
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/coveralls.json:
--------------------------------------------------------------------------------
1 | {
2 | "coverage_options": {
3 | "minimum_coverage": 60
4 | },
5 | "skip_files": [
6 | "web/channels",
7 | "lib/dwylbot.ex",
8 | "test/support/model_case.ex",
9 | "test/support/channel_case.ex",
10 | "test/support/conn_case.ex",
11 | "web/web.ex",
12 | "web/views/error_helpers.ex",
13 | "web/controllers/github_api/http_client.ex"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/priv/repo/seeds.exs:
--------------------------------------------------------------------------------
1 | # Script for populating the database. You can run it as:
2 | #
3 | # mix run priv/repo/seeds.exs
4 | #
5 | # Inside the script, you can read and write to any of your
6 | # repositories directly:
7 | #
8 | # Dwylbot.Repo.insert!(%Dwylbot.SomeModel{})
9 | #
10 | # We recommend using the bang functions (`insert!`, `update!`
11 | # and so on) as they will fail if something goes wrong.
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: elixir
2 | elixir:
3 | - 1.4
4 | addons:
5 | postgresql: '9.4'
6 | env:
7 | - MIX_ENV=test
8 | before_script:
9 | - mix do ecto.create
10 | script:
11 | - mix do deps.get, compile --warnings-as-errors, coveralls.json
12 | after_success:
13 | - bash <(curl -s https://codecov.io/bash)
14 | # See: github.com/dwyl/repo-badges#documentation
15 | after_script:
16 | - MIX_ENV=docs mix deps.get
17 | - MIX_ENV=docs mix inch.report
18 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/views/error_view.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.ErrorView do
2 | use DwylbotWeb, :view
3 |
4 | def render("404.html", _assigns) do
5 | "Page not found"
6 | end
7 |
8 | def render("500.html", _assigns) do
9 | "Internal server error"
10 | end
11 |
12 | # In case no render clause matches or no
13 | # template is found, let's render it as 500
14 | def template_not_found(_template, assigns) do
15 | render "500.html", assigns
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/doc/deploy_heroku.md:
--------------------------------------------------------------------------------
1 | related to the issue 45
2 |
3 | If you follow the instruction on the [official Phoenix documentation](http://www.phoenixframework.org/docs/heroku) everything should work properly.
4 |
5 | However sometimes it doesn't!
6 |
7 | On Fedora 25 Elixir version is at the moment (10/05/17) 1.3.1. To tell Heroku to use a different version you need to create a config file. Just follow the steps described [here](https://github.com/HashNuke/heroku-buildpack-elixir#configuration) and everything should be ok now
8 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/router.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Router do
2 | use DwylbotWeb, :router
3 |
4 | pipeline :browser do
5 | plug :accepts, ["html"]
6 | plug :fetch_session
7 | plug :fetch_flash
8 | plug :protect_from_forgery
9 | plug :put_secure_browser_headers
10 | end
11 |
12 | pipeline :api do
13 | plug :accepts, ["json"]
14 | end
15 |
16 | scope "/", DwylbotWeb do
17 | pipe_through :browser
18 |
19 | get "/", PageController, :index
20 | end
21 |
22 | scope "/event", DwylbotWeb do
23 | pipe_through :api
24 |
25 | post "/new", EventController, :new
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/config/test.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # We don't run a server during test. If one is required,
4 | # you can enable the server option below.
5 | config :dwylbot, Dwylbot.Endpoint,
6 | http: [port: 4001],
7 | server: false
8 |
9 | # Print only warnings and errors during test
10 | config :logger, level: :warn
11 |
12 | # Configure your database
13 | config :dwylbot, Dwylbot.Repo,
14 | adapter: Ecto.Adapters.Postgres,
15 | username: "postgres",
16 | password: "postgres",
17 | database: "dwylbot_test",
18 | hostname: "localhost",
19 | pool: Ecto.Adapters.SQL.Sandbox
20 |
21 | config :dwylbot, :github_api, DwylbotWeb.GithubAPI.InMemory
22 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/processes/wait.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.WaitProcess do
2 | @moduledoc """
3 | The delay function is used to create new checking rules processes
4 | """
5 | alias DwylbotWeb.Rules
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 |
8 | def delay(error, payload, event_type, token) do
9 | Process.sleep(error.wait)
10 | if error.verify do
11 | check_errors = Rules.check_errors(payload, event_type, token)
12 | Rules.any_error?(check_errors, error)
13 | && @github_api.report_error(token, error)
14 | else
15 | @github_api.report_error(token, error)
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/views/error_view_test.exs:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.ErrorViewTest do
2 | use DwylbotWeb.ConnCase, async: true
3 |
4 | # Bring render/3 and render_to_string/3 for testing custom views
5 | import Phoenix.View
6 |
7 | test "renders 404.html" do
8 | assert render_to_string(DwylbotWeb.ErrorView, "404.html", []) ==
9 | "Page not found"
10 | end
11 |
12 | test "render 500.html" do
13 | assert render_to_string(DwylbotWeb.ErrorView, "500.html", []) ==
14 | "Internal server error"
15 | end
16 |
17 | test "render any other" do
18 | assert render_to_string(DwylbotWeb.ErrorView, "505.html", []) ==
19 | "Internal server error"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # App artifacts
2 | /_build
3 | /db
4 | /deps
5 | /*.ez
6 |
7 | # Generated on crash by the VM
8 | erl_crash.dump
9 |
10 | # Static artifacts
11 | /assets/node_modules
12 |
13 | # Since we are building assets from web/static,
14 | # we ignore priv/static. You may want to comment
15 | # this depending on your deployment strategy.
16 | /priv/static/
17 |
18 | # The config/prod.secret.exs file by default contains sensitive
19 | # data and you should not commit it into version control.
20 | #
21 | # Alternatively, you may comment the line below and commit the
22 | # secrets file as long as you replace its contents by environment
23 | # variables.
24 | /config/prod.secret.exs
25 | /cover
26 | .env
27 | package-lock.json
28 |
--------------------------------------------------------------------------------
/assets/js/app.js:
--------------------------------------------------------------------------------
1 | // Brunch automatically concatenates all files in your
2 | // watched paths. Those paths can be configured at
3 | // config.paths.watched in "brunch-config.js".
4 | //
5 | // However, those files will only be executed if
6 | // explicitly imported. The only exception are files
7 | // in vendor, which are never wrapped in imports and
8 | // therefore are always executed.
9 |
10 | // Import dependencies
11 | //
12 | // If you no longer want to use a dependency, remember
13 | // to also remove its path from "config.paths.watched".
14 | import "phoenix_html"
15 |
16 | // Import local files
17 | //
18 | // Local files can be imported directly using relative
19 | // paths "./socket" or full ones "web/static/js/socket".
20 |
21 | // import socket from "./socket"
22 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/event_controller.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.EventController do
2 | use DwylbotWeb, :controller
3 | alias DwylbotWeb.WaitProcess, as: WAIT
4 | alias Plug.Conn
5 | alias DwylbotWeb.Rules
6 |
7 | @github_api Application.get_env(:dwylbot, :github_api)
8 |
9 | def new(conn, payload) do
10 | token = @github_api.get_installation_token(payload["installation"]["id"])
11 | [event_type | _] = Conn.get_req_header conn, "x-github-event"
12 | errors = Rules.apply_and_check_errors(payload, event_type, token)
13 | errors
14 | |> Enum.each(fn(error) ->
15 | spawn(WAIT, :delay, [error, payload, event_type, token])
16 | end)
17 | conn
18 | |> put_status(200)
19 | |> json(%{ok: "event received"})
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/gettext.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Gettext do
2 | @moduledoc """
3 | A module providing Internationalization with a gettext-based API.
4 |
5 | By using [Gettext](https://hexdocs.pm/gettext),
6 | your module gains a set of macros for translations, for example:
7 |
8 | import HelloWeb.Gettext
9 |
10 | # Simple translation
11 | gettext "Here is the string to translate"
12 |
13 | # Plural translation
14 | ngettext "Here is the string to translate",
15 | "Here are the strings to translate",
16 | 3
17 |
18 | # Domain-based translation
19 | dgettext "errors", "Here is the error message to translate"
20 |
21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
22 | """
23 | use Gettext, otp_app: :dwylbot
24 | end
25 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/helpers.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Helpers do
2 | @moduledoc """
3 | Helper function
4 | wait: define the time for our rules to wait depeding on the environment
5 | """
6 | @doc """
7 | iex>wait(:prod, 1, 2, 3)
8 | 1
9 | iex>wait(:dev, 1, 2, 3)
10 | 2
11 | iex>wait(:test, 1, 2, 3)
12 | 3
13 | """
14 | def wait(env, prod, dev, test) do
15 | case env do
16 | :prod -> prod
17 | :dev -> dev
18 | :test -> test
19 | end
20 | end
21 |
22 | @doc """
23 | iex>label_member?([%{"id" => 1, "name"=> "lb"}], "lb")
24 | true
25 | iex>label_member?([%{"id" => 1, "name" => "lb"}], "er")
26 | false
27 | """
28 | def label_member?(list_labels, label) do
29 | list_labels
30 | |> Enum.map(&(&1["name"]))
31 | |> Enum.member?(label)
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/templates/page/index.html.eex:
--------------------------------------------------------------------------------
1 |
Welcome to dwylbot
2 |
3 | dwylbot helps humans follow dwyl's GitHub Workflow
4 | so everyone can communicate better and work as a team.
5 |
6 |
7 |
8 |
9 |
10 |
11 | Manage dwylbot installations
12 |
13 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/list_rules.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.List do
2 | @moduledoc """
3 | List of modules errors to check on Github event
4 | Each module must implement apply and check functions
5 | """
6 | alias DwylbotWeb.Rules.Issue
7 | alias DwylbotWeb.Rules.PR
8 | alias DwylbotWeb.Rules.Status
9 |
10 | def get_rules(event_type) do
11 | case event_type do
12 | "issues" ->
13 | [
14 | Issue.Inprogress,
15 | Issue.Noassignees,
16 | Issue.TimeEstimation,
17 | Issue.NoDescription
18 | ]
19 | "pull_request" ->
20 | [
21 | PR.NoDescription,
22 | PR.MergeConflict,
23 | PR.NoAssigneeOrReviewer,
24 | PR.AwaitingReview,
25 | PR.ReviewerButNoAssignee
26 | ]
27 | "status" ->
28 | [
29 | Status.TravisFailure
30 | ]
31 | _ -> []
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/assets/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dwylbot",
3 | "version": "1.0.0",
4 | "description": "Automating our GitHub Workflow to improve team communication/collaboration",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/dwyl/dwylbot.git"
8 | },
9 | "license": "MIT",
10 | "scripts": {
11 | "deploy": "brunch build --production",
12 | "watch": "brunch watch --stdin",
13 | "coverage": "mix coveralls",
14 | "lint": "mix credo --strict"
15 | },
16 | "dependencies": {
17 | "phoenix": "file:../deps/phoenix",
18 | "phoenix_html": "file:../deps/phoenix_html"
19 | },
20 | "devDependencies": {
21 | "babel-brunch": "~6.0.0",
22 | "brunch": "2.10.7",
23 | "clean-css-brunch": "~2.0.0",
24 | "css-brunch": "~2.0.0",
25 | "javascript-brunch": "~2.0.0",
26 | "pre-commit": "^1.2.2",
27 | "uglify-js-brunch": "~2.0.1"
28 | },
29 | "pre-commit": [
30 | "coverage",
31 | "lint"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/templates/layout/app.html.eex:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Hello Dwylbot!
11 | ">
12 |
13 |
14 |
15 |
16 |
17 |
18 |
<%= get_flash(@conn, :info) %>
19 |
<%= get_flash(@conn, :error) %>
20 |
21 |
22 | <%= render @view_module, @view_template, assigns %>
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/rules.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules do
2 | @moduledoc """
3 | Functions to check the wrokflow contribution rules
4 | """
5 | alias DwylbotWeb.Rules.List, as: RulesList
6 |
7 | def apply_and_check_errors(payload, event_type, token) do
8 | rules = RulesList.get_rules(event_type)
9 | rules
10 | |> Enum.filter(fn(m) -> apply(m, :apply?, [payload]) end)
11 | |> Enum.map(fn(m) -> apply(m, :check, [payload, false, token]) end)
12 | |> Enum.filter(fn(e) -> e != nil end)
13 | end
14 |
15 | @doc """
16 | load list of modules representing our rules
17 | and apply the rules to the payload to detect any errors
18 | """
19 | def check_errors(payload, event_type, token) do
20 | rules = RulesList.get_rules(event_type)
21 | rules
22 | |> Enum.map(fn(m) -> apply(m, :check, [payload, true, token]) end)
23 | |> Enum.filter(fn(e) -> e != nil end)
24 | end
25 |
26 | def any_error?(list_errors, error) do
27 | Enum.any?(list_errors, fn(e) -> e.error_type == error.error_type end)
28 | end
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/config/config.exs:
--------------------------------------------------------------------------------
1 | # This file is responsible for configuring your application
2 | # and its dependencies with the aid of the Mix.Config module.
3 | #
4 | # This configuration file is loaded before any dependency and
5 | # is restricted to this project.
6 | use Mix.Config
7 |
8 | # General application configuration
9 | config :dwylbot,
10 | ecto_repos: [Dwylbot.Repo]
11 |
12 | # Configures the endpoint
13 | config :dwylbot, DwylbotWeb.Endpoint,
14 | url: [host: "localhost"],
15 | secret_key_base: System.get_env("SECRET_KEY_BASE"),
16 | render_errors: [view: DwylbotWeb.ErrorView, accepts: ~w(html json)],
17 | pubsub: [name: Dwylbot.PubSub,
18 | adapter: Phoenix.PubSub.PG2]
19 |
20 | # Configures Elixir's Logger
21 | config :logger, :console,
22 | format: "$time $metadata[$level] $message\n",
23 | metadata: [:request_id]
24 |
25 | # define name of the github application
26 | config :dwylbot, :github_app_name, System.get_env("GITHUB_APP_NAME")
27 |
28 | # Import environment specific config. This must remain at the bottom
29 | # of this file so it overrides the configuration defined above.
30 | import_config "#{Mix.env}.exs"
31 |
--------------------------------------------------------------------------------
/lib/dwylbot.ex:
--------------------------------------------------------------------------------
1 | defmodule Dwylbot do
2 | use Application
3 |
4 | # See http://elixir-lang.org/docs/stable/elixir/Application.html
5 | # for more information on OTP Applications
6 | def start(_type, _args) do
7 | import Supervisor.Spec
8 |
9 | # Define workers and child supervisors to be supervised
10 | children = [
11 | # Start the Ecto repository
12 | supervisor(Dwylbot.Repo, []),
13 | # Start the endpoint when the application starts
14 | supervisor(DwylbotWeb.Endpoint, []),
15 | # Start your own worker by calling: Dwylbot.Worker.start_link(arg1, arg2, arg3)
16 | # worker(Dwylbot.Worker, [arg1, arg2, arg3]),
17 | ]
18 |
19 | # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
20 | # for other strategies and supported options
21 | opts = [strategy: :one_for_one, name: Dwylbot.Supervisor]
22 | Supervisor.start_link(children, opts)
23 | end
24 |
25 | # Tell Phoenix to update the endpoint configuration
26 | # whenever the application is updated.
27 | def config_change(changed, _new, removed) do
28 | DwylbotWeb.Endpoint.config_change(changed, removed)
29 | :ok
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/support/channel_case.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.ChannelCase do
2 | @moduledoc """
3 | This module defines the test case to be used by
4 | channel tests.
5 |
6 | Such tests rely on `Phoenix.ChannelTest` and also
7 | import other functionality to make it easier
8 | to build and query models.
9 |
10 | Finally, if the test case interacts with the database,
11 | it cannot be async. For this reason, every test runs
12 | inside a transaction which is reset at the beginning
13 | of the test unless the test case is marked as async.
14 | """
15 |
16 | use ExUnit.CaseTemplate
17 |
18 | using do
19 | quote do
20 | # Import conveniences for testing with channels
21 | use Phoenix.ChannelTest
22 |
23 | alias Dwylbot.Repo
24 | import Ecto
25 | import Ecto.Changeset
26 | import Ecto.Query
27 |
28 |
29 | # The default endpoint for testing
30 | @endpoint DwylbotWeb.Endpoint
31 | end
32 | end
33 |
34 | setup tags do
35 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(Dwylbot.Repo)
36 |
37 | unless tags[:async] do
38 | Ecto.Adapters.SQL.Sandbox.mode(Dwylbot.Repo, {:shared, self()})
39 | end
40 |
41 | :ok
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/support/conn_case.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.ConnCase do
2 | @moduledoc """
3 | This module defines the test case to be used by
4 | tests that require setting up a connection.
5 |
6 | Such tests rely on `Phoenix.ConnTest` and also
7 | import other functionality to make it easier
8 | to build and query models.
9 |
10 | Finally, if the test case interacts with the database,
11 | it cannot be async. For this reason, every test runs
12 | inside a transaction which is reset at the beginning
13 | of the test unless the test case is marked as async.
14 | """
15 |
16 | use ExUnit.CaseTemplate
17 |
18 | using do
19 | quote do
20 | # Import conveniences for testing with connections
21 | use Phoenix.ConnTest
22 |
23 | alias Dwylbot.Repo
24 | import Ecto
25 | import Ecto.Changeset
26 | import Ecto.Query
27 |
28 | import DwylbotWeb.Router.Helpers
29 |
30 | # The default endpoint for testing
31 | @endpoint DwylbotWeb.Endpoint
32 | end
33 | end
34 |
35 | setup tags do
36 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(Dwylbot.Repo)
37 |
38 | unless tags[:async] do
39 | Ecto.Adapters.SQL.Sandbox.mode(Dwylbot.Repo, {:shared, self()})
40 | end
41 |
42 | {:ok, conn: Phoenix.ConnTest.build_conn()}
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/channels/user_socket.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.UserSocket do
2 | use Phoenix.Socket
3 |
4 | ## Channels
5 | # channel "room:*", Dwylbot.RoomChannel
6 |
7 | ## Transports
8 | transport :websocket, Phoenix.Transports.WebSocket
9 | # transport :longpoll, Phoenix.Transports.LongPoll
10 |
11 | # Socket params are passed from the client and can
12 | # be used to verify and authenticate a user. After
13 | # verification, you can put default assigns into
14 | # the socket that will be set for all channels, ie
15 | #
16 | # {:ok, assign(socket, :user_id, verified_user_id)}
17 | #
18 | # To deny connection, return `:error`.
19 | #
20 | # See `Phoenix.Token` documentation for examples in
21 | # performing token verification on connect.
22 | def connect(_params, socket) do
23 | {:ok, socket}
24 | end
25 |
26 | # Socket id's are topics that allow you to identify all sockets
27 | # for a given user:
28 | #
29 | # def id(socket), do: "users_socket:#{socket.assigns.user_id}"
30 | #
31 | # Would allow you to broadcast a "disconnect" event and terminate
32 | # all active sockets and channels for a given user:
33 | #
34 | # Dwylbot.Endpoint.broadcast("users_socket:#{user.id}", "disconnect", %{})
35 | #
36 | # Returning `nil` makes this socket anonymous.
37 | def id(_socket), do: nil
38 | end
39 |
--------------------------------------------------------------------------------
/test/controllers/event_controller_test.exs:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.EventTestController do
2 | use DwylbotWeb.ConnCase
3 | alias Poison.Parser, as: PP
4 | alias Plug.Conn
5 | doctest DwylbotWeb.Rules.Helpers, import: true
6 | doctest DwylbotWeb.Rules.PR.ReviewerButNoAssignee, import: true
7 |
8 | @fixtures [
9 | %{payload: "add_label", event: "issues" },
10 | %{payload: "inprogress", event: "issues"},
11 | %{payload: "no_description", event: "issues" },
12 | %{payload: "unassigned_inprogress", event: "issues" },
13 | %{payload: "pr_no_description", event: "pull_request" },
14 | %{payload: "pr_merge_conflict", event: "pull_request" },
15 | %{payload: "pr_no_assignee_or_reviewer", event: "pull_request" },
16 | %{payload: "request_reviewer", event: "pull_request" },
17 | %{payload: "failing_test", event: "status" },
18 | %{payload: "pr_reviewer_but_no_assignee", event: "pull_request"}
19 | ]
20 | |> Enum.map(&(%{&1 | payload: "./test/fixtures/#{&1.payload}.json"}))
21 |
22 | test "POST /event/new", %{conn: conn} do
23 | for fixture <- @fixtures do
24 | payload = fixture.payload |> File.read! |> PP.parse!
25 | conn = conn
26 | |> Conn.put_req_header("x-github-event", "#{fixture.event}")
27 | |> post("/event/new", payload)
28 | assert json_response(conn, 200)
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/endpoint.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Endpoint do
2 | use Phoenix.Endpoint, otp_app: :dwylbot
3 |
4 | socket "/socket", DwylbotWeb.UserSocket
5 |
6 | # Serve at "/" the static files from "priv/static" directory.
7 | #
8 | # You should set gzip to true if you are running phoenix.digest
9 | # when deploying your static files in production.
10 | plug Plug.Static,
11 | at: "/", from: :dwylbot, gzip: false,
12 | only: ~w(css fonts images js favicon.ico robots.txt)
13 |
14 | # Code reloading can be explicitly enabled under the
15 | # :code_reloader configuration of your endpoint.
16 | if code_reloading? do
17 | socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
18 | plug Phoenix.LiveReloader
19 | plug Phoenix.CodeReloader
20 | end
21 |
22 | plug Plug.RequestId
23 | plug Plug.Logger
24 |
25 | plug Plug.Parsers,
26 | parsers: [:urlencoded, :multipart, :json],
27 | pass: ["*/*"],
28 | json_decoder: Poison
29 |
30 | plug Plug.MethodOverride
31 | plug Plug.Head
32 |
33 | # The session will be stored in the cookie and signed,
34 | # this means its contents can be read but not tampered with.
35 | # Set :encryption_salt if you would also like to encrypt it.
36 | plug Plug.Session,
37 | store: :cookie,
38 | key: "_dwylbot_key",
39 | signing_salt: "Guv2WEhg"
40 |
41 | plug DwylbotWeb.Router
42 | end
43 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/views/error_helpers.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.ErrorHelpers do
2 | @moduledoc """
3 | Conveniences for translating and building error messages.
4 | """
5 |
6 | use Phoenix.HTML
7 |
8 | @doc """
9 | Generates tag for inlined form input errors.
10 | """
11 | def error_tag(form, field) do
12 | if error = form.errors[field] do
13 | content_tag :span, translate_error(error), class: "help-block"
14 | end
15 | end
16 |
17 | @doc """
18 | Translates an error message using gettext.
19 | """
20 | def translate_error({msg, opts}) do
21 | # Because error messages were defined within Ecto, we must
22 | # call the Gettext module passing our Gettext backend. We
23 | # also use the "errors" domain as translations are placed
24 | # in the errors.po file.
25 | # Ecto will pass the :count keyword if the error message is
26 | # meant to be pluralized.
27 | # On your own code and templates, depending on whether you
28 | # need the message to be pluralized or not, this could be
29 | # written simply as:
30 | #
31 | # dngettext "errors", "1 file", "%{count} files", count
32 | # dgettext "errors", "is invalid"
33 | #
34 | if count = opts[:count] do
35 | Gettext.dngettext(Dwylbot.Gettext, "errors", msg, msg, count, opts)
36 | else
37 | Gettext.dgettext(Dwylbot.Gettext, "errors", msg, opts)
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/config/dev.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # For development, we disable any cache and enable
4 | # debugging and code reloading.
5 | #
6 | # The watchers configuration can be used to run external
7 | # watchers to your application. For example, we use it
8 | # with brunch.io to recompile .js and .css sources.
9 | config :dwylbot, DwylbotWeb.Endpoint,
10 | http: [port: 4000],
11 | debug_errors: true,
12 | code_reloader: true,
13 | check_origin: false,
14 | watchers: [node: ["node_modules/brunch/bin/brunch", "watch", "--stdin",
15 | cd: Path.expand("../assets", __DIR__)]]
16 |
17 |
18 | # Watch static and templates for browser reloading.
19 | config :dwylbot, DwylbotWeb.Endpoint,
20 | live_reload: [
21 | patterns: [
22 | ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
23 | ~r{priv/gettext/.*(po)$},
24 | ~r{lib/dwylbot_web/views/.*(ex)$},
25 | ~r{lib/dwylbot_web/templates/.*(eex)$}
26 | ]
27 | ]
28 |
29 | # Do not include metadata nor timestamps in development logs
30 | config :logger, :console, format: "[$level] $message\n"
31 |
32 | # Set a higher stacktrace during development. Avoid configuring such
33 | # in production as building large stacktraces may be expensive.
34 | config :phoenix, :stacktrace_depth, 20
35 |
36 | # Configure your database
37 | config :dwylbot, Dwylbot.Repo,
38 | adapter: Ecto.Adapters.Postgres,
39 | username: "postgres",
40 | password: "postgres",
41 | database: "dwylbot_dev",
42 | hostname: "localhost",
43 | pool_size: 10
44 |
45 | config :dwylbot, :github_api, DwylbotWeb.GithubAPI.HTTPClient
46 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/pr/no_description.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.PR.NoDescription do
2 | @moduledoc """
3 | Check for error when an issue is created without a description
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_no_description"
8 |
9 | def apply?(payload) do
10 | payload["action"] == "opened"
11 | end
12 |
13 | def check(payload, get_data?, token) do
14 | payload = if get_data? do
15 | url = payload["pull_request"]["url"]
16 | @github_api.get_data(token, %{"pull_request" => url}, @rule_name)
17 | else
18 | payload
19 | end
20 | description = String.trim payload["pull_request"]["body"]
21 | if String.length(description) == 0 do
22 | %{
23 | error_type: @rule_name,
24 | actions: [
25 | %{
26 | comment: payload["sender"] && error_message(payload["sender"]["login"]),
27 | url: payload["pull_request"]["comments_url"]
28 | }
29 | ],
30 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
31 | verify: true
32 | }
33 | else
34 | nil
35 | end
36 | end
37 |
38 | defp error_message(login) do
39 | """
40 | :stop_sign: @#{login}, the pull request has no **description!**
41 | Please add more details to help us understand the context of the pull request.
42 | Please read our [Contribution guide](https://github.com/dwyl/contributing#notes-on-creating-good-pull-requests) on how to create a good pull request.
43 | Thanks! :heart:
44 | """
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/test/support/data_case.ex:
--------------------------------------------------------------------------------
1 | defmodule Dwylbot.DataCase do
2 | @moduledoc """
3 | This module defines the setup for tests requiring
4 | access to the application's data layer.
5 |
6 | You may define functions here to be used as helpers in
7 | your tests.
8 |
9 | Finally, if the test case interacts with the database,
10 | it cannot be async. For this reason, every test runs
11 | inside a transaction which is reset at the beginning
12 | of the test unless the test case is marked as async.
13 | """
14 |
15 | use ExUnit.CaseTemplate
16 |
17 | using do
18 | quote do
19 | alias Dwylbot.Repo
20 |
21 | import Ecto
22 | import Ecto.Changeset
23 | import Ecto.Query
24 | import Dwylbot.DataCase
25 | end
26 | end
27 |
28 | setup tags do
29 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(Dwylbot.Repo)
30 |
31 | unless tags[:async] do
32 | Ecto.Adapters.SQL.Sandbox.mode(Dwylbot.Repo, {:shared, self()})
33 | end
34 |
35 | :ok
36 | end
37 |
38 | @doc """
39 | A helper that transform changeset errors to a map of messages.
40 |
41 | assert {:error, changeset} = Accounts.create_user(%{password: "short"})
42 | assert "password is too short" in errors_on(changeset).password
43 | assert %{password: ["password is too short"]} = errors_on(changeset)
44 |
45 | """
46 | def errors_on(changeset) do
47 | Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
48 | Enum.reduce(opts, message, fn {key, value}, acc ->
49 | String.replace(acc, "%{#{key}}", to_string(value))
50 | end)
51 | end)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/issue/noassignees.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Issue.Noassignees do
2 | @moduledoc """
3 | Check errors when an assignee is removed but the in-progress label
4 | is still on the issue (list of assignees should be empty too)
5 | """
6 | alias DwylbotWeb.Rules.Helpers
7 | @github_api Application.get_env(:dwylbot, :github_api)
8 | @rule_name "issue_unassigned_noassignees"
9 |
10 | def apply?(payload) do
11 | payload["action"] == "unassigned"
12 | end
13 |
14 | def check(payload, get_data?, token) do
15 | payload = if get_data? do
16 | url = payload["issue"]["url"]
17 | @github_api.get_data(token, %{"issue" => url}, @rule_name)
18 | else
19 | payload
20 | end
21 | assignees = payload["issue"]["assignees"]
22 | labels = payload["issue"]["labels"]
23 | in_progress = Enum.any?(labels, fn(l) -> l["name"] == "in-progress" end)
24 | if in_progress && Enum.empty?(assignees) do
25 | %{
26 | error_type: @rule_name,
27 | actions: [
28 | %{
29 | comment: payload["sender"] && error_message(payload["sender"]["login"]),
30 | url: payload["issue"]["comments_url"]
31 | }
32 | ],
33 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
34 | verify: true
35 | }
36 | else
37 | nil
38 | end
39 | end
40 |
41 | defp error_message(login) do
42 | """
43 | :warning: @#{login} the assignee for this issue has been removed with the `in-progress` label still attached.
44 | Please remove the `in-progress` label if this issue is no longer being worked on or assign a user to this issue if it is still in progress.
45 | """
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/issue/inprogress.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Issue.Inprogress do
2 | @moduledoc """
3 | Check errors for "in-progress and no assignees" errors
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "issue_inprogress_noassignees"
8 |
9 | def apply?(payload) do
10 | payload["action"] == "labeled" && payload["label"]["name"] == "in-progress"
11 | end
12 |
13 | def check(payload, get_data?, token) do
14 | payload = if get_data? do
15 | url = payload["issue"]["url"]
16 | @github_api.get_data(token, %{"issue" => url}, @rule_name)
17 | else
18 | payload
19 | end
20 |
21 | assignees = payload["issue"]["assignees"]
22 | labels = payload["issue"]["labels"]
23 | in_progress = Enum.any?(labels, fn(l) -> l["name"] == "in-progress" end)
24 | if in_progress && Enum.empty?(assignees) do
25 | %{
26 | error_type: @rule_name,
27 | actions: [
28 | %{
29 | comment: payload["sender"] && error_message(payload["sender"]["login"]),
30 | url: payload["issue"]["comments_url"]
31 | },
32 | %{
33 | add_assignees: [payload["sender"]["login"]],
34 | url: "#{payload["issue"]["url"]}/assignees"
35 | }
36 | ],
37 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
38 | verify: true
39 | }
40 | else
41 | nil
42 | end
43 | end
44 |
45 | defp error_message(login) do
46 | """
47 | @#{login} the `in-progress` label has been added to this issue **without an Assignee**.
48 | dwylbot has automatically assigned you.
49 | """
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/issue/no_description.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Issue.NoDescription do
2 | @moduledoc """
3 | Check for error when an issue is created without a description
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "issue_no_description"
8 |
9 | def apply?(payload) do
10 | payload["action"] == "opened"
11 | end
12 |
13 | def check(payload, get_data?, token) do
14 | payload = if get_data? do
15 | url = payload["issue"]["url"]
16 | @github_api.get_data(token, %{"issue" => url}, @rule_name)
17 | else
18 | payload
19 | end
20 |
21 | description = String.trim payload["issue"]["body"]
22 | if String.length(description) == 0 do
23 | %{
24 | error_type: @rule_name,
25 | actions: [
26 | %{
27 | comment: payload["sender"] && error_message(payload["sender"]["login"]),
28 | url: payload["issue"]["comments_url"]
29 | }
30 | ],
31 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
32 | verify: true
33 | }
34 | else
35 | nil
36 | end
37 | end
38 |
39 | defp error_message(login) do
40 | """
41 | :warning: @#{login}, this issue has no description. Please add a description to help others understand the context of this issue.
42 |
43 | --
44 |
45 | You can read more about how to create an issue in a dwyl repository [here](https://github.com/dwyl/contributing#part-1-describe-your-question-the-idea-or-user-story-in-an-issue).
46 | Full guidelines for contributing to a dwyl repository can be found [here](https://github.com/dwyl/contributing/blob/master/README.md).
47 | """
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/issue/time_estimation.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Issue.TimeEstimation do
2 | @moduledoc """
3 | Check errors for "in-progress and not time estimation" errors
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "issue_no_estimation"
8 |
9 | def apply?(payload) do
10 | payload["action"] == "labeled" && payload["label"]["name"] == "in-progress"
11 | end
12 |
13 | def check(payload, get_data?, token) do
14 | payload = if get_data? do
15 | url = payload["issue"]["url"]
16 | @github_api.get_data(token, %{"issue" => url}, @rule_name)
17 | else
18 | payload
19 | end
20 |
21 | labels = payload["issue"]["labels"]
22 | in_progress = Enum.any?(labels, fn(l) -> l["name"] == "in-progress" end)
23 | epic = Enum.any?(labels, fn(l) -> l["name"] == "epic" end)
24 | estimation = labels
25 | |> Enum.map(fn(l) -> Regex.match?(~r/T\d{1,3}[mhd]/, l["name"]) end)
26 | |> Enum.reduce(false, fn(x, acc) -> x || acc end)
27 | if in_progress and not epic and not estimation do
28 | %{
29 | error_type: @rule_name,
30 | actions: [
31 | %{
32 | comment: payload["sender"] && error_message(payload["sender"]["login"]),
33 | url: payload["issue"]["comments_url"]
34 | }
35 | ],
36 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
37 | verify: true
38 | }
39 | else
40 | nil
41 | end
42 | end
43 |
44 | defp error_message(login) do
45 | """
46 | @#{login} the `in-progress` label has been added to this issue **without a time estimation**.
47 | Please add a time estimation to this issue before applying the `in-progress` label.
48 | """
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/assets/brunch-config.js:
--------------------------------------------------------------------------------
1 | exports.config = {
2 | // See http://brunch.io/#documentation for docs.
3 | files: {
4 | javascripts: {
5 | joinTo: "js/app.js"
6 |
7 | // To use a separate vendor.js bundle, specify two files path
8 | // http://brunch.io/docs/config#-files-
9 | // joinTo: {
10 | // "js/app.js": /^(web\/static\/js)/,
11 | // "js/vendor.js": /^(web\/static\/vendor)|(deps)/
12 | // }
13 | //
14 | // To change the order of concatenation of files, explicitly mention here
15 | // order: {
16 | // before: [
17 | // "web/static/vendor/js/jquery-2.1.1.js",
18 | // "web/static/vendor/js/bootstrap.min.js"
19 | // ]
20 | // }
21 | },
22 | stylesheets: {
23 | joinTo: "css/app.css",
24 | order: {
25 | after: ["web/static/css/app.css"] // concat app.css last
26 | }
27 | },
28 | templates: {
29 | joinTo: "js/app.js"
30 | }
31 | },
32 |
33 | conventions: {
34 | // This option sets where we should place non-css and non-js assets in.
35 | // By default, we set this to "/assets/static". Files in this directory
36 | // will be copied to `paths.public`, which is "priv/static" by default.
37 | assets: /^(static)/
38 | },
39 |
40 | // Phoenix paths configuration
41 | paths: {
42 | // Dependencies and current project directories to watch
43 | watched: ["static", "css", "js", "vendor"],
44 |
45 | // Where to compile files to
46 | public: "../priv/static"
47 | },
48 |
49 | // Configure your plugins
50 | plugins: {
51 | babel: {
52 | // Do not use ES6 compiler in vendor code
53 | ignore: [/vendor/]
54 | }
55 | },
56 |
57 | modules: {
58 | autoRequire: {
59 | "js/app.js": ["js/app"]
60 | }
61 | },
62 |
63 | npm: {
64 | enabled: true
65 | }
66 | };
67 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/status/travis_failure.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.Status.TravisFailure do
2 | @moduledoc """
3 | Check for test failing on PR with "awaiting-review" label
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_failing_test"
8 |
9 | def apply?(payload) do
10 | payload["state"] == "failure"
11 | end
12 |
13 | def check(payload, _get_data?, token) do
14 | payload = @github_api.get_issue_from_status(token, payload, @rule_name)
15 | labels = payload["issue"]["labels"]
16 | if Helpers.label_member?(labels, "awaiting-review") do
17 | %{
18 | error_type: @rule_name,
19 | actions: [
20 | %{
21 | remove_assignees: get_assignees_login(payload["issue"]["assignees"]),
22 | url: "#{payload["issue"]["url"]}/assignees"
23 | },
24 | %{
25 | comment: error_message(payload["pull_request"]["user"]["login"]),
26 | url: payload["issue"]["comments_url"]
27 | },
28 | %{
29 | add_assignees: [payload["pull_request"]["user"]["login"]],
30 | url: "#{payload["issue"]["url"]}/assignees"
31 | },
32 | %{
33 | remove_label: "awaiting-review",
34 | url: "#{payload["issue"]["url"]}/labels"
35 | }
36 | ],
37 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
38 | verify: false
39 | }
40 | else
41 | nil
42 | end
43 | end
44 |
45 | defp error_message(login) do
46 | """
47 | :warning: @#{login}, the pull request is in "awaiting-review" but some tests are failing.
48 | Please fix the tests and reassign when ready :+1:
49 | Thanks
50 | """
51 | end
52 |
53 | defp get_assignees_login(assignees) do
54 | assignees
55 | |> Enum.map(fn(a) -> a["login"] end)
56 | end
57 |
58 | end
59 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/pr/no_assignee_or_reviewer.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.PR.NoAssigneeOrReviewer do
2 | @moduledoc """
3 | Check for error when an PR has awaiting-review but no assignees
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_no_assignee_or_reviewer"
8 |
9 | def apply?(payload) do
10 | reviewers = payload["pull_request"]["requested_reviewers"] |> Enum.map(&(&1["login"]))
11 | payload["action"] in ~w(labeled unassigned assigned) && Enum.empty?(reviewers)
12 | end
13 |
14 | def check(payload, _get_data?, token) do
15 | author_event = payload["sender"]["login"]
16 | url = payload["pull_request"]["issue_url"]
17 | payload = @github_api.get_data(token, %{"issue" => url}, @rule_name)
18 | labels = payload["issue"]["labels"]
19 | assignees = payload["issue"]["assignees"]
20 | author = payload["issue"]["user"]["login"]
21 | incorrect_assignee = wrong_assignee(assignees, author)
22 | if Helpers.label_member?(labels, "awaiting-review") && incorrect_assignee do
23 | %{
24 | error_type: @rule_name,
25 | actions: [
26 | %{
27 | comment: error_message(author_event),
28 | url: payload["issue"]["comments_url"]
29 | }
30 | ],
31 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
32 | verify: true
33 | }
34 | else
35 | nil
36 | end
37 | end
38 |
39 | defp error_message(login) do
40 | """
41 | :warning: @#{login}, the pull request is in "awaiting-review" but doesn't have a reviewer or a correct assignee.
42 | Please assign someone to review the pull request, thanks.
43 | """
44 | end
45 |
46 | defp wrong_assignee(assignees, login) do
47 | case length(assignees) do
48 | 0 -> true
49 | 1 ->
50 | name = assignees
51 | |> List.first()
52 | |> Map.get("login")
53 |
54 | (name == login)
55 | _ -> false
56 | end
57 | end
58 |
59 | end
60 |
--------------------------------------------------------------------------------
/lib/dwylbot_web.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb do
2 | @moduledoc """
3 | A module that keeps using definitions for controllers,
4 | views and so on.
5 |
6 | This can be used in your application as:
7 |
8 | use DwylbotWeb, :controller
9 | use DwylbotWeb, :view
10 |
11 | The definitions below will be executed for every view,
12 | controller, etc, so keep them short and clean, focused
13 | on imports, uses and aliases.
14 |
15 | Do NOT define functions inside the quoted expressions
16 | below.
17 | """
18 |
19 | def model do
20 | quote do
21 | use Ecto.Schema
22 |
23 | import Ecto
24 | import Ecto.Changeset
25 | import Ecto.Query
26 | end
27 | end
28 |
29 | def controller do
30 | quote do
31 | use Phoenix.Controller, namespace: DwylbotWeb
32 |
33 | alias Dwylbot.Repo
34 | import Ecto
35 | import Ecto.Query
36 |
37 | import DwylbotWeb.Router.Helpers
38 | import DwylbotWeb.Gettext
39 | end
40 | end
41 |
42 | def view do
43 | quote do
44 | use Phoenix.View, root: "lib/dwylbot_web/templates",
45 | namespace: DwylbotWeb
46 |
47 | # Import convenience functions from controllers
48 | import Phoenix.Controller, only: [
49 | get_csrf_token: 0,
50 | get_flash: 2,
51 | view_module: 1
52 | ]
53 |
54 | # Use all HTML functionality (forms, tags, etc)
55 | use Phoenix.HTML
56 |
57 | import DwylbotWeb.Router.Helpers
58 | import DwylbotWeb.ErrorHelpers
59 | import DwylbotWeb.Gettext
60 | end
61 | end
62 |
63 | def router do
64 | quote do
65 | use Phoenix.Router
66 | end
67 | end
68 |
69 | def channel do
70 | quote do
71 | use Phoenix.Channel
72 |
73 | alias Dwylbot.Repo
74 | import Ecto
75 | import Ecto.Query
76 | import DwylbotWeb.Gettext
77 | end
78 | end
79 |
80 | @doc """
81 | When used, dispatch to the appropriate controller/view/etc.
82 | """
83 | defmacro __using__(which) when is_atom(which) do
84 | apply(__MODULE__, which, [])
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/doc/github_authentication.md:
--------------------------------------------------------------------------------
1 | # Why
2 |
3 | We are using Github OAuth to authenticate the user in the dwylbot application.
4 | This allow the application to use the users Github account to create/delete webhooks on the selected repositories. This also allow dwylbot to use the users Github account to create comments on issues, this help dwylbot not being blocked by the Github API limit on the number of requests
5 |
6 | # Implementation
7 |
8 | It's a good idea to refresh your memory with the OAuth flow. You can read a good description on the [digitalocean tutorial](https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2) and on the [Github web application flow section](https://developer.github.com/v3/oauth/#web-application-flow). The main flow is:
9 | 1. The user click on the authorise link (signup link)
10 | 2. The application receive an authorization code from the API service (Github)
11 | 3. The application request a token by sending back the authorization code to the API service
12 | 4. The application receive the token
13 |
14 | We are using [ueberauth](https://github.com/ueberauth/ueberauth) and [ueberauth_github](https://github.com/ueberauth/ueberauth_github) which simplify the Implementation of the OAuth2 flow.
15 |
16 | Install the dependencies in mix.exs:
17 | ```
18 | # mix.exs
19 |
20 | defp deps do
21 | [{:phoenix, "~> 1.2.1"},
22 | ...
23 | {:ueberauth, "~> 0.4"},
24 | {:ueberauth_github, "~> 0.4.1"}
25 | ]
26 | end
27 | ```
28 |
29 | ```
30 | # mix.exs
31 |
32 | def application do
33 | [mod: {Dwylbot, []},
34 | applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
35 | :phoenix_ecto, :postgrex, :tentacat, :ueberauth, :ueberauth_github]]
36 | end
37 | ```
38 |
39 | and run ```mix deps.get``` in your terminal to downaload the packages.
40 |
41 |
42 | # References
43 |
44 | - github.com/jruts/playwith_phoenix
45 | - https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
46 | - https://developer.github.com/v3/oauth/#web-application-flow
47 | - https://github.com/ueberauth/ueberauth_github
48 | - https://github.com/ueberauth/ueberauth
49 |
--------------------------------------------------------------------------------
/test/fixtures/issue.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/3",
3 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
4 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/labels{/name}",
5 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/comments",
6 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/events",
7 | "html_url": "https://github.com/SimonLab/github_app/issues/3",
8 | "id": 235532030,
9 | "number": 3,
10 | "title": "Test issue",
11 | "user": {
12 | "login": "SimonLab",
13 | "id": 6057298,
14 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
15 | "gravatar_id": "",
16 | "url": "https://api.github.com/users/SimonLab",
17 | "html_url": "https://github.com/SimonLab",
18 | "followers_url": "https://api.github.com/users/SimonLab/followers",
19 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
20 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
21 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
22 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
23 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
24 | "repos_url": "https://api.github.com/users/SimonLab/repos",
25 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
26 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
27 | "type": "User",
28 | "site_admin": false
29 | },
30 | "labels": [
31 | {
32 | "id": 624855442,
33 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/in-progress",
34 | "name": "in-progress",
35 | "color": "009688",
36 | "default": false
37 | }
38 | ],
39 | "state": "open",
40 | "locked": false,
41 | "assignee": null,
42 | "assignees": [
43 |
44 | ],
45 | "milestone": null,
46 | "comments": 0,
47 | "created_at": "2017-06-13T12:09:09Z",
48 | "updated_at": "2017-06-13T13:25:48Z",
49 | "closed_at": null,
50 | "body": "This is a test issue for dwylbot"
51 | }
52 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/pr/merge_conflict.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.PR.MergeConflict do
2 | @moduledoc """
3 | Check for error when a PR has a merge conflict
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_merge_conflicts"
8 |
9 | def apply?(payload) do
10 | payload["action"] == "closed" && payload["pull_request"]["merged"]
11 | end
12 |
13 | def check(payload, _get_data?, token) do
14 | payload = @github_api.get_pull_requests(token, payload, @rule_name)
15 |
16 | actions = payload
17 | |> Enum.filter(fn(pr) ->
18 | pr["pull_request"]["mergeable"] == false
19 | && !Helpers.label_member?(pr["issue"]["labels"], "merge-conflicts")
20 | end)
21 | |> Enum.map(fn(pr) ->
22 | [
23 | %{
24 | remove_assignees: get_assignees_login(pr["issue"]["assignees"]),
25 | url: "#{pr["issue"]["url"]}/assignees"
26 | },
27 | %{
28 | comment: error_message(pr["pull_request"]["user"]["login"]),
29 | url: pr["pull_request"]["comments_url"]
30 | },
31 | %{
32 | add_assignees: [pr["pull_request"]["user"]["login"]],
33 | url: "#{pr["issue"]["url"]}/assignees"
34 | },
35 | %{
36 | add_labels: ["merge-conflicts"],
37 | url: "#{pr["issue"]["url"]}/labels"
38 | },
39 | %{
40 | remove_label: "awaiting-review",
41 | url: "#{pr["issue"]["url"]}/labels"
42 | }
43 | ]
44 | end)
45 | |> Enum.concat
46 |
47 | if length(actions) > 0 do
48 | %{
49 | error_type: @rule_name,
50 | actions: actions,
51 | wait: Helpers.wait(Mix.env, 40_000, 1000, 1),
52 | verify: false
53 | }
54 | else
55 | nil
56 | end
57 | end
58 |
59 | defp get_assignees_login(assignees) do
60 | assignees
61 | |> Enum.map(fn(a) -> a["login"] end)
62 | end
63 |
64 | defp error_message(login) do
65 | """
66 | :warning: @#{login}, the pull request has a **merge conflict**.
67 | Please resolve the conflict and reassign when ready :+1:
68 | Thanks!
69 | """
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule Dwylbot.Mixfile do
2 | use Mix.Project
3 |
4 | def project do
5 | [app: :dwylbot,
6 | version: "0.0.1",
7 | elixir: "~> 1.4",
8 | elixirc_paths: elixirc_paths(Mix.env),
9 | compilers: [:phoenix, :gettext] ++ Mix.compilers,
10 | test_coverage: [tool: ExCoveralls],
11 | preferred_cli_env: ["coveralls": :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test],
12 | build_embedded: Mix.env == :prod,
13 | start_permanent: Mix.env == :prod,
14 | aliases: aliases(),
15 | deps: deps()]
16 | end
17 |
18 | # Configuration for the OTP application.
19 | #
20 | # Type `mix help compile.app` for more information.
21 | def application do
22 | [mod: {Dwylbot, []},
23 | applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
24 | :phoenix_ecto, :postgrex, :httpoison, :joken, :jose]]
25 | end
26 |
27 | # Specifies which paths to compile per environment.
28 | defp elixirc_paths(:test), do: ["lib", "test/support"]
29 | defp elixirc_paths(_), do: ["lib"]
30 |
31 | # Specifies your project dependencies.
32 | #
33 | # Type `mix help deps` for examples and options.
34 | defp deps do
35 | [{:phoenix, "~> 1.3.0"},
36 | {:phoenix_pubsub, "~> 1.0"},
37 | {:phoenix_ecto, "~> 3.2"},
38 | {:postgrex, ">= 0.0.0"},
39 | {:phoenix_html, "~> 2.10"},
40 | {:phoenix_live_reload, "~> 1.0", only: :dev},
41 | {:gettext, "~> 0.11"},
42 | {:cowboy, "~> 1.0"},
43 | {:excoveralls, "~> 0.6", only: :test},
44 | {:credo, "~> 0.8.10"},
45 | {:httpoison, "~> 0.11.2"},
46 | {:joken, "~> 1.4.1"},
47 | {:jose, "~> 1.8"}
48 | ]
49 | end
50 |
51 | # Aliases are shortcuts or tasks specific to the current project.
52 | # For example, to create, migrate and run the seeds file at once:
53 | #
54 | # $ mix ecto.setup
55 | #
56 | # See the documentation for `Mix` for more info on aliases.
57 | defp aliases do
58 | ["ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
59 | "ecto.reset": ["ecto.drop", "ecto.setup"],
60 | "test": ["ecto.create --quiet", "ecto.migrate", "test"]]
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/pr/awaiting_review.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.PR.AwaitingReview do
2 | @moduledoc """
3 | add awaiting-review if a reviewer has been added to the PR
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_awaiting_review"
8 |
9 | def apply?(payload) do
10 | (payload["action"] == "review_requested")
11 | end
12 |
13 | def check(payload, _get_data?, token) do
14 | urls = %{
15 | "issue" => payload["pull_request"]["issue_url"],
16 | "pull_request" => payload["pull_request"]["url"]
17 | }
18 | payload = @github_api.get_data(token, urls, @rule_name)
19 |
20 | reviewers = payload["pull_request"]["requested_reviewers"]
21 | |> Enum.map(&(&1["login"]))
22 |
23 | in_progress = payload["issue"]["labels"]
24 | |> Helpers.label_member?("in-progress")
25 |
26 | if (!Enum.empty?(reviewers) && !in_progress) do
27 | %{
28 | error_type: @rule_name,
29 | actions: [
30 | %{
31 | add_labels: ["awaiting-review"],
32 | url: "#{payload["issue"]["url"]}/labels"
33 | },
34 | %{
35 | add_assignees: reviewers,
36 | url: "#{payload["issue"]["url"]}/assignees"
37 | },
38 | %{
39 | comment: error_message(payload["issue"]["user"]["login"]),
40 | url: payload["issue"]["comments_url"]
41 | },
42 | ],
43 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
44 | verify: true
45 | }
46 | else
47 | nil
48 | end
49 | end
50 |
51 | defp error_message(login) do
52 | """
53 | @#{login}, hoorah! 🎉 It's review time! 👀
54 |
55 | I couldn't help but notice that there isn't an `in-progress` label on this pull request and a **Reviewer**
56 | has been added...makes me think that this pull request is ready for review 🤔
57 |
58 | To save you time ⏳ I've added the **Reviewer** as an **Assignee** and I've added the `awaiting-review`
59 | label - automatically - just like magic! 🎩 🐰 ✨. Please correct me if I'm wrong, but if I got it right
60 | this time I hope it helps you! 😄
61 |
62 | """
63 | end
64 |
65 | end
66 |
--------------------------------------------------------------------------------
/assets/js/socket.js:
--------------------------------------------------------------------------------
1 | // NOTE: The contents of this file will only be executed if
2 | // you uncomment its entry in "web/static/js/app.js".
3 |
4 | // To use Phoenix channels, the first step is to import Socket
5 | // and connect at the socket path in "lib/my_app/endpoint.ex":
6 | import {Socket} from "phoenix"
7 |
8 | let socket = new Socket("/socket", {params: {token: window.userToken}})
9 |
10 | // When you connect, you'll often need to authenticate the client.
11 | // For example, imagine you have an authentication plug, `MyAuth`,
12 | // which authenticates the session and assigns a `:current_user`.
13 | // If the current user exists you can assign the user's token in
14 | // the connection for use in the layout.
15 | //
16 | // In your "web/router.ex":
17 | //
18 | // pipeline :browser do
19 | // ...
20 | // plug MyAuth
21 | // plug :put_user_token
22 | // end
23 | //
24 | // defp put_user_token(conn, _) do
25 | // if current_user = conn.assigns[:current_user] do
26 | // token = Phoenix.Token.sign(conn, "user socket", current_user.id)
27 | // assign(conn, :user_token, token)
28 | // else
29 | // conn
30 | // end
31 | // end
32 | //
33 | // Now you need to pass this token to JavaScript. You can do so
34 | // inside a script tag in "web/templates/layout/app.html.eex":
35 | //
36 | //
37 | //
38 | // You will need to verify the user token in the "connect/2" function
39 | // in "web/channels/user_socket.ex":
40 | //
41 | // def connect(%{"token" => token}, socket) do
42 | // # max_age: 1209600 is equivalent to two weeks in seconds
43 | // case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do
44 | // {:ok, user_id} ->
45 | // {:ok, assign(socket, :user, user_id)}
46 | // {:error, reason} ->
47 | // :error
48 | // end
49 | // end
50 | //
51 | // Finally, pass the token on connect as below. Or remove it
52 | // from connect if you don't care about authentication.
53 |
54 | socket.connect()
55 |
56 | // Now that you are connected, you can join channels with a topic:
57 | let channel = socket.channel("topic:subtopic", {})
58 | channel.join()
59 | .receive("ok", resp => { console.log("Joined successfully", resp) })
60 | .receive("error", resp => { console.log("Unable to join", resp) })
61 |
62 | export default socket
63 |
--------------------------------------------------------------------------------
/priv/gettext/en/LC_MESSAGES/errors.po:
--------------------------------------------------------------------------------
1 | ## `msgid`s in this file come from POT (.pot) files.
2 | ##
3 | ## Do not add, change, or remove `msgid`s manually here as
4 | ## they're tied to the ones in the corresponding POT file
5 | ## (with the same domain).
6 | ##
7 | ## Use `mix gettext.extract --merge` or `mix gettext.merge`
8 | ## to merge POT files into PO files.
9 | msgid ""
10 | msgstr ""
11 | "Language: en\n"
12 |
13 | ## From Ecto.Changeset.cast/4
14 | msgid "can't be blank"
15 | msgstr ""
16 |
17 | ## From Ecto.Changeset.unique_constraint/3
18 | msgid "has already been taken"
19 | msgstr ""
20 |
21 | ## From Ecto.Changeset.put_change/3
22 | msgid "is invalid"
23 | msgstr ""
24 |
25 | ## From Ecto.Changeset.validate_format/3
26 | msgid "has invalid format"
27 | msgstr ""
28 |
29 | ## From Ecto.Changeset.validate_subset/3
30 | msgid "has an invalid entry"
31 | msgstr ""
32 |
33 | ## From Ecto.Changeset.validate_exclusion/3
34 | msgid "is reserved"
35 | msgstr ""
36 |
37 | ## From Ecto.Changeset.validate_confirmation/3
38 | msgid "does not match confirmation"
39 | msgstr ""
40 |
41 | ## From Ecto.Changeset.no_assoc_constraint/3
42 | msgid "is still associated to this entry"
43 | msgstr ""
44 |
45 | msgid "are still associated to this entry"
46 | msgstr ""
47 |
48 | ## From Ecto.Changeset.validate_length/3
49 | msgid "should be %{count} character(s)"
50 | msgid_plural "should be %{count} character(s)"
51 | msgstr[0] ""
52 | msgstr[1] ""
53 |
54 | msgid "should have %{count} item(s)"
55 | msgid_plural "should have %{count} item(s)"
56 | msgstr[0] ""
57 | msgstr[1] ""
58 |
59 | msgid "should be at least %{count} character(s)"
60 | msgid_plural "should be at least %{count} character(s)"
61 | msgstr[0] ""
62 | msgstr[1] ""
63 |
64 | msgid "should have at least %{count} item(s)"
65 | msgid_plural "should have at least %{count} item(s)"
66 | msgstr[0] ""
67 | msgstr[1] ""
68 |
69 | msgid "should be at most %{count} character(s)"
70 | msgid_plural "should be at most %{count} character(s)"
71 | msgstr[0] ""
72 | msgstr[1] ""
73 |
74 | msgid "should have at most %{count} item(s)"
75 | msgid_plural "should have at most %{count} item(s)"
76 | msgstr[0] ""
77 | msgstr[1] ""
78 |
79 | ## From Ecto.Changeset.validate_number/3
80 | msgid "must be less than %{number}"
81 | msgstr ""
82 |
83 | msgid "must be greater than %{number}"
84 | msgstr ""
85 |
86 | msgid "must be less than or equal to %{number}"
87 | msgstr ""
88 |
89 | msgid "must be greater than or equal to %{number}"
90 | msgstr ""
91 |
92 | msgid "must be equal to %{number}"
93 | msgstr ""
94 |
--------------------------------------------------------------------------------
/priv/gettext/errors.pot:
--------------------------------------------------------------------------------
1 | ## This file is a PO Template file.
2 | ##
3 | ## `msgid`s here are often extracted from source code.
4 | ## Add new translations manually only if they're dynamic
5 | ## translations that can't be statically extracted.
6 | ##
7 | ## Run `mix gettext.extract` to bring this file up to
8 | ## date. Leave `msgstr`s empty as changing them here as no
9 | ## effect: edit them in PO (`.po`) files instead.
10 |
11 | ## From Ecto.Changeset.cast/4
12 | msgid "can't be blank"
13 | msgstr ""
14 |
15 | ## From Ecto.Changeset.unique_constraint/3
16 | msgid "has already been taken"
17 | msgstr ""
18 |
19 | ## From Ecto.Changeset.put_change/3
20 | msgid "is invalid"
21 | msgstr ""
22 |
23 | ## From Ecto.Changeset.validate_format/3
24 | msgid "has invalid format"
25 | msgstr ""
26 |
27 | ## From Ecto.Changeset.validate_subset/3
28 | msgid "has an invalid entry"
29 | msgstr ""
30 |
31 | ## From Ecto.Changeset.validate_exclusion/3
32 | msgid "is reserved"
33 | msgstr ""
34 |
35 | ## From Ecto.Changeset.validate_confirmation/3
36 | msgid "does not match confirmation"
37 | msgstr ""
38 |
39 | ## From Ecto.Changeset.no_assoc_constraint/3
40 | msgid "is still associated to this entry"
41 | msgstr ""
42 |
43 | msgid "are still associated to this entry"
44 | msgstr ""
45 |
46 | ## From Ecto.Changeset.validate_length/3
47 | msgid "should be %{count} character(s)"
48 | msgid_plural "should be %{count} character(s)"
49 | msgstr[0] ""
50 | msgstr[1] ""
51 |
52 | msgid "should have %{count} item(s)"
53 | msgid_plural "should have %{count} item(s)"
54 | msgstr[0] ""
55 | msgstr[1] ""
56 |
57 | msgid "should be at least %{count} character(s)"
58 | msgid_plural "should be at least %{count} character(s)"
59 | msgstr[0] ""
60 | msgstr[1] ""
61 |
62 | msgid "should have at least %{count} item(s)"
63 | msgid_plural "should have at least %{count} item(s)"
64 | msgstr[0] ""
65 | msgstr[1] ""
66 |
67 | msgid "should be at most %{count} character(s)"
68 | msgid_plural "should be at most %{count} character(s)"
69 | msgstr[0] ""
70 | msgstr[1] ""
71 |
72 | msgid "should have at most %{count} item(s)"
73 | msgid_plural "should have at most %{count} item(s)"
74 | msgstr[0] ""
75 | msgstr[1] ""
76 |
77 | ## From Ecto.Changeset.validate_number/3
78 | msgid "must be less than %{number}"
79 | msgstr ""
80 |
81 | msgid "must be greater than %{number}"
82 | msgstr ""
83 |
84 | msgid "must be less than or equal to %{number}"
85 | msgstr ""
86 |
87 | msgid "must be greater than or equal to %{number}"
88 | msgstr ""
89 |
90 | msgid "must be equal to %{number}"
91 | msgstr ""
92 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/github_api/in_memory.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.GithubAPI.InMemory do
2 | @moduledoc """
3 | mock of github api functions for tests
4 | """
5 | alias Poison.Parser, as: PP
6 |
7 | def get_installations(_token) do
8 | [
9 | %{"account" => %{"login" => "dwyl"}, "id" => "1"},
10 | %{"account" => %{"login" => "FocusHub"}, "id" => "2"}
11 | ]
12 | end
13 |
14 | def get_repositories(_token, _id_installation) do
15 | [
16 | %{"name" => "learn-elixir"}
17 | ]
18 | end
19 |
20 | def get_installation_token(_installation_id) do
21 | "token_installation_1234"
22 | end
23 |
24 | def get_data(_token, _urls, rule_name) do
25 | mock = get_mock_file(rule_name)
26 | mock
27 | |> Enum.map(fn({type, file}) ->
28 | data = file
29 | |> File.read!()
30 | |> PP.parse!()
31 | {type, data}
32 | end)
33 | |> Enum.into(%{})
34 | end
35 |
36 | defp get_mock_file(rule_name) do
37 | config = %{
38 | "issue_inprogress_noassignees" =>
39 | [{"issue", "./test/fixtures/issue.json"}],
40 | "issue_no_description" =>
41 | [{"issue", "./test/fixtures/issue.json"}],
42 | "issue_unassigned_noassignees" =>
43 | [{"issue", "./test/fixtures/issue.json"}],
44 | "issue_no_estimation" =>
45 | [{"issue", "./test/fixtures/issue.json"}],
46 | "pr_no_assignee_or_reviewer" =>
47 | [{"issue", "./test/fixtures/issue_from_pr.json"}],
48 | "pr_reviewer_but_no_assignee" =>
49 | [{"issue", "./test/fixtures/issue_from_pr.json"}],
50 | "pr_no_description" =>
51 | [{"pull_request", "./test/fixtures/pull_request.json"}],
52 | "pr_merge_conflicts" =>
53 | [
54 | {"issue", "./test/fixtures/issue.json"},
55 | {"pull_request", "./test/fixtures/pr.json"}
56 | ],
57 | "pr_awaiting_review" =>
58 | [
59 | {"issue", "./test/fixtures/issue_from_pr.json"},
60 | {"pull_request", "./test/fixtures/pr_reviewers-not_inprogress.json"}
61 | ],
62 | "pr_failing_test" =>
63 | [
64 | {"issue", "./test/fixtures/issue_from_pr_failing.json"},
65 | {"pull_request", "./test/fixtures/pr_failing.json"}
66 | ],
67 | }
68 | Map.get(config, rule_name)
69 | end
70 |
71 | def get_pull_requests(_token, _payload, rule_name) do
72 | [get_data(nil, nil, rule_name)]
73 | end
74 |
75 | def get_issue_from_status(_token, _payload, rule_name) do
76 | get_data(nil, nil, rule_name)
77 | end
78 |
79 | def report_error(_token, _error) do
80 | %{ok: 200}
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/rules/pr/reviewer_but_no_assignee.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.Rules.PR.ReviewerButNoAssignee do
2 | @moduledoc """
3 | Check for error when an PR has awaiting-review but no assignees
4 | """
5 | alias DwylbotWeb.Rules.Helpers
6 | @github_api Application.get_env(:dwylbot, :github_api)
7 | @rule_name "pr_reviewer_but_no_assignee"
8 |
9 | def apply?(payload) do
10 | reviewers = payload["pull_request"]["requested_reviewers"] |> Enum.map(&(&1["login"]))
11 | payload["action"] in ~w(labeled unassigned assigned) && !Enum.empty?(reviewers)
12 | end
13 |
14 | def check(payload, _get_data?, token) do
15 | reviewers = payload["pull_request"]["requested_reviewers"] |> Enum.map(&(&1["login"]))
16 | author_event = payload["sender"]["login"]
17 | url = payload["pull_request"]["issue_url"]
18 | payload = @github_api.get_data(token, %{"issue" => url}, @rule_name)
19 | labels = payload["issue"]["labels"]
20 | assignees = payload["issue"]["assignees"]
21 | author = payload["issue"]["user"]["login"]
22 | incorrect_assignee = wrong_assignee(assignees, author)
23 | if Helpers.label_member?(labels, "awaiting-review") && incorrect_assignee do
24 | %{
25 | error_type: @rule_name,
26 | actions: [
27 | %{
28 | comment: error_message(author_event),
29 | url: payload["issue"]["comments_url"]
30 | },
31 | %{
32 | add_assignees: [reviewers],
33 | url: "#{payload["issue"]["url"]}/assignees"
34 | }
35 | ],
36 | wait: Helpers.wait(Mix.env, 30_000, 1000, 1),
37 | verify: true
38 | }
39 | else
40 | nil
41 | end
42 | end
43 |
44 | defp error_message(login) do
45 | """
46 | :wave: @#{login}, you have requested a review for this pull request so we have taken the liberty of assigning the reviewers :tada:.
47 |
48 | Have a great day :sunny: and keep up the good work :computer: :clap:
49 | """
50 | end
51 |
52 | @doc """
53 | iex>wrong_assignee([],"SimonLab")
54 | true
55 | iex>wrong_assignee([%{"login" => "SimonLab"}], "naazy")
56 | false
57 | iex>wrong_assignee([%{"login" => "iteles"},%{"login" => "naazy"}], "naazy")
58 | false
59 | iex>wrong_assignee([%{"login" => "iteles"}],"iteles")
60 | true
61 | iex>wrong_assignee([%{"login" => "naazy"}, %{"login" => "iteles"}],"iteles")
62 | false
63 | """
64 |
65 | def wrong_assignee(assignees, login) do
66 | case length(assignees) do
67 | 0 -> true
68 | 1 ->
69 | name = assignees
70 | |> List.first()
71 | |> Map.get("login")
72 |
73 | (name == login)
74 | _ -> false
75 | end
76 | end
77 |
78 | end
79 |
--------------------------------------------------------------------------------
/config/prod.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # For production, we configure the host to read the PORT
4 | # from the system environment. Therefore, you will need
5 | # to set PORT=80 before running your server.
6 | #
7 | # You should also configure the url host to something
8 | # meaningful, we use this information when generating URLs.
9 | #
10 | # Finally, we also include the path to a manifest
11 | # containing the digested version of static files. This
12 | # manifest is generated by the mix phoenix.digest task
13 | # which you typically run after static files are built.
14 | config :dwylbot, Dwylbot.Endpoint,
15 | http: [port: {:system, "PORT"}],
16 | url: [scheme: "https", host: "dwylbot.herokuapp.com", port: 443],
17 | force_ssl: [rewrite_on: [:x_forwarded_proto]],
18 | cache_static_manifest: "priv/static/cache_manifest.json",
19 | secret_key_base: System.get_env("SECRET_KEY_BASE"),
20 | debug_errors: true
21 |
22 | # Do not print debug messages in production
23 | # config :logger, level: :info
24 | config :logger, :console, format: "[$level] $message\n"
25 | # Configure your database
26 | config :dwylbot, Dwylbot.Repo,
27 | adapter: Ecto.Adapters.Postgres,
28 | url: System.get_env("DATABASE_URL"),
29 | pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
30 | ssl: true
31 |
32 | config :dwylbot, :github_api, DwylbotWeb.GithubAPI.HTTPClient
33 |
34 | # ## SSL Support
35 | #
36 | # To get SSL working, you will need to add the `https` key
37 | # to the previous section and set your `:url` port to 443:
38 | #
39 | # config :dwylbot, Dwylbot.Endpoint,
40 | # ...
41 | # url: [host: "example.com", port: 443],
42 | # https: [port: 443,
43 | # keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
44 | # certfile: System.get_env("SOME_APP_SSL_CERT_PATH")]
45 | #
46 | # Where those two env variables return an absolute path to
47 | # the key and cert in disk or a relative path inside priv,
48 | # for example "priv/ssl/server.key".
49 | #
50 | # We also recommend setting `force_ssl`, ensuring no data is
51 | # ever sent via http, always redirecting to https:
52 | #
53 | # config :dwylbot, Dwylbot.Endpoint,
54 | # force_ssl: [hsts: true]
55 | #
56 | # Check `Plug.SSL` for all available options in `force_ssl`.
57 |
58 | # ## Using releases
59 | #
60 | # If you are doing OTP releases, you need to instruct Phoenix
61 | # to start the server for all endpoints:
62 | #
63 | # config :phoenix, :serve_endpoints, true
64 | #
65 | # Alternatively, you can configure exactly which server to
66 | # start per endpoint:
67 | #
68 | # config :dwylbot, Dwylbot.Endpoint, server: true
69 | #
70 | # Finally import the config/prod.secret.exs
71 | # which should be versioned separately.
72 | # import_config "prod.secret.exs"
73 |
--------------------------------------------------------------------------------
/test/fixtures/issue_pr.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/23",
3 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
4 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/23/labels{/name}",
5 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/23/comments",
6 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/23/events",
7 | "html_url": "https://github.com/SimonLab/github_app/pull/23",
8 | "id": 236714975,
9 | "number": 23,
10 | "title": "merge conflict 2",
11 | "user": {
12 | "login": "SimonLab",
13 | "id": 6057298,
14 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
15 | "gravatar_id": "",
16 | "url": "https://api.github.com/users/SimonLab",
17 | "html_url": "https://github.com/SimonLab",
18 | "followers_url": "https://api.github.com/users/SimonLab/followers",
19 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
20 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
21 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
22 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
23 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
24 | "repos_url": "https://api.github.com/users/SimonLab/repos",
25 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
26 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
27 | "type": "User",
28 | "site_admin": false
29 | },
30 | "labels": [
31 | ],
32 | "state": "open",
33 | "locked": false,
34 | "assignee": {
35 | "login": "SimonLab",
36 | "id": 6057298,
37 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
38 | "gravatar_id": "",
39 | "url": "https://api.github.com/users/SimonLab",
40 | "html_url": "https://github.com/SimonLab",
41 | "followers_url": "https://api.github.com/users/SimonLab/followers",
42 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
43 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
44 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
45 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
46 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
47 | "repos_url": "https://api.github.com/users/SimonLab/repos",
48 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
49 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
50 | "type": "User",
51 | "site_admin": false
52 | },
53 | "assignees": [
54 | {
55 | "login": "SimonLab",
56 | "id": 6057298,
57 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
58 | "gravatar_id": "",
59 | "url": "https://api.github.com/users/SimonLab",
60 | "html_url": "https://github.com/SimonLab",
61 | "followers_url": "https://api.github.com/users/SimonLab/followers",
62 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
63 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
64 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
65 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
66 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
67 | "repos_url": "https://api.github.com/users/SimonLab/repos",
68 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
69 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
70 | "type": "User",
71 | "site_admin": false
72 | }
73 | ],
74 | "milestone": null,
75 | "comments": 4,
76 | "created_at": "2017-06-18T11:13:01Z",
77 | "updated_at": "2017-06-19T14:09:24Z",
78 | "closed_at": null,
79 | "pull_request": {
80 | "url": "https://api.github.com/repos/SimonLab/github_app/pulls/23",
81 | "html_url": "https://github.com/SimonLab/github_app/pull/23",
82 | "diff_url": "https://github.com/SimonLab/github_app/pull/23.diff",
83 | "patch_url": "https://github.com/SimonLab/github_app/pull/23.patch"
84 | },
85 | "body": "test",
86 | "closed_by": null
87 | }
88 |
--------------------------------------------------------------------------------
/test/fixtures/issue_from_pr_failing.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/24",
3 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
4 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/labels{/name}",
5 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/comments",
6 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/events",
7 | "html_url": "https://github.com/SimonLab/github_app/pull/24",
8 | "id": 237176280,
9 | "number": 24,
10 | "title": "add a test",
11 | "user": {
12 | "login": "SimonLab",
13 | "id": 6057298,
14 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
15 | "gravatar_id": "",
16 | "url": "https://api.github.com/users/SimonLab",
17 | "html_url": "https://github.com/SimonLab",
18 | "followers_url": "https://api.github.com/users/SimonLab/followers",
19 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
20 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
21 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
22 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
23 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
24 | "repos_url": "https://api.github.com/users/SimonLab/repos",
25 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
26 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
27 | "type": "User",
28 | "site_admin": false
29 | },
30 | "labels": [
31 | {
32 | "id": 624855444,
33 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/awaiting-review",
34 | "name": "awaiting-review",
35 | "color": "f39c12",
36 | "default": false
37 | }
38 | ],
39 | "state": "open",
40 | "locked": false,
41 | "assignee": {
42 | "login": "dwylbot",
43 | "id": 24862484,
44 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
45 | "gravatar_id": "",
46 | "url": "https://api.github.com/users/dwylbot",
47 | "html_url": "https://github.com/dwylbot",
48 | "followers_url": "https://api.github.com/users/dwylbot/followers",
49 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
50 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
51 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
52 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
53 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
54 | "repos_url": "https://api.github.com/users/dwylbot/repos",
55 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
56 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
57 | "type": "User",
58 | "site_admin": false
59 | },
60 | "assignees": [
61 | {
62 | "login": "dwylbot",
63 | "id": 24862484,
64 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
65 | "gravatar_id": "",
66 | "url": "https://api.github.com/users/dwylbot",
67 | "html_url": "https://github.com/dwylbot",
68 | "followers_url": "https://api.github.com/users/dwylbot/followers",
69 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
70 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
71 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
72 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
73 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
74 | "repos_url": "https://api.github.com/users/dwylbot/repos",
75 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
76 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
77 | "type": "User",
78 | "site_admin": false
79 | }
80 | ],
81 | "milestone": null,
82 | "comments": 0,
83 | "created_at": "2017-06-20T11:21:34Z",
84 | "updated_at": "2017-06-21T14:44:48Z",
85 | "closed_at": null,
86 | "pull_request": {
87 | "url": "https://api.github.com/repos/SimonLab/github_app/pulls/24",
88 | "html_url": "https://github.com/SimonLab/github_app/pull/24",
89 | "diff_url": "https://github.com/SimonLab/github_app/pull/24.diff",
90 | "patch_url": "https://github.com/SimonLab/github_app/pull/24.patch"
91 | },
92 | "body": "test",
93 | "closed_by": null
94 | }
95 |
--------------------------------------------------------------------------------
/test/fixtures/issue_from_pr.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/24",
3 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
4 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/labels{/name}",
5 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/comments",
6 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/24/events",
7 | "html_url": "https://github.com/SimonLab/github_app/pull/24",
8 | "id": 237176280,
9 | "number": 24,
10 | "title": "add a test",
11 | "user": {
12 | "login": "SimonLab",
13 | "id": 6057298,
14 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
15 | "gravatar_id": "",
16 | "url": "https://api.github.com/users/SimonLab",
17 | "html_url": "https://github.com/SimonLab",
18 | "followers_url": "https://api.github.com/users/SimonLab/followers",
19 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
20 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
21 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
22 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
23 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
24 | "repos_url": "https://api.github.com/users/SimonLab/repos",
25 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
26 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
27 | "type": "User",
28 | "site_admin": false
29 | },
30 | "labels": [
31 | {
32 | "id": 624855444,
33 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/awaiting-review",
34 | "name": "awaiting-review",
35 | "color": "f39c12",
36 | "default": false
37 | }
38 | ],
39 | "state": "open",
40 | "locked": false,
41 | "assignee": {
42 | "login": "SimonLab",
43 | "id": 6057298,
44 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
45 | "gravatar_id": "",
46 | "url": "https://api.github.com/users/SimonLab",
47 | "html_url": "https://github.com/SimonLab",
48 | "followers_url": "https://api.github.com/users/SimonLab/followers",
49 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
50 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
51 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
52 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
53 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
54 | "repos_url": "https://api.github.com/users/SimonLab/repos",
55 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
56 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
57 | "type": "User",
58 | "site_admin": false
59 | },
60 | "assignees": [
61 | {
62 | "login": "SimonLab",
63 | "id": 6057298,
64 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
65 | "gravatar_id": "",
66 | "url": "https://api.github.com/users/SimonLab",
67 | "html_url": "https://github.com/SimonLab",
68 | "followers_url": "https://api.github.com/users/SimonLab/followers",
69 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
70 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
71 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
72 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
73 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
74 | "repos_url": "https://api.github.com/users/SimonLab/repos",
75 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
76 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
77 | "type": "User",
78 | "site_admin": false
79 | }
80 | ],
81 | "milestone": null,
82 | "comments": 3,
83 | "created_at": "2017-06-20T11:21:34Z",
84 | "updated_at": "2017-06-20T20:29:32Z",
85 | "closed_at": null,
86 | "pull_request": {
87 | "url": "https://api.github.com/repos/SimonLab/github_app/pulls/24",
88 | "html_url": "https://github.com/SimonLab/github_app/pull/24",
89 | "diff_url": "https://github.com/SimonLab/github_app/pull/24.diff",
90 | "patch_url": "https://github.com/SimonLab/github_app/pull/24.patch"
91 | },
92 | "body": "test",
93 | "closed_by": null
94 | }
95 |
--------------------------------------------------------------------------------
/lib/dwylbot_web/controllers/github_api/http_client.ex:
--------------------------------------------------------------------------------
1 | defmodule DwylbotWeb.GithubAPI.HTTPClient do
2 | @moduledoc """
3 | wrapper functions for the API Github App API
4 | """
5 | alias Poison.Parser, as: PP
6 | alias JOSE.JWK, as: JJ
7 | import Joken
8 |
9 | @media_type "application/vnd.github.machine-man-preview+json"
10 | @github_root "https://api.github.com"
11 |
12 | defp header(token) do
13 | ["Authorization": "token #{token}", "Accept": @media_type]
14 | end
15 |
16 | defp headerBearer(token) do
17 | ["Authorization": "Bearer #{token}", "Accept": @media_type]
18 | end
19 |
20 | def get_installations(token) do
21 | "#{@github_root}/user/installations"
22 | |> HTTPoison.get!(header(token), [])
23 | |> Map.fetch!(:body)
24 | |> PP.parse!
25 | |> Map.get("installations")
26 | end
27 |
28 | def get_repositories(token, id_installation) do
29 | "#{@github_root}/user/installations/#{id_installation}/repositories"
30 | |> HTTPoison.get!(header(token), [])
31 | |> Map.fetch!(:body)
32 | |> PP.parse!
33 | |> Map.get("repositories")
34 | end
35 |
36 | def get_installation_token(installation_id) do
37 | private_key = System.get_env("PRIVATE_APP_KEY")
38 | github_app_id = System.get_env("GITHUB_APP_ID")
39 | key = JJ.from_pem(private_key)
40 | my_token = %{
41 | iss: github_app_id,
42 | iat: DateTime.utc_now |> DateTime.to_unix,
43 | exp: (DateTime.utc_now |> DateTime.to_unix) + 100
44 | }
45 | |> token()
46 | |> sign(rs256(key))
47 | |> get_compact()
48 |
49 | "#{@github_root}/installations/#{installation_id}/access_tokens"
50 | |> HTTPoison.post!([], headerBearer(my_token))
51 | |> Map.fetch!(:body)
52 | |> PP.parse!
53 | |> Map.get("token")
54 | end
55 |
56 | def report_error(token, errors) do
57 | errors.actions
58 | |> Enum.each(fn(action) -> post_action(action, token) end)
59 | end
60 |
61 | defp post_action(action, token) do
62 | case action do
63 | %{comment: comment, url: url} ->
64 | feedback = """
65 |
66 | Any questions, complaints, feedback, contributions?
67 | [](https://github.com/dwyl/dwylbot/issues "Discuss your ideas/suggestions with us!")
68 | If you prefer, you can also send us anonymous feedback: https://dwyl-feedback.herokuapp.com/feedback/new
69 | """
70 | message = comment <> feedback
71 | url
72 | |> HTTPoison.post!(Poison.encode!(%{body: message}), header(token))
73 |
74 | %{add_assignees: assignees, url: url} ->
75 | url
76 | |> HTTPoison.post!(
77 | Poison.encode!(%{assignees: assignees}), header(token)
78 | )
79 |
80 | %{remove_assignees: assignees, url: url} ->
81 | HTTPoison.request!(
82 | :delete, url, Poison.encode!(%{assignees: assignees}), header(token)
83 | )
84 |
85 | %{replace_labels: labels, url: url} ->
86 | url
87 | |> HTTPoison.put!(Poison.encode!(labels), header(token))
88 |
89 | %{add_labels: labels, url: url} ->
90 | url
91 | |> HTTPoison.post!(Poison.encode!(labels), header(token))
92 |
93 | %{remove_label: label, url: url} ->
94 | url <> "/#{label}"
95 | |> HTTPoison.delete!(header(token), [])
96 | end
97 | end
98 |
99 | def get_data(token, urls, _module_rule) do
100 | urls
101 | |> Enum.map(fn({type, url}) ->
102 | {type, get(token, url)}
103 | end)
104 | |> Enum.into(%{})
105 | end
106 |
107 | defp get(token, url) do
108 | url
109 | |> HTTPoison.get!(header(token), [])
110 | |> Map.fetch!(:body)
111 | |> PP.parse!()
112 | end
113 |
114 | def get_pull_requests(token, payload, rule_name) do
115 | "#{@github_root}/repos/#{payload["repository"]["full_name"]}/pulls"
116 | |> HTTPoison.get!(header(token), [])
117 | |> Map.fetch!(:body)
118 | |> PP.parse!
119 | |> Enum.map(fn(pr) ->
120 | urls = %{
121 | "issue" => pr["issue_url"],
122 | "pull_request" => pr["url"]
123 | }
124 | get_data(token, urls, rule_name)
125 | end)
126 | end
127 |
128 | def get_issue_from_status(token, payload, rule_name) do
129 | pull_request_payload = %{
130 | "repository" => %{
131 | "full_name" => payload["repository"]["full_name"]
132 | }
133 | }
134 | pull_requests = get_pull_requests(token, pull_request_payload, rule_name)
135 |
136 | branch_name = payload["branches"]
137 | |> List.first()
138 | |> Map.get("name")
139 |
140 | pull_requests
141 | |> Enum.filter(fn(data) ->
142 | data["pull_request"]["head"]["label"] =~ branch_name
143 | end)
144 | |> List.first()
145 | end
146 |
147 | end
148 |
--------------------------------------------------------------------------------
/.credo.exs:
--------------------------------------------------------------------------------
1 | # This file contains the configuration for Credo and you are probably reading
2 | # this after creating it with `mix credo.gen.config`.
3 | #
4 | # If you find anything wrong or unclear in this file, please report an
5 | # issue on GitHub: https://github.com/rrrene/credo/issues
6 | #
7 | %{
8 | #
9 | # You can have as many configs as you like in the `configs:` field.
10 | configs: [
11 | %{
12 | #
13 | # Run any config using `mix credo -C `. If no config name is given
14 | # "default" is used.
15 | name: "default",
16 | #
17 | # These are the files included in the analysis:
18 | files: %{
19 | #
20 | # You can give explicit globs or simply directories.
21 | # In the latter case `**/*.{ex,exs}` will be used.
22 | included: ["lib/", "src/", "web/", "apps/"],
23 | excluded: ["lib/dwylbot.ex"]
24 | },
25 | #
26 | # If you create your own checks, you must specify the source files for
27 | # them here, so they can be loaded by Credo before running the analysis.
28 | requires: [],
29 | #
30 | # Credo automatically checks for updates, like e.g. Hex does.
31 | # You can disable this behaviour below:
32 | check_for_updates: true,
33 | #
34 | # If you want to enforce a style guide and need a more traditional linting
35 | # experience, you can change `strict` to `true` below:
36 | strict: true,
37 | #
38 | # If you want to use uncolored output by default, you can change `color`
39 | # to `false` below:
40 | color: true,
41 | #
42 | # You can customize the parameters of any check by adding a second element
43 | # to the tuple.
44 | #
45 | # To disable a check put `false` as second element:
46 | #
47 | # {Credo.Check.Design.DuplicatedCode, false}
48 | #
49 | checks: [
50 | {Credo.Check.Consistency.ExceptionNames},
51 | {Credo.Check.Consistency.LineEndings},
52 | {Credo.Check.Consistency.MultiAliasImportRequireUse, false},
53 | {Credo.Check.Consistency.ParameterPatternMatching},
54 | {Credo.Check.Consistency.SpaceAroundOperators},
55 | {Credo.Check.Consistency.SpaceInParentheses},
56 | {Credo.Check.Consistency.TabsOrSpaces},
57 |
58 | # For some checks, like AliasUsage, you can only customize the priority
59 | # Priority values are: `low, normal, high, higher`
60 | {Credo.Check.Design.AliasUsage, priority: :low},
61 |
62 | # For others you can set parameters
63 |
64 | # If you don't want the `setup` and `test` macro calls in ExUnit tests
65 | # or the `schema` macro in Ecto schemas to trigger DuplicatedCode, just
66 | # set the `excluded_macros` parameter to `[:schema, :setup, :test]`.
67 | {Credo.Check.Design.DuplicatedCode, excluded_macros: []},
68 |
69 | # You can also customize the exit_status of each check.
70 | # If you don't want TODO comments to cause `mix credo` to fail, just
71 | # set this value to 0 (zero).
72 | {Credo.Check.Design.TagTODO, exit_status: 2},
73 | {Credo.Check.Design.TagFIXME},
74 |
75 | {Credo.Check.Readability.FunctionNames},
76 | {Credo.Check.Readability.LargeNumbers},
77 | {Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 80},
78 | {Credo.Check.Readability.ModuleAttributeNames},
79 | {Credo.Check.Readability.ModuleDoc},
80 | {Credo.Check.Readability.ModuleNames},
81 | {Credo.Check.Readability.ParenthesesOnZeroArityDefs},
82 | {Credo.Check.Readability.ParenthesesInCondition},
83 | {Credo.Check.Readability.PredicateFunctionNames},
84 | {Credo.Check.Readability.PreferImplicitTry},
85 | {Credo.Check.Readability.RedundantBlankLines},
86 | {Credo.Check.Readability.StringSigils},
87 | {Credo.Check.Readability.TrailingBlankLine},
88 | {Credo.Check.Readability.TrailingWhiteSpace},
89 | {Credo.Check.Readability.VariableNames},
90 | {Credo.Check.Readability.Semicolons},
91 | {Credo.Check.Readability.SpaceAfterCommas},
92 |
93 | {Credo.Check.Refactor.DoubleBooleanNegation},
94 | {Credo.Check.Refactor.CondStatements},
95 | {Credo.Check.Refactor.CyclomaticComplexity},
96 | {Credo.Check.Refactor.FunctionArity},
97 | {Credo.Check.Refactor.MatchInCondition},
98 | {Credo.Check.Refactor.NegatedConditionsInUnless},
99 | {Credo.Check.Refactor.NegatedConditionsWithElse},
100 | {Credo.Check.Refactor.Nesting},
101 | {Credo.Check.Refactor.PipeChainStart},
102 | {Credo.Check.Refactor.UnlessWithElse},
103 |
104 | {Credo.Check.Warning.BoolOperationOnSameValues},
105 | {Credo.Check.Warning.IExPry},
106 | {Credo.Check.Warning.IoInspect},
107 | {Credo.Check.Warning.LazyLogging},
108 | {Credo.Check.Warning.OperationOnSameValues},
109 | {Credo.Check.Warning.OperationWithConstantResult},
110 | {Credo.Check.Warning.UnusedEnumOperation},
111 | {Credo.Check.Warning.UnusedFileOperation},
112 | {Credo.Check.Warning.UnusedKeywordOperation},
113 | {Credo.Check.Warning.UnusedListOperation},
114 | {Credo.Check.Warning.UnusedPathOperation},
115 | {Credo.Check.Warning.UnusedRegexOperation},
116 | {Credo.Check.Warning.UnusedStringOperation},
117 | {Credo.Check.Warning.UnusedTupleOperation},
118 |
119 | # Controversial and experimental checks (opt-in, just remove `, false`)
120 | #
121 | {Credo.Check.Refactor.ABCSize, false},
122 | {Credo.Check.Refactor.AppendSingleItem, false},
123 | {Credo.Check.Refactor.VariableRebinding, false},
124 | {Credo.Check.Warning.MapGetUnsafePass, false},
125 |
126 | # Deprecated checks (these will be deleted after a grace period)
127 | {Credo.Check.Readability.Specs, false},
128 | {Credo.Check.Warning.NameRedeclarationByAssignment, false},
129 | {Credo.Check.Warning.NameRedeclarationByCase, false},
130 | {Credo.Check.Warning.NameRedeclarationByDef, false},
131 | {Credo.Check.Warning.NameRedeclarationByFn, false},
132 |
133 | # Custom checks can be created using `mix credo.gen.check`.
134 | #
135 | ]
136 | }
137 | ]
138 | }
139 |
--------------------------------------------------------------------------------
/mix.lock:
--------------------------------------------------------------------------------
1 | %{"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
2 | "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
3 | "certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], [], "hexpm"},
4 | "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
5 | "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
6 | "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"},
7 | "credo": {:hex, :credo, "0.8.10", "261862bb7363247762e1063713bb85df2bbd84af8d8610d1272cd9c1943bba63", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}], "hexpm"},
8 | "db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
9 | "decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [:mix], [], "hexpm"},
10 | "ecto": {:hex, :ecto, "2.2.7", "2074106ff4a5cd9cb2b54b12ca087c4b659ddb3f6b50be4562883c1d763fb031", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
11 | "excoveralls": {:hex, :excoveralls, "0.8.0", "99d2691d3edf8612f128be3f9869c4d44b91c67cec92186ce49470ae7a7404cf", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
12 | "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"},
13 | "file_system": {:hex, :file_system, "0.2.2", "7f1e9de4746f4eb8a4ca8f2fbab582d84a4e40fa394cce7bfcb068b988625b06", [], [], "hexpm"},
14 | "gettext": {:hex, :gettext, "0.14.0", "1a019a2e51d5ad3d126efe166dcdf6563768e5d06c32a99ad2281a1fa94b4c72", [:mix], [], "hexpm"},
15 | "hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.0.2", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
16 | "httpoison": {:hex, :httpoison, "0.11.2", "9e59f17a473ef6948f63c51db07320477bad8ba88cf1df60a3eee01150306665", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
17 | "idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
18 | "joken": {:hex, :joken, "1.4.1", "16b87dcbad59dfb1e75231b9d6e504d852ce11f849efb7150a41dcad29dba8e1", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
19 | "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
20 | "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"},
21 | "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
22 | "mime": {:hex, :mime, "1.2.0", "78adaa84832b3680de06f88f0997e3ead3b451a440d183d688085be2d709b534", [:mix], [], "hexpm"},
23 | "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
24 | "phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
25 | "phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
26 | "phoenix_html": {:hex, :phoenix_html, "2.10.5", "4f9df6b0fb7422a9440a73182a566cb9cbe0e3ffe8884ef9337ccf284fc1ef0a", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
27 | "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.3", "1d178429fc8950b12457d09c6afec247bfe1fcb6f36209e18fbb0221bdfe4d41", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
28 | "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [:mix], [], "hexpm"},
29 | "plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
30 | "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
31 | "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
32 | "postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
33 | "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"},
34 | "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
35 | "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], [], "hexpm"}}
36 |
--------------------------------------------------------------------------------
/test/fixtures/no_description.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "opened",
3 | "issue": {
4 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/4",
5 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
6 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/4/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/4/comments",
8 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/4/events",
9 | "html_url": "https://github.com/SimonLab/github_app/issues/4",
10 | "id": 236156185,
11 | "number": 4,
12 | "title": "Test issue without description",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 |
34 | ],
35 | "state": "open",
36 | "locked": false,
37 | "assignee": null,
38 | "assignees": [
39 |
40 | ],
41 | "milestone": null,
42 | "comments": 0,
43 | "created_at": "2017-06-15T11:16:14Z",
44 | "updated_at": "2017-06-15T11:16:14Z",
45 | "closed_at": null,
46 | "body": ""
47 | },
48 | "repository": {
49 | "id": 92847353,
50 | "name": "github_app",
51 | "full_name": "SimonLab/github_app",
52 | "owner": {
53 | "login": "SimonLab",
54 | "id": 6057298,
55 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
56 | "gravatar_id": "",
57 | "url": "https://api.github.com/users/SimonLab",
58 | "html_url": "https://github.com/SimonLab",
59 | "followers_url": "https://api.github.com/users/SimonLab/followers",
60 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
61 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
62 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
63 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
64 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
65 | "repos_url": "https://api.github.com/users/SimonLab/repos",
66 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
67 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
68 | "type": "User",
69 | "site_admin": false
70 | },
71 | "private": false,
72 | "html_url": "https://github.com/SimonLab/github_app",
73 | "description": "a Github App to play with integrations",
74 | "fork": false,
75 | "url": "https://api.github.com/repos/SimonLab/github_app",
76 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
77 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
78 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
79 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
80 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
81 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
82 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
83 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
84 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
85 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
86 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
87 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
88 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
89 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
90 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
91 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
92 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
93 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
94 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
95 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
96 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
97 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
98 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
99 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
100 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
101 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
102 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
103 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
104 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
105 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
106 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
107 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
108 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
109 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
110 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
111 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
112 | "created_at": "2017-05-30T15:26:26Z",
113 | "updated_at": "2017-05-30T15:36:26Z",
114 | "pushed_at": "2017-06-13T10:52:54Z",
115 | "git_url": "git://github.com/SimonLab/github_app.git",
116 | "ssh_url": "git@github.com:SimonLab/github_app.git",
117 | "clone_url": "https://github.com/SimonLab/github_app.git",
118 | "svn_url": "https://github.com/SimonLab/github_app",
119 | "homepage": null,
120 | "size": 56,
121 | "stargazers_count": 0,
122 | "watchers_count": 0,
123 | "language": "Elixir",
124 | "has_issues": true,
125 | "has_projects": true,
126 | "has_downloads": true,
127 | "has_wiki": true,
128 | "has_pages": false,
129 | "forks_count": 0,
130 | "mirror_url": null,
131 | "open_issues_count": 4,
132 | "forks": 0,
133 | "open_issues": 4,
134 | "watchers": 0,
135 | "default_branch": "initialise"
136 | },
137 | "sender": {
138 | "login": "SimonLab",
139 | "id": 6057298,
140 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
141 | "gravatar_id": "",
142 | "url": "https://api.github.com/users/SimonLab",
143 | "html_url": "https://github.com/SimonLab",
144 | "followers_url": "https://api.github.com/users/SimonLab/followers",
145 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
146 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
147 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
148 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
149 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
150 | "repos_url": "https://api.github.com/users/SimonLab/repos",
151 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
152 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
153 | "type": "User",
154 | "site_admin": false
155 | },
156 | "installation": {
157 | "id": 31449
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/test/fixtures/dwylbot-test-bug-label.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1",
5 | "repository_url": "https://api.github.com/repos/dwylbot/dwylbot-test",
6 | "labels_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/comments",
8 | "events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/events",
9 | "html_url": "https://github.com/dwylbot/dwylbot-test/issues/1",
10 | "id": 213376929,
11 | "number": 1,
12 | "title": "This is not an issue",
13 | "user": {
14 | "login": "dwylbot",
15 | "id": 24862484,
16 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/dwylbot",
19 | "html_url": "https://github.com/dwylbot",
20 | "followers_url": "https://api.github.com/users/dwylbot/followers",
21 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
25 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
26 | "repos_url": "https://api.github.com/users/dwylbot/repos",
27 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 557832098,
35 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels/bug",
36 | "name": "bug",
37 | "color": "ee0701",
38 | "default": true
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [],
45 | "milestone": null,
46 | "comments": 0,
47 | "created_at": "2017-03-10T15:51:03Z",
48 | "updated_at": "2017-03-10T16:49:57Z",
49 | "closed_at": null,
50 | "body": "This is not a comment"
51 | },
52 | "label": {
53 | "id": 557832098,
54 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels/bug",
55 | "name": "bug",
56 | "color": "ee0701",
57 | "default": true
58 | },
59 | "repository": {
60 | "id": 84574865,
61 | "name": "dwylbot-test",
62 | "full_name": "dwylbot/dwylbot-test",
63 | "owner": {
64 | "login": "dwylbot",
65 | "id": 24862484,
66 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
67 | "gravatar_id": "",
68 | "url": "https://api.github.com/users/dwylbot",
69 | "html_url": "https://github.com/dwylbot",
70 | "followers_url": "https://api.github.com/users/dwylbot/followers",
71 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
72 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
73 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
74 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
75 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
76 | "repos_url": "https://api.github.com/users/dwylbot/repos",
77 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
78 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
79 | "type": "User",
80 | "site_admin": false
81 | },
82 | "private": false,
83 | "html_url": "https://github.com/dwylbot/dwylbot-test",
84 | "description": "A test repository where dwylbot can add some comments",
85 | "fork": false,
86 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test",
87 | "forks_url": "https://api.github.com/repos/dwylbot/dwylbot-test/forks",
88 | "keys_url": "https://api.github.com/repos/dwylbot/dwylbot-test/keys{/key_id}",
89 | "collaborators_url": "https://api.github.com/repos/dwylbot/dwylbot-test/collaborators{/collaborator}",
90 | "teams_url": "https://api.github.com/repos/dwylbot/dwylbot-test/teams",
91 | "hooks_url": "https://api.github.com/repos/dwylbot/dwylbot-test/hooks",
92 | "issue_events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/events{/number}",
93 | "events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/events",
94 | "assignees_url": "https://api.github.com/repos/dwylbot/dwylbot-test/assignees{/user}",
95 | "branches_url": "https://api.github.com/repos/dwylbot/dwylbot-test/branches{/branch}",
96 | "tags_url": "https://api.github.com/repos/dwylbot/dwylbot-test/tags",
97 | "blobs_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/blobs{/sha}",
98 | "git_tags_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/tags{/sha}",
99 | "git_refs_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/refs{/sha}",
100 | "trees_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/trees{/sha}",
101 | "statuses_url": "https://api.github.com/repos/dwylbot/dwylbot-test/statuses/{sha}",
102 | "languages_url": "https://api.github.com/repos/dwylbot/dwylbot-test/languages",
103 | "stargazers_url": "https://api.github.com/repos/dwylbot/dwylbot-test/stargazers",
104 | "contributors_url": "https://api.github.com/repos/dwylbot/dwylbot-test/contributors",
105 | "subscribers_url": "https://api.github.com/repos/dwylbot/dwylbot-test/subscribers",
106 | "subscription_url": "https://api.github.com/repos/dwylbot/dwylbot-test/subscription",
107 | "commits_url": "https://api.github.com/repos/dwylbot/dwylbot-test/commits{/sha}",
108 | "git_commits_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/commits{/sha}",
109 | "comments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/comments{/number}",
110 | "issue_comment_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/comments{/number}",
111 | "contents_url": "https://api.github.com/repos/dwylbot/dwylbot-test/contents/{+path}",
112 | "compare_url": "https://api.github.com/repos/dwylbot/dwylbot-test/compare/{base}...{head}",
113 | "merges_url": "https://api.github.com/repos/dwylbot/dwylbot-test/merges",
114 | "archive_url": "https://api.github.com/repos/dwylbot/dwylbot-test/{archive_format}{/ref}",
115 | "downloads_url": "https://api.github.com/repos/dwylbot/dwylbot-test/downloads",
116 | "issues_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues{/number}",
117 | "pulls_url": "https://api.github.com/repos/dwylbot/dwylbot-test/pulls{/number}",
118 | "milestones_url": "https://api.github.com/repos/dwylbot/dwylbot-test/milestones{/number}",
119 | "notifications_url": "https://api.github.com/repos/dwylbot/dwylbot-test/notifications{?since,all,participating}",
120 | "labels_url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels{/name}",
121 | "releases_url": "https://api.github.com/repos/dwylbot/dwylbot-test/releases{/id}",
122 | "deployments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/deployments",
123 | "created_at": "2017-03-10T15:41:09Z",
124 | "updated_at": "2017-03-10T15:41:09Z",
125 | "pushed_at": "2017-03-10T15:41:10Z",
126 | "git_url": "git://github.com/dwylbot/dwylbot-test.git",
127 | "ssh_url": "git@github.com:dwylbot/dwylbot-test.git",
128 | "clone_url": "https://github.com/dwylbot/dwylbot-test.git",
129 | "svn_url": "https://github.com/dwylbot/dwylbot-test",
130 | "homepage": null,
131 | "size": 0,
132 | "stargazers_count": 0,
133 | "watchers_count": 0,
134 | "language": null,
135 | "has_issues": true,
136 | "has_downloads": true,
137 | "has_wiki": true,
138 | "has_pages": false,
139 | "forks_count": 0,
140 | "mirror_url": null,
141 | "open_issues_count": 1,
142 | "forks": 0,
143 | "open_issues": 1,
144 | "watchers": 0,
145 | "default_branch": "master"
146 | },
147 | "sender": {
148 | "login": "dwylbot",
149 | "id": 24862484,
150 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
151 | "gravatar_id": "",
152 | "url": "https://api.github.com/users/dwylbot",
153 | "html_url": "https://github.com/dwylbot",
154 | "followers_url": "https://api.github.com/users/dwylbot/followers",
155 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
156 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
157 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
158 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
159 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
160 | "repos_url": "https://api.github.com/users/dwylbot/repos",
161 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
162 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
163 | "type": "User",
164 | "site_admin": false
165 | }
166 | }
--------------------------------------------------------------------------------
/test/fixtures/dwylbot-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1",
5 | "repository_url": "https://api.github.com/repos/dwylbot/dwylbot-test",
6 | "labels_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/comments",
8 | "events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/1/events",
9 | "html_url": "https://github.com/dwylbot/dwylbot-test/issues/1",
10 | "id": 213376929,
11 | "number": 1,
12 | "title": "This is not an issue",
13 | "user": {
14 | "login": "dwylbot",
15 | "id": 24862484,
16 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/dwylbot",
19 | "html_url": "https://github.com/dwylbot",
20 | "followers_url": "https://api.github.com/users/dwylbot/followers",
21 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
25 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
26 | "repos_url": "https://api.github.com/users/dwylbot/repos",
27 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 557864446,
35 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels/in-progress",
36 | "name": "in-progress",
37 | "color": "009688",
38 | "default": false
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [],
45 | "milestone": null,
46 | "comments": 0,
47 | "created_at": "2017-03-10T15:51:03Z",
48 | "updated_at": "2017-03-10T15:51:14Z",
49 | "closed_at": null,
50 | "body": "This is not a comment"
51 | },
52 | "label": {
53 | "id": 557864446,
54 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels/in-progress",
55 | "name": "in-progress",
56 | "color": "009688",
57 | "default": false
58 | },
59 | "repository": {
60 | "id": 84574865,
61 | "name": "dwylbot-test",
62 | "full_name": "dwylbot/dwylbot-test",
63 | "owner": {
64 | "login": "dwylbot",
65 | "id": 24862484,
66 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
67 | "gravatar_id": "",
68 | "url": "https://api.github.com/users/dwylbot",
69 | "html_url": "https://github.com/dwylbot",
70 | "followers_url": "https://api.github.com/users/dwylbot/followers",
71 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
72 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
73 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
74 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
75 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
76 | "repos_url": "https://api.github.com/users/dwylbot/repos",
77 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
78 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
79 | "type": "User",
80 | "site_admin": false
81 | },
82 | "private": false,
83 | "html_url": "https://github.com/dwylbot/dwylbot-test",
84 | "description": "A test repository where dwylbot can add some comments",
85 | "fork": false,
86 | "url": "https://api.github.com/repos/dwylbot/dwylbot-test",
87 | "forks_url": "https://api.github.com/repos/dwylbot/dwylbot-test/forks",
88 | "keys_url": "https://api.github.com/repos/dwylbot/dwylbot-test/keys{/key_id}",
89 | "collaborators_url": "https://api.github.com/repos/dwylbot/dwylbot-test/collaborators{/collaborator}",
90 | "teams_url": "https://api.github.com/repos/dwylbot/dwylbot-test/teams",
91 | "hooks_url": "https://api.github.com/repos/dwylbot/dwylbot-test/hooks",
92 | "issue_events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/events{/number}",
93 | "events_url": "https://api.github.com/repos/dwylbot/dwylbot-test/events",
94 | "assignees_url": "https://api.github.com/repos/dwylbot/dwylbot-test/assignees{/user}",
95 | "branches_url": "https://api.github.com/repos/dwylbot/dwylbot-test/branches{/branch}",
96 | "tags_url": "https://api.github.com/repos/dwylbot/dwylbot-test/tags",
97 | "blobs_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/blobs{/sha}",
98 | "git_tags_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/tags{/sha}",
99 | "git_refs_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/refs{/sha}",
100 | "trees_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/trees{/sha}",
101 | "statuses_url": "https://api.github.com/repos/dwylbot/dwylbot-test/statuses/{sha}",
102 | "languages_url": "https://api.github.com/repos/dwylbot/dwylbot-test/languages",
103 | "stargazers_url": "https://api.github.com/repos/dwylbot/dwylbot-test/stargazers",
104 | "contributors_url": "https://api.github.com/repos/dwylbot/dwylbot-test/contributors",
105 | "subscribers_url": "https://api.github.com/repos/dwylbot/dwylbot-test/subscribers",
106 | "subscription_url": "https://api.github.com/repos/dwylbot/dwylbot-test/subscription",
107 | "commits_url": "https://api.github.com/repos/dwylbot/dwylbot-test/commits{/sha}",
108 | "git_commits_url": "https://api.github.com/repos/dwylbot/dwylbot-test/git/commits{/sha}",
109 | "comments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/comments{/number}",
110 | "issue_comment_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues/comments{/number}",
111 | "contents_url": "https://api.github.com/repos/dwylbot/dwylbot-test/contents/{+path}",
112 | "compare_url": "https://api.github.com/repos/dwylbot/dwylbot-test/compare/{base}...{head}",
113 | "merges_url": "https://api.github.com/repos/dwylbot/dwylbot-test/merges",
114 | "archive_url": "https://api.github.com/repos/dwylbot/dwylbot-test/{archive_format}{/ref}",
115 | "downloads_url": "https://api.github.com/repos/dwylbot/dwylbot-test/downloads",
116 | "issues_url": "https://api.github.com/repos/dwylbot/dwylbot-test/issues{/number}",
117 | "pulls_url": "https://api.github.com/repos/dwylbot/dwylbot-test/pulls{/number}",
118 | "milestones_url": "https://api.github.com/repos/dwylbot/dwylbot-test/milestones{/number}",
119 | "notifications_url": "https://api.github.com/repos/dwylbot/dwylbot-test/notifications{?since,all,participating}",
120 | "labels_url": "https://api.github.com/repos/dwylbot/dwylbot-test/labels{/name}",
121 | "releases_url": "https://api.github.com/repos/dwylbot/dwylbot-test/releases{/id}",
122 | "deployments_url": "https://api.github.com/repos/dwylbot/dwylbot-test/deployments",
123 | "created_at": "2017-03-10T15:41:09Z",
124 | "updated_at": "2017-03-10T15:41:09Z",
125 | "pushed_at": "2017-03-10T15:41:10Z",
126 | "git_url": "git://github.com/dwylbot/dwylbot-test.git",
127 | "ssh_url": "git@github.com:dwylbot/dwylbot-test.git",
128 | "clone_url": "https://github.com/dwylbot/dwylbot-test.git",
129 | "svn_url": "https://github.com/dwylbot/dwylbot-test",
130 | "homepage": null,
131 | "size": 0,
132 | "stargazers_count": 0,
133 | "watchers_count": 0,
134 | "language": null,
135 | "has_issues": true,
136 | "has_downloads": true,
137 | "has_wiki": true,
138 | "has_pages": false,
139 | "forks_count": 0,
140 | "mirror_url": null,
141 | "open_issues_count": 1,
142 | "forks": 0,
143 | "open_issues": 1,
144 | "watchers": 0,
145 | "default_branch": "master"
146 | },
147 | "sender": {
148 | "login": "dwylbot",
149 | "id": 24862484,
150 | "avatar_url": "https://avatars3.githubusercontent.com/u/24862484?v=3",
151 | "gravatar_id": "",
152 | "url": "https://api.github.com/users/dwylbot",
153 | "html_url": "https://github.com/dwylbot",
154 | "followers_url": "https://api.github.com/users/dwylbot/followers",
155 | "following_url": "https://api.github.com/users/dwylbot/following{/other_user}",
156 | "gists_url": "https://api.github.com/users/dwylbot/gists{/gist_id}",
157 | "starred_url": "https://api.github.com/users/dwylbot/starred{/owner}{/repo}",
158 | "subscriptions_url": "https://api.github.com/users/dwylbot/subscriptions",
159 | "organizations_url": "https://api.github.com/users/dwylbot/orgs",
160 | "repos_url": "https://api.github.com/users/dwylbot/repos",
161 | "events_url": "https://api.github.com/users/dwylbot/events{/privacy}",
162 | "received_events_url": "https://api.github.com/users/dwylbot/received_events",
163 | "type": "User",
164 | "site_admin": false
165 | }
166 | }
--------------------------------------------------------------------------------
/test/fixtures/add_label.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/3",
5 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
6 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/comments",
8 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/events",
9 | "html_url": "https://github.com/SimonLab/github_app/issues/3",
10 | "id": 235532030,
11 | "number": 3,
12 | "title": "Test issue",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 616109535,
35 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/enhancement",
36 | "name": "enhancement",
37 | "color": "84b6eb",
38 | "default": true
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [
45 |
46 | ],
47 | "milestone": null,
48 | "comments": 0,
49 | "created_at": "2017-06-13T12:09:09Z",
50 | "updated_at": "2017-06-13T12:09:09Z",
51 | "closed_at": null,
52 | "body": "This is a test issue for dwylbot"
53 | },
54 | "label": {
55 | "id": 616109535,
56 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/enhancement",
57 | "name": "enhancement",
58 | "color": "84b6eb",
59 | "default": true
60 | },
61 | "repository": {
62 | "id": 92847353,
63 | "name": "github_app",
64 | "full_name": "SimonLab/github_app",
65 | "owner": {
66 | "login": "SimonLab",
67 | "id": 6057298,
68 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
69 | "gravatar_id": "",
70 | "url": "https://api.github.com/users/SimonLab",
71 | "html_url": "https://github.com/SimonLab",
72 | "followers_url": "https://api.github.com/users/SimonLab/followers",
73 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
74 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
75 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
76 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
77 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
78 | "repos_url": "https://api.github.com/users/SimonLab/repos",
79 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
80 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
81 | "type": "User",
82 | "site_admin": false
83 | },
84 | "private": false,
85 | "html_url": "https://github.com/SimonLab/github_app",
86 | "description": "a Github App to play with integrations",
87 | "fork": false,
88 | "url": "https://api.github.com/repos/SimonLab/github_app",
89 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
90 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
91 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
92 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
93 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
94 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
95 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
96 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
97 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
98 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
99 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
100 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
101 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
102 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
103 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
104 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
105 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
106 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
107 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
108 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
109 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
110 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
111 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
112 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
113 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
114 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
115 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
116 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
117 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
118 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
119 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
120 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
121 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
122 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
123 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
124 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
125 | "created_at": "2017-05-30T15:26:26Z",
126 | "updated_at": "2017-05-30T15:36:26Z",
127 | "pushed_at": "2017-06-13T10:52:54Z",
128 | "git_url": "git://github.com/SimonLab/github_app.git",
129 | "ssh_url": "git@github.com:SimonLab/github_app.git",
130 | "clone_url": "https://github.com/SimonLab/github_app.git",
131 | "svn_url": "https://github.com/SimonLab/github_app",
132 | "homepage": null,
133 | "size": 56,
134 | "stargazers_count": 0,
135 | "watchers_count": 0,
136 | "language": "Elixir",
137 | "has_issues": true,
138 | "has_projects": true,
139 | "has_downloads": true,
140 | "has_wiki": true,
141 | "has_pages": false,
142 | "forks_count": 0,
143 | "mirror_url": null,
144 | "open_issues_count": 3,
145 | "forks": 0,
146 | "open_issues": 3,
147 | "watchers": 0,
148 | "default_branch": "initialise"
149 | },
150 | "sender": {
151 | "login": "SimonLab",
152 | "id": 6057298,
153 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
154 | "gravatar_id": "",
155 | "url": "https://api.github.com/users/SimonLab",
156 | "html_url": "https://github.com/SimonLab",
157 | "followers_url": "https://api.github.com/users/SimonLab/followers",
158 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
159 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
160 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
161 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
162 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
163 | "repos_url": "https://api.github.com/users/SimonLab/repos",
164 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
165 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
166 | "type": "User",
167 | "site_admin": false
168 | },
169 | "installation": {
170 | "id": 31449
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/test/fixtures/inprogress.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/3",
5 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
6 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/comments",
8 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/3/events",
9 | "html_url": "https://github.com/SimonLab/github_app/issues/3",
10 | "id": 235532030,
11 | "number": 3,
12 | "title": "Test issue",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 624855442,
35 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/in-progress",
36 | "name": "in-progress",
37 | "color": "009688",
38 | "default": false
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [
45 |
46 | ],
47 | "milestone": null,
48 | "comments": 0,
49 | "created_at": "2017-06-13T12:09:09Z",
50 | "updated_at": "2017-06-13T13:25:48Z",
51 | "closed_at": null,
52 | "body": "This is a test issue for dwylbot"
53 | },
54 | "label": {
55 | "id": 624855442,
56 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/in-progress",
57 | "name": "in-progress",
58 | "color": "009688",
59 | "default": false
60 | },
61 | "repository": {
62 | "id": 92847353,
63 | "name": "github_app",
64 | "full_name": "SimonLab/github_app",
65 | "owner": {
66 | "login": "SimonLab",
67 | "id": 6057298,
68 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
69 | "gravatar_id": "",
70 | "url": "https://api.github.com/users/SimonLab",
71 | "html_url": "https://github.com/SimonLab",
72 | "followers_url": "https://api.github.com/users/SimonLab/followers",
73 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
74 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
75 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
76 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
77 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
78 | "repos_url": "https://api.github.com/users/SimonLab/repos",
79 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
80 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
81 | "type": "User",
82 | "site_admin": false
83 | },
84 | "private": false,
85 | "html_url": "https://github.com/SimonLab/github_app",
86 | "description": "a Github App to play with integrations",
87 | "fork": false,
88 | "url": "https://api.github.com/repos/SimonLab/github_app",
89 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
90 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
91 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
92 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
93 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
94 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
95 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
96 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
97 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
98 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
99 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
100 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
101 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
102 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
103 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
104 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
105 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
106 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
107 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
108 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
109 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
110 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
111 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
112 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
113 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
114 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
115 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
116 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
117 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
118 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
119 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
120 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
121 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
122 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
123 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
124 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
125 | "created_at": "2017-05-30T15:26:26Z",
126 | "updated_at": "2017-05-30T15:36:26Z",
127 | "pushed_at": "2017-06-13T10:52:54Z",
128 | "git_url": "git://github.com/SimonLab/github_app.git",
129 | "ssh_url": "git@github.com:SimonLab/github_app.git",
130 | "clone_url": "https://github.com/SimonLab/github_app.git",
131 | "svn_url": "https://github.com/SimonLab/github_app",
132 | "homepage": null,
133 | "size": 56,
134 | "stargazers_count": 0,
135 | "watchers_count": 0,
136 | "language": "Elixir",
137 | "has_issues": true,
138 | "has_projects": true,
139 | "has_downloads": true,
140 | "has_wiki": true,
141 | "has_pages": false,
142 | "forks_count": 0,
143 | "mirror_url": null,
144 | "open_issues_count": 3,
145 | "forks": 0,
146 | "open_issues": 3,
147 | "watchers": 0,
148 | "default_branch": "initialise"
149 | },
150 | "sender": {
151 | "login": "SimonLab",
152 | "id": 6057298,
153 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
154 | "gravatar_id": "",
155 | "url": "https://api.github.com/users/SimonLab",
156 | "html_url": "https://github.com/SimonLab",
157 | "followers_url": "https://api.github.com/users/SimonLab/followers",
158 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
159 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
160 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
161 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
162 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
163 | "repos_url": "https://api.github.com/users/SimonLab/repos",
164 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
165 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
166 | "type": "User",
167 | "site_admin": false
168 | },
169 | "installation": {
170 | "id": 31449
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/test/fixtures/in_progress.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/dwyl/dwylbot/issues/14",
5 | "repository_url": "https://api.github.com/repos/dwyl/dwylbot",
6 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/comments",
8 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/events",
9 | "html_url": "https://github.com/dwyl/dwylbot/issues/14",
10 | "id": 212716409,
11 | "number": 14,
12 | "title": "Test issue to trigger webhooks",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 546296559,
35 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-progress",
36 | "name": "in-progress",
37 | "color": "009688",
38 | "default": false
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [],
45 | "milestone": null,
46 | "comments": 0,
47 | "created_at": "2017-03-08T12:06:33Z",
48 | "updated_at": "2017-03-08T13:09:56Z",
49 | "closed_at": null,
50 | "body": "This is a test issue that we use to trigger webhooks for example by changing labels."
51 | },
52 | "label": {
53 | "id": 546296559,
54 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-progress",
55 | "name": "in-progress",
56 | "color": "009688",
57 | "default": false
58 | },
59 | "repository": {
60 | "id": 82936511,
61 | "name": "dwylbot",
62 | "full_name": "dwyl/dwylbot",
63 | "owner": {
64 | "login": "dwyl",
65 | "id": 11708465,
66 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
67 | "gravatar_id": "",
68 | "url": "https://api.github.com/users/dwyl",
69 | "html_url": "https://github.com/dwyl",
70 | "followers_url": "https://api.github.com/users/dwyl/followers",
71 | "following_url": "https://api.github.com/users/dwyl/following{/other_user}",
72 | "gists_url": "https://api.github.com/users/dwyl/gists{/gist_id}",
73 | "starred_url": "https://api.github.com/users/dwyl/starred{/owner}{/repo}",
74 | "subscriptions_url": "https://api.github.com/users/dwyl/subscriptions",
75 | "organizations_url": "https://api.github.com/users/dwyl/orgs",
76 | "repos_url": "https://api.github.com/users/dwyl/repos",
77 | "events_url": "https://api.github.com/users/dwyl/events{/privacy}",
78 | "received_events_url": "https://api.github.com/users/dwyl/received_events",
79 | "type": "Organization",
80 | "site_admin": false
81 | },
82 | "private": false,
83 | "html_url": "https://github.com/dwyl/dwylbot",
84 | "description": ":robot: Automating our GitHub Workflow to improve team communication/collaboration and reduce tedious repetition!",
85 | "fork": false,
86 | "url": "https://api.github.com/repos/dwyl/dwylbot",
87 | "forks_url": "https://api.github.com/repos/dwyl/dwylbot/forks",
88 | "keys_url": "https://api.github.com/repos/dwyl/dwylbot/keys{/key_id}",
89 | "collaborators_url": "https://api.github.com/repos/dwyl/dwylbot/collaborators{/collaborator}",
90 | "teams_url": "https://api.github.com/repos/dwyl/dwylbot/teams",
91 | "hooks_url": "https://api.github.com/repos/dwyl/dwylbot/hooks",
92 | "issue_events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/events{/number}",
93 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/events",
94 | "assignees_url": "https://api.github.com/repos/dwyl/dwylbot/assignees{/user}",
95 | "branches_url": "https://api.github.com/repos/dwyl/dwylbot/branches{/branch}",
96 | "tags_url": "https://api.github.com/repos/dwyl/dwylbot/tags",
97 | "blobs_url": "https://api.github.com/repos/dwyl/dwylbot/git/blobs{/sha}",
98 | "git_tags_url": "https://api.github.com/repos/dwyl/dwylbot/git/tags{/sha}",
99 | "git_refs_url": "https://api.github.com/repos/dwyl/dwylbot/git/refs{/sha}",
100 | "trees_url": "https://api.github.com/repos/dwyl/dwylbot/git/trees{/sha}",
101 | "statuses_url": "https://api.github.com/repos/dwyl/dwylbot/statuses/{sha}",
102 | "languages_url": "https://api.github.com/repos/dwyl/dwylbot/languages",
103 | "stargazers_url": "https://api.github.com/repos/dwyl/dwylbot/stargazers",
104 | "contributors_url": "https://api.github.com/repos/dwyl/dwylbot/contributors",
105 | "subscribers_url": "https://api.github.com/repos/dwyl/dwylbot/subscribers",
106 | "subscription_url": "https://api.github.com/repos/dwyl/dwylbot/subscription",
107 | "commits_url": "https://api.github.com/repos/dwyl/dwylbot/commits{/sha}",
108 | "git_commits_url": "https://api.github.com/repos/dwyl/dwylbot/git/commits{/sha}",
109 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/comments{/number}",
110 | "issue_comment_url": "https://api.github.com/repos/dwyl/dwylbot/issues/comments{/number}",
111 | "contents_url": "https://api.github.com/repos/dwyl/dwylbot/contents/{+path}",
112 | "compare_url": "https://api.github.com/repos/dwyl/dwylbot/compare/{base}...{head}",
113 | "merges_url": "https://api.github.com/repos/dwyl/dwylbot/merges",
114 | "archive_url": "https://api.github.com/repos/dwyl/dwylbot/{archive_format}{/ref}",
115 | "downloads_url": "https://api.github.com/repos/dwyl/dwylbot/downloads",
116 | "issues_url": "https://api.github.com/repos/dwyl/dwylbot/issues{/number}",
117 | "pulls_url": "https://api.github.com/repos/dwyl/dwylbot/pulls{/number}",
118 | "milestones_url": "https://api.github.com/repos/dwyl/dwylbot/milestones{/number}",
119 | "notifications_url": "https://api.github.com/repos/dwyl/dwylbot/notifications{?since,all,participating}",
120 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/labels{/name}",
121 | "releases_url": "https://api.github.com/repos/dwyl/dwylbot/releases{/id}",
122 | "deployments_url": "https://api.github.com/repos/dwyl/dwylbot/deployments",
123 | "created_at": "2017-02-23T14:42:53Z",
124 | "updated_at": "2017-03-08T10:32:45Z",
125 | "pushed_at": "2017-03-08T11:59:28Z",
126 | "git_url": "git://github.com/dwyl/dwylbot.git",
127 | "ssh_url": "git@github.com:dwyl/dwylbot.git",
128 | "clone_url": "https://github.com/dwyl/dwylbot.git",
129 | "svn_url": "https://github.com/dwyl/dwylbot",
130 | "homepage": "",
131 | "size": 63,
132 | "stargazers_count": 8,
133 | "watchers_count": 8,
134 | "language": null,
135 | "has_issues": true,
136 | "has_downloads": true,
137 | "has_wiki": true,
138 | "has_pages": false,
139 | "forks_count": 1,
140 | "mirror_url": null,
141 | "open_issues_count": 13,
142 | "forks": 1,
143 | "open_issues": 13,
144 | "watchers": 8,
145 | "default_branch": "master"
146 | },
147 | "organization": {
148 | "login": "dwyl",
149 | "id": 11708465,
150 | "url": "https://api.github.com/orgs/dwyl",
151 | "repos_url": "https://api.github.com/orgs/dwyl/repos",
152 | "events_url": "https://api.github.com/orgs/dwyl/events",
153 | "hooks_url": "https://api.github.com/orgs/dwyl/hooks",
154 | "issues_url": "https://api.github.com/orgs/dwyl/issues",
155 | "members_url": "https://api.github.com/orgs/dwyl/members{/member}",
156 | "public_members_url": "https://api.github.com/orgs/dwyl/public_members{/member}",
157 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
158 | "description": "Start here: https://github.com/dwyl/start-here"
159 | },
160 | "sender": {
161 | "login": "SimonLab",
162 | "id": 6057298,
163 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
164 | "gravatar_id": "",
165 | "url": "https://api.github.com/users/SimonLab",
166 | "html_url": "https://github.com/SimonLab",
167 | "followers_url": "https://api.github.com/users/SimonLab/followers",
168 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
169 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
170 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
171 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
172 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
173 | "repos_url": "https://api.github.com/users/SimonLab/repos",
174 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
175 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
176 | "type": "User",
177 | "site_admin": false
178 | }
179 | }
--------------------------------------------------------------------------------
/test/fixtures/multiple_labels.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "labeled",
3 | "issue": {
4 | "url": "https://api.github.com/repos/dwyl/dwylbot/issues/14",
5 | "repository_url": "https://api.github.com/repos/dwyl/dwylbot",
6 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/comments",
8 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/events",
9 | "html_url": "https://github.com/dwyl/dwylbot/issues/14",
10 | "id": 212716409,
11 | "number": 14,
12 | "title": "Test issue to trigger webhooks",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 546294054,
35 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/help%20wanted",
36 | "name": "help wanted",
37 | "color": "128A0C",
38 | "default": true
39 | },
40 | {
41 | "id": 546296559,
42 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-progress",
43 | "name": "in-progress",
44 | "color": "009688",
45 | "default": false
46 | },
47 | {
48 | "id": 546296550,
49 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-review",
50 | "name": "in-review",
51 | "color": "128A0C",
52 | "default": false
53 | }
54 | ],
55 | "state": "open",
56 | "locked": false,
57 | "assignee": null,
58 | "assignees": [],
59 | "milestone": null,
60 | "comments": 0,
61 | "created_at": "2017-03-08T12:06:33Z",
62 | "updated_at": "2017-03-08T13:19:53Z",
63 | "closed_at": null,
64 | "body": "This is a test issue that we use to trigger webhooks for example by changing labels."
65 | },
66 | "label": {
67 | "id": 546296550,
68 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-review",
69 | "name": "in-review",
70 | "color": "128A0C",
71 | "default": false
72 | },
73 | "repository": {
74 | "id": 82936511,
75 | "name": "dwylbot",
76 | "full_name": "dwyl/dwylbot",
77 | "owner": {
78 | "login": "dwyl",
79 | "id": 11708465,
80 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
81 | "gravatar_id": "",
82 | "url": "https://api.github.com/users/dwyl",
83 | "html_url": "https://github.com/dwyl",
84 | "followers_url": "https://api.github.com/users/dwyl/followers",
85 | "following_url": "https://api.github.com/users/dwyl/following{/other_user}",
86 | "gists_url": "https://api.github.com/users/dwyl/gists{/gist_id}",
87 | "starred_url": "https://api.github.com/users/dwyl/starred{/owner}{/repo}",
88 | "subscriptions_url": "https://api.github.com/users/dwyl/subscriptions",
89 | "organizations_url": "https://api.github.com/users/dwyl/orgs",
90 | "repos_url": "https://api.github.com/users/dwyl/repos",
91 | "events_url": "https://api.github.com/users/dwyl/events{/privacy}",
92 | "received_events_url": "https://api.github.com/users/dwyl/received_events",
93 | "type": "Organization",
94 | "site_admin": false
95 | },
96 | "private": false,
97 | "html_url": "https://github.com/dwyl/dwylbot",
98 | "description": ":robot: Automating our GitHub Workflow to improve team communication/collaboration and reduce tedious repetition!",
99 | "fork": false,
100 | "url": "https://api.github.com/repos/dwyl/dwylbot",
101 | "forks_url": "https://api.github.com/repos/dwyl/dwylbot/forks",
102 | "keys_url": "https://api.github.com/repos/dwyl/dwylbot/keys{/key_id}",
103 | "collaborators_url": "https://api.github.com/repos/dwyl/dwylbot/collaborators{/collaborator}",
104 | "teams_url": "https://api.github.com/repos/dwyl/dwylbot/teams",
105 | "hooks_url": "https://api.github.com/repos/dwyl/dwylbot/hooks",
106 | "issue_events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/events{/number}",
107 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/events",
108 | "assignees_url": "https://api.github.com/repos/dwyl/dwylbot/assignees{/user}",
109 | "branches_url": "https://api.github.com/repos/dwyl/dwylbot/branches{/branch}",
110 | "tags_url": "https://api.github.com/repos/dwyl/dwylbot/tags",
111 | "blobs_url": "https://api.github.com/repos/dwyl/dwylbot/git/blobs{/sha}",
112 | "git_tags_url": "https://api.github.com/repos/dwyl/dwylbot/git/tags{/sha}",
113 | "git_refs_url": "https://api.github.com/repos/dwyl/dwylbot/git/refs{/sha}",
114 | "trees_url": "https://api.github.com/repos/dwyl/dwylbot/git/trees{/sha}",
115 | "statuses_url": "https://api.github.com/repos/dwyl/dwylbot/statuses/{sha}",
116 | "languages_url": "https://api.github.com/repos/dwyl/dwylbot/languages",
117 | "stargazers_url": "https://api.github.com/repos/dwyl/dwylbot/stargazers",
118 | "contributors_url": "https://api.github.com/repos/dwyl/dwylbot/contributors",
119 | "subscribers_url": "https://api.github.com/repos/dwyl/dwylbot/subscribers",
120 | "subscription_url": "https://api.github.com/repos/dwyl/dwylbot/subscription",
121 | "commits_url": "https://api.github.com/repos/dwyl/dwylbot/commits{/sha}",
122 | "git_commits_url": "https://api.github.com/repos/dwyl/dwylbot/git/commits{/sha}",
123 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/comments{/number}",
124 | "issue_comment_url": "https://api.github.com/repos/dwyl/dwylbot/issues/comments{/number}",
125 | "contents_url": "https://api.github.com/repos/dwyl/dwylbot/contents/{+path}",
126 | "compare_url": "https://api.github.com/repos/dwyl/dwylbot/compare/{base}...{head}",
127 | "merges_url": "https://api.github.com/repos/dwyl/dwylbot/merges",
128 | "archive_url": "https://api.github.com/repos/dwyl/dwylbot/{archive_format}{/ref}",
129 | "downloads_url": "https://api.github.com/repos/dwyl/dwylbot/downloads",
130 | "issues_url": "https://api.github.com/repos/dwyl/dwylbot/issues{/number}",
131 | "pulls_url": "https://api.github.com/repos/dwyl/dwylbot/pulls{/number}",
132 | "milestones_url": "https://api.github.com/repos/dwyl/dwylbot/milestones{/number}",
133 | "notifications_url": "https://api.github.com/repos/dwyl/dwylbot/notifications{?since,all,participating}",
134 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/labels{/name}",
135 | "releases_url": "https://api.github.com/repos/dwyl/dwylbot/releases{/id}",
136 | "deployments_url": "https://api.github.com/repos/dwyl/dwylbot/deployments",
137 | "created_at": "2017-02-23T14:42:53Z",
138 | "updated_at": "2017-03-08T10:32:45Z",
139 | "pushed_at": "2017-03-08T11:59:28Z",
140 | "git_url": "git://github.com/dwyl/dwylbot.git",
141 | "ssh_url": "git@github.com:dwyl/dwylbot.git",
142 | "clone_url": "https://github.com/dwyl/dwylbot.git",
143 | "svn_url": "https://github.com/dwyl/dwylbot",
144 | "homepage": "",
145 | "size": 63,
146 | "stargazers_count": 8,
147 | "watchers_count": 8,
148 | "language": null,
149 | "has_issues": true,
150 | "has_downloads": true,
151 | "has_wiki": true,
152 | "has_pages": false,
153 | "forks_count": 1,
154 | "mirror_url": null,
155 | "open_issues_count": 13,
156 | "forks": 1,
157 | "open_issues": 13,
158 | "watchers": 8,
159 | "default_branch": "master"
160 | },
161 | "organization": {
162 | "login": "dwyl",
163 | "id": 11708465,
164 | "url": "https://api.github.com/orgs/dwyl",
165 | "repos_url": "https://api.github.com/orgs/dwyl/repos",
166 | "events_url": "https://api.github.com/orgs/dwyl/events",
167 | "hooks_url": "https://api.github.com/orgs/dwyl/hooks",
168 | "issues_url": "https://api.github.com/orgs/dwyl/issues",
169 | "members_url": "https://api.github.com/orgs/dwyl/members{/member}",
170 | "public_members_url": "https://api.github.com/orgs/dwyl/public_members{/member}",
171 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
172 | "description": "Start here: https://github.com/dwyl/start-here"
173 | },
174 | "sender": {
175 | "login": "SimonLab",
176 | "id": 6057298,
177 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
178 | "gravatar_id": "",
179 | "url": "https://api.github.com/users/SimonLab",
180 | "html_url": "https://github.com/SimonLab",
181 | "followers_url": "https://api.github.com/users/SimonLab/followers",
182 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
183 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
184 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
185 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
186 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
187 | "repos_url": "https://api.github.com/users/SimonLab/repos",
188 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
189 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
190 | "type": "User",
191 | "site_admin": false
192 | }
193 | }
--------------------------------------------------------------------------------
/test/fixtures/unassigned_inprogress.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "unassigned",
3 | "issue": {
4 | "url": "https://api.github.com/repos/SimonLab/github_app/issues/7",
5 | "repository_url": "https://api.github.com/repos/SimonLab/github_app",
6 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/issues/7/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/7/comments",
8 | "events_url": "https://api.github.com/repos/SimonLab/github_app/issues/7/events",
9 | "html_url": "https://github.com/SimonLab/github_app/issues/7",
10 | "id": 236160343,
11 | "number": 7,
12 | "title": "and another one",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 624855442,
35 | "url": "https://api.github.com/repos/SimonLab/github_app/labels/in-progress",
36 | "name": "in-progress",
37 | "color": "009688",
38 | "default": false
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": null,
44 | "assignees": [
45 |
46 | ],
47 | "milestone": null,
48 | "comments": 1,
49 | "created_at": "2017-06-15T11:35:42Z",
50 | "updated_at": "2017-06-15T12:07:39Z",
51 | "closed_at": null,
52 | "body": ""
53 | },
54 | "assignee": {
55 | "login": "SimonLab",
56 | "id": 6057298,
57 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
58 | "gravatar_id": "",
59 | "url": "https://api.github.com/users/SimonLab",
60 | "html_url": "https://github.com/SimonLab",
61 | "followers_url": "https://api.github.com/users/SimonLab/followers",
62 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
63 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
64 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
65 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
66 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
67 | "repos_url": "https://api.github.com/users/SimonLab/repos",
68 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
69 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
70 | "type": "User",
71 | "site_admin": false
72 | },
73 | "repository": {
74 | "id": 92847353,
75 | "name": "github_app",
76 | "full_name": "SimonLab/github_app",
77 | "owner": {
78 | "login": "SimonLab",
79 | "id": 6057298,
80 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
81 | "gravatar_id": "",
82 | "url": "https://api.github.com/users/SimonLab",
83 | "html_url": "https://github.com/SimonLab",
84 | "followers_url": "https://api.github.com/users/SimonLab/followers",
85 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
86 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
87 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
88 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
89 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
90 | "repos_url": "https://api.github.com/users/SimonLab/repos",
91 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
92 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
93 | "type": "User",
94 | "site_admin": false
95 | },
96 | "private": false,
97 | "html_url": "https://github.com/SimonLab/github_app",
98 | "description": "a Github App to play with integrations",
99 | "fork": false,
100 | "url": "https://api.github.com/repos/SimonLab/github_app",
101 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
102 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
103 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
104 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
105 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
106 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
107 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
108 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
109 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
110 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
111 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
112 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
113 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
114 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
115 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
116 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
117 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
118 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
119 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
120 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
121 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
122 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
123 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
124 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
125 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
126 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
127 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
128 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
129 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
130 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
131 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
132 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
133 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
134 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
135 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
136 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
137 | "created_at": "2017-05-30T15:26:26Z",
138 | "updated_at": "2017-05-30T15:36:26Z",
139 | "pushed_at": "2017-06-13T10:52:54Z",
140 | "git_url": "git://github.com/SimonLab/github_app.git",
141 | "ssh_url": "git@github.com:SimonLab/github_app.git",
142 | "clone_url": "https://github.com/SimonLab/github_app.git",
143 | "svn_url": "https://github.com/SimonLab/github_app",
144 | "homepage": null,
145 | "size": 56,
146 | "stargazers_count": 0,
147 | "watchers_count": 0,
148 | "language": "Elixir",
149 | "has_issues": true,
150 | "has_projects": true,
151 | "has_downloads": true,
152 | "has_wiki": true,
153 | "has_pages": false,
154 | "forks_count": 0,
155 | "mirror_url": null,
156 | "open_issues_count": 4,
157 | "forks": 0,
158 | "open_issues": 4,
159 | "watchers": 0,
160 | "default_branch": "initialise"
161 | },
162 | "sender": {
163 | "login": "SimonLab",
164 | "id": 6057298,
165 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
166 | "gravatar_id": "",
167 | "url": "https://api.github.com/users/SimonLab",
168 | "html_url": "https://github.com/SimonLab",
169 | "followers_url": "https://api.github.com/users/SimonLab/followers",
170 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
171 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
172 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
173 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
174 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
175 | "repos_url": "https://api.github.com/users/SimonLab/repos",
176 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
177 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
178 | "type": "User",
179 | "site_admin": false
180 | },
181 | "installation": {
182 | "id": 31449
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/test/fixtures/failing_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 1317973162,
3 | "sha": "8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
4 | "name": "SimonLab/github_app",
5 | "target_url": "https://travis-ci.org/SimonLab/github_app/builds/244896119?utm_source=github_status&utm_medium=notification",
6 | "context": "continuous-integration/travis-ci/push",
7 | "description": "The Travis CI build failed",
8 | "state": "failure",
9 | "commit": {
10 | "sha": "8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
11 | "commit": {
12 | "author": {
13 | "name": "simonLab",
14 | "email": "simon.labondance@gmail.com",
15 | "date": "2017-06-20T11:21:07Z"
16 | },
17 | "committer": {
18 | "name": "simonLab",
19 | "email": "simon.labondance@gmail.com",
20 | "date": "2017-06-20T11:21:07Z"
21 | },
22 | "message": "add a test",
23 | "tree": {
24 | "sha": "548582a6650a3a52f9c8029084df56e79316454d",
25 | "url": "https://api.github.com/repos/SimonLab/github_app/git/trees/548582a6650a3a52f9c8029084df56e79316454d"
26 | },
27 | "url": "https://api.github.com/repos/SimonLab/github_app/git/commits/8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
28 | "comment_count": 0
29 | },
30 | "url": "https://api.github.com/repos/SimonLab/github_app/commits/8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
31 | "html_url": "https://github.com/SimonLab/github_app/commit/8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
32 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/commits/8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d/comments",
33 | "author": {
34 | "login": "SimonLab",
35 | "id": 6057298,
36 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
37 | "gravatar_id": "",
38 | "url": "https://api.github.com/users/SimonLab",
39 | "html_url": "https://github.com/SimonLab",
40 | "followers_url": "https://api.github.com/users/SimonLab/followers",
41 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
42 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
43 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
44 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
45 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
46 | "repos_url": "https://api.github.com/users/SimonLab/repos",
47 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
48 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
49 | "type": "User",
50 | "site_admin": false
51 | },
52 | "committer": {
53 | "login": "SimonLab",
54 | "id": 6057298,
55 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
56 | "gravatar_id": "",
57 | "url": "https://api.github.com/users/SimonLab",
58 | "html_url": "https://github.com/SimonLab",
59 | "followers_url": "https://api.github.com/users/SimonLab/followers",
60 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
61 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
62 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
63 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
64 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
65 | "repos_url": "https://api.github.com/users/SimonLab/repos",
66 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
67 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
68 | "type": "User",
69 | "site_admin": false
70 | },
71 | "parents": [
72 | {
73 | "sha": "dd2297e5eb4fe96e8891e7e18a055d0aad646423",
74 | "url": "https://api.github.com/repos/SimonLab/github_app/commits/dd2297e5eb4fe96e8891e7e18a055d0aad646423",
75 | "html_url": "https://github.com/SimonLab/github_app/commit/dd2297e5eb4fe96e8891e7e18a055d0aad646423"
76 | }
77 | ]
78 | },
79 | "branches": [
80 | {
81 | "name": "failing-test",
82 | "commit": {
83 | "sha": "8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d",
84 | "url": "https://api.github.com/repos/SimonLab/github_app/commits/8fd77e64bf1c49f30ae52cf8b74561db4ae9ce1d"
85 | }
86 | }
87 | ],
88 | "created_at": "2017-06-21T10:34:13Z",
89 | "updated_at": "2017-06-21T10:34:13Z",
90 | "repository": {
91 | "id": 92847353,
92 | "name": "github_app",
93 | "full_name": "SimonLab/github_app",
94 | "owner": {
95 | "login": "SimonLab",
96 | "id": 6057298,
97 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
98 | "gravatar_id": "",
99 | "url": "https://api.github.com/users/SimonLab",
100 | "html_url": "https://github.com/SimonLab",
101 | "followers_url": "https://api.github.com/users/SimonLab/followers",
102 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
103 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
104 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
105 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
106 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
107 | "repos_url": "https://api.github.com/users/SimonLab/repos",
108 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
109 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
110 | "type": "User",
111 | "site_admin": false
112 | },
113 | "private": false,
114 | "html_url": "https://github.com/SimonLab/github_app",
115 | "description": "a Github App to play with integrations",
116 | "fork": false,
117 | "url": "https://api.github.com/repos/SimonLab/github_app",
118 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
119 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
120 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
121 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
122 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
123 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
124 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
125 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
126 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
127 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
128 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
129 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
130 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
131 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
132 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
133 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
134 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
135 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
136 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
137 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
138 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
139 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
140 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
141 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
142 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
143 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
144 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
145 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
146 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
147 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
148 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
149 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
150 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
151 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
152 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
153 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
154 | "created_at": "2017-05-30T15:26:26Z",
155 | "updated_at": "2017-05-30T15:36:26Z",
156 | "pushed_at": "2017-06-20T11:21:34Z",
157 | "git_url": "git://github.com/SimonLab/github_app.git",
158 | "ssh_url": "git@github.com:SimonLab/github_app.git",
159 | "clone_url": "https://github.com/SimonLab/github_app.git",
160 | "svn_url": "https://github.com/SimonLab/github_app",
161 | "homepage": null,
162 | "size": 63,
163 | "stargazers_count": 0,
164 | "watchers_count": 0,
165 | "language": "Elixir",
166 | "has_issues": true,
167 | "has_projects": true,
168 | "has_downloads": true,
169 | "has_wiki": true,
170 | "has_pages": false,
171 | "forks_count": 0,
172 | "mirror_url": null,
173 | "open_issues_count": 7,
174 | "forks": 0,
175 | "open_issues": 7,
176 | "watchers": 0,
177 | "default_branch": "initialise"
178 | },
179 | "sender": {
180 | "login": "SimonLab",
181 | "id": 6057298,
182 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
183 | "gravatar_id": "",
184 | "url": "https://api.github.com/users/SimonLab",
185 | "html_url": "https://github.com/SimonLab",
186 | "followers_url": "https://api.github.com/users/SimonLab/followers",
187 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
188 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
189 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
190 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
191 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
192 | "repos_url": "https://api.github.com/users/SimonLab/repos",
193 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
194 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
195 | "type": "User",
196 | "site_admin": false
197 | },
198 | "installation": {
199 | "id": 31449
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/test/fixtures/assignee.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "assigned",
3 | "issue": {
4 | "url": "https://api.github.com/repos/dwyl/dwylbot/issues/14",
5 | "repository_url": "https://api.github.com/repos/dwyl/dwylbot",
6 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/labels{/name}",
7 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/comments",
8 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/14/events",
9 | "html_url": "https://github.com/dwyl/dwylbot/issues/14",
10 | "id": 212716409,
11 | "number": 14,
12 | "title": "Test issue to trigger webhooks",
13 | "user": {
14 | "login": "SimonLab",
15 | "id": 6057298,
16 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
17 | "gravatar_id": "",
18 | "url": "https://api.github.com/users/SimonLab",
19 | "html_url": "https://github.com/SimonLab",
20 | "followers_url": "https://api.github.com/users/SimonLab/followers",
21 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
22 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
23 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
24 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
25 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
26 | "repos_url": "https://api.github.com/users/SimonLab/repos",
27 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
28 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
29 | "type": "User",
30 | "site_admin": false
31 | },
32 | "labels": [
33 | {
34 | "id": 546296559,
35 | "url": "https://api.github.com/repos/dwyl/dwylbot/labels/in-progress",
36 | "name": "in-progress",
37 | "color": "009688",
38 | "default": false
39 | }
40 | ],
41 | "state": "open",
42 | "locked": false,
43 | "assignee": {
44 | "login": "SimonLab",
45 | "id": 6057298,
46 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
47 | "gravatar_id": "",
48 | "url": "https://api.github.com/users/SimonLab",
49 | "html_url": "https://github.com/SimonLab",
50 | "followers_url": "https://api.github.com/users/SimonLab/followers",
51 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
52 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
53 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
54 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
55 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
56 | "repos_url": "https://api.github.com/users/SimonLab/repos",
57 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
58 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
59 | "type": "User",
60 | "site_admin": false
61 | },
62 | "assignees": [
63 | {
64 | "login": "SimonLab",
65 | "id": 6057298,
66 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
67 | "gravatar_id": "",
68 | "url": "https://api.github.com/users/SimonLab",
69 | "html_url": "https://github.com/SimonLab",
70 | "followers_url": "https://api.github.com/users/SimonLab/followers",
71 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
72 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
73 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
74 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
75 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
76 | "repos_url": "https://api.github.com/users/SimonLab/repos",
77 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
78 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
79 | "type": "User",
80 | "site_admin": false
81 | }
82 | ],
83 | "milestone": null,
84 | "comments": 0,
85 | "created_at": "2017-03-08T12:06:33Z",
86 | "updated_at": "2017-03-08T13:18:05Z",
87 | "closed_at": null,
88 | "body": "This is a test issue that we use to trigger webhooks for example by changing labels."
89 | },
90 | "assignee": {
91 | "login": "SimonLab",
92 | "id": 6057298,
93 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
94 | "gravatar_id": "",
95 | "url": "https://api.github.com/users/SimonLab",
96 | "html_url": "https://github.com/SimonLab",
97 | "followers_url": "https://api.github.com/users/SimonLab/followers",
98 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
99 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
100 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
101 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
102 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
103 | "repos_url": "https://api.github.com/users/SimonLab/repos",
104 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
105 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
106 | "type": "User",
107 | "site_admin": false
108 | },
109 | "repository": {
110 | "id": 82936511,
111 | "name": "dwylbot",
112 | "full_name": "dwyl/dwylbot",
113 | "owner": {
114 | "login": "dwyl",
115 | "id": 11708465,
116 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
117 | "gravatar_id": "",
118 | "url": "https://api.github.com/users/dwyl",
119 | "html_url": "https://github.com/dwyl",
120 | "followers_url": "https://api.github.com/users/dwyl/followers",
121 | "following_url": "https://api.github.com/users/dwyl/following{/other_user}",
122 | "gists_url": "https://api.github.com/users/dwyl/gists{/gist_id}",
123 | "starred_url": "https://api.github.com/users/dwyl/starred{/owner}{/repo}",
124 | "subscriptions_url": "https://api.github.com/users/dwyl/subscriptions",
125 | "organizations_url": "https://api.github.com/users/dwyl/orgs",
126 | "repos_url": "https://api.github.com/users/dwyl/repos",
127 | "events_url": "https://api.github.com/users/dwyl/events{/privacy}",
128 | "received_events_url": "https://api.github.com/users/dwyl/received_events",
129 | "type": "Organization",
130 | "site_admin": false
131 | },
132 | "private": false,
133 | "html_url": "https://github.com/dwyl/dwylbot",
134 | "description": ":robot: Automating our GitHub Workflow to improve team communication/collaboration and reduce tedious repetition!",
135 | "fork": false,
136 | "url": "https://api.github.com/repos/dwyl/dwylbot",
137 | "forks_url": "https://api.github.com/repos/dwyl/dwylbot/forks",
138 | "keys_url": "https://api.github.com/repos/dwyl/dwylbot/keys{/key_id}",
139 | "collaborators_url": "https://api.github.com/repos/dwyl/dwylbot/collaborators{/collaborator}",
140 | "teams_url": "https://api.github.com/repos/dwyl/dwylbot/teams",
141 | "hooks_url": "https://api.github.com/repos/dwyl/dwylbot/hooks",
142 | "issue_events_url": "https://api.github.com/repos/dwyl/dwylbot/issues/events{/number}",
143 | "events_url": "https://api.github.com/repos/dwyl/dwylbot/events",
144 | "assignees_url": "https://api.github.com/repos/dwyl/dwylbot/assignees{/user}",
145 | "branches_url": "https://api.github.com/repos/dwyl/dwylbot/branches{/branch}",
146 | "tags_url": "https://api.github.com/repos/dwyl/dwylbot/tags",
147 | "blobs_url": "https://api.github.com/repos/dwyl/dwylbot/git/blobs{/sha}",
148 | "git_tags_url": "https://api.github.com/repos/dwyl/dwylbot/git/tags{/sha}",
149 | "git_refs_url": "https://api.github.com/repos/dwyl/dwylbot/git/refs{/sha}",
150 | "trees_url": "https://api.github.com/repos/dwyl/dwylbot/git/trees{/sha}",
151 | "statuses_url": "https://api.github.com/repos/dwyl/dwylbot/statuses/{sha}",
152 | "languages_url": "https://api.github.com/repos/dwyl/dwylbot/languages",
153 | "stargazers_url": "https://api.github.com/repos/dwyl/dwylbot/stargazers",
154 | "contributors_url": "https://api.github.com/repos/dwyl/dwylbot/contributors",
155 | "subscribers_url": "https://api.github.com/repos/dwyl/dwylbot/subscribers",
156 | "subscription_url": "https://api.github.com/repos/dwyl/dwylbot/subscription",
157 | "commits_url": "https://api.github.com/repos/dwyl/dwylbot/commits{/sha}",
158 | "git_commits_url": "https://api.github.com/repos/dwyl/dwylbot/git/commits{/sha}",
159 | "comments_url": "https://api.github.com/repos/dwyl/dwylbot/comments{/number}",
160 | "issue_comment_url": "https://api.github.com/repos/dwyl/dwylbot/issues/comments{/number}",
161 | "contents_url": "https://api.github.com/repos/dwyl/dwylbot/contents/{+path}",
162 | "compare_url": "https://api.github.com/repos/dwyl/dwylbot/compare/{base}...{head}",
163 | "merges_url": "https://api.github.com/repos/dwyl/dwylbot/merges",
164 | "archive_url": "https://api.github.com/repos/dwyl/dwylbot/{archive_format}{/ref}",
165 | "downloads_url": "https://api.github.com/repos/dwyl/dwylbot/downloads",
166 | "issues_url": "https://api.github.com/repos/dwyl/dwylbot/issues{/number}",
167 | "pulls_url": "https://api.github.com/repos/dwyl/dwylbot/pulls{/number}",
168 | "milestones_url": "https://api.github.com/repos/dwyl/dwylbot/milestones{/number}",
169 | "notifications_url": "https://api.github.com/repos/dwyl/dwylbot/notifications{?since,all,participating}",
170 | "labels_url": "https://api.github.com/repos/dwyl/dwylbot/labels{/name}",
171 | "releases_url": "https://api.github.com/repos/dwyl/dwylbot/releases{/id}",
172 | "deployments_url": "https://api.github.com/repos/dwyl/dwylbot/deployments",
173 | "created_at": "2017-02-23T14:42:53Z",
174 | "updated_at": "2017-03-08T10:32:45Z",
175 | "pushed_at": "2017-03-08T11:59:28Z",
176 | "git_url": "git://github.com/dwyl/dwylbot.git",
177 | "ssh_url": "git@github.com:dwyl/dwylbot.git",
178 | "clone_url": "https://github.com/dwyl/dwylbot.git",
179 | "svn_url": "https://github.com/dwyl/dwylbot",
180 | "homepage": "",
181 | "size": 63,
182 | "stargazers_count": 8,
183 | "watchers_count": 8,
184 | "language": null,
185 | "has_issues": true,
186 | "has_downloads": true,
187 | "has_wiki": true,
188 | "has_pages": false,
189 | "forks_count": 1,
190 | "mirror_url": null,
191 | "open_issues_count": 13,
192 | "forks": 1,
193 | "open_issues": 13,
194 | "watchers": 8,
195 | "default_branch": "master"
196 | },
197 | "organization": {
198 | "login": "dwyl",
199 | "id": 11708465,
200 | "url": "https://api.github.com/orgs/dwyl",
201 | "repos_url": "https://api.github.com/orgs/dwyl/repos",
202 | "events_url": "https://api.github.com/orgs/dwyl/events",
203 | "hooks_url": "https://api.github.com/orgs/dwyl/hooks",
204 | "issues_url": "https://api.github.com/orgs/dwyl/issues",
205 | "members_url": "https://api.github.com/orgs/dwyl/members{/member}",
206 | "public_members_url": "https://api.github.com/orgs/dwyl/public_members{/member}",
207 | "avatar_url": "https://avatars2.githubusercontent.com/u/11708465?v=3",
208 | "description": "Start here: https://github.com/dwyl/start-here"
209 | },
210 | "sender": {
211 | "login": "SimonLab",
212 | "id": 6057298,
213 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
214 | "gravatar_id": "",
215 | "url": "https://api.github.com/users/SimonLab",
216 | "html_url": "https://github.com/SimonLab",
217 | "followers_url": "https://api.github.com/users/SimonLab/followers",
218 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
219 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
220 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
221 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
222 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
223 | "repos_url": "https://api.github.com/users/SimonLab/repos",
224 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
225 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
226 | "type": "User",
227 | "site_admin": false
228 | }
229 | }
--------------------------------------------------------------------------------
/test/fixtures/pull_request.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://api.github.com/repos/SimonLab/github_app/pulls/12",
3 | "id": 125922040,
4 | "html_url": "https://github.com/SimonLab/github_app/pull/12",
5 | "diff_url": "https://github.com/SimonLab/github_app/pull/12.diff",
6 | "patch_url": "https://github.com/SimonLab/github_app/pull/12.patch",
7 | "issue_url": "https://api.github.com/repos/SimonLab/github_app/issues/12",
8 | "number": 12,
9 | "state": "open",
10 | "locked": false,
11 | "title": "add tests webhook request",
12 | "user": {
13 | "login": "SimonLab",
14 | "id": 6057298,
15 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
16 | "gravatar_id": "",
17 | "url": "https://api.github.com/users/SimonLab",
18 | "html_url": "https://github.com/SimonLab",
19 | "followers_url": "https://api.github.com/users/SimonLab/followers",
20 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
21 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
22 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
23 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
24 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
25 | "repos_url": "https://api.github.com/users/SimonLab/repos",
26 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
27 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
28 | "type": "User",
29 | "site_admin": false
30 | },
31 | "body": "",
32 | "created_at": "2017-06-15T22:04:17Z",
33 | "updated_at": "2017-06-15T22:04:17Z",
34 | "closed_at": null,
35 | "merged_at": null,
36 | "merge_commit_sha": null,
37 | "assignee": null,
38 | "assignees": [
39 |
40 | ],
41 | "requested_reviewers": [
42 |
43 | ],
44 | "milestone": null,
45 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/pulls/12/commits",
46 | "review_comments_url": "https://api.github.com/repos/SimonLab/github_app/pulls/12/comments",
47 | "review_comment_url": "https://api.github.com/repos/SimonLab/github_app/pulls/comments{/number}",
48 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/issues/12/comments",
49 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/4c89843226484d878aad8a5db246eb575b20860f",
50 | "head": {
51 | "label": "SimonLab:test-pr",
52 | "ref": "test-pr",
53 | "sha": "4c89843226484d878aad8a5db246eb575b20860f",
54 | "user": {
55 | "login": "SimonLab",
56 | "id": 6057298,
57 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
58 | "gravatar_id": "",
59 | "url": "https://api.github.com/users/SimonLab",
60 | "html_url": "https://github.com/SimonLab",
61 | "followers_url": "https://api.github.com/users/SimonLab/followers",
62 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
63 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
64 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
65 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
66 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
67 | "repos_url": "https://api.github.com/users/SimonLab/repos",
68 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
69 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
70 | "type": "User",
71 | "site_admin": false
72 | },
73 | "repo": {
74 | "id": 92847353,
75 | "name": "github_app",
76 | "full_name": "SimonLab/github_app",
77 | "owner": {
78 | "login": "SimonLab",
79 | "id": 6057298,
80 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
81 | "gravatar_id": "",
82 | "url": "https://api.github.com/users/SimonLab",
83 | "html_url": "https://github.com/SimonLab",
84 | "followers_url": "https://api.github.com/users/SimonLab/followers",
85 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
86 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
87 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
88 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
89 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
90 | "repos_url": "https://api.github.com/users/SimonLab/repos",
91 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
92 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
93 | "type": "User",
94 | "site_admin": false
95 | },
96 | "private": false,
97 | "html_url": "https://github.com/SimonLab/github_app",
98 | "description": "a Github App to play with integrations",
99 | "fork": false,
100 | "url": "https://api.github.com/repos/SimonLab/github_app",
101 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
102 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
103 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
104 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
105 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
106 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
107 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
108 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
109 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
110 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
111 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
112 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
113 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
114 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
115 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
116 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
117 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
118 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
119 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
120 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
121 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
122 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
123 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
124 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
125 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
126 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
127 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
128 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
129 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
130 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
131 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
132 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
133 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
134 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
135 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
136 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
137 | "created_at": "2017-05-30T15:26:26Z",
138 | "updated_at": "2017-05-30T15:36:26Z",
139 | "pushed_at": "2017-06-15T22:02:33Z",
140 | "git_url": "git://github.com/SimonLab/github_app.git",
141 | "ssh_url": "git@github.com:SimonLab/github_app.git",
142 | "clone_url": "https://github.com/SimonLab/github_app.git",
143 | "svn_url": "https://github.com/SimonLab/github_app",
144 | "homepage": null,
145 | "size": 56,
146 | "stargazers_count": 0,
147 | "watchers_count": 0,
148 | "language": "Elixir",
149 | "has_issues": true,
150 | "has_projects": true,
151 | "has_downloads": true,
152 | "has_wiki": true,
153 | "has_pages": false,
154 | "forks_count": 0,
155 | "mirror_url": null,
156 | "open_issues_count": 5,
157 | "forks": 0,
158 | "open_issues": 5,
159 | "watchers": 0,
160 | "default_branch": "initialise"
161 | }
162 | },
163 | "base": {
164 | "label": "SimonLab:initialise",
165 | "ref": "initialise",
166 | "sha": "82a1c04b1ae5d4bab0fef4b34a99a6a8be43b823",
167 | "user": {
168 | "login": "SimonLab",
169 | "id": 6057298,
170 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
171 | "gravatar_id": "",
172 | "url": "https://api.github.com/users/SimonLab",
173 | "html_url": "https://github.com/SimonLab",
174 | "followers_url": "https://api.github.com/users/SimonLab/followers",
175 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
176 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
177 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
178 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
179 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
180 | "repos_url": "https://api.github.com/users/SimonLab/repos",
181 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
182 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
183 | "type": "User",
184 | "site_admin": false
185 | },
186 | "repo": {
187 | "id": 92847353,
188 | "name": "github_app",
189 | "full_name": "SimonLab/github_app",
190 | "owner": {
191 | "login": "SimonLab",
192 | "id": 6057298,
193 | "avatar_url": "https://avatars1.githubusercontent.com/u/6057298?v=3",
194 | "gravatar_id": "",
195 | "url": "https://api.github.com/users/SimonLab",
196 | "html_url": "https://github.com/SimonLab",
197 | "followers_url": "https://api.github.com/users/SimonLab/followers",
198 | "following_url": "https://api.github.com/users/SimonLab/following{/other_user}",
199 | "gists_url": "https://api.github.com/users/SimonLab/gists{/gist_id}",
200 | "starred_url": "https://api.github.com/users/SimonLab/starred{/owner}{/repo}",
201 | "subscriptions_url": "https://api.github.com/users/SimonLab/subscriptions",
202 | "organizations_url": "https://api.github.com/users/SimonLab/orgs",
203 | "repos_url": "https://api.github.com/users/SimonLab/repos",
204 | "events_url": "https://api.github.com/users/SimonLab/events{/privacy}",
205 | "received_events_url": "https://api.github.com/users/SimonLab/received_events",
206 | "type": "User",
207 | "site_admin": false
208 | },
209 | "private": false,
210 | "html_url": "https://github.com/SimonLab/github_app",
211 | "description": "a Github App to play with integrations",
212 | "fork": false,
213 | "url": "https://api.github.com/repos/SimonLab/github_app",
214 | "forks_url": "https://api.github.com/repos/SimonLab/github_app/forks",
215 | "keys_url": "https://api.github.com/repos/SimonLab/github_app/keys{/key_id}",
216 | "collaborators_url": "https://api.github.com/repos/SimonLab/github_app/collaborators{/collaborator}",
217 | "teams_url": "https://api.github.com/repos/SimonLab/github_app/teams",
218 | "hooks_url": "https://api.github.com/repos/SimonLab/github_app/hooks",
219 | "issue_events_url": "https://api.github.com/repos/SimonLab/github_app/issues/events{/number}",
220 | "events_url": "https://api.github.com/repos/SimonLab/github_app/events",
221 | "assignees_url": "https://api.github.com/repos/SimonLab/github_app/assignees{/user}",
222 | "branches_url": "https://api.github.com/repos/SimonLab/github_app/branches{/branch}",
223 | "tags_url": "https://api.github.com/repos/SimonLab/github_app/tags",
224 | "blobs_url": "https://api.github.com/repos/SimonLab/github_app/git/blobs{/sha}",
225 | "git_tags_url": "https://api.github.com/repos/SimonLab/github_app/git/tags{/sha}",
226 | "git_refs_url": "https://api.github.com/repos/SimonLab/github_app/git/refs{/sha}",
227 | "trees_url": "https://api.github.com/repos/SimonLab/github_app/git/trees{/sha}",
228 | "statuses_url": "https://api.github.com/repos/SimonLab/github_app/statuses/{sha}",
229 | "languages_url": "https://api.github.com/repos/SimonLab/github_app/languages",
230 | "stargazers_url": "https://api.github.com/repos/SimonLab/github_app/stargazers",
231 | "contributors_url": "https://api.github.com/repos/SimonLab/github_app/contributors",
232 | "subscribers_url": "https://api.github.com/repos/SimonLab/github_app/subscribers",
233 | "subscription_url": "https://api.github.com/repos/SimonLab/github_app/subscription",
234 | "commits_url": "https://api.github.com/repos/SimonLab/github_app/commits{/sha}",
235 | "git_commits_url": "https://api.github.com/repos/SimonLab/github_app/git/commits{/sha}",
236 | "comments_url": "https://api.github.com/repos/SimonLab/github_app/comments{/number}",
237 | "issue_comment_url": "https://api.github.com/repos/SimonLab/github_app/issues/comments{/number}",
238 | "contents_url": "https://api.github.com/repos/SimonLab/github_app/contents/{+path}",
239 | "compare_url": "https://api.github.com/repos/SimonLab/github_app/compare/{base}...{head}",
240 | "merges_url": "https://api.github.com/repos/SimonLab/github_app/merges",
241 | "archive_url": "https://api.github.com/repos/SimonLab/github_app/{archive_format}{/ref}",
242 | "downloads_url": "https://api.github.com/repos/SimonLab/github_app/downloads",
243 | "issues_url": "https://api.github.com/repos/SimonLab/github_app/issues{/number}",
244 | "pulls_url": "https://api.github.com/repos/SimonLab/github_app/pulls{/number}",
245 | "milestones_url": "https://api.github.com/repos/SimonLab/github_app/milestones{/number}",
246 | "notifications_url": "https://api.github.com/repos/SimonLab/github_app/notifications{?since,all,participating}",
247 | "labels_url": "https://api.github.com/repos/SimonLab/github_app/labels{/name}",
248 | "releases_url": "https://api.github.com/repos/SimonLab/github_app/releases{/id}",
249 | "deployments_url": "https://api.github.com/repos/SimonLab/github_app/deployments",
250 | "created_at": "2017-05-30T15:26:26Z",
251 | "updated_at": "2017-05-30T15:36:26Z",
252 | "pushed_at": "2017-06-15T22:02:33Z",
253 | "git_url": "git://github.com/SimonLab/github_app.git",
254 | "ssh_url": "git@github.com:SimonLab/github_app.git",
255 | "clone_url": "https://github.com/SimonLab/github_app.git",
256 | "svn_url": "https://github.com/SimonLab/github_app",
257 | "homepage": null,
258 | "size": 56,
259 | "stargazers_count": 0,
260 | "watchers_count": 0,
261 | "language": "Elixir",
262 | "has_issues": true,
263 | "has_projects": true,
264 | "has_downloads": true,
265 | "has_wiki": true,
266 | "has_pages": false,
267 | "forks_count": 0,
268 | "mirror_url": null,
269 | "open_issues_count": 5,
270 | "forks": 0,
271 | "open_issues": 5,
272 | "watchers": 0,
273 | "default_branch": "initialise"
274 | }
275 | },
276 | "_links": {
277 | "self": {
278 | "href": "https://api.github.com/repos/SimonLab/github_app/pulls/12"
279 | },
280 | "html": {
281 | "href": "https://github.com/SimonLab/github_app/pull/12"
282 | },
283 | "issue": {
284 | "href": "https://api.github.com/repos/SimonLab/github_app/issues/12"
285 | },
286 | "comments": {
287 | "href": "https://api.github.com/repos/SimonLab/github_app/issues/12/comments"
288 | },
289 | "review_comments": {
290 | "href": "https://api.github.com/repos/SimonLab/github_app/pulls/12/comments"
291 | },
292 | "review_comment": {
293 | "href": "https://api.github.com/repos/SimonLab/github_app/pulls/comments{/number}"
294 | },
295 | "commits": {
296 | "href": "https://api.github.com/repos/SimonLab/github_app/pulls/12/commits"
297 | },
298 | "statuses": {
299 | "href": "https://api.github.com/repos/SimonLab/github_app/statuses/4c89843226484d878aad8a5db246eb575b20860f"
300 | }
301 | },
302 | "merged": false,
303 | "mergeable": null,
304 | "rebaseable": null,
305 | "mergeable_state": "unknown",
306 | "merged_by": null,
307 | "comments": 0,
308 | "review_comments": 0,
309 | "maintainer_can_modify": false,
310 | "commits": 1,
311 | "additions": 68,
312 | "deletions": 5,
313 | "changed_files": 4
314 | }
315 |
--------------------------------------------------------------------------------