Skip to content

Commit 11c658e

Browse files
feat: support cloning assets to created releases (#18)
* feat: support cloning assets to created releases * docs: automated doc update * fix: fix pathing
1 parent eb09597 commit 11c658e

File tree

6 files changed

+91
-44
lines changed

6 files changed

+91
-44
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ jobs:
4848
| target | Target for new tags/releases in this repo. If not set, will use the default branch | `false` | |
4949
| skip_draft | Skip draft releases | `false` | false |
5050
| skip_prerelease | Skip Prereleases | `false` | false |
51+
| copy_assets | If true, copy assets from source repo releases to the newly created releases | `false` | false |
5152
| limit | A limit of how many releases to add on a single run. Good for not overwhelming CI systems | `false` | 0 |
5253
| dry_run | If true, just output what releases would have been made but do not make releases | `false` | false |
5354
| min_version | If set, we will ignore any releases from the source repo that are less than min_version | `false` | |

action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ inputs:
2020
skip_prerelease:
2121
description: "Skip Prereleases"
2222
default: False
23+
copy_assets:
24+
description: "If true, copy assets from source repo releases to the newly created releases"
25+
default: False
2326
limit:
2427
description: "A limit of how many releases to add on a single run. Good for not overwhelming CI systems"
2528
default: 0

gha_clone_releases/main.py

+20-44
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
from actions_toolkit import core as actions_toolkit
55
from github import Github
66
from github.GithubException import GithubException
7-
from github.GitRelease import GitRelease
8-
from packaging.version import InvalidVersion
9-
from packaging.version import parse as parse_version
7+
8+
from gha_clone_releases.utils.assets import download_asset
9+
from gha_clone_releases.utils.releases import get_missing_releases
1010

1111
# This code is automatically generated by actions.yml and make generate-inputs
1212
###START_INPUT_AUTOMATION###
@@ -20,6 +20,10 @@
2020
},
2121
"skip_draft": {"description": "Skip draft releases", "default": False},
2222
"skip_prerelease": {"description": "Skip Prereleases", "default": False},
23+
"copy_assets": {
24+
"description": "If true, copy assets from source repo releases to the newly created releases",
25+
"default": False,
26+
},
2327
"limit": {
2428
"description": "A limit of how many releases to add on a single run. Good for not overwhelming CI systems",
2529
"default": 0,
@@ -79,6 +83,11 @@ def get_inputs() -> dict[str, Any]:
7983
if isinstance(parsed_inputs["skip_prerelease"], str)
8084
else parsed_inputs["skip_prerelease"]
8185
)
86+
parsed_inputs["copy_assets"] = (
87+
parsed_inputs["copy_assets"].lower() == "true"
88+
if isinstance(parsed_inputs["copy_assets"], str)
89+
else parsed_inputs["copy_assets"]
90+
)
8291
parsed_inputs["dest_repo"] = (
8392
os.environ.get("GITHUB_REPOSITORY") if parsed_inputs["dest_repo"] is None else parsed_inputs["dest_repo"]
8493
)
@@ -87,46 +96,6 @@ def get_inputs() -> dict[str, Any]:
8796
return parsed_inputs
8897

8998

