From 98436714fa69df7d74e0162179dfb34fbfc69e17 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 24 Jan 2023 03:33:30 +0100 Subject: [PATCH 1/3] fix(ConfigManager): add missing log property --- index.js | 2 +- lib/configManager.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 52194601..d8125dfb 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,7 @@ module.exports = (robot, _, Settings = require('./lib/settings')) => { try { deploymentConfig = await loadYamlFileSystem() robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) - const configManager = new ConfigManager(context, ref) + const configManager = new ConfigManager(context, ref, robot.log) const runtimeConfig = await configManager.loadGlobalSettingsYaml() const config = Object.assign({}, deploymentConfig, runtimeConfig) robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) diff --git a/lib/configManager.js b/lib/configManager.js index 5d20f8f3..0dd64d86 100644 --- a/lib/configManager.js +++ b/lib/configManager.js @@ -1,9 +1,10 @@ const path = require('path') const yaml = require('js-yaml') module.exports = class ConfigManager { - constructor (context, ref) { + constructor (context, ref, log) { this.context = context this.ref = ref + this.log = log } /** From c3ad7b400c888b98355fbbba3c0a627b59d6ffea Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 24 Jan 2023 03:47:04 +0100 Subject: [PATCH 2/3] feat(collaborators): listen to member changes Add listeners for repository collaborator events: - member - team Synchronizes settings when users or teams are added, removed, and when permissions for a member is changed. --- app.yml | 51 ++++--- index.js | 20 ++- lib/configManager.js | 4 +- test/fixtures/events/member.json | 134 +++++++++++++++++ .../events/team.added_to_repository.json | 140 ++++++++++++++++++ test/fixtures/events/team.edited.json | 140 ++++++++++++++++++ .../events/team.removed_from_repository.json | 140 ++++++++++++++++++ test/unit/index.test.js | 90 ++++++++++- 8 files changed, 684 insertions(+), 35 deletions(-) create mode 100644 test/fixtures/events/member.json create mode 100644 test/fixtures/events/team.added_to_repository.json create mode 100644 test/fixtures/events/team.edited.json create mode 100644 test/fixtures/events/team.removed_from_repository.json diff --git a/app.yml b/app.yml index 5c32ff47..97bd4c12 100644 --- a/app.yml +++ b/app.yml @@ -27,7 +27,7 @@ default_events: # - issues # - label # - milestone - # - member + - member # - membership # - org_block # - organization @@ -42,10 +42,10 @@ default_events: - repository # - repository_import # - status - # - team + - team # - team_add # - watch - + # The set of permissions needed by the GitHub App. The format of the object uses # the permission name for the key (for example, issues) and the access type for # the value (for example, write). @@ -54,86 +54,85 @@ default_permissions: # Repository creation, deletion, settings, teams, and collaborators. # https://developer.github.com/v3/apps/permissions/#permission-on-administration administration: write - + # Checks on code. # https://developer.github.com/v3/apps/permissions/#permission-on-checks checks: write - + # Repository contents, commits, branches, downloads, releases, and merges. # https://developer.github.com/v3/apps/permissions/#permission-on-contents contents: write - + # Deployments and deployment statuses. # https://developer.github.com/v3/apps/permissions/#permission-on-deployments # deployments: read - + # Issues and related comments, assignees, labels, and milestones. # https://developer.github.com/v3/apps/permissions/#permission-on-issues issues: write - + # Search repositories, list collaborators, and access repository metadata. # https://developer.github.com/v3/apps/permissions/#metadata-permissions metadata: read - + # Retrieve Pages statuses, configuration, and builds, as well as create new builds. # https://developer.github.com/v3/apps/permissions/#permission-on-pages # pages: read - + # Pull requests and related comments, assignees, labels, milestones, and merges. # https://developer.github.com/v3/apps/permissions/#permission-on-pull-requests pull_requests: write - + # Manage the post-receive hooks for a repository. # https://developer.github.com/v3/apps/permissions/#permission-on-repository-hooks # repository_hooks: read - + # Manage repository projects, columns, and cards. # https://developer.github.com/v3/apps/permissions/#permission-on-repository-projects # repository_projects: read - + # Retrieve security vulnerability alerts. # https://developer.github.com/v4/object/repositoryvulnerabilityalert/ # vulnerability_alerts: read - + # Commit statuses. # https://developer.github.com/v3/apps/permissions/#permission-on-statuses statuses: write - + # Organization members and teams. # https://developer.github.com/v3/apps/permissions/#permission-on-members members: write - + # View and manage users blocked by the organization. # https://developer.github.com/v3/apps/permissions/#permission-on-organization-user-blocking # organization_user_blocking: read - + # Manage organization projects, columns, and cards. # https://developer.github.com/v3/apps/permissions/#permission-on-organization-projects # organization_projects: read - + # Manage team discussions and related comments. # https://developer.github.com/v3/apps/permissions/#permission-on-team-discussions # team_discussions: read - + # Manage the post-receive hooks for an organization. # https://developer.github.com/v3/apps/permissions/#permission-on-organization-hooks # organization_hooks: read - + # Get notified of, and update, content references. # https://developer.github.com/v3/apps/permissions/ organization_administration: write - - + + # The name of the GitHub App. Defaults to the name specified in package.json name: Safe Settings - + # The homepage of your GitHub App. url: https://github.com/github/safe-settings - + # A description of the GitHub App. # description: A description of my awesome app - + # Set to true when your GitHub App is available to the public or false when it is only accessible to the owner of the app. # Default: true public: false - \ No newline at end of file diff --git a/index.js b/index.js index d8125dfb..54369580 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,7 @@ module.exports = (robot, _, Settings = require('./lib/settings')) => { try { deploymentConfig = await loadYamlFileSystem() robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) - const configManager = new ConfigManager(context, ref, robot.log) + const configManager = new ConfigManager(context, ref) const runtimeConfig = await configManager.loadGlobalSettingsYaml() const config = Object.assign({}, deploymentConfig, runtimeConfig) robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) @@ -265,6 +265,24 @@ module.exports = (robot, _, Settings = require('./lib/settings')) => { return syncSettings(false, context) }) + const member_change_events = [ + 'member', + 'team.added_to_repository', + 'team.removed_from_repository', + 'team.edited' + ] + robot.on(member_change_events, async context => { + const { payload } = context + const { sender } = payload + robot.log.debug('Repository member edited by ', JSON.stringify(sender)) + if (sender.type === 'Bot') { + robot.log.debug('Repository member edited by Bot') + return + } + robot.log.debug('Repository member edited by a Human') + return syncSettings(false, context) + }) + robot.on('repository.edited', async context => { const { payload } = context const { changes, repository, sender } = payload diff --git a/lib/configManager.js b/lib/configManager.js index 0dd64d86..645e0ff8 100644 --- a/lib/configManager.js +++ b/lib/configManager.js @@ -1,10 +1,10 @@ const path = require('path') const yaml = require('js-yaml') module.exports = class ConfigManager { - constructor (context, ref, log) { + constructor (context, ref) { this.context = context this.ref = ref - this.log = log + this.log = context.log } /** diff --git a/test/fixtures/events/member.json b/test/fixtures/events/member.json new file mode 100644 index 00000000..7f123af0 --- /dev/null +++ b/test/fixtures/events/member.json @@ -0,0 +1,134 @@ +{ + "action": "edited", + "member": { + "login": "bkeepers", + "id": 173, + "avatar_url": "https://avatars.githubusercontent.com/u/173?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/bkeepers", + "html_url": "https://github.com/bkeepers", + "followers_url": "https://api.github.com/users/bkeepers/followers", + "following_url": "https://api.github.com/users/bkeepers/following{/other_user}", + "gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}", + "starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions", + "organizations_url": "https://api.github.com/users/bkeepers/orgs", + "repos_url": "https://api.github.com/users/bkeepers/repos", + "events_url": "https://api.github.com/users/bkeepers/events{/privacy}", + "received_events_url": "https://api.github.com/users/bkeepers/received_events", + "type": "User", + "site_admin": true + }, + "changes": { "permission": { "from": "triage", "to": "read" } }, + "repository": { + "id": 68308403, + "name": "botland", + "full_name": "bkeepers-inc/botland", + "owner": { + "name": "bkeepers-inc", + "email": null + }, + "private": true, + "html_url": "https://github.com/bkeepers-inc/botland", + "description": "Playground for testing bots.", + "fork": false, + "url": "https://github.com/bkeepers-inc/botland", + "forks_url": "https://api.github.com/repos/bkeepers-inc/botland/forks", + "keys_url": "https://api.github.com/repos/bkeepers-inc/botland/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/bkeepers-inc/botland/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/bkeepers-inc/botland/teams", + "hooks_url": "https://api.github.com/repos/bkeepers-inc/botland/hooks", + "issue_events_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/events{/number}", + "events_url": "https://api.github.com/repos/bkeepers-inc/botland/events", + "assignees_url": "https://api.github.com/repos/bkeepers-inc/botland/assignees{/user}", + "branches_url": "https://api.github.com/repos/bkeepers-inc/botland/branches{/branch}", + "tags_url": "https://api.github.com/repos/bkeepers-inc/botland/tags", + "blobs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/bkeepers-inc/botland/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/bkeepers-inc/botland/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/bkeepers-inc/botland/statuses/{sha}", + "languages_url": "https://api.github.com/repos/bkeepers-inc/botland/languages", + "stargazers_url": "https://api.github.com/repos/bkeepers-inc/botland/stargazers", + "contributors_url": "https://api.github.com/repos/bkeepers-inc/botland/contributors", + "subscribers_url": "https://api.github.com/repos/bkeepers-inc/botland/subscribers", + "subscription_url": "https://api.github.com/repos/bkeepers-inc/botland/subscription", + "commits_url": "https://api.github.com/repos/bkeepers-inc/botland/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/bkeepers-inc/botland/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/bkeepers-inc/botland/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/bkeepers-inc/botland/contents/{+path}", + "compare_url": "https://api.github.com/repos/bkeepers-inc/botland/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/bkeepers-inc/botland/merges", + "archive_url": "https://api.github.com/repos/bkeepers-inc/botland/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/bkeepers-inc/botland/downloads", + "issues_url": "https://api.github.com/repos/bkeepers-inc/botland/issues{/number}", + "pulls_url": "https://api.github.com/repos/bkeepers-inc/botland/pulls{/number}", + "milestones_url": "https://api.github.com/repos/bkeepers-inc/botland/milestones{/number}", + "notifications_url": "https://api.github.com/repos/bkeepers-inc/botland/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/bkeepers-inc/botland/labels{/name}", + "releases_url": "https://api.github.com/repos/bkeepers-inc/botland/releases{/id}", + "deployments_url": "https://api.github.com/repos/bkeepers-inc/botland/deployments", + "created_at": 1473954711, + "updated_at": "2016-12-19T19:41:29Z", + "pushed_at": 1484891974, + "git_url": "git://github.com/bkeepers-inc/botland.git", + "ssh_url": "git@github.com:bkeepers-inc/botland.git", + "clone_url": "https://github.com/bkeepers-inc/botland.git", + "svn_url": "https://github.com/bkeepers-inc/botland", + "homepage": "", + "size": 1, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 6, + "forks": 0, + "open_issues": 6, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master", + "organization": "bkeepers-inc" + }, + "organization": { + "login": "bkeepers-inc", + "id": 11724939, + "url": "https://api.github.com/orgs/bkeepers-inc", + "repos_url": "https://api.github.com/orgs/bkeepers-inc/repos", + "events_url": "https://api.github.com/orgs/bkeepers-inc/events", + "hooks_url": "https://api.github.com/orgs/bkeepers-inc/hooks", + "issues_url": "https://api.github.com/orgs/bkeepers-inc/issues", + "members_url": "https://api.github.com/orgs/bkeepers-inc/members{/member}", + "public_members_url": "https://api.github.com/orgs/bkeepers-inc/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/11724939?v=3", + "description": null + }, + "sender": { + "login": "bkeepers", + "id": 173, + "avatar_url": "https://avatars.githubusercontent.com/u/173?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/bkeepers", + "html_url": "https://github.com/bkeepers", + "followers_url": "https://api.github.com/users/bkeepers/followers", + "following_url": "https://api.github.com/users/bkeepers/following{/other_user}", + "gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}", + "starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions", + "organizations_url": "https://api.github.com/users/bkeepers/orgs", + "repos_url": "https://api.github.com/users/bkeepers/repos", + "events_url": "https://api.github.com/users/bkeepers/events{/privacy}", + "received_events_url": "https://api.github.com/users/bkeepers/received_events", + "type": "User", + "site_admin": true + }, + "installation": { + "id": 6274 + } +} diff --git a/test/fixtures/events/team.added_to_repository.json b/test/fixtures/events/team.added_to_repository.json new file mode 100644 index 00000000..3057a2fd --- /dev/null +++ b/test/fixtures/events/team.added_to_repository.json @@ -0,0 +1,140 @@ +{ + "action": "added_to_repository", + "team": { + "name": "editors", + "id": 1, + "node_id": "MDQ6VGVhbTEK=", + "slug": "editors", + "description": "Editors team", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/1", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/editors", + "members_url": "https://api.github.com/organizations/11724939/team/1/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/1/repos", + "permission": "pull", + "parent": { + "name": "all-users", + "id": 2, + "node_id": "MDQ6VGVhbTIK=", + "slug": "all-users", + "description": "All users", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/2", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/all-users", + "members_url": "https://api.github.com/organizations/11724939/team/2/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/2/repos", + "permission": "pull" + } + }, + "repository": { + "id": 68308403, + "name": "botland", + "full_name": "bkeepers-inc/botland", + "owner": { + "name": "bkeepers-inc", + "email": null + }, + "private": true, + "html_url": "https://github.com/bkeepers-inc/botland", + "description": "Playground for testing bots.", + "fork": false, + "url": "https://github.com/bkeepers-inc/botland", + "forks_url": "https://api.github.com/repos/bkeepers-inc/botland/forks", + "keys_url": "https://api.github.com/repos/bkeepers-inc/botland/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/bkeepers-inc/botland/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/bkeepers-inc/botland/teams", + "hooks_url": "https://api.github.com/repos/bkeepers-inc/botland/hooks", + "issue_events_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/events{/number}", + "events_url": "https://api.github.com/repos/bkeepers-inc/botland/events", + "assignees_url": "https://api.github.com/repos/bkeepers-inc/botland/assignees{/user}", + "branches_url": "https://api.github.com/repos/bkeepers-inc/botland/branches{/branch}", + "tags_url": "https://api.github.com/repos/bkeepers-inc/botland/tags", + "blobs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/bkeepers-inc/botland/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/bkeepers-inc/botland/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/bkeepers-inc/botland/statuses/{sha}", + "languages_url": "https://api.github.com/repos/bkeepers-inc/botland/languages", + "stargazers_url": "https://api.github.com/repos/bkeepers-inc/botland/stargazers", + "contributors_url": "https://api.github.com/repos/bkeepers-inc/botland/contributors", + "subscribers_url": "https://api.github.com/repos/bkeepers-inc/botland/subscribers", + "subscription_url": "https://api.github.com/repos/bkeepers-inc/botland/subscription", + "commits_url": "https://api.github.com/repos/bkeepers-inc/botland/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/bkeepers-inc/botland/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/bkeepers-inc/botland/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/bkeepers-inc/botland/contents/{+path}", + "compare_url": "https://api.github.com/repos/bkeepers-inc/botland/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/bkeepers-inc/botland/merges", + "archive_url": "https://api.github.com/repos/bkeepers-inc/botland/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/bkeepers-inc/botland/downloads", + "issues_url": "https://api.github.com/repos/bkeepers-inc/botland/issues{/number}", + "pulls_url": "https://api.github.com/repos/bkeepers-inc/botland/pulls{/number}", + "milestones_url": "https://api.github.com/repos/bkeepers-inc/botland/milestones{/number}", + "notifications_url": "https://api.github.com/repos/bkeepers-inc/botland/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/bkeepers-inc/botland/labels{/name}", + "releases_url": "https://api.github.com/repos/bkeepers-inc/botland/releases{/id}", + "deployments_url": "https://api.github.com/repos/bkeepers-inc/botland/deployments", + "created_at": 1473954711, + "updated_at": "2016-12-19T19:41:29Z", + "pushed_at": 1484891974, + "git_url": "git://github.com/bkeepers-inc/botland.git", + "ssh_url": "git@github.com:bkeepers-inc/botland.git", + "clone_url": "https://github.com/bkeepers-inc/botland.git", + "svn_url": "https://github.com/bkeepers-inc/botland", + "homepage": "", + "size": 1, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 6, + "forks": 0, + "open_issues": 6, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master", + "organization": "bkeepers-inc" + }, + "organization": { + "login": "bkeepers-inc", + "id": 11724939, + "url": "https://api.github.com/orgs/bkeepers-inc", + "repos_url": "https://api.github.com/orgs/bkeepers-inc/repos", + "events_url": "https://api.github.com/orgs/bkeepers-inc/events", + "hooks_url": "https://api.github.com/orgs/bkeepers-inc/hooks", + "issues_url": "https://api.github.com/orgs/bkeepers-inc/issues", + "members_url": "https://api.github.com/orgs/bkeepers-inc/members{/member}", + "public_members_url": "https://api.github.com/orgs/bkeepers-inc/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/11724939?v=3", + "description": null + }, + "sender": { + "login": "bkeepers", + "id": 173, + "avatar_url": "https://avatars.githubusercontent.com/u/173?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/bkeepers", + "html_url": "https://github.com/bkeepers", + "followers_url": "https://api.github.com/users/bkeepers/followers", + "following_url": "https://api.github.com/users/bkeepers/following{/other_user}", + "gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}", + "starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions", + "organizations_url": "https://api.github.com/users/bkeepers/orgs", + "repos_url": "https://api.github.com/users/bkeepers/repos", + "events_url": "https://api.github.com/users/bkeepers/events{/privacy}", + "received_events_url": "https://api.github.com/users/bkeepers/received_events", + "type": "User", + "site_admin": true + }, + "installation": { + "id": 6274 + } +} diff --git a/test/fixtures/events/team.edited.json b/test/fixtures/events/team.edited.json new file mode 100644 index 00000000..5d3d8642 --- /dev/null +++ b/test/fixtures/events/team.edited.json @@ -0,0 +1,140 @@ +{ + "action": "edited", + "team": { + "name": "editors", + "id": 1, + "node_id": "MDQ6VGVhbTEK=", + "slug": "editors", + "description": "Editors team", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/1", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/editors", + "members_url": "https://api.github.com/organizations/11724939/team/1/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/1/repos", + "permission": "pull", + "parent": { + "name": "all-users", + "id": 2, + "node_id": "MDQ6VGVhbTIK=", + "slug": "all-users", + "description": "All users", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/2", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/all-users", + "members_url": "https://api.github.com/organizations/11724939/team/2/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/2/repos", + "permission": "pull" + } + }, + "repository": { + "id": 68308403, + "name": "botland", + "full_name": "bkeepers-inc/botland", + "owner": { + "name": "bkeepers-inc", + "email": null + }, + "private": true, + "html_url": "https://github.com/bkeepers-inc/botland", + "description": "Playground for testing bots.", + "fork": false, + "url": "https://github.com/bkeepers-inc/botland", + "forks_url": "https://api.github.com/repos/bkeepers-inc/botland/forks", + "keys_url": "https://api.github.com/repos/bkeepers-inc/botland/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/bkeepers-inc/botland/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/bkeepers-inc/botland/teams", + "hooks_url": "https://api.github.com/repos/bkeepers-inc/botland/hooks", + "issue_events_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/events{/number}", + "events_url": "https://api.github.com/repos/bkeepers-inc/botland/events", + "assignees_url": "https://api.github.com/repos/bkeepers-inc/botland/assignees{/user}", + "branches_url": "https://api.github.com/repos/bkeepers-inc/botland/branches{/branch}", + "tags_url": "https://api.github.com/repos/bkeepers-inc/botland/tags", + "blobs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/bkeepers-inc/botland/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/bkeepers-inc/botland/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/bkeepers-inc/botland/statuses/{sha}", + "languages_url": "https://api.github.com/repos/bkeepers-inc/botland/languages", + "stargazers_url": "https://api.github.com/repos/bkeepers-inc/botland/stargazers", + "contributors_url": "https://api.github.com/repos/bkeepers-inc/botland/contributors", + "subscribers_url": "https://api.github.com/repos/bkeepers-inc/botland/subscribers", + "subscription_url": "https://api.github.com/repos/bkeepers-inc/botland/subscription", + "commits_url": "https://api.github.com/repos/bkeepers-inc/botland/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/bkeepers-inc/botland/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/bkeepers-inc/botland/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/bkeepers-inc/botland/contents/{+path}", + "compare_url": "https://api.github.com/repos/bkeepers-inc/botland/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/bkeepers-inc/botland/merges", + "archive_url": "https://api.github.com/repos/bkeepers-inc/botland/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/bkeepers-inc/botland/downloads", + "issues_url": "https://api.github.com/repos/bkeepers-inc/botland/issues{/number}", + "pulls_url": "https://api.github.com/repos/bkeepers-inc/botland/pulls{/number}", + "milestones_url": "https://api.github.com/repos/bkeepers-inc/botland/milestones{/number}", + "notifications_url": "https://api.github.com/repos/bkeepers-inc/botland/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/bkeepers-inc/botland/labels{/name}", + "releases_url": "https://api.github.com/repos/bkeepers-inc/botland/releases{/id}", + "deployments_url": "https://api.github.com/repos/bkeepers-inc/botland/deployments", + "created_at": 1473954711, + "updated_at": "2016-12-19T19:41:29Z", + "pushed_at": 1484891974, + "git_url": "git://github.com/bkeepers-inc/botland.git", + "ssh_url": "git@github.com:bkeepers-inc/botland.git", + "clone_url": "https://github.com/bkeepers-inc/botland.git", + "svn_url": "https://github.com/bkeepers-inc/botland", + "homepage": "", + "size": 1, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 6, + "forks": 0, + "open_issues": 6, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master", + "organization": "bkeepers-inc" + }, + "organization": { + "login": "bkeepers-inc", + "id": 11724939, + "url": "https://api.github.com/orgs/bkeepers-inc", + "repos_url": "https://api.github.com/orgs/bkeepers-inc/repos", + "events_url": "https://api.github.com/orgs/bkeepers-inc/events", + "hooks_url": "https://api.github.com/orgs/bkeepers-inc/hooks", + "issues_url": "https://api.github.com/orgs/bkeepers-inc/issues", + "members_url": "https://api.github.com/orgs/bkeepers-inc/members{/member}", + "public_members_url": "https://api.github.com/orgs/bkeepers-inc/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/11724939?v=3", + "description": null + }, + "sender": { + "login": "bkeepers", + "id": 173, + "avatar_url": "https://avatars.githubusercontent.com/u/173?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/bkeepers", + "html_url": "https://github.com/bkeepers", + "followers_url": "https://api.github.com/users/bkeepers/followers", + "following_url": "https://api.github.com/users/bkeepers/following{/other_user}", + "gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}", + "starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions", + "organizations_url": "https://api.github.com/users/bkeepers/orgs", + "repos_url": "https://api.github.com/users/bkeepers/repos", + "events_url": "https://api.github.com/users/bkeepers/events{/privacy}", + "received_events_url": "https://api.github.com/users/bkeepers/received_events", + "type": "User", + "site_admin": true + }, + "installation": { + "id": 6274 + } +} diff --git a/test/fixtures/events/team.removed_from_repository.json b/test/fixtures/events/team.removed_from_repository.json new file mode 100644 index 00000000..0830a059 --- /dev/null +++ b/test/fixtures/events/team.removed_from_repository.json @@ -0,0 +1,140 @@ +{ + "action": "removed_from_repository", + "team": { + "name": "editors", + "id": 1, + "node_id": "MDQ6VGVhbTEK=", + "slug": "editors", + "description": "Editors team", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/1", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/editors", + "members_url": "https://api.github.com/organizations/11724939/team/1/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/1/repos", + "permission": "pull", + "parent": { + "name": "all-users", + "id": 2, + "node_id": "MDQ6VGVhbTIK=", + "slug": "all-users", + "description": "All users", + "privacy": "closed", + "url": "https://api.github.com/organizations/11724939/team/2", + "html_url": "https://github.com/orgs/bkeepers-inc/teams/all-users", + "members_url": "https://api.github.com/organizations/11724939/team/2/members{/member}", + "repositories_url": "https://api.github.com/organizations/11724939/team/2/repos", + "permission": "pull" + } + }, + "repository": { + "id": 68308403, + "name": "botland", + "full_name": "bkeepers-inc/botland", + "owner": { + "name": "bkeepers-inc", + "email": null + }, + "private": true, + "html_url": "https://github.com/bkeepers-inc/botland", + "description": "Playground for testing bots.", + "fork": false, + "url": "https://github.com/bkeepers-inc/botland", + "forks_url": "https://api.github.com/repos/bkeepers-inc/botland/forks", + "keys_url": "https://api.github.com/repos/bkeepers-inc/botland/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/bkeepers-inc/botland/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/bkeepers-inc/botland/teams", + "hooks_url": "https://api.github.com/repos/bkeepers-inc/botland/hooks", + "issue_events_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/events{/number}", + "events_url": "https://api.github.com/repos/bkeepers-inc/botland/events", + "assignees_url": "https://api.github.com/repos/bkeepers-inc/botland/assignees{/user}", + "branches_url": "https://api.github.com/repos/bkeepers-inc/botland/branches{/branch}", + "tags_url": "https://api.github.com/repos/bkeepers-inc/botland/tags", + "blobs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/bkeepers-inc/botland/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/bkeepers-inc/botland/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/bkeepers-inc/botland/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/bkeepers-inc/botland/statuses/{sha}", + "languages_url": "https://api.github.com/repos/bkeepers-inc/botland/languages", + "stargazers_url": "https://api.github.com/repos/bkeepers-inc/botland/stargazers", + "contributors_url": "https://api.github.com/repos/bkeepers-inc/botland/contributors", + "subscribers_url": "https://api.github.com/repos/bkeepers-inc/botland/subscribers", + "subscription_url": "https://api.github.com/repos/bkeepers-inc/botland/subscription", + "commits_url": "https://api.github.com/repos/bkeepers-inc/botland/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/bkeepers-inc/botland/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/bkeepers-inc/botland/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/bkeepers-inc/botland/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/bkeepers-inc/botland/contents/{+path}", + "compare_url": "https://api.github.com/repos/bkeepers-inc/botland/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/bkeepers-inc/botland/merges", + "archive_url": "https://api.github.com/repos/bkeepers-inc/botland/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/bkeepers-inc/botland/downloads", + "issues_url": "https://api.github.com/repos/bkeepers-inc/botland/issues{/number}", + "pulls_url": "https://api.github.com/repos/bkeepers-inc/botland/pulls{/number}", + "milestones_url": "https://api.github.com/repos/bkeepers-inc/botland/milestones{/number}", + "notifications_url": "https://api.github.com/repos/bkeepers-inc/botland/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/bkeepers-inc/botland/labels{/name}", + "releases_url": "https://api.github.com/repos/bkeepers-inc/botland/releases{/id}", + "deployments_url": "https://api.github.com/repos/bkeepers-inc/botland/deployments", + "created_at": 1473954711, + "updated_at": "2016-12-19T19:41:29Z", + "pushed_at": 1484891974, + "git_url": "git://github.com/bkeepers-inc/botland.git", + "ssh_url": "git@github.com:bkeepers-inc/botland.git", + "clone_url": "https://github.com/bkeepers-inc/botland.git", + "svn_url": "https://github.com/bkeepers-inc/botland", + "homepage": "", + "size": 1, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 6, + "forks": 0, + "open_issues": 6, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master", + "organization": "bkeepers-inc" + }, + "organization": { + "login": "bkeepers-inc", + "id": 11724939, + "url": "https://api.github.com/orgs/bkeepers-inc", + "repos_url": "https://api.github.com/orgs/bkeepers-inc/repos", + "events_url": "https://api.github.com/orgs/bkeepers-inc/events", + "hooks_url": "https://api.github.com/orgs/bkeepers-inc/hooks", + "issues_url": "https://api.github.com/orgs/bkeepers-inc/issues", + "members_url": "https://api.github.com/orgs/bkeepers-inc/members{/member}", + "public_members_url": "https://api.github.com/orgs/bkeepers-inc/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/11724939?v=3", + "description": null + }, + "sender": { + "login": "bkeepers", + "id": 173, + "avatar_url": "https://avatars.githubusercontent.com/u/173?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/bkeepers", + "html_url": "https://github.com/bkeepers", + "followers_url": "https://api.github.com/users/bkeepers/followers", + "following_url": "https://api.github.com/users/bkeepers/following{/other_user}", + "gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}", + "starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions", + "organizations_url": "https://api.github.com/users/bkeepers/orgs", + "repos_url": "https://api.github.com/users/bkeepers/repos", + "events_url": "https://api.github.com/users/bkeepers/events{/privacy}", + "received_events_url": "https://api.github.com/users/bkeepers/received_events", + "type": "User", + "site_admin": true + }, + "installation": { + "id": 6274 + } +} diff --git a/test/unit/index.test.js b/test/unit/index.test.js index 06a471f4..077c0a65 100644 --- a/test/unit/index.test.js +++ b/test/unit/index.test.js @@ -1,18 +1,37 @@ -const { Application } = require('probot') +const { Probot, ProbotOctokit } = require('probot') const plugin = require('../../index') describe('plugin', () => { let app, event, sync, github beforeEach(() => { - app = new Application() + class Octokit { + static defaults () { + return Octokit + } + + constructor () { + this.config = { + get: jest.fn().mockReturnValue({}) + } + this.repos = { + getContent: jest.fn(() => Promise.resolve({ data: { content: '' } })) + } + } + + auth () { + return this + } + } + + app = new Probot({ secret: "abcdef", Octokit }) github = { repos: { getContents: jest.fn(() => Promise.resolve({ data: { content: '' } })) } } app.auth = () => Promise.resolve(github) - + app.log = { debug: jest.fn(), error: console.error } event = { name: 'push', payload: JSON.parse(JSON.stringify(require('../fixtures/events/push.settings.json'))) @@ -65,13 +84,72 @@ describe('plugin', () => { }) }) - describe('repository created', async () => { + describe('member event', () => { + beforeEach(() => { + event = { + name: 'member', + payload: require('../fixtures/events/member.json') + } + }) + + it('does sync settings', async () => { + await app.receive(event) + expect(sync).toHaveBeenCalled() + }) + }) + + describe('team added to repository', () => { + beforeEach(() => { + event = { + name: 'team.added_to_repository', + payload: require('../fixtures/events/team.added_to_repository.json') + } + }) + + it('does sync settings', async () => { + await app.receive(event) + expect(sync).toHaveBeenCalled() + }) + }) + + describe('team removed from repository', () => { + beforeEach(() => { + event = { + name: 'team.removed_from_repository', + payload: require('../fixtures/events/team.removed_from_repository.json') + } + }) + + it('does sync settings', async () => { + await app.receive(event) + expect(sync).toHaveBeenCalled() + }) + }) + + describe('team access changed', () => { + beforeEach(() => { + event = { + name: 'team.edited', + payload: require('../fixtures/events/team.edited.json') + } + }) + + it('does sync settings', async () => { + await app.receive(event) + expect(sync).toHaveBeenCalled() + }) + }) + + describe('repository created', () => { event = { name: 'repository.created', payload: {} } - await app.receive(event) - expect(sync).toHaveBeenCalled() + it('does sync settings', async () => { + await app.receive(event) + expect(sync).toHaveBeenCalled() + }) }) + }) From 852fa64887a6fb3def7490639e227b7b3143c98f Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 24 Jan 2023 22:53:39 +0100 Subject: [PATCH 3/3] fix(mergedeep): hasChanges for empty source and non-empty target Fix for empty collaborators config not removing excess members. Using config `collaborators: []` this fix makes sure that manually added collaborators are removed. --- lib/mergeDeep.js | 5 ++++- test/unit/lib/mergeDeep.test.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/mergeDeep.js b/lib/mergeDeep.js index 7b7fd4ae..bcf629f5 100644 --- a/lib/mergeDeep.js +++ b/lib/mergeDeep.js @@ -163,7 +163,10 @@ class MergeDeep { modifications = this.removeEmptyAndNulls(modifications, key) additions = this.removeEmptyAndNulls(additions, key) } - return ({ additions, modifications, hasChanges: !this.isEmpty(additions) || !this.isEmpty(modifications) }) + let hasChanges = !this.isEmpty(additions) || !this.isEmpty(modifications) + // Indicate changes when source is empty and target is not + hasChanges |= this.isEmpty(source) && !this.isEmpty(target) + return ({ additions, modifications, hasChanges }) } validateOverride (key, baseconfig, overrideconfig) { diff --git a/test/unit/lib/mergeDeep.test.js b/test/unit/lib/mergeDeep.test.js index ea0732c8..e4893949 100644 --- a/test/unit/lib/mergeDeep.test.js +++ b/test/unit/lib/mergeDeep.test.js @@ -1013,3 +1013,15 @@ it('CompareDeep produces correct result for arrays of named objects', () => { expect(result.modifications.teams).toEqual(['developers']) }) + +it('CompareDeep result has changes when source is empty and target is not', () => { + const ignorableFields = [] + const mergeDeep = new MergeDeep(log, ignorableFields) + const target = [ + { username: 'unwanted-collaborator' } + ] + const source = [] + const result = mergeDeep.compareDeep(target, source) + + expect(result.hasChanges).toBeTruthy() +})