forked from space-wizards/space-station-14
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactions_changelogs_since_last_run.py
executable file
·148 lines (115 loc) · 4.41 KB
/
actions_changelogs_since_last_run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
#
# Sends updates to a Discord webhook for new changelog entries since the last GitHub Actions publish run.
# Automatically figures out the last run and changelog contents with the GitHub API.
#
import io
import itertools
import os
import requests
import yaml
from typing import Any, Iterable
GITHUB_API_URL = os.environ.get("GITHUB_API_URL", "https://api.github.com")
GITHUB_REPOSITORY = os.environ["GITHUB_REPOSITORY"]
GITHUB_RUN = os.environ["GITHUB_RUN_ID"]
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
DISCORD_WEBHOOK_URL = os.environ.get("DISCORD_WEBHOOK_URL")
CHANGELOG_FILE = "Resources/Changelog/Changelog.yml"
TYPES_TO_EMOJI = {
"Fix": "🐛",
"Add": "🆕",
"Remove": "❌",
"Tweak": "⚒️"
}
ChangelogEntry = dict[str, Any]
def main():
if not DISCORD_WEBHOOK_URL:
return
session = requests.Session()
session.headers["Authorization"] = f"Bearer {GITHUB_TOKEN}"
session.headers["Accept"] = "Accept: application/vnd.github+json"
session.headers["X-GitHub-Api-Version"] = "2022-11-28"
most_recent = get_most_recent_workflow(session)
last_sha = most_recent['head_commit']['id']
print(f"Last successful publish job was {most_recent['id']}: {last_sha}")
last_changelog = yaml.safe_load(get_last_changelog(session, last_sha))
with open(CHANGELOG_FILE, "r") as f:
cur_changelog = yaml.safe_load(f)
diff = diff_changelog(last_changelog, cur_changelog)
send_to_discord(diff)
def get_most_recent_workflow(sess: requests.Session) -> Any:
workflow_run = get_current_run(sess)
past_runs = get_past_runs(sess, workflow_run)
for run in past_runs['workflow_runs']:
# First past successful run that isn't our current run.
if run["id"] == workflow_run["id"]:
continue
return run
def get_current_run(sess: requests.Session) -> Any:
resp = sess.get(f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/actions/runs/{GITHUB_RUN}")
resp.raise_for_status()
return resp.json()
def get_past_runs(sess: requests.Session, current_run: Any) -> Any:
"""
Get all successful workflow runs before our current one.
"""
params = {
"status": "success",
"created": f"<={current_run['created_at']}"
}
resp = sess.get(f"{current_run['workflow_url']}/runs", params=params)
resp.raise_for_status()
return resp.json()
def get_last_changelog(sess: requests.Session, sha: str) -> str:
"""
Use GitHub API to get the previous version of the changelog YAML (Actions builds are fetched with a shallow clone)
"""
params = {
"ref": sha,
}
headers = {
"Accept": "application/vnd.github.raw"
}
resp = sess.get(f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/contents/{CHANGELOG_FILE}", headers=headers, params=params)
resp.raise_for_status()
return resp.text
def diff_changelog(old: dict[str, Any], cur: dict[str, Any]) -> Iterable[ChangelogEntry]:
"""
Find all new entries not present in the previous publish.
"""
old_entry_ids = {e["id"] for e in old["Entries"]}
return (e for e in cur["Entries"] if e["id"] not in old_entry_ids)
def send_to_discord(entries: Iterable[ChangelogEntry]) -> None:
if not DISCORD_WEBHOOK_URL:
print(f"No discord webhook URL found, skipping discord send")
return
content = io.StringIO()
count: int = 0
for name, group in itertools.groupby(entries, lambda x: x["author"]):
content.write(f"**{name}** updated:\n")
for entry in group:
for change in entry["changes"]:
emoji = TYPES_TO_EMOJI.get(change['type'], "❓")
message = change['message']
url = entry.get("url")
count += 1
if url and url.strip():
content.write(f"{emoji} [-]({url}) {message}\n")
else:
content.write(f"{emoji} - {message}\n")
if count == 0:
print("Skipping discord push as no changelog entries found")
return
print(f"Posting {count} changelog entries to discord webhook")
body = {
"content": content.getvalue(),
# Do not allow any mentions.
"allowed_mentions": {
"parse": []
},
# SUPPRESS_EMBEDS
"flags": 1 << 2
}
response = requests.post(DISCORD_WEBHOOK_URL, json=body)
response.raise_for_status()
main()