Skip to content

Commit 953a4ee

Browse files
committed
Merge remote-tracking branch 'origin/master' into davidfischer/enable-timezone-support
2 parents 0a01b96 + 104c3a6 commit 953a4ee

File tree

1,495 files changed

+149658
-66254
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,495 files changed

+149658
-66254
lines changed

.codecov.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
comment:
2+
layout: "diff, files"

.coveragerc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
[run]
2+
branch = true
3+
source = .
24
omit =
35
*/**/migrations/*
6+
*/**/management/commands/*
7+
*/**/settings/*
8+
*/**/settings.py
9+
analytics/vendor/*
10+
rtd_tests/*
11+
*/**/tests/**
12+
wsgi.py
13+
14+
[report]
15+
exclude_lines =
16+
if self.debug:
17+
pragma: no cover
18+
raise NotImplementedError
19+
if __name__ == .__main__.:
20+
if getattr(settings, 'DEBUG'):

.travis.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ matrix:
1616
script: tox
1717
- python: 3.6
1818
env: TOXENV=eslint
19+
- python: 3.6
20+
env: TOXENV=migrations
1921
cache:
2022
directories:
2123
- ~/.cache/pip
2224
- ~/.nvm/nvm.sh
2325
- ~/.npm
26+
before_install:
27+
- sudo apt-get install -y git
2428
install:
2529
- ./scripts/travis/install_elasticsearch.sh
2630
- pip install tox-travis
@@ -42,4 +46,6 @@ notifications:
4246

4347
branches:
4448
only:
45-
- master
49+
- master
50+
- rel # Community release branch
51+
- relcorp # Corporate release branch

CHANGELOG.rst

Lines changed: 137 additions & 0 deletions
Large diffs are not rendered by default.

README.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Welcome to Read the Docs
22
========================
33

4-
|build-status| |docs|
4+
|build-status| |docs| |coverage|
55

66
Purpose
77
-------
@@ -70,6 +70,11 @@ when you push to GitHub.
7070
:scale: 100%
7171
:target: https://docs.readthedocs.io/en/latest/?badge=latest
7272

73+
.. |coverage| image:: https://codecov.io/gh/rtfd/readthedocs.org/branch/master/graph/badge.svg
74+
:alt: Test coverage
75+
:scale: 100%
76+
:target: https://codecov.io/gh/rtfd/readthedocs.org
77+
7378
License
7479
-------
7580

contrib/add-project.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
"""
2+
Script to add a Git project as cloned from a Github repository
3+
to ReadTheDocs. Invoke from the checkout.
4+
"""
5+
6+
__requires__ = ['requests-toolbelt', 'autocommand', 'keyring']
7+
8+
9+
import os
10+
import getpass
11+
import re
12+
import urllib.parse
13+
import subprocess
14+
import pathlib
15+
16+
import autocommand
17+
import keyring
18+
from requests_toolbelt import sessions
19+
20+
21+
rtd = sessions.BaseUrlSession(
22+
os.environ.get('RTD_URL', 'https://readthedocs.org/api/v2/'))
23+
github = sessions.BaseUrlSession('https://api.github.com/')
24+
github.headers.update(Accept='application/vnd.github.v3+json')
25+
26+
27+
class User:
28+
"""
29+
A User (with a password) in RTD.
30+
31+
Resolves username using ``getpass.getuser()``. Override with
32+
RTD_USERNAME environment variable.
33+
34+
Resolves password using keyring. Install keyring and run
35+
``keyring set https://readthedocs.org/ $USER`` to set the pw.
36+
Override with RTD_PASSWORD environment variable.
37+
"""
38+
def __init__(self):
39+
self.name = os.environ.get('RTD_USERNAME') or getpass.getuser()
40+
system = rtd.create_url('/')
41+
self.password = (
42+
os.environ.get('RTD_PASSWORD')
43+
or keyring.get_password(system, self.name)
44+
)
45+
46+
@property
47+
def id(self):
48+
resp = rtd.get('../v1/user/', params=dict(username=self.name))
49+
resp.raise_for_status()
50+
ob, = resp.json()['objects']
51+
return ob['id']
52+
53+
@property
54+
def tuple(self):
55+
return self.name, self.password
56+
57+
58+
class Sluggable(str):
59+
"""
60+
A name for use in RTD with a 'slug' version.
61+
"""
62+
@property
63+
def slug(self):
64+
return self.replace('.', '')
65+
66+
67+
class Repo:
68+
"""
69+
A Git repo
70+
"""
71+
72+
def __init__(self, root):
73+
self.root = root
74+
cmd = ['git', '-C', root, 'remote', 'get-url', 'origin']
75+
proc = subprocess.run(
76+
cmd, check=True, text=True, stdout=subprocess.PIPE)
77+
self.url = proc.stdout.strip()
78+
79+
@property
80+
def name(self):
81+
return Sluggable(pathlib.Path(self.url).stem)
82+
83+
84+
def create_project(repo):
85+
"""
86+
Create the project from a Repo
87+
"""
88+
user = User()
89+
payload = dict(
90+
repo=repo.url,
91+
slug=repo.name.slug,
92+
name=repo.name,
93+
users=[user.id],
94+
)
95+
resp = rtd.post('project/', json=payload, auth=user.tuple)
96+
resp.raise_for_status()
97+
98+
99+
def configure_github(name, url):
100+
"""
101+
Given a project name and webhook URL, configure the webhook
102+
in GitHub.
103+
104+
Resolves username from ``getpass.getuser()``. Override with
105+
``GITHUB_USERNAME``.
106+
107+
Resolves access token from keyring for username and system
108+
'github.com'. Override with ``GITHUB_TOKEN`` environment
109+
variable.
110+
"""
111+
user = os.environ.get('GITHUB_USERNAME') or getpass.getuser()
112+
token = (
113+
keyring.get_password('github.com', user)
114+
or os.environ['GITHUB_TOKEN']
115+
)
116+
headers = dict(Authorization=f'token {token}')
117+
path = f'/repos/{user}/{name}/hooks'
118+
params = dict(
119+
name='web',
120+
config=dict(
121+
url=url,
122+
content_type='json',
123+
),
124+
)
125+
github.post(path, json=params, headers=headers)
126+
127+
128+
def configure_webhook(name):
129+
"""
130+
Identify the webhook URL for a RTD project named name.
131+
"""
132+
login_path = '/accounts/login/'
133+
resp = rtd.get(login_path)
134+
token = rtd.cookies.get('csrftoken') or rtd.cookies['csrf']
135+
user = User()
136+
params = dict(
137+
login=user.name,
138+
password=user.password,
139+
csrfmiddlewaretoken=token,
140+
next='/',
141+
)
142+
headers = dict(Referer=rtd.create_url(login_path))
143+
resp = rtd.post(login_path, data=params, headers=headers)
144+
token = rtd.cookies.get('csrftoken') or rtd.cookies['csrf']
145+
params = dict(
146+
integration_type='github_webhook',
147+
csrfmiddlewaretoken=token,
148+
next='/',
149+
)
150+
create_path = f'/dashboard/{name.slug}/integrations/create/'
151+
headers = dict(
152+
Referer=rtd.create_url(create_path),
153+
)
154+
resp = rtd.post(
155+
create_path,
156+
data=params,
157+
headers=headers,
158+
)
159+
resp.raise_for_status()
160+
ref = re.search(f'<a href="(.*?)">.*?webhook.*?</a>', resp.text).group(1)
161+
return urllib.parse.urljoin(resp.url, ref)
162+
163+
164+
@autocommand.autocommand(__name__)
165+
def main(repo: Repo = Repo('.')):
166+
create_project(repo)
167+
url = configure_webhook(repo.name)
168+
configure_github(repo.name, url)

docs/.rstcheck.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[rstcheck]
2-
ignore_directives=automodule,http:get
2+
ignore_directives=automodule,http:get,tabs,tab
33
ignore_roles=djangosetting,setting
44
ignore_messages=(Duplicate implicit target name: ".*")|(Hyperlink target ".*" is not referenced)

0 commit comments

Comments
 (0)