diff --git a/github/Organization.py b/github/Organization.py index d4e5aa10..fc682966 100644 --- a/github/Organization.py +++ b/github/Organization.py @@ -20,6 +20,7 @@ # Copyright 2018 Tim Boring # # Copyright 2018 sfdye # # Copyright 2018 Steve Kowalik # +# Copyright 2023 Mauricio Martinez # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # @@ -39,6 +40,8 @@ # # ################################################################################ +from __future__ import annotations + from datetime import datetime import github.Event @@ -645,14 +648,16 @@ class Organization(github.GithubObject.CompletableGithubObject): secret_name, unencrypted_value, visibility="all", - selected_repositories=github.GithubObject.NotSet, + selected_repositories: github.GithubObject.Opt[ + list[github.Repository.Repository] + ] = github.GithubObject.NotSet, ): """ :calls: `PUT /orgs/{org}/actions/secrets/{secret_name} `_ :param secret_name: string :param unencrypted_value: string :param visibility: string - :param selected_repositories: list of :class:`github.Repository.Repository` + :param selected_repositories: Optional list of :class:`github.Repository.Repository` :rtype: bool """ assert isinstance(secret_name, str), secret_name @@ -731,6 +736,48 @@ class Organization(github.GithubObject.CompletableGithubObject): ) return github.Team.Team(self._requester, headers, data, completed=True) + def create_variable( + self, + variable_name: str, + value: str, + visibility: str = "all", + selected_repositories: github.GithubObject.Opt[ + list[github.Repository.Repository] + ] = github.GithubObject.NotSet, + ) -> bool: + """ + :calls: `PUT /orgs/{org}/actions/variables/ `_ + :param variable_name: string + :param value: string + :param visibility: string + :param selected_repositories: list of :class:`github.Repository.Repository` + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + assert isinstance(value, str), value + assert isinstance(visibility, str), visibility + if visibility == "selected": + assert isinstance(selected_repositories, list) and all( + isinstance(element, github.Repository.Repository) + for element in selected_repositories + ), selected_repositories + else: + assert selected_repositories is github.GithubObject.NotSet + + post_parameters = { + "name": variable_name, + "value": value, + "visibility": visibility, + } + if selected_repositories is not github.GithubObject.NotSet: + post_parameters["selected_repository_ids"] = [ + element.id for element in selected_repositories + ] + status, headers, data = self._requester.requestJson( + "POST", f"{self.url}/actions/variables", input=post_parameters + ) + return status == 201 + def delete_hook(self, id): """ :calls: `DELETE /orgs/{owner}/hooks/{id} `_ @@ -754,6 +801,18 @@ class Organization(github.GithubObject.CompletableGithubObject): ) return status == 204 + def delete_variable(self, variable_name: str) -> bool: + """ + :calls: `DELETE /orgs/{org}/actions/variables/{variable_name} `_ + :param variable_name: string + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + status, headers, data = self._requester.requestJson( + "DELETE", f"{self.url}/actions/variables/{variable_name}" + ) + return status == 204 + def edit( self, billing_email=github.GithubObject.NotSet, @@ -847,6 +906,51 @@ class Organization(github.GithubObject.CompletableGithubObject): ) return github.Hook.Hook(self._requester, headers, data, completed=True) + def update_variable( + self, + variable_name: str, + value: str, + visibility: str = "all", + selected_repositories: github.GithubObject.Opt[ + list[github.Repository.Repository] + ] = github.GithubObject.NotSet, + ) -> bool: + """ + :calls: `PATCH /orgs/{org}/actions/variables/{variable_name} `_ + :param variable_name: string + :param value: string + :param visibility: string + :param selected_repositories: Optional list of :class:`github.Repository.Repository` + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + assert isinstance(value, str), value + assert isinstance(visibility, str), visibility + if visibility == "selected": + assert isinstance(selected_repositories, list) and all( + isinstance(element, github.Repository.Repository) + for element in selected_repositories + ), selected_repositories + else: + assert selected_repositories is github.GithubObject.NotSet + + patch_parameters = { + "name": variable_name, + "value": value, + "visibility": visibility, + } + if selected_repositories is not github.GithubObject.NotSet: + patch_parameters["selected_repository_ids"] = [ + element.id for element in selected_repositories + ] + + status, headers, data = self._requester.requestJson( + "PATCH", + f"{self.url}/actions/variables/{variable_name}", + input=patch_parameters, + ) + return status == 204 + def get_events(self): """ :calls: `GET /orgs/{org}/events `_ diff --git a/github/Organization.pyi b/github/Organization.pyi index ad443bdc..b392df42 100644 --- a/github/Organization.pyi +++ b/github/Organization.pyi @@ -87,6 +87,13 @@ class Organization(CompletableGithubObject): privacy: Union[str, _NotSetType] = ..., description: Union[str, _NotSetType] = ..., ) -> Team: ... + def create_variable( + self, + variable_name: str, + value: str, + visibility: str = ..., + selected_repositories: Union[List[Repository], _NotSetType] = ..., + ) -> bool: ... @property def created_at(self) -> datetime: ... def delete_hook(self, id: int) -> None: ... @@ -97,6 +104,7 @@ class Organization(CompletableGithubObject): def description(self) -> str: ... @property def disk_usage(self) -> int: ... + def delete_variable(self, variable_name: str) -> bool: ... def edit( self, billing_email: Union[str, _NotSetType] = ..., @@ -115,6 +123,13 @@ class Organization(CompletableGithubObject): events: Union[_NotSetType, List[str]] = ..., active: Union[bool, _NotSetType] = ..., ) -> Hook: ... + def update_variable( + self, + variable_name: str, + value: str, + visibility: str = ..., + selected_repositories: Union[List[Repository], _NotSetType] = ..., + ) -> bool: ... @property def email(self) -> Optional[str]: ... @property diff --git a/github/Repository.py b/github/Repository.py index 1710bb45..680b3237 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -104,6 +104,7 @@ # Copyright 2023 Jonathan Leitschuh # # Copyright 2023 Sol Redfern <59831933+Tsuesun@users.noreply.github.com> # # Copyright 2023 Mikhail f. Shiryaev # +# Copyright 2023 Mauricio Martinez # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # @@ -1714,6 +1715,44 @@ class Repository(github.GithubObject.CompletableGithubObject): ) return status == 201 + def create_variable(self, variable_name: str, value: str) -> bool: + """ + :calls: `POST /repos/{owner}/{repo}/actions/variables/{variable_name} `_ + :param variable_name: string + :param value: string + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + assert isinstance(value, str), value + post_parameters = { + "name": variable_name, + "value": value, + } + status, headers, data = self._requester.requestJson( + "POST", f"{self.url}/actions/variables", input=post_parameters + ) + return status == 201 + + def update_variable(self, variable_name: str, value: str) -> bool: + """ + :calls: `PATCH /repos/{owner}/{repo}/actions/variables/{variable_name} `_ + :param variable_name: string + :param value: string + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + assert isinstance(value, str), value + patch_parameters = { + "name": variable_name, + "value": value, + } + status, headers, data = self._requester.requestJson( + "PATCH", + f"{self.url}/actions/variables/{variable_name}", + input=patch_parameters, + ) + return status == 204 + def delete_secret(self, secret_name): """ :calls: `DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name} `_ @@ -1726,6 +1765,18 @@ class Repository(github.GithubObject.CompletableGithubObject): ) return status == 204 + def delete_variable(self, variable_name: str) -> bool: + """ + :calls: `DELETE /repos/{owner}/{repo}/actions/variables/{variable_name} `_ + :param variable_name: string + :rtype: bool + """ + assert isinstance(variable_name, str), variable_name + status, headers, data = self._requester.requestJson( + "DELETE", f"{self.url}/actions/variables/{variable_name}" + ) + return status == 204 + def create_source_import( self, vcs, diff --git a/github/Repository.pyi b/github/Repository.pyi index 8cbfeece..558f93d6 100644 --- a/github/Repository.pyi +++ b/github/Repository.pyi @@ -296,7 +296,10 @@ class Repository(CompletableGithubObject): self, event_type: str, client_payload: Union[Dict[str, Any], _NotSetType] = ... ) -> bool: ... def create_secret(self, secret_name: str, unencrypted_value: str) -> bool: ... + def create_variable(self, variable_name: str, value: str) -> bool: ... + def update_variable(self, variable_name: str, value: str) -> bool: ... def delete_secret(self, secret_name: str) -> bool: ... + def delete_variable(self, variable_name: str) -> bool: ... def create_source_import( self, vcs: str, diff --git a/tests/Organization.py b/tests/Organization.py index 4504063f..d5a27d6f 100644 --- a/tests/Organization.py +++ b/tests/Organization.py @@ -13,6 +13,7 @@ # Copyright 2018 Raihaan <31362124+res0nance@users.noreply.github.com> # # Copyright 2018 Tim Boring # # Copyright 2018 sfdye # +# Copyright 2023 Mauricio Martinez # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # @@ -509,3 +510,9 @@ class Organization(Framework.TestCase): self.assertEqual(installations[0].target_id, 3344556) self.assertEqual(installations[0].target_type, "User") self.assertEqual(installations.totalCount, 1) + + def testOrgVariable(self): + self.org = self.g.get_organization("tecnoly") + self.assertTrue(self.org.create_variable("variable_name", "variable-value")) + self.assertTrue(self.org.update_variable("variable_name", "variable-value123")) + self.assertTrue(self.org.delete_variable("variable_name")) diff --git a/tests/ReplayData/Organization.testOrgVariable.txt b/tests/ReplayData/Organization.testOrgVariable.txt new file mode 100644 index 00000000..3fe9fe1c --- /dev/null +++ b/tests/ReplayData/Organization.testOrgVariable.txt @@ -0,0 +1,44 @@ +https +GET +api.github.com +None +/orgs/tecnoly +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:30 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"151546d41ba356a3ab126e7c41b4eac41d400db050ebc80fe18396328233c2af"'), ('Last-Modified', 'Wed, 30 Nov 2022 08:14:01 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org, read:org, repo, user, write:org'), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4900'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '100'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', '6590:2BA8:EAFB2:1DBE2F:649C87C2')] +{"login":"tecnoly","id":87164276,"node_id":"MDEyOk9yZ2FuaXphdGlvbjg3MTY0Mjc2","url":"https://api.github.com/orgs/tecnoly","repos_url":"https://api.github.com/orgs/tecnoly/repos","events_url":"https://api.github.com/orgs/tecnoly/events","hooks_url":"https://api.github.com/orgs/tecnoly/hooks","issues_url":"https://api.github.com/orgs/tecnoly/issues","members_url":"https://api.github.com/orgs/tecnoly/members{/member}","public_members_url":"https://api.github.com/orgs/tecnoly/public_members{/member}","avatar_url":"https://avatars.githubusercontent.com/u/87164276?v=4","description":"","name":"Tecnoly","company":null,"blog":null,"location":"Mexico","email":null,"twitter_username":null,"is_verified":false,"has_organization_projects":true,"has_repository_projects":true,"public_repos":5,"public_gists":0,"followers":0,"following":0,"html_url":"https://github.com/tecnoly","created_at":"2021-07-09T04:52:53Z","updated_at":"2022-11-30T08:14:01Z","type":"Organization","total_private_repos":0,"owned_private_repos":0,"private_gists":0,"disk_usage":2205,"collaborators":0,"billing_email":"mmartinez@tecno.ly","default_repository_permission":"read","members_can_create_repositories":true,"two_factor_requirement_enabled":true,"members_allowed_repository_creation_type":"public","members_can_create_public_repositories":true,"members_can_create_private_repositories":false,"members_can_create_internal_repositories":false,"members_can_create_pages":true,"members_can_fork_private_repositories":false,"web_commit_signoff_required":false,"members_can_create_public_pages":true,"members_can_create_private_pages":true,"plan":{"name":"free","space":976562499,"private_repos":10000,"filled_seats":2,"seats":0},"advanced_security_enabled_for_new_repositories":false,"dependabot_alerts_enabled_for_new_repositories":true,"dependabot_security_updates_enabled_for_new_repositories":true,"dependency_graph_enabled_for_new_repositories":true,"secret_scanning_enabled_for_new_repositories":false,"secret_scanning_push_protection_enabled_for_new_repositories":false,"secret_scanning_push_protection_custom_link_enabled":false,"secret_scanning_push_protection_custom_link":null} + +https +POST +api.github.com +None +/orgs/tecnoly/actions/variables +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'} +{"name": "variable_name", "value": "variable-value", "visibility": "all"} +201 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:26 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Content-Length', '2'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', '"ab9b40dea6722e415dd424b31be226eac6da76ca693e83c73fed865610a4937e"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org'), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4905'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '95'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('X-GitHub-Request-Id', '6FD1:95BE:1234AD:24C286:649C87BD')] +{} + +https +PATCH +api.github.com +None +/orgs/tecnoly/actions/variables/variable_name +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'} +{"name": "variable_name", "value": "variable-value123", "visibility": "all"} +204 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:26 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org'), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4904'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '96'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('X-GitHub-Request-Id', '6BED:76E5:D6F66:1B439F:649C87BE')] + + +https +DELETE +api.github.com +None +/orgs/tecnoly/actions/variables/variable_name +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +204 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:27 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org'), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4903'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '97'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('X-GitHub-Request-Id', '60E5:796C:F6B59:1F4388:649C87BF')] + + diff --git a/tests/ReplayData/Repository.testRepoVariable.txt b/tests/ReplayData/Repository.testRepoVariable.txt new file mode 100644 index 00000000..9823a5a9 --- /dev/null +++ b/tests/ReplayData/Repository.testRepoVariable.txt @@ -0,0 +1,33 @@ +https +POST +api.github.com +None +/repos/jacquev6/PyGithub/actions/variables +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'} +{"name": "variable_name", "value": "variable-value"} +201 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:32 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Content-Length', '2'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', '"ab9b40dea6722e415dd424b31be226eac6da76ca693e83c73fed865610a4937e"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', ''), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4899'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '101'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('X-GitHub-Request-Id', '608F:387C:CEA47:1A4258:649C87C3')] +{} + +https +PATCH +api.github.com +None +/repos/jacquev6/PyGithub/actions/variables/variable_name +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'} +{"name": "variable_name", "value": "variable-value123"} +204 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:33 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', ''), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4898'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '102'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('X-GitHub-Request-Id', '6BD2:49D7:E5FA9:1D2240:649C87C5')] + + +https +DELETE +api.github.com +None +/repos/jacquev6/PyGithub/actions/variables/variable_name +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +204 +[('Server', 'GitHub.com'), ('Date', 'Wed, 28 Jun 2023 19:19:35 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, admin:ssh_signing_key, audit_log, codespace, delete:packages, delete_repo, gist, notifications, project, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', ''), ('github-authentication-token-expiration', '2023-07-05 17:42:21 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4897'), ('X-RateLimit-Reset', '1687981543'), ('X-RateLimit-Used', '103'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('X-GitHub-Request-Id', '10FC:400A:BB162:17BE3C:649C87C6')] + + diff --git a/tests/Repository.py b/tests/Repository.py index 641a2025..0b2cc9e1 100644 --- a/tests/Repository.py +++ b/tests/Repository.py @@ -27,6 +27,7 @@ # Copyright 2018 Will Yardley # # Copyright 2018 sfdye # # Copyright 2020 Pascal Hofmann # +# Copyright 2023 Mauricio Martinez # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # @@ -1931,6 +1932,11 @@ class Repository(Framework.TestCase): self.assertEqual("refs/tags/v0.5", refs[4].ref) self.assertEqual("refs/tags/v0.6", refs[5].ref) + def testRepoVariable(self): + self.assertTrue(self.repo.create_variable("variable_name", "variable-value")) + self.assertTrue(self.repo.update_variable("variable_name", "variable-value123")) + self.assertTrue(self.repo.delete_variable("variable_name")) + class LazyRepository(Framework.TestCase): def setUp(self):