Skip to content

Commit dfc2974

Browse files
authored
Extend awards action (#1933)
* add an action that extends awards.csv on PR merges * change trigger to pull_request, add unfiltered step for logging
1 parent 34c7218 commit dfc2974

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

.github/workflows/extend-awards.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: extend-awards
2+
run-name: Extending awards
3+
on:
4+
pull_request:
5+
types: [ closed ]
6+
branches:
7+
- master
8+
jobs:
9+
unfiltered:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- run: echo '${{ toJson(github) }}'
13+
if_merged:
14+
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-python@v5
19+
with:
20+
python-version: '3.13'
21+
- run: pip install requests
22+
- run: python extend-awards.py '${{ toJson(github) }}'
23+
env:
24+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25+
- uses: peter-evans/create-pull-request@v7
26+
with:
27+
commit-message: extending awards
28+
title: Extending awards

extend-awards.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import json, os, re, requests, sys
2+
3+
difficulties = {'good-first-issue':20000,'easy':100000,'medium':250000,'medium-hard':500000,'hard':1000000}
4+
priorities = {'low':0.5,'medium':1.5,'high':2,'urgent':3}
5+
ignored = ['huumn', 'ekzyis']
6+
fn = 'awards.csv'
7+
8+
sess = requests.Session()
9+
headers = {'Authorization':'Bearer %s' % os.getenv('GITHUB_TOKEN') }
10+
awards = []
11+
12+
def getIssue(n):
13+
url = 'https://api.github.com/repos/stackernews/stacker.news/issues/' + n
14+
r = sess.get(url, headers=headers)
15+
j = json.loads(r.text)
16+
return j
17+
18+
def findIssueInPR(j):
19+
p = re.compile('(#|https://github.com/stackernews/stacker.news/issues/)([0-9]+)')
20+
for m in p.finditer(j['title']):
21+
return m.group(2)
22+
if not 'body' in j or j['body'] is None:
23+
return
24+
for s in j['body'].split('\n'):
25+
for m in p.finditer(s):
26+
return m.group(2)
27+
28+
def addAward(user, kind, pr, issue, difficulty, priority, count, amount):
29+
if amount >= 1000000 and amount % 1000000 == 0:
30+
amount = str(int(amount / 1000000)) + 'm'
31+
elif amount >= 1000 and amount % 1000 == 0:
32+
amount = str(int(amount / 1000)) + 'k'
33+
for a in awards:
34+
if a[0] == user and a[1] == kind and a[2] == pr:
35+
print('found existing entry %s' % a)
36+
if a[8] != amount:
37+
print('warning: amount %s != %s' % (a[8], amount))
38+
return
39+
if count < 1:
40+
count = ''
41+
addr = '???'
42+
for a in awards:
43+
if a[0] == user and a[9] != '???':
44+
addr = a[9]
45+
print('adding %s,%s,%s,%s,%s,%s,%s,,%s,%s,???' % (user, kind, pr, issue, difficulty, priority, count, amount, addr))
46+
with open(fn, 'a') as f:
47+
print('%s,%s,%s,%s,%s,%s,%s,,%s,%s,???' % (user, kind, pr, issue, difficulty, priority, count, amount, addr), file=f)
48+
49+
def countReviews(pr):
50+
url = 'https://api.github.com/repos/stackernews/stacker.news/issues/%s/timeline' % pr
51+
r = sess.get(url, headers=headers)
52+
j = json.loads(r.text)
53+
count = 0
54+
for e in j:
55+
if e['event'] == 'reviewed' and e['state'] == 'changes_requested':
56+
count += 1
57+
return count
58+
59+
def checkPR(pr):
60+
i = getIssue(pr)
61+
if not 'pull_request' in i or not 'merged_at' in i['pull_request']:
62+
print('pr %s is not a merged pull request' % pr)
63+
return
64+
print('pr %s' % pr)
65+
n = findIssueInPR(i)
66+
if not n:
67+
print('pr %s does not solve an issue' % pr)
68+
return
69+
print('solves issue %s' % n)
70+
j = getIssue(n)
71+
difficulty = ''
72+
amount = 0
73+
priority = ''
74+
multiplier = 1
75+
for l in j['labels']:
76+
for d in difficulties:
77+
if l['name'] == 'difficulty:' + d:
78+
difficulty = d
79+
amount = difficulties[d]
80+
for p in priorities:
81+
if l['name'] == 'priority:' + p:
82+
priority = p
83+
multiplier = priorities[p]
84+
if amount * multiplier <= 0:
85+
print('issue gives no award')
86+
return
87+
count = countReviews(pr)
88+
if count >= 10:
89+
print('too many reviews, no award')
90+
return
91+
if count > 0:
92+
print('%d reviews, %d%% reduction' % (count, count * 10))
93+
award = amount * multiplier * (10 - count) / 10
94+
print('award is %d' % award)
95+
if i['user']['login'] not in ignored:
96+
addAward(i['user']['login'], 'pr', '#' + pr, '#' + n, difficulty, priority, count, award)
97+
if j['user']['login'] not in ignored:
98+
count = 0
99+
addAward(j['user']['login'], 'issue', '#' + pr, '#' + n, difficulty, priority, count, int(award / 10))
100+
101+
with open(fn, 'r') as f:
102+
for s in f:
103+
s = s.split('\n')[0]
104+
awards.append(s.split(','))
105+
106+
j = json.loads(sys.argv[1])
107+
url = j['event']['pull_request']['_links']['commits']['href']
108+
r = sess.get(url, headers=headers)
109+
j = json.loads(r.text)
110+
for c in j:
111+
m = re.search('\\(#([0-9]+)\\)$', c['commit']['message'].split('\n')[0])
112+
if m:
113+
checkPR(m.group(1))
114+
exit(0)
115+
print('no PR found in commit')
116+

0 commit comments

Comments
 (0)