1414
1515import m2r
1616import os
17+ import re
18+ import semver
1719import sys
1820
1921from CPAC import __version__
2224from github .GithubException import RateLimitExceededException , \
2325 UnknownObjectException
2426
27+ # "Dealing with Invalid Versions" from
28+ # https://python-semver.readthedocs.io/en/latest/usage.html
29+
30+
31+ def coerce (version ):
32+ """
33+ Convert an incomplete version string into a semver-compatible VersionInfo
34+ object
35+
36+ * Tries to detect a "basic" version string (``major.minor.patch``).
37+ * If not enough components can be found, missing components are
38+ set to zero to obtain a valid semver version.
39+
40+ :param str version: the version string to convert
41+ :return: a tuple with a :class:`VersionInfo` instance (or ``None``
42+ if it's not a version) and the rest of the string which doesn't
43+ belong to a basic version.
44+ :rtype: tuple(:class:`VersionInfo` | None, str)
45+ """
46+ BASEVERSION = re .compile (
47+ r"""[vV]?
48+ (?P<major>0|[1-9]\d*)
49+ (\.
50+ (?P<minor>0|[1-9]\d*)
51+ (\.
52+ (?P<patch>0|[1-9]\d*)
53+ )?
54+ )?
55+ """ ,
56+ re .VERBOSE ,
57+ )
58+
59+ match = BASEVERSION .search (version )
60+ if not match :
61+ return (None , version )
62+
63+ ver = {
64+ key : 0 if value is None else value for key , value in match .groupdict ().items ()
65+ }
66+ ver = semver .VersionInfo (** ver )
67+ rest = match .string [match .end () :] # noqa:E203
68+ return ver , rest
69+
70+
71+ def compare_versions (new , old ):
72+ """
73+ Function to compare two versions.
74+
75+ Parameters
76+ ----------
77+ new: str
78+
79+ old: str
80+
81+ Returns
82+ -------
83+ bool
84+ Is the "new" at least as new as "old"?
85+ """
86+ comparisons = list (zip (coerce (new ), coerce (old )))
87+ if any ([v is None for v in comparisons [0 ]]):
88+ return (False )
89+ outright = semver .compare (str (comparisons [0 ][0 ]), str (comparisons [0 ][1 ]))
90+ return (
91+ bool (outright == 1 ) or bool (
92+ (outright == 0 ) and comparisons [1 ][0 ] >= comparisons [1 ][1 ]
93+ )
94+ )
95+
96+
2597# If extensions (or modules to document with autodoc) are in another directory,
2698# add these directories to sys.path here. If the directory is relative to the
2799# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -110,6 +182,17 @@ def _gh_rate_limit():
110182 gh_tags = []
111183gh_tags .sort (reverse = True )
112184
185+ build_version_path = os .path .abspath (os .path .join (
186+ __file__ , os .pardir , os .pardir , os .pardir , 'build_version.txt'
187+ ))
188+ # don't build release notes for newer releases
189+ if os .path .exists (build_version_path ):
190+ with open (build_version_path , 'r' ) as bvf :
191+ build_version = bvf .read ().strip ()
192+ gh_tags = [gh_tag for gh_tag in gh_tags if compare_versions (
193+ build_version , gh_tag
194+ )]
195+
113196# Try to get release notes from GitHub
114197try :
115198 gh_releases = []
@@ -129,9 +212,9 @@ def _gh_rate_limit():
129212 t : {
130213 'name' : t ,
131214 'body' : '' .join ([
132- 'See https://github.com/FCP-INDI/C-PAC/releases/tag/{t} ' ,
133- ' for ' ,
134- 'release notes.'
215+ 'See https://github.com/FCP-INDI/C-PAC/releases/tag/' ,
216+ t ,
217+ ' for release notes.'
135218 ]),
136219 'published_at' : None
137220 } for t in gh_tags
@@ -181,7 +264,7 @@ def _unireplace(release_note, unireplace):
181264 ).strip (),
182265 ' ({})' .format (
183266 dparser .parse (gh_releaseNotes [t ]['published_at' ]).date (
184- ).strftime ('%b %w , %Y' )
267+ ).strftime ('%b %d , %Y' )
185268 ) if gh_releaseNotes [t ]['published_at' ] else ''
186269 )
187270 release_note = '\n ' .join (_unireplace (
@@ -199,13 +282,11 @@ def _unireplace(release_note, unireplace):
199282 {}
200283 ))
201284
202- release_notes_path = os .path .join (
203- release_notes_dir , '{}.rst' .format (t )
204- )
285+ release_notes_path = os .path .join (release_notes_dir , f'{ t } .rst' )
205286 if gh_releaseNotes [t ]['published_at' ] and not os .path .exists (
206287 release_notes_path
207288 ) and not os .path .exists (
208- os .path .join (release_notes_dir , 'v{}.rst' . format ( t ) )
289+ os .path .join (release_notes_dir , f 'v{ t } .rst' )
209290 ):
210291 with open (release_notes_path , 'w+' ) as f :
211292 f .write (release_note )
@@ -243,49 +324,44 @@ def _unireplace(release_note, unireplace):
243324 {}
244325
245326""" .format (
246- '\n ' .join ([
247- '.. include:: /user/release_notes/{}' .format (fp ) for fp in rnd
248- ]),
249- '\n ' .join ([
250- '/user/release_notes/{}' .format (d ) for d in rnd
251- ])
252- )
327+ '\n ' .join ([f'.. include:: /user/release_notes/{ fp } ' for fp in rnd ]),
328+ '\n ' .join ([f'/user/release_notes/{ d } ' for d in rnd ]))
253329with open (os .path .join (release_notes_dir , 'index.rst' ), 'w+' ) as f :
254330 f .write (all_release_notes .strip ())
255331
256332
257333# The full version, including alpha/beta/rc tags.
258- release = '{ } Beta'. format ( __version__ )
334+ release = f' { __version__ } Beta'
259335
260336# The language for content autogenerated by Sphinx. Refer to documentation
261337# for a list of supported languages.
262338# language = None
263- #
339+
264340# There are two options for replacing |today|: either, you set today to some
265341# non-false value, then it is used:
266342# today = ''
267343# Else, today_fmt is used as the format for a strftime call.
268344# today_fmt = '%B %d, %Y'
269- #
345+
270346# List of patterns, relative to source directory, that match files and
271347# directories to ignore when looking for source files.
272348exclude_patterns = ['futuredocs/*' ]
273349
274350# The reST default role (used for this markup: `text`) to use for all
275351# documents.
276352# default_role = None
277- #
353+
278354# If true, '()' will be appended to :func: etc. cross-reference text.
279355# add_function_parentheses = True
280- #
356+
281357# If true, the current module name will be prepended to all description
282358# unit titles (such as .. function::).
283359# add_module_names = True
284- #
360+
285361# If true, sectionauthor and moduleauthor directives will be shown in the
286362# output. They are ignored by default.
287363# show_authors = False
288- #
364+
289365# The name of the Pygments (syntax highlighting) style to use.
290366pygments_style = 'sphinx'
291367
@@ -294,7 +370,7 @@ def _unireplace(release_note, unireplace):
294370
295371# -- Options for HTML output --------------------------------------------------
296372
297- # The theme to use for HTML and HTML Help pages. See the documentation for
373+ # The theme to use for HTML and HTML Help pages. See the documentation for
298374# a list of builtin themes.
299375html_theme = 'classic'
300376
@@ -317,12 +393,12 @@ def _unireplace(release_note, unireplace):
317393]
318394
319395# The name for this set of Sphinx documents. If None, it defaults to
320- # " <project> v<release> documentation" .
396+ # ' <project> v<release> documentation' .
321397# html_title = None
322- #
398+
323399# A shorter title for the navigation bar. Default is the same as html_title.
324400# html_short_title = None
325- #
401+
326402# The name of an image file (relative to this directory) to place at the top
327403# of the sidebar.
328404html_logo = '_static/cpac_logo_vertical.png'
@@ -334,17 +410,17 @@ def _unireplace(release_note, unireplace):
334410
335411# Add any paths that contain custom static files (such as style sheets) here,
336412# relative to this directory. They are copied after the builtin static files,
337- # so a file named " default.css" will overwrite the builtin " default.css" .
413+ # so a file named ' default.css' will overwrite the builtin ' default.css' .
338414html_static_path = ['_static' ]
339415
340416# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
341417# using the given strftime format.
342418# html_last_updated_fmt = '%b %d, %Y'
343- #
419+
344420# If true, SmartyPants will be used to convert quotes and dashes to
345421# typographically correct entities.
346422# html_use_smartypants = True
347- #
423+
348424# Custom sidebar templates, maps document names to template names.
349425html_sidebars = {
350426 '**' : [
@@ -357,30 +433,30 @@ def _unireplace(release_note, unireplace):
357433# Additional templates that should be rendered to pages, maps page names to
358434# template names.
359435# html_additional_pages = {}
360- #
436+
361437# If false, no module index is generated.
362438# html_domain_indices = True
363- #
439+
364440# If false, no index is generated.
365441# html_use_index = True
366- #
442+
367443# If true, the index is split into individual pages for each letter.
368444# html_split_index = False
369- #
445+
370446# If true, links to the reST sources are added to the pages.
371447# html_show_sourcelink = True
372- #
373- # If true, " Created using Sphinx" is shown in the HTML footer. Default is True.
448+
449+ # If true, ' Created using Sphinx' is shown in the HTML footer. Default is True.
374450# html_show_sphinx = True
375- #
376- # If true, " (C) Copyright ..." is shown in the HTML footer. Default is True.
451+
452+ # If true, ' (C) Copyright ...' is shown in the HTML footer. Default is True.
377453# html_show_copyright = True
378- #
454+
379455# If true, an OpenSearch description file will be output, and all pages will
380456# contain a <link> tag referring to it. The value of this option must be the
381457# base URL from which the finished HTML is served.
382458# html_use_opensearch = ''
383- #
459+
384460# This is the file name suffix for HTML files (e.g. '.xhtml').
385461html_file_suffix = '.html'
386462
@@ -415,20 +491,20 @@ def _unireplace(release_note, unireplace):
415491# The name of an image file (relative to this directory) to place at the top of
416492# the title page.
417493# latex_logo = None
418- #
419- # For " manual" documents, if this is true, then toplevel headings are parts,
494+
495+ # For ' manual' documents, if this is true, then toplevel headings are parts,
420496# not chapters.
421497# latex_use_parts = False
422- #
498+
423499# If true, show page references after internal links.
424500# latex_show_pagerefs = False
425- #
501+
426502# If true, show URL addresses after external links.
427503# latex_show_urls = False
428- #
504+
429505# Documents to append as an appendix to all manuals.
430506# latex_appendices = []
431- #
507+
432508# If false, no module index is generated.
433509# latex_domain_indices = True
434510
@@ -454,10 +530,10 @@ def _unireplace(release_note, unireplace):
454530
455531# Documents to append as an appendix to all manuals.
456532# texinfo_appendices = []
457- #
533+
458534# If false, no module index is generated.
459535# texinfo_domain_indices = True
460- #
536+
461537# How to display URL addresses: 'footnote', 'no', or 'inline'.
462538# texinfo_show_urls = 'footnote'
463539
0 commit comments