10000 Merge pull request #32 from tj-python/feat/add-support-for-updating-e… · tj-python/github-deploy@7597f38 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7597f38

Browse files
authored
Merge pull request #32 from tj-python/feat/add-support-for-updating-existing-files
feat: add support for updating existing files
2 parents abe9ad6 + 6b459aa commit 7597f38

File tree

3 files changed

+79
-46
lines changed

3 files changed

+79
-46
lines changed

github_deploy/commands/_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
REPOS_URL = "https://api.github.com/search/repositories?q=org:{org}"
2-
BASE_URL = "https://api.github.com/repos/{repo}/contents/{path}"
2+
FILE_CONTENTS_URL = "https://api.github.com/repos/{repo}/contents/{path}"

github_deploy/commands/_repo_utils.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import base64
2+
import os
23

34
import aiofiles
45
import asyncclick as click
6+
from aiofiles import os as aiofiles_os
57

6-
from github_deploy.commands._constants import REPOS_URL, BASE_URL
8+
from github_deploy.commands._constants import REPOS_URL, FILE_CONTENTS_URL
79
from github_deploy.commands._http_utils import get, delete, put
810
from github_deploy.commands._utils import get_headers
911

@@ -29,7 +31,7 @@ async def delete_content(
2931
if exists:
3032
data["sha"] = current_sha
3133

32-
url = BASE_URL.format(repo=repo, path=dest)
34+
url = FILE_CONTENTS_URL.format(repo=repo, path=dest)
3335

3436
async with semaphore:
3537
response = await delete(
@@ -40,7 +42,7 @@ async def delete_content(
4042

4143

4244
async def check_exists(*, session, repo, dest, token, semaphore, skip_missing):
43-
url = BASE_URL.format(repo=repo, path=dest)
45+
url = FILE_CONTENTS_URL.format(repo=repo, path=dest)
4446

4547
async with semaphore:
4648
response = await get(
@@ -62,6 +64,7 @@ async def upload_content(
6264
token,
6365
semaphore,
6466
exists,
67+
only_update,
6568
current_sha,
6669
current_content
6770
):
@@ -73,6 +76,19 @@ async def upload_content(
7376
if current_content == base64_content:
7477
click.echo("Skipping: Contents are the same.")
7578
return
79+
else:
80+
if exists:
81+
click.echo("Storing backup of existing file...")
82+
83+
dirname, filename = os.path.split(f"{repo}/{dest}")
84+
85+
await aiofiles_os.makedirs(dirname, exist_ok=True)
86+
87+
async with aiofiles.open(f"{dirname}/{filename}", mode="wb") as f:
88+
await f.write(base64.b64decode(current_content))
89+
elif only_update:
90+
click.echo(f"Skipping: only updating existing files.")
91+
return
7692

7793
data = {
7894
"message": f"Updated {dest}"
@@ -83,7 +99,9 @@ async def upload_content(
8399
if exists:
84100
data["sha"] = current_sha
85101

86-
url = BASE_URL.format(repo=repo, path=dest)
102+
url = FILE_CONTENTS_URL.format(repo=repo, path=dest)
103+
104+
click.echo(f"Uploading {source} to {repo}/{dest}...")
87105

88106
async with semaphore:
89107
response = await put(

github_deploy/commands/upload.py

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
async def handle_file_upload(
11-
*, repo, source, dest, overwrite, token, semaphore, session
11+
*, repo, source, dest, overwrite, only_update, token, semaphore, session
1212
):
1313
check_exists_response = await check_exists(
1414
session=session,
@@ -23,19 +23,18 @@ async def handle_file_upload(
2323
current_content = check_exists_response.get("content")
2424
exists = current_sha is not None
2525

26-
if exists and not overwrite:
27-
return click.style(
28-
"Skipped uploading {source} to {repo}/{path}: Found an existing copy.".format(
29-
source=source,
30-
repo=repo,
31-
path=dest,
32-
),
33-
fg="blue",
34-
bold=True,
35-
)
36-
37-
else:
38-
if exists:
26+
if exists:
27+
if not overwrite:
28+
return click.style(
29+
"Skipped uploading {source} to {repo}/{path}: Found an existing copy.".format(
30+
source=source,
31+
repo=repo,
32+
path=dest,
33+
),
34+
fg="blue",
35+
bold=True,
36+
)
37+
else:
3938
click.echo(
4039
click.style(
4140
"Found an existing copy at {repo}/{path} overwriting it's contents...".format(
@@ -45,43 +44,44 @@ async def handle_file_upload(
4544
),
4645
)
4746

48-
upload_response = await upload_content(
49-
session=session,
50-
repo=repo,
51-
source=source,
52-
dest=dest,
53-
token=token,
54-
semaphore=semaphore,
55-
exists=exists,
56-
current_sha=current_sha,
57-
current_content=current_content,
58-
)
47+
upload_response = await upload_content(
48+
session=session,
49+
repo=repo,
50+
source=source,
51+
dest=dest,
52+
token=token,
53+
semaphore=semaphore,
54+
exists=exists,
55+
only_update=only_update,
56+
current_sha=current_sha,
57+
current_content=current_content,
58+
)
5959

60-
if upload_response:
61-
return click.style(
62-
"Successfully uploaded '{source}' to {repo}/{dest}".format(
63-
source=upload_response["content"]["name"],
64-
repo=repo,
65-
dest=upload_response["content"]["path"],
66-
),
67-
fg="green",
68-
bold=True,
69-
)
60+
if upload_response:
61+
return click.style(
62+
"Successfully uploaded '{source}' to {repo}/{dest}".format(
63+
source=upload_response["content"]["name"],
64+
repo=repo,
65+
dest=upload_response["content"]["path"],
66+
),
67+
fg="green",
68+
bold=True,
69+
)
7070

7171

7272
@click.command()
73-
@click.option(
74-
"--org",
75-
prompt=click.style("Enter your github user/organization", bold=True),
76-
help="The github organization.",
77-
)
7873
@click.option(
7974
"--token",
8075
prompt=click.style("Enter your personal access token", bold=True),
8176
help="Personal Access token with read and write access to org.",
8277
hide_input=True,
8378
envvar="TOKEN",
8479
)
80+
@click.option(
81+
"--org",
82+
prompt=click.style("Enter your github user/organization", bold=True),
83+
help="The github organization.",
84+
)
8585
@click.option(
8686
"--source",
8787
prompt=click.style("Enter path to source file", fg="blue"),
@@ -98,16 +98,30 @@ async def handle_file_upload(
9898
prompt=click.style(
9999
"Should we overwrite existing contents at this path", fg="blue"
100100
),
101+
is_flag=True,
102+
show_default=True,
101103
help="Overwrite existing files.",
102104
default=False,
103105
)
106+
@click.option(
107+
"--only-update/--no-only-update",
108+
prompt=click.style(
109+
"Should we only update existing files at this path", fg="blue"
110+
),
111+
is_flag=True,
112+
show_default=True,
113+
help="Only update existing files.",
114+
default=False,
115+
)
104116
@click.option(
105117
"--private/--no-private",
106118
prompt=click.style("Should we Include private repositories", bold=True),
119+
is_flag=True,
120+
show_default=True,
107121
help="Upload files to private repositories.",
108122
default=True,
109123
)
110-
async def main(org, token, source, dest, overwrite, private):
124+
async def main(org, token, source, dest, overwrite, only_update, private):
111125
"""Upload a file to all repositories owned by an organization/user."""
112126
# create instance of Semaphore: max concurrent requests.
113127
semaphore = asyncio.Semaphore(1000)
@@ -171,6 +185,7 @@ async def main(org, token, source, dest, overwrite, private):
171185
dest=dest,
172186
token=token,
173187
overwrite=overwrite,
188+
only_update=only_update,
174189
session=session,
175190
semaphore=semaphore,
176191
)

0 commit comments

Comments
 (0)
0