{"action":"created","comment":{"url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/comments/173846761","pull_request_review_id":103101700,"id":173846761,"diff_hunk":"@@ -0,0 +1,99 @@\n+# RFC 110 - Best Practices for testing and Credentials\n+* Comments: [#110](https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/110)\n+* Proposed by: @djmitche\n+\n+# Summary\n+\n+Taskcluster repositories should pass their tests \"out of the box\": `git clone`, `yarn`, and `yarn test` should result in a successful test run.\n+\n+This is simple for test suites that do not require credentials [1].\n+Otherwise, we must find a way to give useful test results when no credentials are available, while ensuring that all tests get run before code goes into production.\n+\n+Briefly, this proposal suggests a uniform approach to skipping tests that require external services by default, but ensuring that all of those tests run in CI wherever possible.\n+To minimze the loss of test coverage from skipped tests, it suggests use of mocks for external services and running tests against both mocks and actual services, when possible.\n+\n+<sub>[1] or otherwise access external services; such services generally require credentials.</sub>\n+\n+*NOTE*: this RFC only applies to JavaScript libraries and services.\n+\n+## Motivation\n+\n+The testing situation for the Taskcluster services and libraries varies widely from repo to repo, so it is difficult to know what to expect when developing a pull request.\n+for some repositories, `yarn test` does not work out of the box, leading to confusion and friction for contributors.\n+For others, we have had misconfigurations that fail to run all tests on pull requests or pushes to master, allowing deployment of code to production with failing tests.\n+\n+The goals of this proposal, then, are:\n+\n+* A consistent approach to testing across Taskcluster repositories, with a common set of supporting tools\n+* Repositories that are approachable for new contributors\n+* Confidence that production code has passed *all* tests\n+\n+# Details\n+\n+The bulk of this proposal is to document new best practices, as described below.\n+The final best-practices documents would be developed in concert with utilities to support them (in `taskcluster-lib-testing`, for example), and follow the usual review process.\n+\n+Once those best practices and libraries are done, the work that would remain is to upgrade all services and libraries to follow them, and to develop new mocks for the remaining un-mocked external services.\n+\n+## Best Practices (outline)\n+\n+### Credential Management\n+\n+Tests should be capable of fetching credentials needed to access external services either from an on-disk file (for local development) or the Taskcluster-Secrets service vi Taskcluster-Proxy (for use in CI).\n+It should be easy to tell if a specific kind of credential (for example, pulse or AWS) is available.\n+\n+#### Getting Credentials\n+\n+Team members and dedicated contributors will want to know how to set up a full set of credentials for themselves.\n+Include a section in the README describing how to find or generate credentials for each service.\n+\n+For Taskcluster credentials, put the necessary scopes in `scopes.txt` and suggest that the user use taskcluster-cli to generate the credentials:\n+\n+> To obtain Taskcluster client credentials, run `eval $(cat scopes.txt | xargs taskcluster-cli signin)`. This will open a web browser and you'll be prompted to log into Taskcluster. This command requires the taskcluster-cli Go application. Find one at https://github.com/taskcluster/taskcluster-cli/releases.\n+\n+#### Hard Dependencies\n+\n+Some services and libraries depend completely on external services.\n+For example, azure libraries naturally require an Azure account to test against; and pulse libraries will naturally require an AMQP server.\n+Similarly, services with database backends cannot be realistically tested without access to a database server.\n+\n+In such cases, it is OK for the tests to refuse to run at all without configuration for the external services.","path":"rfcs/0110-Best-practices-for-testing-and-credentials.md","position":60,"original_position":60,"commit_id":"a46e3dd00f9acdc9500800cc31c06b8aa9107cf2","original_commit_id":"a46e3dd00f9acdc9500800cc31c06b8aa9107cf2","user":{"login":"jhford","id":607353,"avatar_url":"https://avatars3.githubusercontent.com/u/607353?v=4","gravatar_id":"","url":"https://api.github.com/users/jhford","html_url":"https://github.com/jhford","followers_url":"https://api.github.com/users/jhford/followers","following_url":"https://api.github.com/users/jhford/following{/other_user}","gists_url":"https://api.github.com/users/jhford/gists{/gist_id}","starred_url":"https://api.github.com/users/jhford/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jhford/subscriptions","organizations_url":"https://api.github.com/users/jhford/orgs","repos_url":"https://api.github.com/users/jhford/repos","events_url":"https://api.github.com/users/jhford/events{/privacy}","received_events_url":"https://api.github.com/users/jhford/received_events","type":"User","site_admin":false},"body":"I think this is well phrased.","created_at":"2018-03-12T15:51:29Z","updated_at":"2018-03-12T15:57:51Z","html_url":"https://github.com/taskcluster/taskcluster-rfcs/pull/110#discussion_r173846761","pull_request_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/comments/173846761"},"html":{"href":"https://github.com/taskcluster/taskcluster-rfcs/pull/110#discussion_r173846761"},"pull_request":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110"}}},"pull_request":{"url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110","id":173855352,"html_url":"https://github.com/taskcluster/taskcluster-rfcs/pull/110","diff_url":"https://github.com/taskcluster/taskcluster-rfcs/pull/110.diff","patch_url":"https://github.com/taskcluster/taskcluster-rfcs/pull/110.patch","issue_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/110","number":110,"state":"open","locked":false,"title":"Define testing best-practices regarding credentials","user":{"login":"djmitche","id":28673,"avatar_url":"https://avatars3.githubusercontent.com/u/28673?v=4","gravatar_id":"","url":"https://api.github.com/users/djmitche","html_url":"https://github.com/djmitche","followers_url":"https://api.github.com/users/djmitche/followers","following_url":"https://api.github.com/users/djmitche/following{/other_user}","gists_url":"https://api.github.com/users/djmitche/gists{/gist_id}","starred_url":"https://api.github.com/users/djmitche/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/djmitche/subscriptions","organizations_url":"https://api.github.com/users/djmitche/orgs","repos_url":"https://api.github.com/users/djmitche/repos","events_url":"https://api.github.com/users/djmitche/events{/privacy}","received_events_url":"https://api.github.com/users/djmitche/received_events","type":"User","site_admin":false},"body":"We have [some documentation](https://docs.taskcluster.net/manual/design/devel/best-practices/microservices#test-requirements) about how to test microservices, but nothing about libraries.  Even that documentation is advisory in nature (\"Where possible, try..\").\r\n\r\nIn this Outreachy round, it has become clear that some services are so difficult to get tests running for that they are basically inaccessible to contributors.  So I'm proposing some more stringent practices with regard to testing, to be followed up with some libraries to assist in implementation of those practices.\r\n\r\nRoughly:\r\n\r\n * `yarn && yarn test` should succeed on master for all services and libraries at all times.  If that skips lots of tests, that's OK.\r\n * When there are mocks available for some dependency, tests should *always* run against the mocks and the same tests should run against the real service when appropriate credentials are available.  It's not hard to run the same test suite twice with different conditions (mock and real, in this case).\r\n * When there are no mocks available, tests should skip when no credentials are available.\r\n * When credentials aren't available, the tests against the real service should be skipped\r\n * For pushes to the master branch of the upstream repo, ensure that all tests are run (no skips)\r\n * For PR's, depending on the nature of the credentials, either run all tests or skip some of them.  For example, exposing pulse credentials, or TC credentials with only test-related scopes, via a PR is probably OK and will give better feedback to reviewers of contributions.\r\n * Tests should run primarily via taskcluster-github.  Travis can be used for deployments.\r\n * Tests should have no non-debug output\r\n\r\nAs far as implementation, I'd like to start by just setting this up for all services and libraries (with ample help from utilities in taskcluster-lib-testing).  For some services, like Auth, that will mean we skip just about every test by default.\r\n\r\nIn the second phase, we can start building mocks for the things we still don't have mocks for -- AWS, for example -- as a way of increasing the quality of tests for services and libraries that otherwise have a high proportion of skips.\r\n\r\n---\r\n\r\nI'd like to gather some thoughts on this before formulating this into a proposal..","created_at":"2018-03-08T21:27:45Z","updated_at":"2018-03-12T15:57:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bc3bdf1a802bc1c07b1d9c65eff56d39c1bf24b8","assignee":{"login":"djmitche","id":28673,"avatar_url":"https://avatars3.githubusercontent.com/u/28673?v=4","gravatar_id":"","url":"https://api.github.com/users/djmitche","html_url":"https://github.com/djmitche","followers_url":"https://api.github.com/users/djmitche/followers","following_url":"https://api.github.com/users/djmitche/following{/other_user}","gists_url":"https://api.github.com/users/djmitche/gists{/gist_id}","starred_url":"https://api.github.com/users/djmitche/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/djmitche/subscriptions","organizations_url":"https://api.github.com/users/djmitche/orgs","repos_url":"https://api.github.com/users/djmitche/repos","events_url":"https://api.github.com/users/djmitche/events{/privacy}","received_events_url":"https://api.github.com/users/djmitche/received_events","type":"User","site_admin":false},"assignees":[{"login":"djmitche","id":28673,"avatar_url":"https://avatars3.githubusercontent.com/u/28673?v=4","gravatar_id":"","url":"https://api.github.com/users/djmitche","html_url":"https://github.com/djmitche","followers_url":"https://api.github.com/users/djmitche/followers","following_url":"https://api.github.com/users/djmitche/following{/other_user}","gists_url":"https://api.github.com/users/djmitche/gists{/gist_id}","starred_url":"https://api.github.com/users/djmitche/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/djmitche/subscriptions","organizations_url":"https://api.github.com/users/djmitche/orgs","repos_url":"https://api.github.com/users/djmitche/repos","events_url":"https://api.github.com/users/djmitche/events{/privacy}","received_events_url":"https://api.github.com/users/djmitche/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":598010835,"url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/labels/Phase:%20Proposal","name":"Phase: Proposal","color":"b60205","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110/commits","review_comments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110/comments","review_comment_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/110/comments","statuses_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/statuses/a46e3dd00f9acdc9500800cc31c06b8aa9107cf2","head":{"label":"taskcluster:issue110","ref":"issue110","sha":"a46e3dd00f9acdc9500800cc31c06b8aa9107cf2","user":{"login":"taskcluster","id":6257436,"avatar_url":"https://avatars2.githubusercontent.com/u/6257436?v=4","gravatar_id":"","url":"https://api.github.com/users/taskcluster","html_url":"https://github.com/taskcluster","followers_url":"https://api.github.com/users/taskcluster/followers","following_url":"https://api.github.com/users/taskcluster/following{/other_user}","gists_url":"https://api.github.com/users/taskcluster/gists{/gist_id}","starred_url":"https://api.github.com/users/taskcluster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/taskcluster/subscriptions","organizations_url":"https://api.github.com/users/taskcluster/orgs","repos_url":"https://api.github.com/users/taskcluster/repos","events_url":"https://api.github.com/users/taskcluster/events{/privacy}","received_events_url":"https://api.github.com/users/taskcluster/received_events","type":"Organization","site_admin":false},"repo":{"id":86847026,"name":"taskcluster-rfcs","full_name":"taskcluster/taskcluster-rfcs","owner":{"login":"taskcluster","id":6257436,"avatar_url":"https://avatars2.githubusercontent.com/u/6257436?v=4","gravatar_id":"","url":"https://api.github.com/users/taskcluster","html_url":"https://github.com/taskcluster","followers_url":"https://api.github.com/users/taskcluster/followers","following_url":"https://api.github.com/users/taskcluster/following{/other_user}","gists_url":"https://api.github.com/users/taskcluster/gists{/gist_id}","starred_url":"https://api.github.com/users/taskcluster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/taskcluster/subscriptions","organizations_url":"https://api.github.com/users/taskcluster/orgs","repos_url":"https://api.github.com/users/taskcluster/repos","events_url":"https://api.github.com/users/taskcluster/events{/privacy}","received_events_url":"https://api.github.com/users/taskcluster/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/taskcluster/taskcluster-rfcs","description":"Taskcluster team planning","fork":false,"url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs","forks_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/forks","keys_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/teams","hooks_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/hooks","issue_events_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/events","assignees_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/tags","blobs_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/languages","stargazers_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/stargazers","contributors_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/contributors","subscribers_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/subscribers","subscription_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/subscription","commits_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/merges","archive_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/downloads","issues_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/labels{/name}","releases_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/deployments","created_at":"2017-03-31T18:04:51Z","updated_at":"2018-03-07T13:27:56Z","pushed_at":"2018-03-09T19:14:46Z","git_url":"git://github.com/taskcluster/taskcluster-rfcs.git","ssh_url":"git@github.com:taskcluster/taskcluster-rfcs.git","clone_url":"https://github.com/taskcluster/taskcluster-rfcs.git","svn_url":"https://github.com/taskcluster/taskcluster-rfcs","homepage":"","size":90,"stargazers_count":2,"watchers_count":2,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7,"mirror_url":null,"archived":false,"open_issues_count":38,"license":{"key":"mpl-2.0","name":"Mozilla Public License 2.0","spdx_id":"MPL-2.0","url":"https://api.github.com/licenses/mpl-2.0"},"forks":7,"open_issues":38,"watchers":2,"default_branch":"master"}},"base":{"label":"taskcluster:master","ref":"master","sha":"009228665e80ba427b0382cce4cc780eab0f3b96","user":{"login":"taskcluster","id":6257436,"avatar_url":"https://avatars2.githubusercontent.com/u/6257436?v=4","gravatar_id":"","url":"https://api.github.com/users/taskcluster","html_url":"https://github.com/taskcluster","followers_url":"https://api.github.com/users/taskcluster/followers","following_url":"https://api.github.com/users/taskcluster/following{/other_user}","gists_url":"https://api.github.com/users/taskcluster/gists{/gist_id}","starred_url":"https://api.github.com/users/taskcluster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/taskcluster/subscriptions","organizations_url":"https://api.github.com/users/taskcluster/orgs","repos_url":"https://api.github.com/users/taskcluster/repos","events_url":"https://api.github.com/users/taskcluster/events{/privacy}","received_events_url":"https://api.github.com/users/taskcluster/received_events","type":"Organization","site_admin":false},"repo":{"id":86847026,"name":"taskcluster-rfcs","full_name":"taskcluster/taskcluster-rfcs","owner":{"login":"taskcluster","id":6257436,"avatar_url":"https://avatars2.githubusercontent.com/u/6257436?v=4","gravatar_id":"","url":"https://api.github.com/users/taskcluster","html_url":"https://github.com/taskcluster","followers_url":"https://api.github.com/users/taskcluster/followers","following_url":"https://api.github.com/users/taskcluster/following{/other_user}","gists_url":"https://api.github.com/users/taskcluster/gists{/gist_id}","starred_url":"https://api.github.com/users/taskcluster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/taskcluster/subscriptions","organizations_url":"https://api.github.com/users/taskcluster/orgs","repos_url":"https://api.github.com/users/taskcluster/repos","events_url":"https://api.github.com/users/taskcluster/events{/privacy}","received_events_url":"https://api.github.com/users/taskcluster/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/taskcluster/taskcluster-rfcs","description":"Taskcluster team planning","fork":false,"url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs","forks_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/forks","keys_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/teams","hooks_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/hooks","issue_events_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/events","assignees_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/tags","blobs_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/languages","stargazers_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/stargazers","contributors_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/contributors","subscribers_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/subscribers","subscription_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/subscription","commits_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/merges","archive_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/downloads","issues_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/labels{/name}","releases_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/deployments","created_at":"2017-03-31T18:04:51Z","updated_at":"2018-03-07T13:27:56Z","pushed_at":"2018-03-09T19:14:46Z","git_url":"git://github.com/taskcluster/taskcluster-rfcs.git","ssh_url":"git@github.com:taskcluster/taskcluster-rfcs.git","clone_url":"https://github.com/taskcluster/taskcluster-rfcs.git","svn_url":"https://github.com/taskcluster/taskcluster-rfcs","homepage":"","size":90,"stargazers_count":2,"watchers_count":2,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7,"mirror_url":null,"archived":false,"open_issues_count":38,"license":{"key":"mpl-2.0","name":"Mozilla Public License 2.0","spdx_id":"MPL-2.0","url":"https://api.github.com/licenses/mpl-2.0"},"forks":7,"open_issues":38,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110"},"html":{"href":"https://github.com/taskcluster/taskcluster-rfcs/pull/110"},"issue":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/110"},"comments":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/issues/110/comments"},"review_comments":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110/comments"},"review_comment":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/pulls/110/commits"},"statuses":{"href":"https://api.github.com/repos/taskcluster/taskcluster-rfcs/statuses/a46e3dd00f9acdc9500800cc31c06b8aa9107cf2"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"jhford"}}