diff --git a/Default.sublime-commands b/Default.sublime-commands index fba1c5f73..cfac3ac3e 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -136,6 +136,10 @@ "caption": "github: add fork as remote", "command": "gs_github_add_fork_as_remote" }, + { + "caption": "github: create repo", + "command": "gs_github_create_repo" + }, { "caption": "github: create fork", "command": "gs_github_create_fork" diff --git a/github/commands/__init__.py b/github/commands/__init__.py index 8031c237b..9b575261c 100644 --- a/github/commands/__init__.py +++ b/github/commands/__init__.py @@ -2,6 +2,7 @@ from .commit import * from .configure import * from .create_fork import * +from .create_repo import * from .add_fork_as_remote import * from .pull_request import * from .open_issue import * diff --git a/github/commands/create_repo.py b/github/commands/create_repo.py new file mode 100644 index 000000000..3aee5014d --- /dev/null +++ b/github/commands/create_repo.py @@ -0,0 +1,63 @@ +from functools import partial +import os + +from GitSavvy.common import util +from GitSavvy.core.base_commands import GsWindowCommand +from GitSavvy.core.ui_mixins.input_panel import show_single_line_input_panel +from GitSavvy.core.utils import show_panel +from GitSavvy.core.runtime import on_worker +from GitSavvy.github import github + +from GitSavvy.core.base_commands import Args, GsCommand, Kont + + +__all__ = ( + "gs_github_create_repo", +) + + +def ask_for_repo_name(cmd: GsCommand, args: Args, done: Kont) -> None: + suggestion = ( + os.path.basename(folders[0]) + if (folders := cmd.window.folders()) + else "" + ) + + def on_done(name: str) -> None: + if name: + done(name) + + show_single_line_input_panel("New Repo Name:", suggestion, on_done) + + +def get_github_user_token(cmd: GsCommand, args: Args, done: Kont) -> None: + fqdn = "github.com" + token = cmd.savvy_settings.get("api_tokens", {}).get(fqdn) + if not token: + cmd.window.status_message(f"Abort, no API token found in the settings for {fqdn}.") + return + done(token) + + +class gs_github_create_repo(GsWindowCommand): + defaults = { + "token": get_github_user_token, + "name": ask_for_repo_name + } + + @on_worker + def run(self, token: str, name: str) -> None: + payload = github.create_user_repo(token, name) + self.window.status_message("The repo was created successfully.") + urls = [payload["clone_url"], payload["ssh_url"]] + + def on_remote_name(name: str) -> None: + show_panel(self.window, urls, partial(on_url, name)) + + def on_url(name: str, idx: int) -> None: + url = urls[idx] + self.git("remote", "add", name, url) + self.window.status_message("The new remote was added successfully.") + util.view.refresh_gitsavvy_interfaces(self.window) + + show_single_line_input_panel("Add repo as", "origin", on_remote_name) diff --git a/github/github.py b/github/github.py index 3065ca63e..a524730bb 100644 --- a/github/github.py +++ b/github/github.py @@ -2,6 +2,7 @@ GitHub methods that are functionally separate from anything Sublime-related. """ +from __future__ import annotations import re from webbrowser import open as open_in_browser from functools import partial @@ -230,3 +231,19 @@ def create_fork(github_repo: GitHubRepo, default_branch_only: bool = False): github_repo, {"default_branch_only": default_branch_only} ) + + +def create_user_repo(token: str, repo_name: str) -> dict: + return create_repo(token, None, repo_name) + + +def create_repo(token: str, org: str | None, repo_name: str) -> dict: + host = "api.github.com" + path = f"/orgs/{org}/repos" if org else "/user/repos" + auth = (token, "x-oauth-basic") + payload = {"name": repo_name} + + response = interwebs.post(host, 443, path, https=True, auth=auth, payload=payload) + validate_response(response, method="POST") + + return response.payload