mirror of https://github.com/zulip/zulip.git
webhooks: Support filtering GitHub activity from private repositories.
Currently, the GitHub webhook sends activity from both public and private repositories, which could lead to unintended disclosure of sensitive information from private repositories. This commit introduces a ignore_private_repositories parameter to the webhook URL. When set to true, the webhook ignore processing activity from private repositories, ensuring that such activities are not posted to Zulip streams. By default, if the parameter is omitted or set to false, activities from both public and private repositories are processed normally. This provides users with the flexibility to control the visibility of private repository activities without altering the default behavior. More importantly, this introduces a cleaner mechanism for individual incoming webhooks to declare support for settings not common to all webhook integrations. Fixes #31638.
This commit is contained in:
parent
fdf90f7ad1
commit
d1ff871523
|
@ -20,6 +20,13 @@ format used by the Zulip server that they are interacting with.
|
|||
|
||||
## Changes in Zulip 10.0
|
||||
|
||||
**Feature level 318**
|
||||
|
||||
* [`POST /register`](/api/register-queue): Updated
|
||||
`realm_incoming_webhook_bots` with a new `config_options` key,
|
||||
defining which options should be offered when creating URLs for this
|
||||
integration.
|
||||
|
||||
**Feature level 317**
|
||||
|
||||
* [`POST /user_groups/create`](/api/create-user-group):
|
||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
|||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||
|
||||
API_FEATURE_LEVEL = 317 # Last bumped for inclusion of `group_id` in user group creation response.
|
||||
API_FEATURE_LEVEL = 318 # Last bumped for `WebhookConfigOption` configuration update in realm_incoming_webhook_bots.
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import ClipboardJS from "clipboard";
|
||||
import $ from "jquery";
|
||||
import type * as tippy from "tippy.js";
|
||||
import {z} from "zod";
|
||||
|
||||
import render_generate_integration_url_config_checkbox_modal from "../templates/settings/generate_integration_url_config_checkbox_modal.hbs";
|
||||
import render_generate_integration_url_config_text_modal from "../templates/settings/generate_integration_url_config_text_modal.hbs";
|
||||
import render_generate_integration_url_modal from "../templates/settings/generate_integration_url_modal.hbs";
|
||||
import render_integration_events from "../templates/settings/integration_events.hbs";
|
||||
|
||||
|
@ -14,6 +17,20 @@ import {realm} from "./state_data";
|
|||
import * as stream_data from "./stream_data";
|
||||
import * as util from "./util";
|
||||
|
||||
type ConfigOption = {
|
||||
key: string;
|
||||
label: string;
|
||||
validator: string;
|
||||
};
|
||||
|
||||
const config_option_schema = z.object({
|
||||
key: z.string(),
|
||||
label: z.string(),
|
||||
validator: z.string(),
|
||||
});
|
||||
|
||||
const config_options_schema = z.array(config_option_schema);
|
||||
|
||||
export function show_generate_integration_url_modal(api_key: string): void {
|
||||
const default_url_message = $t_html({defaultMessage: "Integration URL will appear here."});
|
||||
const streams = stream_data.subscribed_subs();
|
||||
|
@ -42,6 +59,7 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
const $integration_url = $("#generate-integration-url-modal .integration-url");
|
||||
const $dialog_submit_button = $("#generate-integration-url-modal .dialog_submit_button");
|
||||
const $show_integration_events = $("#show-integration-events");
|
||||
const $config_container = $("#integration-url-config-options-container");
|
||||
|
||||
$dialog_submit_button.prop("disabled", true);
|
||||
$("#integration-url-stream_widget").prop("disabled", true);
|
||||
|
@ -57,6 +75,40 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
);
|
||||
});
|
||||
|
||||
function render_config(config: ConfigOption[]): void {
|
||||
const validated_config = config_options_schema.parse(config);
|
||||
$config_container.empty();
|
||||
|
||||
for (const option of validated_config) {
|
||||
let $config_element: JQuery;
|
||||
|
||||
if (option.validator === "check_bool") {
|
||||
const config_html = render_generate_integration_url_config_checkbox_modal({
|
||||
key: option.key,
|
||||
label: option.label,
|
||||
});
|
||||
$config_element = $(config_html);
|
||||
$config_element
|
||||
.find(`#integration-url-${option.key}-checkbox`)
|
||||
.on("change", () => {
|
||||
update_url();
|
||||
});
|
||||
} else if (option.validator === "check_string") {
|
||||
const config_html = render_generate_integration_url_config_text_modal({
|
||||
key: option.key,
|
||||
label: option.label,
|
||||
});
|
||||
$config_element = $(config_html);
|
||||
$config_element.find(`#integration-url-${option.key}-text`).on("change", () => {
|
||||
update_url();
|
||||
});
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$config_container.append($config_element);
|
||||
}
|
||||
}
|
||||
|
||||
$override_topic.on("change", function () {
|
||||
const checked = this.checked;
|
||||
$topic_input.parent().toggleClass("hide", !checked);
|
||||
|
@ -109,6 +161,7 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
(bot) => bot.name === selected_integration,
|
||||
);
|
||||
const all_event_types = selected_integration_data?.all_event_types;
|
||||
const config = selected_integration_data?.config_options;
|
||||
|
||||
if (all_event_types !== null) {
|
||||
$("#integration-events-parameter").removeClass("hide");
|
||||
|
@ -136,8 +189,27 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
params.set("topic", topic_name);
|
||||
}
|
||||
}
|
||||
|
||||
const selected_events = set_events_param(params);
|
||||
|
||||
if (config) {
|
||||
for (const option of config) {
|
||||
let $input_element;
|
||||
if (option.validator === "check_bool") {
|
||||
$input_element = $(`#integration-url-${option.key}-checkbox`);
|
||||
if ($input_element.prop("checked")) {
|
||||
params.set(option.key, "true");
|
||||
}
|
||||
} else if (option.validator === "check_string") {
|
||||
$input_element = $(`#integration-url-${option.key}-text`);
|
||||
const value = $input_element.val();
|
||||
if (value) {
|
||||
params.set(option.key, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const realm_url = realm.realm_url;
|
||||
const base_url = `${realm_url}/api/v1/external/`;
|
||||
$integration_url.text(`${base_url}${selected_integration}?${params.toString()}`);
|
||||
|
@ -181,6 +253,15 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
integration_input_dropdown_widget.render();
|
||||
$(".integration-url-name-wrapper").trigger("input");
|
||||
|
||||
const selected_integration = integration_input_dropdown_widget.value();
|
||||
const selected_integration_data = realm.realm_incoming_webhook_bots.find(
|
||||
(bot) => bot.name === selected_integration,
|
||||
);
|
||||
|
||||
if (selected_integration_data?.config_options) {
|
||||
render_config(selected_integration_data.config_options);
|
||||
}
|
||||
|
||||
dropdown.hide();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
@ -265,6 +346,7 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
|||
$topic_input.parent().addClass("hide");
|
||||
|
||||
stream_input_dropdown_widget.render(direct_messages_option.unique_id);
|
||||
$config_container.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -342,7 +342,15 @@ export const realm_schema = z.object({
|
|||
display_name: z.string(),
|
||||
name: z.string(),
|
||||
all_event_types: z.nullable(z.array(z.string())),
|
||||
// We currently ignore the `config` field in these objects.
|
||||
config_options: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
label: z.string(),
|
||||
validator: z.string(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
}),
|
||||
),
|
||||
realm_inline_image_preview: z.boolean(),
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div class="input-group" id="integration-url-{{key}}-container">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="integration-url-{{key}}-checkbox" class="integration-url-parameter" />
|
||||
<span class="rendered-checkbox"></span>
|
||||
</label>
|
||||
<label class="inline" for="integration-url-{{key}}-checkbox">{{label}}</label>
|
||||
</div>
|
|
@ -0,0 +1,4 @@
|
|||
<div class="input-group" id="integration-url-{{key}}-container">
|
||||
<label for="integration-url-{{key}}-text" class="modal-label-field">{{label}}</label>
|
||||
<input type="text" id="integration-url-{{key}}-text" class="modal_text_input integration-url-parameter" value=""/>
|
||||
</div>
|
|
@ -25,6 +25,9 @@
|
|||
<label for="integration-url-topic-input" class="modal-label-field">{{t "Topic"}}</label>
|
||||
<input type="text" id="integration-url-topic-input" class="modal_text_input integration-url-parameter" maxlength="{{ max_topic_length }}" />
|
||||
</div>
|
||||
<div id="integration-url-config-options-container">
|
||||
<!-- Dynamic Config Options will be rendered here -->
|
||||
</div>
|
||||
<div id="integration-events-parameter" class="input-group hide">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="show-integration-events"/>
|
||||
|
|
|
@ -621,7 +621,16 @@ def fetch_initial_state_data(
|
|||
"name": integration.name,
|
||||
"display_name": integration.display_name,
|
||||
"all_event_types": get_all_event_types_for_integration(integration),
|
||||
"config": {c[1]: c[0] for c in integration.config_options},
|
||||
"config_options": [
|
||||
{
|
||||
"key": c.name,
|
||||
"label": c.description,
|
||||
"validator": c.validator.__name__,
|
||||
}
|
||||
for c in integration.config_options
|
||||
]
|
||||
if integration.config_options
|
||||
else [],
|
||||
}
|
||||
for integration in WEBHOOK_INTEGRATIONS
|
||||
if integration.legacy is False
|
||||
|
|
|
@ -12,6 +12,8 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from django_stubs_ext import StrPromise
|
||||
|
||||
from zerver.lib.storage import static_path
|
||||
from zerver.lib.validator import check_bool, check_string
|
||||
from zerver.lib.webhooks.common import WebhookConfigOption
|
||||
|
||||
"""This module declares all of the (documented) integrations available
|
||||
in the Zulip server. The Integration class is used as part of
|
||||
|
@ -34,7 +36,7 @@ Over time, we expect this registry to grow additional convenience
|
|||
features for writing and configuring integrations efficiently.
|
||||
"""
|
||||
|
||||
OptionValidator: TypeAlias = Callable[[str, str], str | None]
|
||||
OptionValidator: TypeAlias = Callable[[str, str], str | bool | None]
|
||||
|
||||
META_CATEGORY: dict[str, StrPromise] = {
|
||||
"meta-integration": gettext_lazy("Integration frameworks"),
|
||||
|
@ -75,7 +77,7 @@ class Integration:
|
|||
doc: str | None = None,
|
||||
stream_name: str | None = None,
|
||||
legacy: bool = False,
|
||||
config_options: Sequence[tuple[str, str, OptionValidator]] = [],
|
||||
config_options: Sequence[WebhookConfigOption] = [],
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.client_name = client_name
|
||||
|
@ -198,7 +200,7 @@ class WebhookIntegration(Integration):
|
|||
doc: str | None = None,
|
||||
stream_name: str | None = None,
|
||||
legacy: bool = False,
|
||||
config_options: Sequence[tuple[str, str, OptionValidator]] = [],
|
||||
config_options: Sequence[WebhookConfigOption] = [],
|
||||
dir_name: str | None = None,
|
||||
) -> None:
|
||||
if client_name is None:
|
||||
|
@ -408,6 +410,18 @@ WEBHOOK_INTEGRATIONS: list[WebhookIntegration] = [
|
|||
logo="images/integrations/logos/github.svg",
|
||||
function="zerver.webhooks.github.view.api_github_webhook",
|
||||
stream_name="github",
|
||||
config_options=[
|
||||
WebhookConfigOption(
|
||||
name="branches",
|
||||
description="Filter by branches (comma-separated list)",
|
||||
validator=check_string,
|
||||
),
|
||||
WebhookConfigOption(
|
||||
name="ignore_private_repositories",
|
||||
description="Exclude notifications from private repositories",
|
||||
validator=check_bool,
|
||||
),
|
||||
],
|
||||
),
|
||||
WebhookIntegration(
|
||||
"githubsponsors",
|
||||
|
|
|
@ -130,7 +130,9 @@ def check_valid_bot_config(
|
|||
for integration in WEBHOOK_INTEGRATIONS:
|
||||
if integration.name == service_name:
|
||||
# key: validator
|
||||
config_options = {c[1]: c[2] for c in integration.config_options}
|
||||
config_options = {
|
||||
option.name: option.validator for option in integration.config_options
|
||||
}
|
||||
break
|
||||
if not config_options:
|
||||
raise JsonableError(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import fnmatch
|
||||
import importlib
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Any, TypeAlias
|
||||
from urllib.parse import unquote
|
||||
|
@ -49,6 +50,13 @@ SETUP_MESSAGE_USER_PART = " by {user_name}"
|
|||
OptionalUserSpecifiedTopicStr: TypeAlias = Annotated[str | None, ApiParamConfig("topic")]
|
||||
|
||||
|
||||
@dataclass
|
||||
class WebhookConfigOption:
|
||||
name: str
|
||||
description: str
|
||||
validator: Callable[[str, str], str | bool | None]
|
||||
|
||||
|
||||
def get_setup_webhook_message(integration: str, user_name: str | None = None) -> str:
|
||||
content = SETUP_MESSAGE_TEMPLATE.format(integration=integration)
|
||||
if user_name:
|
||||
|
|
|
@ -14714,8 +14714,8 @@ paths:
|
|||
such filtering.
|
||||
|
||||
**Changes**: New in Zulip 8.0 (feature level 207).
|
||||
config:
|
||||
$ref: "#/components/schemas/BotConfiguration"
|
||||
config_options:
|
||||
$ref: "#/components/schemas/WebhookConfigOption"
|
||||
recent_private_conversations:
|
||||
description: |
|
||||
Present if `recent_private_conversations` is present in `fetch_event_types`.
|
||||
|
@ -21990,6 +21990,36 @@ components:
|
|||
description: |
|
||||
`{config_key}`: Description/value of the configuration data key.
|
||||
type: string
|
||||
WebhookConfigOption:
|
||||
type: array
|
||||
description: |
|
||||
An array of configuration options where each option is an
|
||||
object containing a unique identifier, a human-readable name,
|
||||
and a validation function name hinting how to verify the
|
||||
correct input format.
|
||||
|
||||
This is an unstable API expected to be used only by the Zulip web
|
||||
apps. Please discuss in chat.zulip.org before using it.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 318).
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: |
|
||||
A key for the configuration option to use in generated URLs.
|
||||
label:
|
||||
type: string
|
||||
description: |
|
||||
A human-readable label of the configuration option.
|
||||
validator:
|
||||
type: string
|
||||
description: |
|
||||
The name of the validator function for the configuration
|
||||
option. Currently generated values are `check_bool` and
|
||||
`check_str`.
|
||||
CustomProfileField:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
|
|
@ -18,6 +18,7 @@ from zerver.lib.integrations import EMBEDDED_BOTS, WebhookIntegration
|
|||
from zerver.lib.test_classes import UploadSerializeMixin, ZulipTestCase
|
||||
from zerver.lib.test_helpers import avatar_disk_path, get_test_image_file
|
||||
from zerver.lib.utils import assert_is_not_none
|
||||
from zerver.lib.webhooks.common import WebhookConfigOption
|
||||
from zerver.models import RealmUserDefault, Service, Subscription, UserProfile
|
||||
from zerver.models.bots import get_bot_services
|
||||
from zerver.models.realms import BotCreationPolicyEnum, get_realm
|
||||
|
@ -37,7 +38,11 @@ stripe_sample_config_options = [
|
|||
"stripe",
|
||||
["financial"],
|
||||
display_name="Stripe",
|
||||
config_options=[("Stripe API key", "stripe_api_key", _check_string)],
|
||||
config_options=[
|
||||
WebhookConfigOption(
|
||||
name="stripe_api_key", description="Stripe API key", validator=_check_string
|
||||
)
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,412 @@
|
|||
{
|
||||
"action": "closed",
|
||||
"number": 1,
|
||||
"pull_request": {
|
||||
"url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1",
|
||||
"id": 34778301,
|
||||
"html_url": "https://github.com/baxterthehacker/public-repo/pull/1",
|
||||
"diff_url": "https://github.com/baxterthehacker/public-repo/pull/1.diff",
|
||||
"patch_url": "https://github.com/baxterthehacker/public-repo/pull/1.patch",
|
||||
"issue_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1",
|
||||
"number": 1,
|
||||
"state": "merged",
|
||||
"locked": false,
|
||||
"title": "Update the README with new information",
|
||||
"user": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"body": "This is a pretty simple change that we need to pull into master.",
|
||||
"created_at": "2015-05-05T23:40:27Z",
|
||||
"updated_at": "2015-05-05T23:40:27Z",
|
||||
"closed_at": null,
|
||||
"merged_at": null,
|
||||
"merge_commit_sha": null,
|
||||
"assignee": null,
|
||||
"milestone": null,
|
||||
"commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/commits",
|
||||
"review_comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/comments",
|
||||
"review_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments{/number}",
|
||||
"comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1/comments",
|
||||
"statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"head": {
|
||||
"label": "baxterthehacker:changes",
|
||||
"ref": "changes",
|
||||
"sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"user": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"repo": {
|
||||
"id": 35129377,
|
||||
"name": "public-repo",
|
||||
"full_name": "baxterthehacker/public-repo",
|
||||
"owner": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": true,
|
||||
"html_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/baxterthehacker/public-repo",
|
||||
"forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}",
|
||||
"created_at": "2015-05-05T23:40:12Z",
|
||||
"updated_at": "2015-05-05T23:40:12Z",
|
||||
"pushed_at": "2015-05-05T23:40:26Z",
|
||||
"git_url": "git://github.com/baxterthehacker/public-repo.git",
|
||||
"ssh_url": "git@github.com:baxterthehacker/public-repo.git",
|
||||
"clone_url": "https://github.com/baxterthehacker/public-repo.git",
|
||||
"svn_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"homepage": null,
|
||||
"size": 0,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"open_issues_count": 1,
|
||||
"forks": 0,
|
||||
"open_issues": 1,
|
||||
"watchers": 0,
|
||||
"default_branch": "master"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"label": "baxterthehacker:master",
|
||||
"ref": "master",
|
||||
"sha": "9049f1265b7d61be4a8904a9a27120d2064dab3b",
|
||||
"user": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"repo": {
|
||||
"id": 35129377,
|
||||
"name": "public-repo",
|
||||
"full_name": "baxterthehacker/public-repo",
|
||||
"owner": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": false,
|
||||
"html_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/baxterthehacker/public-repo",
|
||||
"forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}",
|
||||
"created_at": "2015-05-05T23:40:12Z",
|
||||
"updated_at": "2015-05-05T23:40:12Z",
|
||||
"pushed_at": "2015-05-05T23:40:26Z",
|
||||
"git_url": "git://github.com/baxterthehacker/public-repo.git",
|
||||
"ssh_url": "git@github.com:baxterthehacker/public-repo.git",
|
||||
"clone_url": "https://github.com/baxterthehacker/public-repo.git",
|
||||
"svn_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"homepage": null,
|
||||
"size": 0,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"open_issues_count": 1,
|
||||
"forks": 0,
|
||||
"open_issues": 1,
|
||||
"watchers": 0,
|
||||
"default_branch": "master"
|
||||
}
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1"
|
||||
},
|
||||
"html": {
|
||||
"href": "https://github.com/baxterthehacker/public-repo/pull/1"
|
||||
},
|
||||
"issue": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1"
|
||||
},
|
||||
"comments": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1/comments"
|
||||
},
|
||||
"review_comments": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/comments"
|
||||
},
|
||||
"review_comment": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments{/number}"
|
||||
},
|
||||
"commits": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/commits"
|
||||
},
|
||||
"statuses": {
|
||||
"href": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"
|
||||
}
|
||||
},
|
||||
"merged": true,
|
||||
"mergeable": null,
|
||||
"mergeable_state": "unknown",
|
||||
"merged_by": null,
|
||||
"comments": 0,
|
||||
"review_comments": 0,
|
||||
"commits": 1,
|
||||
"additions": 1,
|
||||
"deletions": 1,
|
||||
"changed_files": 1
|
||||
},
|
||||
"repository": {
|
||||
"id": 35129377,
|
||||
"name": "public-repo",
|
||||
"full_name": "baxterthehacker/public-repo",
|
||||
"owner": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": true,
|
||||
"html_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/baxterthehacker/public-repo",
|
||||
"forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}",
|
||||
"created_at": "2015-05-05T23:40:12Z",
|
||||
"updated_at": "2015-05-05T23:40:12Z",
|
||||
"pushed_at": "2015-05-05T23:40:26Z",
|
||||
"git_url": "git://github.com/baxterthehacker/public-repo.git",
|
||||
"ssh_url": "git@github.com:baxterthehacker/public-repo.git",
|
||||
"clone_url": "https://github.com/baxterthehacker/public-repo.git",
|
||||
"svn_url": "https://github.com/baxterthehacker/public-repo",
|
||||
"homepage": null,
|
||||
"size": 0,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"open_issues_count": 1,
|
||||
"forks": 0,
|
||||
"open_issues": 1,
|
||||
"watchers": 0,
|
||||
"default_branch": "master"
|
||||
},
|
||||
"sender": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
{
|
||||
"ref": "refs/heads/changes",
|
||||
"before": "9049f1265b7d61be4a8904a9a27120d2064dab3b",
|
||||
"after": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"created": false,
|
||||
"deleted": false,
|
||||
"forced": false,
|
||||
"base_ref": null,
|
||||
"compare": "https://github.com/baxterthehacker/private-repo/compare/9049f1265b7d...0d1a26e67d8f",
|
||||
"commits": [
|
||||
{
|
||||
"id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"tree_id": "f9d2a07e9488b91af2641b26b9407fe22a451433",
|
||||
"distinct": true,
|
||||
"message": "Update README.md",
|
||||
"timestamp": "2015-05-05T19:40:15-04:00",
|
||||
"url": "https://github.com/baxterthehacker/private-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"author": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com",
|
||||
"username": "baxterthehacker"
|
||||
},
|
||||
"committer": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com",
|
||||
"username": "baxterthehacker"
|
||||
},
|
||||
"added": [
|
||||
|
||||
],
|
||||
"removed": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"head_commit": {
|
||||
"id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"tree_id": "f9d2a07e9488b91af2641b26b9407fe22a451433",
|
||||
"distinct": true,
|
||||
"message": "Update README.md",
|
||||
"timestamp": "2015-05-05T19:40:15-04:00",
|
||||
"url": "https://github.com/baxterthehacker/private-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
|
||||
"author": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com",
|
||||
"username": "baxterthehacker"
|
||||
},
|
||||
"committer": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com",
|
||||
"username": "baxterthehacker"
|
||||
},
|
||||
"added": [
|
||||
|
||||
],
|
||||
"removed": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"README.md"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"id": 35129377,
|
||||
"name": "private-repo",
|
||||
"full_name": "baxterthehacker/private-repo",
|
||||
"owner": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com"
|
||||
},
|
||||
"private": true,
|
||||
"html_url": "https://github.com/baxterthehacker/private-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
"url": "https://github.com/baxterthehacker/private-repo",
|
||||
"forks_url": "https://api.github.com/repos/baxterthehacker/private-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/baxterthehacker/private-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/baxterthehacker/private-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/baxterthehacker/private-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/baxterthehacker/private-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/baxterthehacker/private-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/baxterthehacker/private-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/baxterthehacker/private-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/baxterthehacker/private-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/baxterthehacker/private-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/baxterthehacker/private-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/baxterthehacker/private-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/baxterthehacker/private-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/baxterthehacker/private-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/baxterthehacker/private-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/baxterthehacker/private-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/baxterthehacker/private-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/baxterthehacker/private-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/baxterthehacker/private-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/baxterthehacker/private-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/baxterthehacker/private-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/baxterthehacker/private-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/baxterthehacker/private-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/baxterthehacker/private-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/baxterthehacker/private-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/baxterthehacker/private-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/baxterthehacker/private-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/baxterthehacker/private-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/baxterthehacker/private-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/baxterthehacker/private-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterthehacker/private-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterthehacker/private-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterthehacker/private-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterthehacker/private-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterthehacker/private-repo/releases{/id}",
|
||||
"created_at": 1430869212,
|
||||
"updated_at": "2015-05-05T23:40:12Z",
|
||||
"pushed_at": 1430869217,
|
||||
"git_url": "git://github.com/baxterthehacker/private-repo.git",
|
||||
"ssh_url": "git@github.com:baxterthehacker/private-repo.git",
|
||||
"clone_url": "https://github.com/baxterthehacker/private-repo.git",
|
||||
"svn_url": "https://github.com/baxterthehacker/private-repo",
|
||||
"homepage": null,
|
||||
"size": 0,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"open_issues_count": 0,
|
||||
"forks": 0,
|
||||
"open_issues": 0,
|
||||
"watchers": 0,
|
||||
"default_branch": "master",
|
||||
"stargazers": 0,
|
||||
"master_branch": "master"
|
||||
},
|
||||
"pusher": {
|
||||
"name": "baxterthehacker",
|
||||
"email": "baxterthehacker@users.noreply.github.com"
|
||||
},
|
||||
"sender": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
"node_id": "MDEwOJllG9zcXaRcvknzNYyTzM4OUQD=",
|
||||
"name": "infra-core",
|
||||
"full_name": "some-organization/infra-core",
|
||||
"private": true,
|
||||
"private": false,
|
||||
"owner": {
|
||||
"name": "some-organization",
|
||||
"email": null,
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": true,
|
||||
"private": false,
|
||||
"html_url": "https://github.com/baxterandthehackers/public-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
{
|
||||
"action": "created",
|
||||
"repository": {
|
||||
"id": 27496774,
|
||||
"name": "public-repo",
|
||||
"full_name": "baxterandthehackers/public-repo",
|
||||
"owner": {
|
||||
"login": "baxterandthehackers",
|
||||
"id": 7649605,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7649605?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterandthehackers",
|
||||
"html_url": "https://github.com/baxterandthehackers",
|
||||
"followers_url": "https://api.github.com/users/baxterandthehackers/followers",
|
||||
"following_url": "https://api.github.com/users/baxterandthehackers/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterandthehackers/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterandthehackers/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterandthehackers/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterandthehackers/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterandthehackers/repos",
|
||||
"events_url": "https://api.github.com/users/baxterandthehackers/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterandthehackers/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": true,
|
||||
"html_url": "https://github.com/baxterandthehackers/public-repo",
|
||||
"description": "",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/baxterandthehackers/public-repo",
|
||||
"forks_url": "https://api.github.com/repos/baxterandthehackers/public-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/baxterandthehackers/public-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/baxterandthehackers/public-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/baxterandthehackers/public-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/baxterandthehackers/public-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/baxterandthehackers/public-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/baxterandthehackers/public-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/baxterandthehackers/public-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/baxterandthehackers/public-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/baxterandthehackers/public-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/baxterandthehackers/public-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/baxterandthehackers/public-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/baxterandthehackers/public-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/baxterandthehackers/public-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/baxterandthehackers/public-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/baxterandthehackers/public-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/baxterandthehackers/public-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/baxterandthehackers/public-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/baxterandthehackers/public-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/baxterandthehackers/public-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/baxterandthehackers/public-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues/comments/{number}",
|
||||
"contents_url": "https://api.github.com/repos/baxterandthehackers/public-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/baxterandthehackers/public-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/baxterandthehackers/public-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/baxterandthehackers/public-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/baxterandthehackers/public-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
||||
"created_at": "2014-12-03T16:39:25Z",
|
||||
"updated_at": "2014-12-03T16:39:25Z",
|
||||
"pushed_at": "2014-12-03T16:39:25Z",
|
||||
"git_url": "git://github.com/baxterandthehackers/public-repo.git",
|
||||
"ssh_url": "git@github.com:baxterandthehackers/public-repo.git",
|
||||
"clone_url": "https://github.com/baxterandthehackers/public-repo.git",
|
||||
"svn_url": "https://github.com/baxterandthehackers/public-repo",
|
||||
"homepage": null,
|
||||
"size": 0,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": null,
|
||||
"has_issues": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"open_issues_count": 0,
|
||||
"forks": 0,
|
||||
"open_issues": 0,
|
||||
"watchers": 0,
|
||||
"default_branch": "master"
|
||||
},
|
||||
"organization": {
|
||||
"login": "baxterandthehackers",
|
||||
"id": 7649605,
|
||||
"url": "https://api.github.com/orgs/baxterandthehackers",
|
||||
"repos_url": "https://api.github.com/orgs/baxterandthehackers/repos",
|
||||
"events_url": "https://api.github.com/orgs/baxterandthehackers/events",
|
||||
"members_url": "https://api.github.com/orgs/baxterandthehackers/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/baxterandthehackers/public_members{/member}",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7649605?v=2"
|
||||
},
|
||||
"sender": {
|
||||
"login": "baxterthehacker",
|
||||
"id": 6752317,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=2",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/baxterthehacker",
|
||||
"html_url": "https://github.com/baxterthehacker",
|
||||
"followers_url": "https://api.github.com/users/baxterthehacker/followers",
|
||||
"following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/baxterthehacker/orgs",
|
||||
"repos_url": "https://api.github.com/users/baxterthehacker/repos",
|
||||
"events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/baxterthehacker/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
|
@ -61,6 +61,15 @@ class GitHubWebhookTest(WebhookTestCase):
|
|||
expected_message = "baxterthehacker [pushed](https://github.com/baxterthehacker/public-repo/compare/9049f1265b7d...0d1a26e67d8f) 1 commit to branch changes.\n\n* Update README.md ([0d1a26e67d8](https://github.com/baxterthehacker/public-repo/commit/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c))"
|
||||
self.check_webhook("push__1_commit", TOPIC_BRANCH, expected_message)
|
||||
|
||||
def test_push_1_commit_private_repository_skipped(self) -> None:
|
||||
self.url = self.build_webhook_url(ignore_private_repositories="true")
|
||||
self.check_webhook(
|
||||
fixture_name="push__1_commit_private_repository",
|
||||
expected_topic_name=None,
|
||||
expected_message=None,
|
||||
expect_noop=True,
|
||||
)
|
||||
|
||||
def test_push_1_commit_without_username(self) -> None:
|
||||
expected_message = "eeshangarg [pushed](https://github.com/eeshangarg/public-repo/compare/0383613da871...2e8cf535fb38) 1 commit to branch changes. Commits by John Snow (1).\n\n* Update the README ([2e8cf535fb3](https://github.com/eeshangarg/public-repo/commit/2e8cf535fb38a3dab2476cdf856efda904ad4c94))"
|
||||
self.check_webhook("push__1_commit_without_username", TOPIC_BRANCH, expected_message)
|
||||
|
@ -268,6 +277,15 @@ class GitHubWebhookTest(WebhookTestCase):
|
|||
)
|
||||
self.check_webhook("pull_request__merged", TOPIC_PR, expected_message)
|
||||
|
||||
def test_pull_request_merged_msg_private_repository_skipped(self) -> None:
|
||||
self.url = self.build_webhook_url(ignore_private_repositories="true")
|
||||
self.check_webhook(
|
||||
fixture_name="pull_request__merged_private_repository",
|
||||
expected_topic_name=None,
|
||||
expected_message=None,
|
||||
expect_noop=True,
|
||||
)
|
||||
|
||||
def test_public_msg(self) -> None:
|
||||
expected_message = "baxterthehacker made the repository [baxterthehacker/public-repo](https://github.com/baxterthehacker/public-repo) public."
|
||||
self.check_webhook("public", TOPIC_REPO, expected_message)
|
||||
|
@ -284,6 +302,19 @@ class GitHubWebhookTest(WebhookTestCase):
|
|||
expected_message = "baxterthehacker created the repository [baxterandthehackers/public-repo](https://github.com/baxterandthehackers/public-repo)."
|
||||
self.check_webhook("repository", TOPIC_REPO, expected_message)
|
||||
|
||||
def test_private_repository_msg(self) -> None:
|
||||
expected_message = "baxterthehacker created the repository [baxterandthehackers/public-repo](https://github.com/baxterandthehackers/public-repo)."
|
||||
self.check_webhook("repository", TOPIC_REPO, expected_message)
|
||||
|
||||
def test_private_repository_skipped_msg(self) -> None:
|
||||
self.url = self.build_webhook_url(ignore_private_repositories="true")
|
||||
self.check_webhook(
|
||||
fixture_name="repository_private",
|
||||
expected_topic_name=None,
|
||||
expected_message=None,
|
||||
expect_noop=True,
|
||||
)
|
||||
|
||||
def test_team_add_msg(self) -> None:
|
||||
expected_message = "The repository [baxterandthehackers/public-repo](https://github.com/baxterandthehackers/public-repo) was added to team github."
|
||||
self.check_webhook("team_add", TOPIC_REPO, expected_message)
|
||||
|
|
|
@ -3,6 +3,7 @@ from collections.abc import Callable
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from pydantic import Json
|
||||
|
||||
from zerver.decorator import log_unsupported_webhook_event, webhook_view
|
||||
from zerver.lib.exceptions import UnsupportedWebhookEventTypeError
|
||||
|
@ -899,6 +900,7 @@ def api_github_webhook(
|
|||
payload: JsonBodyPayload[WildValue],
|
||||
branches: str | None = None,
|
||||
user_specified_topic: OptionalUserSpecifiedTopicStr = None,
|
||||
ignore_private_repositories: Json[bool] = False,
|
||||
) -> HttpResponse:
|
||||
"""
|
||||
GitHub sends the event as an HTTP header. We have our
|
||||
|
@ -908,6 +910,15 @@ def api_github_webhook(
|
|||
"""
|
||||
header_event = validate_extract_webhook_http_header(request, "X-GitHub-Event", "GitHub")
|
||||
|
||||
# Check if the repository is private and skip processing if ignore_private_repositories is True
|
||||
if (
|
||||
"repository" in payload
|
||||
and payload["repository"]["private"].tame(check_bool)
|
||||
and ignore_private_repositories
|
||||
):
|
||||
# Ignore private repository events
|
||||
return json_success(request)
|
||||
|
||||
event = get_zulip_event_name(header_event, payload, branches)
|
||||
if event is None:
|
||||
# This is nothing to worry about--get_event() returns None
|
||||
|
|
Loading…
Reference in New Issue