__author__ = "Vanessa Sochat"
__copyright__ = "Copyright 2022, Vanessa Sochat"
__license__ = "MPL 2.0"
from action_updater.main.github import sort_major, sort_tags
from action_updater.main.updater import UpdaterBase
schema = {
"type": "object",
"properties": {
# Allow these orgs to use major version strings
"major_orgs": {"type": "array", "items": {"type": "string"}}
},
"additionalProperties": False,
}
[docs]class VersionUpdater(UpdaterBase):
name = "version"
description = "update action versions"
schema = schema
cache = {"tags": {}}
[docs] def detect(self, action):
"""
Detect changes (to be later saved)
"""
# Set the count to 0
self.count = 0
# No point if we don't have jobs!
if not action.steps:
return False
# We will use major versions for these orgs (trusted)
trusted_orgs = self.settings.get("major_orgs")
# For each job, look for steps->updater versions
for step in action.steps:
# We are primarily interested in uses
if "uses" not in step:
continue
repo = step["uses"]
# If we have a local action, nothing to update
if repo.startswith("./"):
continue
# Get the current tag or version (we will want to maintain this convention)
# Create a lookup based on the ref
repo, _ = repo.split("@")
org, _ = repo.split("/", 1)
# Retrieve all tags for the repository, a lookup by tag name
tags = self.cache["tags"].get(repo) or self.get_tags_lookup(repo)
updated = None
if trusted_orgs and org in trusted_orgs:
updated = self.get_major_tag(tags)
if not updated:
updated = self.get_tagged_commit(tags)
# Save repo tags in cache
self.cache["tags"][repo] = tags
# If we don't have tags by this point, no go - we cannot parse
if not updated:
continue
updated = f"{repo}@{updated}"
previous = step["uses"]
# If we added a new comment, update the old one
if "#" in updated:
updated, comment = updated.split("#", 1)
comment = comment.strip()
step["uses"] = updated.strip()
# TODO some check to preserve other previous comments?
step.ca.items["uses"] = [None, None, None, None]
# Add the end of line comment (third position in list)
step.yaml_add_eol_comment(f"# {comment}\n", "uses", column=0)
# Always do the update (regardless of comment!)
step["uses"] = updated.strip()
# Do we have a change?
if step["uses"] != previous:
self.count += 1
return self.count != 0
[docs] def get_major_tag(self, tags):
"""
Given a list of repository tags, get the most up-todate!
"""
# If we have a major org, we trust it and want the major version tag
tags_list = list(tags)
tags_list = [x for x in tags_list if "." not in x]
# Cut out early if we don't have major-only tags
if not tags_list:
return []
# Get ordered major tags
ordered = sort_major(tags_list)
# If we don't have ordered, we could use branches, but skip for now
if not ordered:
return []
tag = ordered[0]._original
# Use latest release verbatim
return tag
[docs] def get_tagged_commit(self, tags):
"""
Given a list of repository tags, get the most up-todate!
"""
# Get ordered major tags
ordered = sort_tags(list(tags))
# First pass - no ordered tags, try to do the same for the major versions
if not ordered:
ordered = sort_major(tags)
# If we don't have ordered, we could use branches, but skip for now
if not ordered:
return []
tag = ordered[0]._original
meta = tags[tag]
commit = meta["object"]["sha"]
return f"{commit} # {tag}"