-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathsphinxext.py
149 lines (131 loc) · 5.29 KB
/
sphinxext.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
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os.path
from docutils import nodes
from docutils.parsers import rst
from docutils.parsers.rst import directives
from docutils import statemachine
from dulwich import repo
from sphinx.util import logging
from sphinx.util.nodes import nested_parse_with_titles
import reno
from reno import config
from reno import defaults
from reno import formatter
from reno import loader
LOG = logging.getLogger(__name__)
class ReleaseNotesDirective(rst.Directive):
has_content = True
# FIXME(dhellmann): We should be able to build this information
# from the configuration options so we don't have to edit it
# manually when we add new options.
option_spec = {
'branch': directives.unchanged,
'reporoot': directives.unchanged,
'relnotessubdir': directives.unchanged,
'notesdir': directives.unchanged,
'version': directives.unchanged,
'collapse-pre-releases': directives.flag,
'earliest-version': directives.unchanged,
'stop-at-branch-base': directives.flag,
'ignore-notes': directives.unchanged,
'unreleased-version-title': directives.unchanged,
}
def _find_reporoot(self, reporoot_opt, relnotessubdir_opt):
"""Find root directory of project."""
reporoot = os.path.abspath(reporoot_opt)
# When building on RTD.org the root directory may not be
# the current directory, so look for it.
try:
return repo.Repo.discover(reporoot).path
except Exception:
pass
for root in ('.', '..', '../..'):
if os.path.exists(os.path.join(root, relnotessubdir_opt)):
return root
raise Exception(
'Could not discover root directory; tried: %s' % ', '.join([
os.path.abspath(root) for root in ('.', '..', '../..')
])
)
def run(self):
title = ' '.join(self.content)
branch = self.options.get('branch')
relnotessubdir = self.options.get(
'relnotessubdir', defaults.RELEASE_NOTES_SUBDIR,
)
reporoot = self._find_reporoot(
self.options.get('reporoot', '.'), relnotessubdir,
)
ignore_notes = [
name.strip()
for name in self.options.get('ignore-notes', '').split(',')
]
conf = config.Config(reporoot, relnotessubdir)
opt_overrides = {}
if 'notesdir' in self.options:
opt_overrides['notesdir'] = self.options.get('notesdir')
version_opt = self.options.get('version')
# FIXME(dhellmann): Force these flags True for now and figure
# out how Sphinx passes a "false" flag later.
# 'collapse-pre-releases' in self.options
opt_overrides['collapse_pre_releases'] = True
# Only stop at the branch base if we have not been told
# explicitly which versions to include.
opt_overrides['stop_at_branch_base'] = (version_opt is None)
if 'earliest-version' in self.options:
opt_overrides['earliest_version'] = self.options.get(
'earliest-version')
if 'unreleased-version-title' in self.options:
opt_overrides['unreleased_version_title'] = self.options.get(
'unreleased-version-title')
if branch:
opt_overrides['branch'] = branch
if ignore_notes:
opt_overrides['ignore_notes'] = ignore_notes
conf.override(**opt_overrides)
notesdir = os.path.join(relnotessubdir, conf.notesdir)
LOG.info('scanning %s for %s release notes' % (
os.path.join(conf.reporoot, notesdir),
branch or 'current branch'))
with loader.Loader(conf) as ldr:
if version_opt is not None:
versions = [
v.strip()
for v in version_opt.split(',')
]
else:
versions = ldr.versions
LOG.info('got versions %s' % (versions,))
text = formatter.format_report(
ldr,
conf,
versions,
title=title,
branch=branch,
)
source_name = '<%s %s>' % (__name__, branch or 'current branch')
result = statemachine.ViewList()
for line_num, line in enumerate(text.splitlines(), 1):
LOG.debug('%4d: %s', line_num, line)
result.append(line, source_name, line_num)
node = nodes.section()
node.document = self.state.document
nested_parse_with_titles(self.state, result, node)
return node.children
def setup(app):
app.add_directive('release-notes', ReleaseNotesDirective)
metadata_dict = {
'version': reno.__version__,
'parallel_read_safe': True
}
return metadata_dict