169 lines
5.7 KiB
Python
169 lines
5.7 KiB
Python
# pylint: disable=invalid-name
|
|
'''
|
|
List GitHub Actions versions used and latest versions
|
|
'''
|
|
import json
|
|
import os
|
|
import ssl
|
|
import urllib.request
|
|
import yaml
|
|
from json.decoder import JSONDecodeError
|
|
|
|
allACTIONS = {}
|
|
listACTIONS = []
|
|
|
|
VER_WIDTH = 10
|
|
NAME_WIDTH = 40
|
|
LINE_WIDTH = 1 + NAME_WIDTH + 5 + VER_WIDTH + 5 + VER_WIDTH + 1
|
|
|
|
def process_walk(key, node):
|
|
'''
|
|
Process walking through the array
|
|
'''
|
|
global allACTIONS
|
|
global listACTIONS
|
|
if key == "uses":
|
|
action = node.split('@')
|
|
version = ""
|
|
if '@' in node:
|
|
version = action[1]
|
|
action = action[0]
|
|
if action not in allACTIONS:
|
|
allACTIONS[action] = {
|
|
"versions": [],
|
|
"latest": ""
|
|
}
|
|
allACTIONS[action]["versions"].append(version)
|
|
allACTIONS[action]["versions"] = list(
|
|
set(
|
|
allACTIONS[action]["versions"]
|
|
)
|
|
)
|
|
listACTIONS.append(node)
|
|
|
|
|
|
def walk(key, node):
|
|
'''
|
|
How to walk through the array
|
|
'''
|
|
if isinstance(node, dict):
|
|
return {k: walk(k, v) for k, v in node.items()}
|
|
elif isinstance(node, list):
|
|
return [walk(key, x) for x in node]
|
|
else:
|
|
return process_walk(key, node)
|
|
|
|
|
|
for r, d, f in os.walk(os.path.join(".", ".github")):
|
|
if "actions" in r or "workflows" in r:
|
|
for filename in f:
|
|
# if it's not a YAML or it's turned off, skip it
|
|
if (".yml" not in filename and ".yaml" not in filename) or (".off" in filename):
|
|
continue
|
|
listACTIONS = []
|
|
# print filename
|
|
filename_line = "-" * (len(os.path.join(r, filename)) + 2)
|
|
print(
|
|
" " +
|
|
filename_line +
|
|
" "
|
|
)
|
|
print("| " + os.path.join(r, filename) + " |")
|
|
# read the file
|
|
with(open(os.path.join(r, filename), "r", encoding="utf-8")) as yamlFile:
|
|
print(
|
|
"|" +
|
|
filename_line +
|
|
"-" +
|
|
("-" * (LINE_WIDTH - len(filename_line) + 1)) +
|
|
" "
|
|
)
|
|
yml = yaml.safe_load(yamlFile)
|
|
walk("uses", yml)
|
|
dictACTIONS = {}
|
|
for k in sorted(list(set(listACTIONS))):
|
|
action = k.split('@')[0]
|
|
version = k.split('@')[1] if '@' in k else ""
|
|
latest = ""
|
|
# if it's not a location action, get the latest version number
|
|
if "./." not in action:
|
|
apiURL = f"https://api.github.com/repos/{action}/releases/latest"
|
|
if True:
|
|
apiReq = None
|
|
try:
|
|
apiReq = urllib.request.urlopen(
|
|
apiURL,
|
|
context=ssl._create_unverified_context()
|
|
)
|
|
except urllib.error.HTTPError as e:
|
|
if e.code != 403:
|
|
print(e.code, apiURL)
|
|
if apiReq:
|
|
apiRes = {}
|
|
try:
|
|
apiRes = json.loads(
|
|
apiReq.read().decode("utf-8"))
|
|
except JSONDecodeError as e:
|
|
raise ValueError("API Request failed: " + apiURL)
|
|
if apiRes:
|
|
latest = apiRes["tag_name"] if "tag_name" in apiRes else ""
|
|
if latest != "":
|
|
allACTIONS[action]["latest"] = latest
|
|
dictACTIONS[action] = version
|
|
# print action name and version info
|
|
for action, version in dictACTIONS.items():
|
|
print(
|
|
"| " + \
|
|
f"{action.ljust(NAME_WIDTH)}" + \
|
|
"\t" + \
|
|
f"{(version or 'N/A').ljust(VER_WIDTH)}" + \
|
|
"\t" + \
|
|
f"{(allACTIONS[action]['latest'] or 'N/A').ljust(VER_WIDTH)}" + \
|
|
" |"
|
|
)
|
|
print(
|
|
" " +
|
|
("-" * (LINE_WIDTH + 2)) +
|
|
" "
|
|
)
|
|
print("")
|
|
|
|
# print outdated versions summary
|
|
first = True
|
|
outdated = False
|
|
for action, actionData in allACTIONS.items():
|
|
if len(actionData["versions"]) > 0:
|
|
if actionData["latest"] != "" and actionData["versions"][0] != actionData["latest"]:
|
|
outdated = True
|
|
if first:
|
|
first = False
|
|
filename_line = "-" * (len("| Outdated |"))
|
|
print(
|
|
" " +
|
|
filename_line +
|
|
" "
|
|
)
|
|
print("| Outdated |")
|
|
print(
|
|
"|" +
|
|
filename_line +
|
|
"-" +
|
|
("-" * (LINE_WIDTH - len(filename_line) + 1)) +
|
|
" "
|
|
)
|
|
print(
|
|
"| " + \
|
|
f"{action.ljust(40)}" + \
|
|
"\t" + \
|
|
f"{(','.join(actionData['versions']) or 'N/A').ljust(10)}" + \
|
|
"\t" + \
|
|
f"{actionData['latest'].ljust(10)}" + \
|
|
" |"
|
|
)
|
|
if outdated:
|
|
print(
|
|
" " +
|
|
("-" * (LINE_WIDTH + 2)) +
|
|
" "
|
|
)
|