Skip to content

Instantly share code, notes, and snippets.

@felddy
Created September 1, 2023 23:40
Show Gist options
  • Save felddy/87312d48b5d5878b6f462b2ae60c3f71 to your computer and use it in GitHub Desktop.
Save felddy/87312d48b5d5878b6f462b2ae60c3f71 to your computer and use it in GitHub Desktop.
Script to add comments containing tag labels for sha-pinned GitHub Action uses
#!/usr/bin/env python3
import argparse
import os
import re
import subprocess
import json
from packaging.version import parse as parse_version
from functools import lru_cache
@lru_cache(maxsize=32)
def get_tag_version_with_gh(repo, sha, debug):
cmd = ['gh', 'api', f'repos/{repo}/git/refs/tags', '--paginate']
try:
output = subprocess.check_output(cmd).decode('utf-8')
except subprocess.CalledProcessError as e:
print(f"An error occurred: {str(e)}. Standard Error Output: {e.stderr}")
return None
tags_data = json.loads(output)
possible_tags = []
for entry in tags_data:
if 'object' in entry and entry['object']['sha'] == sha:
possible_tags.append(entry['ref'].split('/')[-1])
if debug:
print(f"Debug: Available tags for {repo}@{sha}: {possible_tags}")
# Separate semantic and non-semantic versions
semver_tags = []
non_semver_tags = []
for tag in possible_tags:
try:
version = parse_version(tag)
if type(version) is not str:
semver_tags.append((version, tag))
else:
non_semver_tags.append(tag)
except:
non_semver_tags.append(tag)
# Sort semantic versions
semver_tags.sort(key=lambda x: (x[0].epoch, x[0].release, x[0].pre, x[0].dev, x[0].post), reverse=True)
# Sort non-semantic versions
non_semver_tags.sort(reverse=True)
# Prefer semantic versions if available
if semver_tags:
return semver_tags[0][1]
elif non_semver_tags:
return non_semver_tags[0]
else:
return None
def update_yaml_comments(yaml_lines, debug):
updated_lines = []
# Using the updated regex pattern with named groups
pattern = re.compile(r"uses: (?P<repo>[^/@]+/[^/@]+)(?:/[^@]*)?@(?P<sha>[a-f0-9]{40})")
for line in yaml_lines:
match = pattern.search(line)
if match:
# Extract named groups "repo" and "sha"
repo = match.group("repo")
sha = match.group("sha")
tag_version = get_tag_version_with_gh(repo, sha, debug)
# Remove any existing comment starting with "# tag="
line_content = re.sub(r"( # tag=[^\s]+)?", "", line)
if tag_version:
if debug:
print(f"Debug: Selected tag for {repo}@{sha}: {tag_version}")
# Add the new comment, preserving any original newlines
line = f"{line_content.rstrip()} # tag={tag_version}{os.linesep}"
updated_lines.append(line)
return updated_lines
def main():
parser = argparse.ArgumentParser(description='Update GitHub Actions YAML file with tag comments.')
parser.add_argument('files', type=str, nargs='+', help='Paths to the GitHub Actions YAML files.')
parser.add_argument('-i', '--in-place', action='store_true', help='Modify the files in-place.')
parser.add_argument('--debug', action='store_true', help='Enable debug output.')
args = parser.parse_args()
for file_path in args.files:
with open(file_path, 'r') as f:
yaml_lines = f.readlines()
updated_yaml_lines = update_yaml_comments(yaml_lines, args.debug)
if args.in_place:
with open(file_path, 'w') as f:
f.writelines(updated_yaml_lines)
else:
print(f"--- {file_path} ---")
print("".join(updated_yaml_lines))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment