mirror of
https://github.com/odoo/runbot.git
synced 2025-03-27 13:25:47 +07:00
[IMP] conftest: minor cleanups to repo creation
- Use f-strings where appropriate. - Get the repo url from github instead of composing it by hand - Resolve URI template for the contents endpoint instead of hand-building the URL. URI template implementation is janky AF.
This commit is contained in:
parent
88453aa462
commit
e065206f79
61
conftest.py
61
conftest.py
@ -58,6 +58,7 @@ import os
|
|||||||
import pathlib
|
import pathlib
|
||||||
import pprint
|
import pprint
|
||||||
import re
|
import re
|
||||||
|
import secrets
|
||||||
import select
|
import select
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
@ -73,7 +74,7 @@ import xmlrpc.client
|
|||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit, quote
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import requests
|
import requests
|
||||||
@ -366,7 +367,7 @@ def port():
|
|||||||
def page(port):
|
def page(port):
|
||||||
with requests.Session() as s:
|
with requests.Session() as s:
|
||||||
def get(url):
|
def get(url):
|
||||||
r = s.get('http://localhost:{}{}'.format(port, url))
|
r = s.get(f'http://localhost:{port}{url}')
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.content
|
return r.content
|
||||||
yield get
|
yield get
|
||||||
@ -533,6 +534,39 @@ def reviewer_admin(env, partners):
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
VARCHAR = "[0-9a-z_]|%[0-9a-f]{2}"
|
||||||
|
VARNAME = f"(?:(?:{VARCHAR})(?:\.|{VARCHAR})*)"
|
||||||
|
VARLIST = fr"{VARNAME}(?:\,{VARNAME})*"
|
||||||
|
TEMPLATE = re.compile(fr'''
|
||||||
|
\{{
|
||||||
|
# op level 2/3/reserved
|
||||||
|
(?P<operator>[+\#./;?&=,!@|])?
|
||||||
|
(?P<varlist>{VARLIST})
|
||||||
|
# modifier level 4
|
||||||
|
(:? (?P<prefix>:[0-9]+) | (?P<explode>\*) )
|
||||||
|
\}}
|
||||||
|
''', flags=re.VERBOSE | re.IGNORECASE)
|
||||||
|
def template(tmpl, **params):
|
||||||
|
# FIXME: actually implement RFC 6570 cleanly
|
||||||
|
# see https://stackoverflow.com/a/76276177/8182118 for the expansions github
|
||||||
|
# seems to be using (except it's missing + so probably incomplete...)
|
||||||
|
def replacer(m):
|
||||||
|
esc = lambda v: quote(v, safe="")
|
||||||
|
match m['operator']:
|
||||||
|
case None: # simple
|
||||||
|
pass
|
||||||
|
case '+': # allowReserved
|
||||||
|
esc = lambda v: v
|
||||||
|
case s:
|
||||||
|
raise NotImplementedError(f"Operator {s!r} is not supported")
|
||||||
|
|
||||||
|
v = params[m['varlist']]
|
||||||
|
if not isinstance(v, str):
|
||||||
|
raise TypeError(f"Unsupported parameter type {type(v).__name__!r}")
|
||||||
|
return esc(v)
|
||||||
|
|
||||||
|
return TEMPLATE.sub(replacer, tmpl)
|
||||||
|
|
||||||
def check(response):
|
def check(response):
|
||||||
assert response.ok, response.text or response.reason
|
assert response.ok, response.text or response.reason
|
||||||
return response
|
return response
|
||||||
@ -550,10 +584,10 @@ def make_repo(request, config, tunnel, users):
|
|||||||
|
|
||||||
# check whether "owner" is a user or an org, as repo-creation endpoint is
|
# check whether "owner" is a user or an org, as repo-creation endpoint is
|
||||||
# different
|
# different
|
||||||
q = _rate_limited(lambda: github.get('https://api.github.com/users/{}'.format(owner)))
|
q = _rate_limited(lambda: github.get(f'https://api.github.com/users/{owner}'))
|
||||||
q.raise_for_status()
|
q.raise_for_status()
|
||||||
if q.json().get('type') == 'Organization':
|
if q.json().get('type') == 'Organization':
|
||||||
endpoint = 'https://api.github.com/orgs/{}/repos'.format(owner)
|
endpoint = f'https://api.github.com/orgs/{owner}/repos'
|
||||||
else:
|
else:
|
||||||
endpoint = 'https://api.github.com/user/repos'
|
endpoint = 'https://api.github.com/user/repos'
|
||||||
r = check(github.get('https://api.github.com/user'))
|
r = check(github.get('https://api.github.com/user'))
|
||||||
@ -561,13 +595,9 @@ def make_repo(request, config, tunnel, users):
|
|||||||
|
|
||||||
repos = []
|
repos = []
|
||||||
def repomaker(name, *, hooks=True):
|
def repomaker(name, *, hooks=True):
|
||||||
name = 'ignore_%s_%s' % (name, base64.b64encode(os.urandom(6), b'-_').decode())
|
|
||||||
fullname = '{}/{}'.format(owner, name)
|
|
||||||
repo_url = 'https://api.github.com/repos/{}'.format(fullname)
|
|
||||||
|
|
||||||
# create repo
|
# create repo
|
||||||
r = check(github.post(endpoint, json={
|
r = check(github.post(endpoint, json={
|
||||||
'name': name,
|
'name': f'ignore_{name}_{secrets.token_urlsafe(6)}',
|
||||||
'has_issues': True,
|
'has_issues': True,
|
||||||
'has_projects': False,
|
'has_projects': False,
|
||||||
'has_wiki': False,
|
'has_wiki': False,
|
||||||
@ -578,17 +608,18 @@ def make_repo(request, config, tunnel, users):
|
|||||||
'allow_rebase_merge': False,
|
'allow_rebase_merge': False,
|
||||||
}))
|
}))
|
||||||
r = r.json()
|
r = r.json()
|
||||||
|
repo_url = r['url']
|
||||||
# wait for repository visibility
|
# wait for repository visibility
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
if github.head(r['url']).ok:
|
if github.head(repo_url).ok:
|
||||||
break
|
break
|
||||||
|
|
||||||
repo = Repo(github, fullname, repos)
|
repo = Repo(github, r['full_name'], repos)
|
||||||
|
|
||||||
if hooks:
|
if hooks:
|
||||||
# create webhook
|
# create webhook
|
||||||
check(github.post('{}/hooks'.format(repo_url), json={
|
check(github.post(r['hooks_url'], json={
|
||||||
'name': 'web',
|
'name': 'web',
|
||||||
'config': {
|
'config': {
|
||||||
'url': '{}/runbot_merge/hooks'.format(tunnel),
|
'url': '{}/runbot_merge/hooks'.format(tunnel),
|
||||||
@ -599,11 +630,11 @@ def make_repo(request, config, tunnel, users):
|
|||||||
}))
|
}))
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
check(github.put('{}/contents/{}'.format(repo_url, 'a'), json={
|
check(github.put(template(r['contents_url'], path='a'), json={
|
||||||
'path': 'a',
|
'path': 'a',
|
||||||
'message': 'github returns a 409 (Git Repository is Empty) if trying to create a tree in a repo with no objects',
|
'message': 'github returns a 409 (Git Repository is Empty) if trying to create a tree in a repo with no objects',
|
||||||
'content': base64.b64encode(b'whee').decode('ascii'),
|
'content': base64.b64encode(b'whee').decode('ascii'),
|
||||||
'branch': 'garbage_%s' % uuid.uuid4()
|
'branch': f'garbage_{uuid.uuid4()}'
|
||||||
}))
|
}))
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
return repo
|
return repo
|
||||||
@ -880,7 +911,7 @@ class Repo:
|
|||||||
def fork(self, *, token=None):
|
def fork(self, *, token=None):
|
||||||
s = self._get_session(token)
|
s = self._get_session(token)
|
||||||
|
|
||||||
r = s.post('https://api.github.com/repos/{}/forks'.format(self.name))
|
r = s.post(f'https://api.github.com/repos/{self.name}/forks')
|
||||||
assert 200 <= r.status_code < 300, r.text
|
assert 200 <= r.status_code < 300, r.text
|
||||||
|
|
||||||
repo_name = r.json()['full_name']
|
repo_name = r.json()['full_name']
|
||||||
|
Loading…
Reference in New Issue
Block a user