1+ import os
2+ import re
3+ import json
4+ import requests
5+ from datetime import datetime
6+
7+ github_headers = {'Authorization' : 'token %s' % os .environ .get ("GITHUB_TOKEN" )}
8+
9+ repo_info_table = {
10+ "caddy" : {
11+ "name" : "caddy" ,
12+ "type" : "github" ,
13+ "owner" : "caddyserver" ,
14+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
15+ },
16+ "envtpl" : {
17+ "name" : "envtpl" ,
18+ "type" : "github" ,
19+ "owner" : "subfuzion" ,
20+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
21+ },
22+ "erlang" : {
23+ "name" : "otp" ,
24+ "type" : "github" ,
25+ "owner" : "erlang" ,
26+ "match" : "^OTP-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
27+ },
28+ "fluentd" : {
29+ "name" : "fluentd" ,
30+ "type" : "github" ,
31+ "owner" : "fluent" ,
32+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
33+ },
34+ "go" : {
35+ "name" : "go" ,
36+ "type" : "github" ,
37+ "owner" : "golang" ,
38+ "match" : "^go[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
39+ },
40+ "gosu" : {
41+ "name" : "gosu" ,
42+ "type" : "github" ,
43+ "owner" : "tianon" ,
44+ "match" : "^[0-9]{1,}\.[0-9]{1,}$" ,
45+ },
46+ "grafana" : {
47+ "name" : "grafana" ,
48+ "type" : "github" ,
49+ "owner" : "grafana" ,
50+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
51+ },
52+ "helm" : {
53+ "name" : "helm" ,
54+ "type" : "github" ,
55+ "owner" : "helm" ,
56+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
57+ },
58+ "influxdb" : {
59+ "name" : "influxdb" ,
60+ "type" : "github" ,
61+ "owner" : "influxdata" ,
62+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
63+ },
64+ "ini-file" : {
65+ "name" : "ini-file" ,
66+ "type" : "github" ,
67+ "owner" : "bitnami" ,
68+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
69+ },
70+ "java" : {
71+ "name" : "jdk" ,
72+ "type" : "github" ,
73+ "owner" : "openjdk" ,
74+ "match" : "^jdk-[0-9]{1,}\+[0-9]{1,}$" ,
75+ },
76+ "jq" : {
77+ "name" : "jq" ,
78+ "type" : "github" ,
79+ "owner" : "stedolan" ,
80+ "match" : "^jq-[0-9]{1,}\.[0-9]{1,}\.?[0-9]{0}$" ,
81+ },
82+ "kubectl" : {
83+ "name" : "kubectl" ,
84+ "type" : "github" ,
85+ "owner" : "kubernetes" ,
86+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
87+ },
88+ "mariadb" : {
89+ "name" : "server" ,
90+ "type" : "github" ,
91+ "owner" : "MariaDB" ,
92+ "match" : "^mariadb-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
93+ },
94+ "mc" : {
95+ "name" : "mc" ,
96+ "type" : "github" ,
97+ "owner" : "minio" ,
98+ "match" : "^RELEASE\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}Z$" ,
99+ },
100+ "minio" : {
101+ "name" : "minio" ,
102+ "type" : "github" ,
103+ "owner" : "minio" ,
104+ "match" : "^RELEASE\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}Z$" ,
105+ },
106+ "nginx" : {
107+ "name" : "nginx" ,
108+ "type" : "github" ,
109+ "owner" : "nginx" ,
110+ "match" : "^release-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
111+ },
112+ "node" : {
113+ "name" : "node" ,
114+ "type" : "github" ,
115+ "owner" : "nodejs" ,
116+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
117+ },
118+ "pack" : {
119+ "name" : "pack" ,
120+ "type" : "github" ,
121+ "owner" : "buildpacks" ,
122+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
123+ },
124+ "php" : {
125+ "name" : "php-src" ,
126+ "type" : "github" ,
127+ "owner" : "php" ,
128+ "match" : "^php-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
129+ },
130+ "podman" : {
131+ "name" : "podman" ,
132+ "type" : "github" ,
133+ "owner" : "containers" ,
134+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
135+ },
136+ "postgis" : {
137+ "name" : "postgis" ,
138+ "type" : "github" ,
139+ "owner" : "postgis" ,
140+ "match" : "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
141+ },
142+ "postgresql" : {
143+ "name" : "postgres" ,
144+ "type" : "github" ,
145+ "owner" : "postgres" ,
146+ "match" : "^REL_[0-9]{1,}_[0-9]{1,}$" ,
147+ },
148+ "python" : {
149+ "name" : "cpython" ,
150+ "type" : "github" ,
151+ "owner" : "python" ,
152+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
153+ },
154+ "rabbitmq" : {
155+ "name" : "rabbitmq-server" ,
156+ "type" : "github" ,
157+ "owner" : "rabbitmq" ,
158+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
159+ },
160+ "redis" : {
161+ "name" : "redis" ,
162+ "type" : "github" ,
163+ "owner" : "redis" ,
164+ "match" : "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
165+ },
166+ "registry" : {
167+ "name" : "distribution" ,
168+ "type" : "github" ,
169+ "owner" : "distribution" ,
170+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
171+ },
172+ "ruby" : {
173+ "name" : "ruby" ,
174+ "type" : "github" ,
175+ "owner" : "ruby" ,
176+ "match" : "^v[0-9]{1,}_[0-9]{1,}_[0-9]{1,}$" ,
177+ },
178+ "rust" : {
179+ "name" : "rust" ,
180+ "type" : "github" ,
181+ "owner" : "rust-lang" ,
182+ "match" : "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
183+ },
184+ "telegraf" : {
185+ "name" : "telegraf" ,
186+ "type" : "github" ,
187+ "owner" : "influxdata" ,
188+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
189+ },
190+ "wait-for-port" : {
191+ "name" : "wait-for-port" ,
192+ "type" : "github" ,
193+ "owner" : "bitnami" ,
194+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
195+ },
196+ "wal-g" : {
197+ "name" : "wal-g" ,
198+ "type" : "github" ,
199+ "owner" : "wal-g" ,
200+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.?[0-9]{0}$" ,
201+ },
202+ "yj" : {
203+ "name" : "yj" ,
204+ "type" : "github" ,
205+ "owner" : "sclevine" ,
206+ "match" : "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$" ,
207+ },
208+ }
209+
210+
211+ def create_github_tag (stack , tag_name ):
212+ sha = requests .get (
213+ "https://api.github.com/repos/drycc/stacks/git/trees/main" ,
214+ headers = github_headers ,
215+ ).json ()["sha" ]
216+ response = requests .post (
217+ "https://api.github.com/repos/drycc/stacks/git/tags" ,
218+ data = json .dumps ({
219+ "tag" : tag_name ,
220+ "object" : sha ,
221+ "message" : f"new build for { stack } " ,
222+ "type" : "commit" ,
223+ }),
224+ headers = github_headers ,
225+ ).json ()
226+ params = dict (ref = f"refs/tags/{ tag_name } " , sha = response ['object' ]['sha' ])
227+ response = requests .post (
228+ 'https://api.github.com/repos/drycc/stacks/git/refs' ,
229+ data = json .dumps (params ),
230+ headers = github_headers ,
231+ )
232+
233+
234+ def create_github_issue (stack , tag_name ):
235+ strip_regex = "^[a-zA-Z\-_]{1,}"
236+ replace_regex = "[a-zA-Z\+\-_]{1,}"
237+ version = tag_name
238+ if re .search (strip_regex , tag_name ):
239+ version = re .subn (strip_regex , "" , tag_name )[0 ]
240+ if re .search (replace_regex , version ):
241+ version = re .subn (replace_regex , "." , version )[0 ].strip ("." )
242+ if requests .get (
243+ f"https://api.github.com/repos/drycc/stacks/git/ref/tags/{ stack } @{ version } " ,
244+ headers = github_headers ,
245+ ).status_code == 404 :
246+ create_github_tag (stack , f"{ stack } @{ version } " )
247+ link = f"https://github.com/search?q=org%3Adrycc+install-stack+{ stack } &type=code"
248+ requests .post (
249+ "https://api.github.com/repos/drycc/stacks/issues" ,
250+ data = json .dumps ({
251+ "title" : f"new build for { stack } @{ version } " ,
252+ "body" : f"Please judge whether the [referenced item]({ link } ) needs to be changed." ,
253+ "labels" : ["tag" ]
254+ }),
255+ headers = github_headers ,
256+ )
257+
258+
259+ github_tags_graphql = """
260+ query {
261+ repository(owner: "{owner}", name: "{name}") {
262+ refs(refPrefix: "refs/tags/", first: 10, orderBy: {field: TAG_COMMIT_DATE, direction: DESC}) {
263+ edges {
264+ node {
265+ name
266+ target {
267+ oid
268+ ... on Tag {
269+ commitUrl
270+ tagger {
271+ date
272+ }
273+ }
274+ }
275+ }
276+ }
277+ }
278+ }
279+ }
280+ """
281+
282+ def check_github_version (stack ):
283+ info = repo_info_table [stack ]
284+ response = requests .post (
285+ "https://api.github.com/graphql" ,
286+ data = json .dumps ({
287+ "query" : github_tags_graphql .replace (
288+ "{owner}" , info ["owner" ]).replace ("{name}" , info ["name" ]),
289+ }),
290+ headers = github_headers ,
291+ )
292+ for tag in response .json ()["data" ]["repository" ]["refs" ]["edges" ]:
293+ if "tagger" in tag ["node" ]["target" ]:
294+ date = datetime .strptime (
295+ tag ["node" ]["target" ]["tagger" ]["date" ][:19 ], "%Y-%m-%dT%H:%M:%S" )
296+ else :
297+ date = datetime .strptime (
298+ requests .get (
299+ "https://api.github.com/repos/{}/{}/commits/{}" .format (
300+ info ["owner" ], info ["name" ], tag ["node" ]["target" ]["oid" ]
301+ ), headers = github_headers
302+ ).json ()["commit" ]["author" ]["date" ][:19 ],
303+ "%Y-%m-%dT%H:%M:%S"
304+ )
305+ if re .match (info ["match" ], tag ["node" ]["name" ]):
306+ if (datetime .utcnow () - date ).days < 5 :
307+ create_github_issue (stack , tag ["node" ]["name" ])
308+ else :
309+ break
310+
311+
312+ def main ():
313+ for stack in os .listdir (os .path .join (os .path .dirname (__file__ ), ".." , "stacks" )):
314+ if stack not in repo_info_table :
315+ raise NotImplementedError (f"{ stack } not in repo_info_table" )
316+ else :
317+ repo_type = repo_info_table [stack ]["type" ]
318+ if repo_type != "github" :
319+ raise NotImplementedError (f"{ repo_type } NotImplemented" )
320+ else :
321+ check_github_version (stack )
322+
323+
324+ if __name__ == "__main__" :
325+ main ()
0 commit comments