diff --git a/github_deploy/commands/_constants.py b/github_deploy/commands/_constants.py index 1249c71..a8fb431 100644 --- a/github_deploy/commands/_constants.py +++ b/github_deploy/commands/_constants.py @@ -1,2 +1,2 @@ REPOS_URL = "https://api.github.com/search/repositories?q=org:{org}" -BASE_URL = "https://api.github.com/repos/{repo}/contents/{path}" +FILE_CONTENTS_URL = "https://api.github.com/repos/{repo}/contents/{path}" diff --git a/github_deploy/commands/_repo_utils.py b/github_deploy/commands/_repo_utils.py index 438d970..64b7d55 100644 --- a/github_deploy/commands/_repo_utils.py +++ b/github_deploy/commands/_repo_utils.py @@ -1,9 +1,11 @@ import base64 +import os import aiofiles import asyncclick as click +from aiofiles import os as aiofiles_os -from github_deploy.commands._constants import REPOS_URL, BASE_URL +from github_deploy.commands._constants import REPOS_URL, FILE_CONTENTS_URL from github_deploy.commands._http_utils import get, delete, put from github_deploy.commands._utils import get_headers @@ -29,7 +31,7 @@ async def delete_content( if exists: data["sha"] = current_sha - url = BASE_URL.format(repo=repo, path=dest) + url = FILE_CONTENTS_URL.format(repo=repo, path=dest) async with semaphore: response = await delete( @@ -40,7 +42,7 @@ async def delete_content( async def check_exists(*, session, repo, dest, token, semaphore, skip_missing): - url = BASE_URL.format(repo=repo, path=dest) + url = FILE_CONTENTS_URL.format(repo=repo, path=dest) async with semaphore: response = await get( @@ -62,6 +64,7 @@ async def upload_content( token, semaphore, exists, + only_update, current_sha, current_content ): @@ -73,6 +76,19 @@ async def upload_content( if current_content == base64_content: click.echo("Skipping: Contents are the same.") return + else: + if exists: + click.echo("Storing backup of existing file...") + + dirname, filename = os.path.split(f"{repo}/{dest}") + + await aiofiles_os.makedirs(dirname, exist_ok=True) + + async with aiofiles.open(f"{dirname}/{filename}", mode="wb") as f: + await f.write(base64.b64decode(current_content)) + elif only_update: + click.echo(f"Skipping: only updating existing files.") + return data = { "message": f"Updated {dest}" @@ -83,7 +99,9 @@ async def upload_content( if exists: data["sha"] = current_sha - url = BASE_URL.format(repo=repo, path=dest) + url = FILE_CONTENTS_URL.format(repo=repo, path=dest) + + click.echo(f"Uploading {source} to {repo}/{dest}...") async with semaphore: response = await put( diff --git a/github_deploy/commands/upload.py b/github_deploy/commands/upload.py index 3baf4a3..9d2e32d 100644 --- a/github_deploy/commands/upload.py +++ b/github_deploy/commands/upload.py @@ -8,7 +8,7 @@ async def handle_file_upload( - *, repo, source, dest, overwrite, token, semaphore, session + *, repo, source, dest, overwrite, only_update, token, semaphore, session ): check_exists_response = await check_exists( session=session, @@ -23,19 +23,18 @@ async def handle_file_upload( current_content = check_exists_response.get("content") exists = current_sha is not None - if exists and not overwrite: - return click.style( - "Skipped uploading {source} to {repo}/{path}: Found an existing copy.".format( - source=source, - repo=repo, - path=dest, - ), - fg="blue", - bold=True, - ) - - else: - if exists: + if exists: + if not overwrite: + return click.style( + "Skipped uploading {source} to {repo}/{path}: Found an existing copy.".format( + source=source, + repo=repo, + path=dest, + ), + fg="blue", + bold=True, + ) + else: click.echo( click.style( "Found an existing copy at {repo}/{path} overwriting it's contents...".format( @@ -45,36 +44,32 @@ async def handle_file_upload( ), ) - upload_response = await upload_content( - session=session, - repo=repo, - source=source, - dest=dest, - token=token, - semaphore=semaphore, - exists=exists, - current_sha=current_sha, - current_content=current_content, - ) + upload_response = await upload_content( + session=session, + repo=repo, + source=source, + dest=dest, + token=token, + semaphore=semaphore, + exists=exists, + only_update=only_update, + current_sha=current_sha, + current_content=current_content, + ) - if upload_response: - return click.style( - "Successfully uploaded '{source}' to {repo}/{dest}".format( - source=upload_response["content"]["name"], - repo=repo, - dest=upload_response["content"]["path"], - ), - fg="green", - bold=True, - ) + if upload_response: + return click.style( + "Successfully uploaded '{source}' to {repo}/{dest}".format( + source=upload_response["content"]["name"], + repo=repo, + dest=upload_response["content"]["path"], + ), + fg="green", + bold=True, + ) @click.command() -@click.option( - "--org", - prompt=click.style("Enter your github user/organization", bold=True), - help="The github organization.", -) @click.option( "--token", prompt=click.style("Enter your personal access token", bold=True), @@ -82,6 +77,11 @@ async def handle_file_upload( hide_input=True, envvar="TOKEN", ) +@click.option( + "--org", + prompt=click.style("Enter your github user/organization", bold=True), + help="The github organization.", +) @click.option( "--source", prompt=click.style("Enter path to source file", fg="blue"), @@ -98,16 +98,30 @@ async def handle_file_upload( prompt=click.style( "Should we overwrite existing contents at this path", fg="blue" ), + is_flag=True, + show_default=True, help="Overwrite existing files.", default=False, ) +@click.option( + "--only-update/--no-only-update", + prompt=click.style( + "Should we only update existing files at this path", fg="blue" + ), + is_flag=True, + show_default=True, + help="Only update existing files.", + default=False, +) @click.option( "--private/--no-private", prompt=click.style("Should we Include private repositories", bold=True), + is_flag=True, + show_default=True, help="Upload files to private repositories.", default=True, ) -async def main(org, token, source, dest, overwrite, private): +async def main(org, token, source, dest, overwrite, only_update, private): """Upload a file to all repositories owned by an organization/user.""" # create instance of Semaphore: max concurrent requests. semaphore = asyncio.Semaphore(1000) @@ -171,6 +185,7 @@ async def main(org, token, source, dest, overwrite, private): dest=dest, token=token, overwrite=overwrite, + only_update=only_update, session=session, semaphore=semaphore, )
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: