-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbiotools-patch.py
235 lines (203 loc) · 7.13 KB
/
biotools-patch.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# install requires dockerfile_parse requests gitpython
# expect Dockerfile path as argv 1
# expect env var GITHUB_BIOTOOLS_TOKEN (to create PR)
# ssh rsa key must be mounted in container if any
from dockerfile_parse import DockerfileParser
import requests
import sys
import os
import logging
import re
# import json
# from collections import OrderedDict
import dockerparse_arg_fix
import git
import datetime
from copy import deepcopy
from yaml import load, dump
try:
from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
from yaml import Loader, Dumper
logging.basicConfig(level=logging.INFO)
BOT_LABEL = 'biocontainers-bot-import'
GIT_REPO = '[email protected]:bio-tools/content.git'
# GIT_REPO = '[email protected]:biocontainers-bot/content.git'
def repoSetup(branch):
repo = None
if os.path.exists('/tmp/biotools-content'):
repo = git.Repo('/tmp/biotools-content')
if branch is not None:
logging.info("Use existing repo, checkout to %s" % branch)
mygit = repo.git
mygit.config('--local', 'user.name', 'Biocontainers bot')
mygit.checkout(branch)
return (repo, branch)
else:
repo = git.Repo.clone_from(GIT_REPO, os.path.join('/tmp', 'biotools-content'), branch='master')
# fork = repo.create_remote('fork', '[email protected]:biocontainers-bot/content.git')
mygit = repo.git
mygit.config('--local', 'user.name', 'Biocontainers bot')
if branch is None:
branch = 'biocontainers-bot-import-%d' % datetime.datetime.now().timestamp()
mygit.checkout('HEAD', b=branch)
else:
mygit.fetch('origin', branch)
mygit.checkout(branch)
logging.info("Init repo, use branch %s" % branch)
return (repo, branch)
def getPRBranch(id):
github_url = 'https://api.github.com/repos/bio-tools/content/pulls/%s' % id
res = requests.get(github_url)
pr = res.json()
pr_branch = pr['head']['ref']
logging.info("PR %d branch = %s" % (id, pr_branch))
return pr_branch
def hasPR():
github_url = 'https://api.github.com/search/issues'
res = requests.get(github_url, params={
'q': 'is:pr state:open label:%s repo:bio-tools/content' % BOT_LABEL
})
# ?q=is:pr%20state:open%20label:%20repo:bio-tools/content'
if res.status_code not in [200]:
return None
issues = res.json()
for issue in issues['items']:
# Take first found
logging.info("Found existing PR %d" % issue['number'])
branch = getPRBranch(issue['number'])
return branch
logging.info("No existing PR found")
return None
def createPR(branch):
logging.info("Create new PR for branch %s" % branch)
headers = {
'Accept': 'application/vnd.github.v3+json',
'Authorization': 'token ' + str(os.environ['GITHUB_BIOTOOLS_TOKEN'])
}
github_url = 'https://api.github.com/repos/%s/pulls' % ("bio-tools/content")
res = requests.post(
github_url,
json={
'title': "biocontainers-bot metadata import PR",
'head': branch,
"base": "master"
},
headers=headers
)
if not res.status_code in [200, 201]:
logging.error("Failed to create pull request: %s", res.text)
return False
pr = res.json()
issue = pr['number']
logging.info("PR %d created" % issue)
github_url = 'https://api.github.com/repos/%s/issues/%d' % ("bio-tools/content", issue)
res = requests.post(
github_url,
json={
'labels': [BOT_LABEL],
},
headers=headers
)
if not res.status_code in [200]:
logging.error("Failed to add issue label: %d" % res.status_code)
logging.info("Tagged issue: %d" % issue)
return True
docker_file = None
if len(sys.argv) > 1 and sys.argv[1]:
docker_file = sys.argv[1]
else:
logging.error("no Dockerfile specified")
sys.exit(1)
# use an existing branch ?
branch = None
hasPROpen = False
if len(sys.argv) > 2 and sys.argv[2]:
# if branch specified, we suppose there is an existing PR for this branch
branch = sys.argv[2]
logging.info("Branch %s requested" % branch)
hasPROpen = True
if not docker_file or not os.path.exists(docker_file):
logging.error("Could not find Dockerfile "+str(docker_file))
sys.exit(1)
with open(docker_file, 'r') as content_file:
content = content_file.read()
dfp = DockerfileParser(path='/tmp')
dfp.content = content
#Need to double check on ARGs here
dfp = dockerparse_arg_fix.reload_arg_to_env(dfp, content)
labels = dfp.labels
# biotools check
biotools_label = 'extra.identifiers.biotools'
biotools = None
if biotools_label not in labels:
logging.error("No biotools label")
# sys.exit(0)
else:
biotools = labels[biotools_label].strip()
version = labels["software.version"]
versionExtra = labels["version"]
name = labels["software"]
if 'container' in labels:
name = labels['container']
containerVersion = 'v%s_cv%s' % (version, str(versionExtra))
if branch is None:
# no branch specified, look for an existing PR
branch = hasPR()
if branch is not None:
hasPROpen = True
(repo, branch) = repoSetup(branch)
dirname = '/tmp/biotools-content/data/' + name
bioContainersFile = '/tmp/biotools-content/data/' + name + '/biocontainers.yaml'
if biotools is not None:
dirname = '/tmp/biotools-content/data/' + biotools
bioContainersFile = '/tmp/biotools-content/data/' + biotools + '/biocontainers.yaml'
if not os.path.exists(dirname):
os.makedirs(dirname)
cLabels = {}
for k, v in labels.items():
cLabels[k] = v
data = {
'software': name,
'labels': deepcopy(cLabels),
'versions': []
}
softwares = {'softwares': {}}
softwares["softwares"][name] = data
if os.path.exists(bioContainersFile):
with open(bioContainersFile) as fp:
# softwares = json.load(fp, object_pairs_hook=OrderedDict)
softwares = load(fp, Loader=Loader)
if name not in softwares["softwares"]:
softwares["softwares"][name] = data
exists = False
for download in softwares["softwares"][name]["versions"]:
if download["version"] == containerVersion:
exists = True
break
if not exists:
newDownload = {
"url": "biocontainers/" + name + ":" + containerVersion,
"version": containerVersion,
"type": "Container file",
"labels": deepcopy(cLabels)
}
softwares["softwares"][name]["versions"].append(newDownload)
with open(bioContainersFile, 'w') as fp:
# json.dump(softwares, fp, indent=4, separators=(', ', ': '), ensure_ascii=False)
dump(softwares, fp, Dumper=Dumper)
repo.index.add([bioContainersFile])
if biotools is not None:
repo.index.commit("Add version for %s:%s" % (biotools, containerVersion))
else:
repo.index.commit("Add version for %s:%s" % (name, containerVersion))
try:
logging.info("Push to branch %s" % branch)
if not hasPROpen:
repo.git.push('-u', 'origin', branch)
createPR(branch)
else:
repo.git.push()
except Exception as e:
logging.exception('failed to push fork: ' + str(e))
sys.exit(0)