90-
class ReleaseWrapper:
91-
def __init__(self, release: GitRelease):
92-
self.release = release
93-
94-
def __eq__(self, other_release: GitRelease):
95-
return self.release.title == other_release.release.title
96-
97-
def __hash__(self):
98-
return hash(self.release.title)
99-
100-
101-
def exceeds_min_version(release_version: str, min_version: str):
102-
"""Checks if a version exceeds a minimum version using packaging.version.parse"""
103-
if min_version is not None:
104-
try:
105-
result = parse_version(release_version) > parse_version(min_version)
106-
except InvalidVersion as exc:
107-
actions_toolkit.error(f"{release_version} Is an invalid version {exc}")
108-
return False
109-
actions_toolkit.debug(f"{release_version} exceeds_min_version result {result}")
110-
return result
111-
return True
112-
113-
114-
def get_missing_releases(source_releases, dest_releases, min_version) -> list[GitRelease]:
115-
"""Compares two sets of releases and returns a list of releases in the source that are not in the destination"""
116-
117-
def sort_key(release: GitRelease):
118-
return release.title
119-
120-
source_releases = {
121-
ReleaseWrapper(release) for release in source_releases if exceeds_min_version(release.title, min_version)
122-
}
123-
dest_releases = {ReleaseWrapper(release) for release in dest_releases}
124-
125-
releases = [release.release for release in list(source_releases - dest_releases)]
126-
releases.sort(key=lambda release: release.published_at, reverse=True)
127-
return releases
128-
129-
13099
def main():
131100
"""Get all releases from a source repo and create them on
132101
the repo we are running this action in
@@ -165,7 +134,7 @@ def main():
165134
actions_toolkit.info(f"Adding {release.tag_name} to {inputs['dest_repo']}")
166135
target = this_repo.default_branch if inputs["target"] is None else inputs["target"]
167136
try:
168-
this_repo.create_git_release(
137+
new_release = this_repo.create_git_release(
169138
tag=release.tag_name,
170139
name=release.title,
171140
message=release.body,
@@ -176,6 +145,13 @@ def main():
176145
added_releases.append(release.tag_name)
177146
except GithubException as exc:
178147
actions_toolkit.error(f"Error while adding a release for {release.tag_name}. {exc}")
148+
if inputs["copy_assets"]:
149+
for asset in release.assets:
150+
try:
151+
this_asset = download_asset(asset_name=asset.name, asset_url=asset.browser_download_url)
152+
new_release.upload_asset(this_asset)
153+
except Exception as exc:
154+
actions_toolkit.error(f"Error while copying asset {asset.name}. {exc}")
179155
actions_toolkit.set_output("addedReleases", ",".join(added_releases))
180156
actions_toolkit.set_output("skippedReleasesCount", skipped)
181157
actions_toolkit.set_output("addedReleasesCount", len(added_releases))

gha_clone_releases/utils/__init__.py

Whitespace-only changes.

gha_clone_releases/utils/assets.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import os
2+
import requests
3+
import tempfile
4+
5+
6+
def download_asset(asset_name: str, asset_url: str) -> str:
7+
"""Downloads an asset from a release and returns the path to the downloaded file"""
8+
response = requests.get(asset_url, stream=True, timeout=(60, 300))
9+
response.raise_for_status() # Check for any errors during the request
10+
11+
# Create a temporary directory to store the downloaded file
12+
temp_dir = tempfile.mkdtemp()
13+
14+
# Construct the full path to the downloaded file
15+
file_path = os.path.join(temp_dir, asset_name)
16+
17+
# Write the response content to the file
18+
with open(file_path, "wb") as fh:
19+
for chunk in response.iter_content(chunk_size=8192):
20+
if chunk: # Filter out any potential empty chunks
21+
fh.write(chunk)
22+
23+
return file_path

gha_clone_releases/utils/releases.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from github.GitRelease import GitRelease
2+
from packaging.version import InvalidVersion
3+
from packaging.version import parse as parse_version
4+
from actions_toolkit import core as actions_toolkit
5+
6+
7+
class ReleaseWrapper:
8+
def __init__(self, release: GitRelease):
9+
self.release = release
10+
11+
def __eq__(self, other_release: GitRelease):
12+
return self.release.title == other_release.release.title
13+
14+
def __hash__(self):
15+
return hash(self.release.title)
16+
17+
18+
def exceeds_min_version(release_version: str, min_version: str):
19+
"""Checks if a version exceeds a minimum version using packaging.version.parse"""
20+
if min_version is not None:
21+
try:
22+
result = parse_version(release_version) > parse_version(min_version)
23+
except InvalidVersion as exc:
24+
actions_toolkit.error(f"{release_version} Is an invalid version {exc}")
25+
return False
26+
actions_toolkit.debug(f"{release_version} exceeds_min_version result {result}")
27+
return result
28+
return True
29+
30+
31+
def get_missing_releases(source_releases, dest_releases, min_version) -> list[GitRelease]:
32+
"""Compares two sets of releases and returns a list of releases in the source that are not in the destination"""
33+
34+
def sort_key(release: GitRelease):
35+
return release.title
36+
37+
source_releases = {
38+
ReleaseWrapper(release) for release in source_releases if exceeds_min_version(release.title, min_version)
39+
}
40+
dest_releases = {ReleaseWrapper(release) for release in dest_releases}
41+
42+
releases = [release.release for release in list(source_releases - dest_releases)]
43+
releases.sort(key=lambda release: release.published_at, reverse=True)
44+
return releases

0 commit comments

Comments
 (0)