Organization.py
1 ############################ Copyrights and license ############################ 2 # # 3 # Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> # 4 # Copyright 2012 Zearin <zearin@gonk.net> # 5 # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # 6 # Copyright 2014 Vincent Jacques <vincent@vincent-jacques.net> # 7 # Copyright 2016 Jannis Gebauer <ja.geb@me.com> # 8 # Copyright 2016 Peter Buckley <dx-pbuckley@users.noreply.github.com> # 9 # Copyright 2017 Balázs Rostás <rostas.balazs@gmail.com> # 10 # Copyright 2018 Anton Nguyen <afnguyen85@gmail.com> # 11 # Copyright 2018 Jacopo Notarstefano <jacopo.notarstefano@gmail.com> # 12 # Copyright 2018 Jasper van Wanrooy <jasper@vanwanrooy.net> # 13 # Copyright 2018 Raihaan <31362124+res0nance@users.noreply.github.com> # 14 # Copyright 2018 Tim Boring <tboring@hearst.com> # 15 # Copyright 2018 sfdye <tsfdye@gmail.com> # 16 # Copyright 2023 Mauricio Martinez <mauricio.martinez@premise.com> # 17 # # 18 # This file is part of PyGithub. # 19 # http://pygithub.readthedocs.io/ # 20 # # 21 # PyGithub is free software: you can redistribute it and/or modify it under # 22 # the terms of the GNU Lesser General Public License as published by the Free # 23 # Software Foundation, either version 3 of the License, or (at your option) # 24 # any later version. # 25 # # 26 # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # 27 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # 28 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # 29 # details. # 30 # # 31 # You should have received a copy of the GNU Lesser General Public License # 32 # along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # 33 # # 34 ################################################################################ 35 36 from datetime import datetime, timezone 37 from unittest import mock 38 39 import github 40 41 from . import Framework 42 43 44 class Organization(Framework.TestCase): 45 def setUp(self): 46 super().setUp() 47 self.org = self.g.get_organization("BeaverSoftware") 48 49 def testAttributes(self): 50 self.assertEqual(self.org.avatar_url, "https://avatars1.githubusercontent.com/u/1?v=4") 51 self.assertEqual(self.org.billing_email, "foo@example.com") 52 self.assertEqual(self.org.blog, "http://www.example.com") 53 self.assertEqual(self.org.collaborators, 9) 54 self.assertEqual(self.org.company, None) 55 self.assertEqual( 56 self.org.created_at, 57 datetime(2014, 1, 9, 16, 56, 17, tzinfo=timezone.utc), 58 ) 59 self.assertEqual(self.org.default_repository_permission, "none") 60 self.assertEqual(self.org.description, "BeaverSoftware writes software.") 61 self.assertEqual(self.org.disk_usage, 2) 62 self.assertEqual(self.org.email, "") 63 self.assertEqual(self.org.followers, 0) 64 self.assertEqual(self.org.following, 0) 65 self.assertEqual(self.org.gravatar_id, None) 66 self.assertTrue(self.org.has_organization_projects) 67 self.assertTrue(self.org.has_repository_projects) 68 self.assertEqual(self.org.hooks_url, "https://api.github.com/orgs/BeaverSoftware/hooks") 69 self.assertEqual(self.org.html_url, "https://github.com/BeaverSoftware") 70 self.assertEqual(self.org.id, 1) 71 self.assertEqual(self.org.issues_url, "https://api.github.com/orgs/BeaverSoftware/issues") 72 self.assertEqual(self.org.location, "Paris, France") 73 self.assertEqual(self.org.login, "BeaverSoftware") 74 self.assertFalse(self.org.members_can_create_repositories) 75 self.assertEqual(self.org.name, "BeaverSoftware") 76 self.assertEqual(self.org.owned_private_repos, 0) 77 self.assertEqual(self.org.plan.name, "free") 78 self.assertEqual(self.org.plan.private_repos, 3) 79 self.assertEqual(self.org.plan.space, 1) 80 self.assertEqual(self.org.plan.filled_seats, 3) 81 self.assertEqual(self.org.plan.seats, 0) 82 self.assertEqual(self.org.private_gists, 0) 83 self.assertEqual(self.org.public_gists, 0) 84 self.assertEqual(self.org.public_repos, 27) 85 self.assertEqual(self.org.total_private_repos, 7) 86 self.assertEqual(self.org.two_factor_requirement_enabled, None) 87 self.assertEqual(self.org.type, "Organization") 88 self.assertEqual(self.org.url, "https://api.github.com/orgs/BeaverSoftware") 89 self.assertEqual(repr(self.org), 'Organization(login="BeaverSoftware")') 90 91 def testAddMembersDefaultRole(self): 92 lyloa = self.g.get_user("lyloa") 93 self.assertFalse(self.org.has_in_members(lyloa)) 94 self.org.add_to_members(lyloa, role="member") 95 # 'Pending' members won't be in /orgs/:org/members/:user 96 self.assertFalse(self.org.has_in_members(lyloa)) 97 self.org.remove_from_membership(lyloa) 98 self.assertFalse(self.org.has_in_members(lyloa)) 99 100 def testAddMembersAdminRole(self): 101 lyloa = self.g.get_user("lyloa") 102 self.assertFalse(self.org.has_in_members(lyloa)) 103 self.org.add_to_members(lyloa, role="admin") 104 # 'Pending' members won't be in /orgs/:org/members/:user 105 self.assertFalse(self.org.has_in_members(lyloa)) 106 self.org.remove_from_membership(lyloa) 107 self.assertFalse(self.org.has_in_members(lyloa)) 108 109 def testEditWithoutArguments(self): 110 self.org.edit() 111 112 def testEditWithAllArguments(self): 113 self.org.edit( 114 "BeaverSoftware2@vincent-jacques.net", 115 "http://vincent-jacques.net", 116 "Company edited by PyGithub", 117 "Description edited by PyGithub", 118 "BeaverSoftware2@vincent-jacques.net", 119 "Location edited by PyGithub", 120 "Name edited by PyGithub", 121 ) 122 self.assertEqual(self.org.billing_email, "BeaverSoftware2@vincent-jacques.net") 123 self.assertEqual(self.org.blog, "http://vincent-jacques.net") 124 self.assertEqual(self.org.company, "Company edited by PyGithub") 125 self.assertEqual(self.org.description, "Description edited by PyGithub") 126 self.assertEqual(self.org.email, "BeaverSoftware2@vincent-jacques.net") 127 self.assertEqual(self.org.location, "Location edited by PyGithub") 128 self.assertEqual(self.org.name, "Name edited by PyGithub") 129 130 def testEditHookWithMinimalParameters(self): 131 hook = self.org.create_hook("web", {"url": "http://foobar.com"}) 132 hook = self.org.edit_hook(hook.id, "mobile", {"url": "http://barfoo.com"}) 133 self.assertEqual(hook.name, "mobile") 134 135 def testEditHookWithAllParameters(self): 136 hook = self.org.create_hook("web", {"url": "http://foobar.com"}, ["fork"], False) 137 hook = self.org.edit_hook(hook.id, "mobile", {"url": "http://barfoo.com"}, ["spoon"], True) 138 self.assertEqual(hook.name, "mobile") 139 self.assertEqual(hook.events, ["spoon"]) 140 self.assertEqual(hook.active, True) 141 142 def testCreateTeam(self): 143 team = self.org.create_team("Team created by PyGithub") 144 self.assertEqual(team.id, 189850) 145 146 def testCreateTeamWithAllArguments(self): 147 repo = self.org.get_repo("FatherBeaver") 148 team = self.org.create_team( 149 "Team also created by PyGithub", 150 [repo], 151 "push", 152 "secret", 153 "Description also created by PyGithub", 154 ) 155 self.assertEqual(team.id, 189852) 156 self.assertEqual(team.description, "Description also created by PyGithub") 157 158 def testDeleteHook(self): 159 hook = self.org.create_hook("web", {"url": "http://foobar.com"}) 160 self.org.delete_hook(hook.id) 161 162 def testPublicMembers(self): 163 lyloa = self.g.get_user("Lyloa") 164 self.assertFalse(self.org.has_in_public_members(lyloa)) 165 self.org.add_to_public_members(lyloa) 166 self.assertTrue(self.org.has_in_public_members(lyloa)) 167 self.org.remove_from_public_members(lyloa) 168 self.assertFalse(self.org.has_in_public_members(lyloa)) 169 170 def testGetPublicMembers(self): 171 self.assertListKeyEqual(self.org.get_public_members(), lambda u: u.login, ["jacquev6"]) 172 173 def testGetHook(self): 174 hook = self.org.get_hook(257993) 175 self.assertEqual(hook.name, "web") 176 177 def testGetHooks(self): 178 self.assertListKeyEqual(self.org.get_hooks(), lambda h: h.id, [257993]) 179 180 def testGetHookDelivery(self): 181 delivery = self.org.get_hook_delivery(257993, 12345) 182 self.assertEqual(delivery.id, 12345) 183 self.assertEqual(delivery.guid, "abcde-12345") 184 self.assertEqual( 185 delivery.delivered_at, 186 datetime(2012, 5, 27, 6, 0, 32, tzinfo=timezone.utc), 187 ) 188 self.assertEqual(delivery.redelivery, False) 189 self.assertEqual(delivery.duration, 0.27) 190 self.assertEqual(delivery.status, "OK") 191 self.assertEqual(delivery.status_code, 200) 192 self.assertEqual(delivery.event, "issues") 193 self.assertEqual(delivery.action, "opened") 194 self.assertEqual(delivery.installation_id, 123) 195 self.assertEqual(delivery.repository_id, 456) 196 self.assertEqual(delivery.url, "https://www.example-webhook.com") 197 self.assertIsInstance(delivery.request, github.HookDelivery.HookDeliveryRequest) 198 self.assertEqual(delivery.request.headers, {"content-type": "application/json"}) 199 self.assertEqual(delivery.request.payload, {"action": "opened"}) 200 self.assertIsInstance(delivery.response, github.HookDelivery.HookDeliveryResponse) 201 self.assertEqual(delivery.response.headers, {"content-type": "text/html;charset=utf-8"}) 202 self.assertEqual(delivery.response.payload, "ok") 203 204 def testGetHookDeliveries(self): 205 deliveries = list(self.org.get_hook_deliveries(257993)) 206 self.assertEqual(len(deliveries), 1) 207 self.assertEqual(deliveries[0].id, 12345) 208 self.assertEqual(deliveries[0].guid, "abcde-12345") 209 self.assertEqual( 210 deliveries[0].delivered_at, 211 datetime(2012, 5, 27, 6, 0, 32, tzinfo=timezone.utc), 212 ) 213 self.assertEqual(deliveries[0].redelivery, False) 214 self.assertEqual(deliveries[0].duration, 0.27) 215 self.assertEqual(deliveries[0].status, "OK") 216 self.assertEqual(deliveries[0].status_code, 200) 217 self.assertEqual(deliveries[0].event, "issues") 218 self.assertEqual(deliveries[0].action, "opened") 219 self.assertEqual(deliveries[0].installation_id, 123) 220 self.assertEqual(deliveries[0].repository_id, 456) 221 self.assertEqual(deliveries[0].url, "https://www.example-webhook.com") 222 223 def testGetIssues(self): 224 self.assertListKeyEqual(self.org.get_issues(), lambda i: i.id, []) 225 226 def testGetIssuesWithAllArguments(self): 227 requestedByUser = self.g.get_user().get_repo("PyGithub").get_label("Requested by user") 228 issues = self.org.get_issues( 229 "assigned", 230 "closed", 231 [requestedByUser], 232 "comments", 233 "asc", 234 datetime(2012, 5, 28, 23, 0, 0, tzinfo=timezone.utc), 235 ) 236 self.assertListKeyEqual(issues, lambda i: i.id, []) 237 238 def testGetMembers(self): 239 self.assertListKeyEqual(self.org.get_members(), lambda u: u.login, ["cjuniet", "jacquev6", "Lyloa"]) 240 241 def testGetOutsideCollaborators(self): 242 self.assertListKeyEqual(self.org.get_outside_collaborators(), lambda u: u.login, ["octocat"]) 243 244 def testOutsideCollaborators(self): 245 octocat = self.g.get_user("octocat") 246 self.org.convert_to_outside_collaborator(octocat) 247 self.assertListKeyEqual(self.org.get_outside_collaborators(), lambda u: u.login, ["octocat"]) 248 self.org.remove_outside_collaborator(octocat) 249 self.assertEqual(list(self.org.get_outside_collaborators()), []) 250 251 def testMembers(self): 252 lyloa = self.g.get_user("Lyloa") 253 self.assertTrue(self.org.has_in_members(lyloa)) 254 self.org.remove_from_members(lyloa) 255 self.assertFalse(self.org.has_in_members(lyloa)) 256 257 def testGetRepos(self): 258 repos = self.org.get_repos() 259 self.assertListKeyEqual(repos, lambda r: r.name, ["FatherBeaver", "TestPyGithub"]) 260 self.assertListKeyEqual(repos, lambda r: r.has_pages, [True, False]) 261 self.assertListKeyEqual(repos, lambda r: r.has_wiki, [True, True]) 262 263 def testGetReposSorted(self): 264 repos = self.org.get_repos(sort="updated", direction="desc") 265 self.assertListKeyEqual( 266 repos, 267 lambda r: r.name, 268 ["TestPyGithub", "FatherBeaver"], 269 ) 270 self.assertListKeyEqual( 271 repos, 272 lambda r: r.has_pages, 273 [False, True], 274 ) 275 276 def testGetReposWithType(self): 277 repos = self.org.get_repos("public") 278 self.assertListKeyEqual(repos, lambda r: r.name, ["FatherBeaver", "PyGithub"]) 279 self.assertListKeyEqual(repos, lambda r: r.has_pages, [True, True]) 280 281 def testGetEvents(self): 282 self.assertListKeyEqual( 283 self.org.get_events(), 284 lambda e: e.type, 285 [ 286 "CreateEvent", 287 "CreateEvent", 288 "PushEvent", 289 "PushEvent", 290 "DeleteEvent", 291 "DeleteEvent", 292 "PushEvent", 293 "PushEvent", 294 "DeleteEvent", 295 "DeleteEvent", 296 "PushEvent", 297 "PushEvent", 298 "PushEvent", 299 "CreateEvent", 300 "CreateEvent", 301 "CreateEvent", 302 "CreateEvent", 303 "CreateEvent", 304 "PushEvent", 305 "PushEvent", 306 "PushEvent", 307 "PushEvent", 308 "PushEvent", 309 "PushEvent", 310 "ForkEvent", 311 "CreateEvent", 312 ], 313 ) 314 315 def testGetTeams(self): 316 self.assertListKeyEqual(self.org.get_teams(), lambda t: t.name, ["Members", "Owners"]) 317 318 def testGetTeamBySlug(self): 319 team = self.org.get_team_by_slug("Members") 320 self.assertEqual(team.id, 141496) 321 322 def testCreateHookWithMinimalParameters(self): 323 hook = self.org.create_hook("web", {"url": "http://foobar.com"}) 324 self.assertEqual(hook.id, 257967) 325 326 def testCreateHookWithAllParameters(self): 327 hook = self.org.create_hook("web", {"url": "http://foobar.com"}, ["fork"], False) 328 self.assertTrue(hook.active) 329 self.assertEqual(hook.id, 257993) 330 331 def testCreateRepoWithMinimalArguments(self): 332 repo = self.org.create_repo(name="TestPyGithub") 333 self.assertEqual(repo.url, "https://api.github.com/repos/BeaverSoftware/TestPyGithub") 334 self.assertTrue(repo.has_wiki) 335 self.assertTrue(repo.has_pages) 336 337 def testCreateRepoWithAllArguments(self): 338 team = self.org.get_team(141496) 339 repo = self.org.create_repo( 340 name="TestPyGithub2", 341 description="Repo created by PyGithub", 342 homepage="http://foobar.com", 343 private=False, 344 visibility="public", 345 has_issues=False, 346 has_projects=False, 347 has_wiki=False, 348 has_downloads=False, 349 team_id=team.id, 350 allow_update_branch=True, 351 allow_squash_merge=False, 352 allow_merge_commit=False, 353 allow_rebase_merge=True, 354 delete_branch_on_merge=False, 355 ) 356 self.assertEqual(repo.url, "https://api.github.com/repos/BeaverSoftware/TestPyGithub2") 357 self.assertTrue(repo.allow_update_branch) 358 self.assertFalse(repo.has_wiki) 359 self.assertFalse(repo.has_pages) 360 361 def testCreateRepositoryWithAutoInit(self): 362 repo = self.org.create_repo(name="TestPyGithub", auto_init=True, gitignore_template="Python") 363 self.assertEqual(repo.url, "https://api.github.com/repos/BeaverSoftware/TestPyGithub") 364 self.assertTrue(repo.has_pages) 365 self.assertTrue(repo.has_wiki) 366 367 def testCreateFork(self): 368 pygithub = self.g.get_user("jacquev6").get_repo("PyGithub") 369 repo = self.org.create_fork(pygithub) 370 self.assertEqual(repo.url, "https://api.github.com/repos/BeaverSoftware/PyGithub") 371 self.assertFalse(repo.has_wiki) 372 self.assertFalse(repo.has_pages) 373 374 def testCreateRepoFromTemplate(self): 375 template_repo = self.g.get_repo("actions/hello-world-docker-action") 376 377 repo = self.org.create_repo_from_template("hello-world-docker-action-new", template_repo) 378 self.assertEqual( 379 repo.url, 380 "https://api.github.com/repos/BeaverSoftware/hello-world-docker-action-new", 381 ) 382 self.assertFalse(repo.is_template) 383 384 def testCreateRepoFromTemplateWithAllArguments(self): 385 template_repo = self.g.get_repo("actions/hello-world-docker-action") 386 387 description = "My repo from template" 388 private = True 389 repo = self.org.create_repo_from_template( 390 "hello-world-docker-action-new", 391 template_repo, 392 description=description, 393 private=private, 394 ) 395 self.assertEqual(repo.description, description) 396 self.assertTrue(repo.private) 397 398 @mock.patch("github.PublicKey.encrypt") 399 def testCreateSecret(self, encrypt): 400 # encrypt returns a non-deterministic value, we need to mock it so the replay data matches 401 encrypt.return_value = "M+5Fm/BqTfB90h3nC7F3BoZuu3nXs+/KtpXwxm9gG211tbRo0F5UiN0OIfYT83CKcx9oKES9Va4E96/b" 402 secret = self.org.create_secret("secret-name", "secret-value", "all") 403 self.assertIsNotNone(secret) 404 405 @mock.patch("github.PublicKey.encrypt") 406 def testCreateSecretSelected(self, encrypt): 407 repos = [self.org.get_repo("TestPyGithub"), self.org.get_repo("FatherBeaver")] 408 # encrypt returns a non-deterministic value, we need to mock it so the replay data matches 409 encrypt.return_value = "M+5Fm/BqTfB90h3nC7F3BoZuu3nXs+/KtpXwxm9gG211tbRo0F5UiN0OIfYT83CKcx9oKES9Va4E96/b" 410 secret = self.org.create_secret("secret-name", "secret-value", "selected", repos) 411 self.assertIsNotNone(secret) 412 self.assertEqual(secret.visibility, "selected") 413 self.assertEqual(list(secret.selected_repositories), repos) 414 415 def testGetSecret(self): 416 repos = [self.org.get_repo("TestPyGithub"), self.org.get_repo("FatherBeaver")] 417 secret = self.org.get_secret("secret-name") 418 self.assertEqual(secret.name, "secret-name") 419 self.assertEqual(secret.created_at, datetime(2019, 8, 10, 14, 59, 22, tzinfo=timezone.utc)) 420 self.assertEqual(secret.updated_at, datetime(2020, 1, 10, 14, 59, 22, tzinfo=timezone.utc)) 421 self.assertEqual(secret.visibility, "selected") 422 self.assertEqual(list(secret.selected_repositories), repos) 423 self.assertEqual(secret.url, "https://api.github.com/orgs/BeaverSoftware/actions/secrets/secret-name") 424 425 def testGetSecrets(self): 426 secrets = self.org.get_secrets() 427 self.assertEqual(len(list(secrets)), 1) 428 429 def testInviteUserWithNeither(self): 430 with self.assertRaises(AssertionError) as raisedexp: 431 self.org.invite_user() 432 self.assertEqual("specify only one of email or user", str(raisedexp.exception)) 433 434 def testInviteUserWithBoth(self): 435 jacquev6 = self.g.get_user("jacquev6") 436 with self.assertRaises(AssertionError) as raisedexp: 437 self.org.invite_user(email="foo", user=jacquev6) 438 self.assertEqual("specify only one of email or user", str(raisedexp.exception)) 439 440 def testInviteUserByName(self): 441 jacquev6 = self.g.get_user("jacquev6") 442 self.org.invite_user(user=jacquev6) 443 444 def testInviteUserByEmail(self): 445 self.org.invite_user(email="foo@example.com") 446 447 def testInviteUserWithRoleAndTeam(self): 448 team = self.org.create_team("Team created by PyGithub") 449 self.org.invite_user(email="foo@example.com", role="billing_manager", teams=[team]) 450 451 def testInviteUserAsNonOwner(self): 452 with self.assertRaises(github.GithubException) as raisedexp: 453 self.org.invite_user(email="bar@example.com") 454 self.assertEqual(raisedexp.exception.status, 403) 455 self.assertEqual( 456 raisedexp.exception.data, 457 { 458 "documentation_url": "https://developer.github.com/v3/orgs/members/#create-organization-invitation", 459 "message": "You must be an admin to create an invitation to an organization.", 460 }, 461 ) 462 463 def testCreateMigration(self): 464 self.org = self.g.get_organization("sample-test-organisation") 465 self.assertTrue(isinstance(self.org.create_migration(["sample-repo"]), github.Migration.Migration)) 466 467 def testGetMigrations(self): 468 self.org = self.g.get_organization("sample-test-organisation") 469 self.assertEqual(self.org.get_migrations().totalCount, 2) 470 471 def testGetInstallations(self): 472 installations = self.org.get_installations() 473 self.assertEqual(installations[0].id, 123456) 474 self.assertEqual(installations[0].app_id, 10101) 475 self.assertEqual(installations[0].target_id, 3344556) 476 self.assertEqual(installations[0].target_type, "User") 477 self.assertEqual(installations.totalCount, 1) 478 479 def testCreateVariable(self): 480 variable = self.org.create_variable("variable-name", "variable-value", "all") 481 self.assertIsNotNone(variable) 482 483 def testCreateVariableSelected(self): 484 repos = [self.org.get_repo("TestPyGithub"), self.org.get_repo("FatherBeaver")] 485 variable = self.org.create_variable("variable-name", "variable-value", "selected", repos) 486 self.assertIsNotNone(variable) 487 self.assertEqual(list(variable.selected_repositories), repos) 488 489 def testGetVariable(self): 490 repos = [self.org.get_repo("TestPyGithub"), self.org.get_repo("FatherBeaver")] 491 variable = self.org.get_variable("variable-name") 492 self.assertEqual(variable.name, "variable-name") 493 self.assertEqual(variable.created_at, datetime(2019, 8, 10, 14, 59, 22, tzinfo=timezone.utc)) 494 self.assertEqual(variable.updated_at, datetime(2020, 1, 10, 14, 59, 22, tzinfo=timezone.utc)) 495 self.assertEqual(variable.visibility, "selected") 496 self.assertEqual(list(variable.selected_repositories), repos) 497 self.assertEqual(variable.url, "https://api.github.com/orgs/BeaverSoftware/actions/variables/variable-name") 498 499 def testGetVariables(self): 500 variables = self.org.get_variables() 501 self.assertEqual(len(list(variables)), 1)