Skip to content

Commit

Permalink
patch(release_*.yaml): Fix auto-generated release notes (#222)
Browse files Browse the repository at this point in the history
Follow-up to #213

Fixes #221

GitHub's automatic tag selection is not picking the previous tag
correctly—manually specify tag from last release
  • Loading branch information
carlcsaposs-canonical committed Aug 8, 2024
1 parent da8bb57 commit 91c9b32
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 66 deletions.
12 changes: 4 additions & 8 deletions .github/workflows/release_charm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:
default: .
type: string
create-github-release:
description: Create git tag & GitHub release
description: Create git tag(s) & GitHub release
default: true
type: boolean
charmcraft-snap-revision:
Expand Down Expand Up @@ -71,18 +71,14 @@ jobs:
merge-multiple: true
- name: Upload & release charm
id: release
run: release-charm --directory='${{ inputs.path-to-charm-directory }}' --channel='${{ inputs.channel }}' --create-release-tags='${{ inputs.create-github-release }}'
run: release-charm --directory='${{ inputs.path-to-charm-directory }}' --channel='${{ inputs.channel }}' --create-release='${{ inputs.create-github-release }}'
env:
CHARMCRAFT_AUTH: ${{ secrets.charmhub-token }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload charmcraft logs
if: ${{ failure() && steps.release.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: logs-charmcraft-release-${{ inputs.artifact-prefix }}
path: ~/.local/state/charmcraft/log/
if-no-files-found: error
- name: Create GitHub release
if: ${{ inputs.create-github-release }}
run: gh release create '${{ steps.release.outputs.release_tag }}' --verify-tag --generate-notes --title '${{ steps.release.outputs.release_title }}' --notes-file release_notes.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if-no-files-found: ignore
5 changes: 1 addition & 4 deletions .github/workflows/release_rock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ jobs:
merge-multiple: true
- name: Upload & release rock
id: release
run: release-rock --directory='${{ inputs.path-to-rock-directory }}' --create-release-tag='${{ inputs.create-github-release }}'
- name: Create GitHub release
if: ${{ inputs.create-github-release }}
run: gh release create '${{ steps.release.outputs.release_tag }}' --verify-tag --generate-notes --title '${{ steps.release.outputs.release_title }}' --notes-file release_notes.txt
run: release-rock --directory='${{ inputs.path-to-rock-directory }}' --create-release='${{ inputs.create-github-release }}'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12 changes: 4 additions & 8 deletions .github/workflows/release_snap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ on:
default: .
type: string
create-github-release:
description: Create git tag & GitHub release
description: Create git tag(s) & GitHub release
default: true
type: boolean
snapcraft-snap-revision:
Expand Down Expand Up @@ -74,19 +74,15 @@ jobs:
merge-multiple: true
- name: Upload & release snap
id: release
run: release-snap --directory='${{ inputs.path-to-snap-project-directory }}' --channel='${{ inputs.channel }}' --create-release-tags='${{ inputs.create-github-release }}'
run: release-snap --directory='${{ inputs.path-to-snap-project-directory }}' --channel='${{ inputs.channel }}' --create-release='${{ inputs.create-github-release }}'
env:
SNAPCRAFT_STORE_AUTH: candid
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snap-store-token }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload snapcraft logs
if: ${{ failure() && steps.release.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: logs-snapcraft-release-${{ inputs.artifact-prefix }}
path: ~/.local/state/snapcraft/log/
if-no-files-found: error
- name: Create GitHub release
if: ${{ inputs.create-github-release }}
run: gh release create '${{ steps.release.outputs.release_tag }}' --verify-tag --generate-notes --title '${{ steps.release.outputs.release_title }}' --notes-file release_notes.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if-no-files-found: ignore
119 changes: 73 additions & 46 deletions python/cli/data_platform_workflows_cli/craft_tools/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class OCIResource:
revision: int


def run(command_: list):
def run(command_: list, *, log=True):
"""Run subprocess command & log stderr
Returns:
Expand All @@ -32,16 +32,60 @@ def run(command_: list):
try:
process.check_returncode()
except subprocess.CalledProcessError as e:
logging.error(e.stderr)
if log:
logging.error(e.stderr)
raise
return process.stdout
return process.stdout.strip()


def create_tags_and_release(
*, tags: list[str], release_tag: str, release_title: str, release_notes: str
):
"""Create git tags and GitHub release"""
# Create git tags
logging.info("Pushing git tag(s)")
for tag in tags:
subprocess.run(["git", "tag", tag], check=True)
subprocess.run(["git", "push", "origin", tag], check=True)
# Create GitHub release
logging.info("Creating GitHub release")
# Manually retrieve the last release tag since GitHub's automatic selection of previous tag
# does not always work (specifically if there are older tags that do not have a release).
try:
last_release_tag = json.loads(
run(["gh", "release", "view", "--json", "tagName"], log=False)
)["tagName"]
except subprocess.CalledProcessError as e:
if e.stderr.strip() == "release not found":
last_release_tag = None
else:
logging.error(e.stderr)
raise
if not release_notes.endswith("\n"):
release_notes += "\n"
command = [
"gh",
"release",
"create",
release_tag,
"--verify-tag",
"--generate-notes",
"--title",
release_title,
"--notes",
release_notes,
]
if last_release_tag:
command.extend(("--notes-start-tag", last_release_tag))
logging.info(f"Running {command=}")
subprocess.run(command, check=True)


def snap():
parser = argparse.ArgumentParser()
parser.add_argument("--directory", required=True)
parser.add_argument("--channel", required=True)
parser.add_argument("--create-release-tags", required=True)
parser.add_argument("--create-release", required=True)
args = parser.parse_args()
directory = pathlib.Path(args.directory)

Expand All @@ -57,41 +101,35 @@ class Revision:
architecture = snap_file.name.removesuffix(".snap").split("_")[-1]
logging.info(f"Uploading {snap_file=}")
output = run(["snapcraft", "upload", "--release", args.channel, snap_file])
# Example `output`: "Revision 3 created for 'charmed-postgresql' and released to 'latest/edge'\n"
# Example `output`: "Revision 3 created for 'charmed-postgresql' and released to 'latest/edge'"
match = re.match("Revision ([0-9]+) created for ", output)
assert match, "Unable to parse revision"
revision = int(match.group(1))
logging.info(f"Uploaded snap {revision=} {architecture=}")
revisions.append(Revision(value=revision, architecture=architecture))

if json.loads(args.create_release_tags) is not True:
if json.loads(args.create_release) is not True:
return
logging.info("Pushing git tag(s)")
# Create git tags
for revision in revisions:
tag = f"rev{revision.value}"
subprocess.run(["git", "tag", tag], check=True)
subprocess.run(["git", "push", "origin", tag], check=True)
# Output GitHub release info
release_tag = f"rev{max(revision.value for revision in revisions)}"
github_actions.output["release_tag"] = release_tag
if len(revisions) == 1:
release_title = "Revision "
else:
release_title = "Revisions "
release_title += ", ".join(str(revision.value) for revision in revisions)
github_actions.output["release_title"] = release_title
release_notes = f"Released to {args.channel}"
for revision in revisions:
release_notes += f"\n- {revision.architecture}: revision {revision.value}"
with open("release_notes.txt", "w") as file:
file.write(release_notes)
create_tags_and_release(
tags=[f"rev{revision.value}" for revision in revisions],
release_tag=f"rev{max(revision.value for revision in revisions)}",
release_title=release_title,
release_notes=release_notes,
)


def rock():
parser = argparse.ArgumentParser()
parser.add_argument("--directory", required=True)
parser.add_argument("--create-release-tag", required=True)
parser.add_argument("--create-release", required=True)
args = parser.parse_args()
directory = pathlib.Path(args.directory)

Expand All @@ -106,7 +144,7 @@ def rock():
"--format",
"{{ .Digest }}",
]
).strip()
)
logging.info(f"Uploading {rock_file=}")
run(
[
Expand Down Expand Up @@ -144,19 +182,14 @@ def rock():
.removeprefix("sha256:")
)

if json.loads(args.create_release_tag) is not True:
if json.loads(args.create_release) is not True:
return
logging.info("Pushing git tag")
# Create git tag
tag = f"image-{multi_arch_digest}"
subprocess.run(["git", "tag", tag], check=True)
subprocess.run(["git", "push", "origin", tag], check=True)
# Output GitHub release info
github_actions.output["release_tag"] = tag
github_actions.output["release_title"] = f"Image {multi_arch_digest}"
release_notes = f"Released to {multi_arch_image_name}"
with open("release_notes.txt", "w") as file:
file.write(release_notes)
create_tags_and_release(
tags=[f"image-{multi_arch_digest}"],
release_tag=f"image-{multi_arch_digest}",
release_title=f"Image {multi_arch_digest}",
release_notes=f"Released to {multi_arch_image_name}",
)


def charm():
Expand All @@ -168,7 +201,7 @@ def charm():
parser = argparse.ArgumentParser()
parser.add_argument("--directory", required=True)
parser.add_argument("--channel", required=True)
parser.add_argument("--create-release-tags", required=True)
parser.add_argument("--create-release", required=True)
args = parser.parse_args()
directory = pathlib.Path(args.directory)

Expand Down Expand Up @@ -224,25 +257,19 @@ def charm():
command += ["--resource", f"{oci.resource_name}:{oci.revision}"]
run(command)

if json.loads(args.create_release_tags) is not True:
if json.loads(args.create_release) is not True:
return
# Create git tags
logging.info("Pushing git tag(s)")
for revision in charm_revisions:
tag = f"rev{revision}"
subprocess.run(["git", "tag", tag], check=True)
subprocess.run(["git", "push", "origin", tag], check=True)
# Output GitHub release info
release_tag = f"rev{max(charm_revisions)}"
github_actions.output["release_tag"] = release_tag
if len(charm_revisions) == 1:
release_title = "Revision "
else:
release_title = "Revisions "
release_title += ", ".join(str(revision) for revision in charm_revisions)
github_actions.output["release_title"] = release_title
release_notes = f"Released to {args.channel}\nOCI images:\n" + "\n".join(
f"- {dataclasses.asdict(oci)}" for oci in oci_resources
)
with open("release_notes.txt", "w") as file:
file.write(release_notes)
create_tags_and_release(
tags=[f"rev{revision}" for revision in charm_revisions],
release_tag=f"rev{max(charm_revisions)}",
release_title=release_title,
release_notes=release_notes,
)

0 comments on commit 91c9b32

Please sign in to comment.