def test_without_title(self): result = formatter.format_report( loader=self.ldr, versions_to_include=self.versions, title=None, ) self.assertNotIn('This is the title', result)
def report_cmd(args): "Generates a release notes report" reporoot = args.reporoot.rstrip('/') + '/' notesdir = utils.get_notes_dir(args) collapse = args.collapse_pre_releases ldr = loader.Loader( reporoot=reporoot, notesdir=notesdir, branch=args.branch, collapse_pre_releases=collapse, earliest_version=args.earliest_version, ) if args.version: versions = args.version else: versions = ldr.versions text = formatter.format_report( ldr, versions, title='Release Notes', ) if args.output: with open(args.output, 'w') as f: f.write(text) else: print(text) return
def test_versions(self): result = formatter.format_report( loader=self.ldr, versions_to_include=self.versions, title='This is the title', ) self.assertIn('0.0.0\n=====', result) self.assertIn('1.0.0\n=====', result)
def test_with_title(self): result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, title='This is the title', ) self.assertIn('This is the title', result)
def test_without_title(self): result = formatter.format_report( reporoot=None, scanner_output=self.scanner_output, versions_to_include=self.versions, title=None, ) self.assertNotIn('This is the title', result)
def run(self): env = self.state.document.settings.env app = env.app def info(msg): app.info('[reno] %s' % (msg,)) title = ' '.join(self.content) branch = self.options.get('branch') reporoot_opt = self.options.get('reporoot', '.') reporoot = os.path.abspath(reporoot_opt) relnotessubdir = self.options.get('relnotessubdir', defaults.RELEASE_NOTES_SUBDIR) 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 opt_overrides['stop_at_branch_base'] = True if 'earliest-version' in self.options: opt_overrides['earliest_version'] = self.options.get( 'earliest-version') if branch: opt_overrides['branch'] = branch conf.override(**opt_overrides) notesdir = os.path.join(relnotessubdir, conf.notesdir) info('scanning %s for %s release notes' % (os.path.join(conf.reporoot, notesdir), branch or 'current branch')) ldr = loader.Loader(conf) if version_opt is not None: versions = [ v.strip() for v in version_opt.split(',') ] else: versions = ldr.versions info('got versions %s' % (versions,)) text = formatter.format_report( ldr, versions, title=title, ) source_name = '<' + __name__ + '>' result = statemachine.ViewList() for line in text.splitlines(): result.append(line, source_name) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children
def test_versions(self): result = formatter.format_report( reporoot=None, scanner_output=self.scanner_output, versions_to_include=self.versions, title='This is the title', ) self.assertIn('0.0.0\n=====', result) self.assertIn('1.0.0\n=====', result)
def test_without_title(self): result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, ) self.assertIn('.. _relnotes_0.0.0:', result) self.assertIn('.. _relnotes_0.0.0_Prelude:', result) self.assertIn('.. _relnotes_1.0.0:', result) self.assertIn('.. _relnotes_1.0.0_Known Issues:', result)
def test_with_title(self): self.c.override(unreleased_version_title='Not Released') result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, title='This is the title', ) self.assertIn('Not Released', result) self.assertNotIn('0.1.0-1', result) self.assertIn('.. _This is the title_Not Released:', result)
def test_with_branch(self): result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, branch='stable/queens', ) self.assertIn('.. _relnotes_0.0.0_stable_queens:', result) self.assertIn('.. _relnotes_0.0.0_stable_queens_Prelude:', result) self.assertIn('.. _relnotes_1.0.0_stable_queens:', result) self.assertIn('.. _relnotes_1.0.0_stable_queens_Known Issues:', result)
def test_section_order(self): result = formatter.format_report( loader=self.ldr, versions_to_include=self.versions, title=None, ) prelude_pos = result.index('This is the prelude.') issues_pos = result.index('This is the first issue.') features_pos = result.index('We added a feature!') expected = [prelude_pos, features_pos, issues_pos] actual = list(sorted([prelude_pos, features_pos, issues_pos])) self.assertEqual(expected, actual)
def test_with_title(self): self.c.override(unreleased_version_title='Not Released') result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, title='This is the title', ) self.assertIn('.. _This is the title_0.0.0:', result) self.assertIn('.. _This is the title_0.0.0_Prelude:', result) self.assertIn('.. _This is the title_1.0.0:', result) self.assertIn('.. _This is the title_1.0.0_Known Issues:', result)
def run(self): env = self.state.document.settings.env app = env.app def info(msg): app.info('[reno] %s' % (msg,)) title = ' '.join(self.content) branch = self.options.get('branch') reporoot_opt = self.options.get('reporoot', '.') reporoot = os.path.abspath(reporoot_opt) relnotessubdir = self.options.get('relnotessubdir', defaults.RELEASE_NOTES_SUBDIR) notessubdir = self.options.get('notesdir', defaults.NOTES_SUBDIR) version_opt = self.options.get('version') # FIXME(dhellmann): Force this flag True for now and figure # out how Sphinx passes a "false" flag later. collapse = True # 'collapse-pre-releases' in self.options earliest_version = self.options.get('earliest-version') notesdir = os.path.join(relnotessubdir, notessubdir) info('scanning %s for %s release notes' % (os.path.join(reporoot, notesdir), branch or 'current branch')) ldr = loader.Loader( reporoot=reporoot, notesdir=notesdir, branch=branch, collapse_pre_releases=collapse, earliest_version=earliest_version, ) if version_opt is not None: versions = [ v.strip() for v in version_opt.split(',') ] else: versions = ldr.versions text = formatter.format_report( ldr, versions, title=title, ) source_name = '<' + __name__ + '>' result = ViewList() for line in text.splitlines(): result.append(line, source_name) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children
def test_custom_section_order(self): result = formatter.format_report( loader=self.ldr, config=self.c, versions_to_include=self.versions, title=None, ) prelude_pos = result.index('This is the prelude.') api_pos = result.index('API Changes') features_pos = result.index('New Features') expected = [prelude_pos, api_pos, features_pos] actual = list(sorted([prelude_pos, features_pos, api_pos])) self.assertEqual(expected, actual)
def report_cmd(args, conf): "Generates a release notes report" ldr = loader.Loader(conf) if args.version: versions = args.version else: versions = ldr.versions text = formatter.format_report( ldr, versions, title='Release Notes', ) if args.output: with open(args.output, 'w') as f: f.write(text) else: print(text) return
def run(self): env = self.state.document.settings.env app = env.app def info(msg): app.info('[reno] %s' % (msg,)) title = ' '.join(self.content) branch = self.options.get('branch') reporoot_opt = self.options.get('reporoot', '.') reporoot = os.path.abspath(reporoot_opt) relnotessubdir = self.options.get('relnotessubdir', defaults.RELEASE_NOTES_SUBDIR) notessubdir = self.options.get('notesdir', defaults.NOTES_SUBDIR) version_opt = self.options.get('version') notesdir = os.path.join(relnotessubdir, notessubdir) info('scanning %s for %s release notes' % (os.path.join(reporoot, notesdir), branch or 'current branch')) notes = scanner.get_notes_by_version(reporoot, notesdir, branch) if version_opt is not None: versions = [ v.strip() for v in version_opt.split(',') ] else: versions = notes.keys() text = formatter.format_report( reporoot, notes, versions, title=title, ) source_name = '<' + __name__ + '>' result = ViewList() for line in text.splitlines(): result.append(line, source_name) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children
def report_cmd(args, conf): "Generates a release notes report" ldr = loader.Loader(conf) if args.version: versions = args.version else: versions = ldr.versions text = formatter.format_report( ldr, conf, versions, title=args.title, show_source=args.show_source, ) if args.output: with open(args.output, 'w') as f: f.write(text) else: print(text) return
def report_cmd(args): "Generates a release notes report" reporoot = args.reporoot.rstrip('/') + '/' notesdir = utils.get_notes_dir(args) notes = scanner.get_notes_by_version(reporoot, notesdir, args.branch) if args.version: versions = args.version else: versions = notes.keys() text = formatter.format_report( reporoot, notes, versions, title='Release Notes', ) if args.output: with open(args.output, 'w') as f: f.write(text) else: print(text) return
def run(self): conf = config.Config(self.repo_root, self.rel_notes_dir) # Generate the cache using the configuration options found # in the release notes directory and the default output # filename. cache_filename = cache.write_cache_db( conf=conf, versions_to_include=[], # include all versions outfilename=None, # generate the default name ) log.info('wrote cache file to %s', cache_filename) ldr = loader.Loader(conf) text = formatter.format_report( ldr, conf, ldr.versions, title=self.distribution.metadata.name, ) with open(self.output_file, 'w') as f: f.write(text) log.info('wrote release notes to %s', self.output_file)
def run(self): # type: () -> nodes.Node """ Run to generate the output from .. ddtrace-release-notes:: directive 1. Determine the max version cutoff we need to report for We determine this by traversing the git log until we find the first dev or release branch ref. If we are generating for 1.x branch we will use 2.0 as the cutoff. If we are generating for 0.60 branch we will use 0.61 as the cutoff. We do this to ensure if we are generating notes for older versions we do no include all up to date release notes. Think releasing 0.57.2 when there is 0.58.0, 0.59.0, 1.0.0, etc we only want notes for < 0.58. 2. Iterate through all release branches A release branch is one that matches the ``^[0-9]+.[0-9]+``` pattern Skip any that do not meet the max version cutoff. 3. Determine the earliest version to report for each release branch If the release has only RC releases then use ``.0rc1`` as the earliest version. If there are non-RC releases then use ``.0`` version as the earliest. We do this because we want reno to only report notes that are for that given release branch but it will collapse RC releases if there is a non-RC tag on that branch. So there isn't a consistent "earliest version" we can use for in-progress/dev branches as well as released branches. 4. Generate a reno config for reporting and generate the notes for each branch """ # This is where we will aggregate the generated notes title = " ".join(self.content) result = statemachine.ViewList() # Determine the max version we want to report for max_version = self._get_report_max_version() LOG.info("capping max report version to %r", max_version) # For each release branch, starting with the newest for version, ref in self._release_branches: # If this version is equal to or greater than the max version we want to report for if max_version is not None and version >= max_version: LOG.info("skipping %s >= %s", version, max_version) continue # Older versions did not have reno release notes # DEV: Reno will fail if we try to run on a branch with no notes if (version.major, version.minor) < (0, 44): LOG.info("skipping older version %s", version) continue # Parse the branch name from the ref, we want origin/{major}.{minor}[-dev] _, _, branch = ref.partition("refs/remotes/") # Determine the earliest release tag for this version earliest_version = self._get_earliest_version(version) if not earliest_version: LOG.info("no release tags found for %s", version) continue # Setup reno config conf = config.Config(self._repo.path, "releasenotes") conf.override( branch=branch, collapse_pre_releases=True, stop_at_branch_base=True, earliest_version=earliest_version, ) LOG.info( "scanning %s for %s release notes, stopping at %s", os.path.join(self._repo.path, "releasenotes/notes"), branch, earliest_version, ) # Generate the formatted RST with loader.Loader(conf) as ldr: 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") for line_num, line in enumerate(text.splitlines(), 1): LOG.debug("%4d: %s", line_num, line) result.append(line, source_name, line_num) # Generate the RST nodes to return for rendering node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children
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')) ldr = loader.Loader(conf) 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 generate_release_notes( repo, repo_path, start_revision, end_revision, show_dates, skip_requirement_merges, is_stable, series, email, email_from, email_reply_to, email_tags, include_pypi_link, changes_only, first_release, deliverable_file, description, publishing_dir_name, ): """Return the text of the release notes. :param repo: The name of the repo. :param repo_path: Path to the repo repository on disk. :param start_revision: First reference for finding change log. :param end_revision: Final reference for finding change log. :param show_dates: Boolean indicating whether or not to show dates in the output. :param skip_requirement_merges: Boolean indicating whether to skip merge commits for requirements changes. :param is_stable: Boolean indicating whether this is a stable series or not. :param series: String holding the name of the series. :param email: Boolean indicating whether the output format should be an email message. :param email_from: String containing the sender email address. :param email_reply_to: String containing the email reply-to address. :param email_tags: String containing the email header topic tags to add. :param include_pypi_link: Boolean indicating whether or not to include an automatically generated link to the PyPI package page. :param changes_only: Boolean indicating whether to limit output to the list of changes, without any extra data. :param first_release: Boolean indicating whether this is the first release of the project :param deliverable_file: The deliverable file path from the repo root. :param description: Description of the repo :param publishing_dir_name: The directory on publishings.openstack.org containing the package. """ repo_name = repo.split('/')[-1] # Determine if this is a release candidate or not. is_release_candidate = 'rc' in end_revision # Do not mention the series in independent model since there is none if series == 'independent': series = '' if not email_from: raise RuntimeError('No email-from specified') # Get the commits that are in the desired range... git_range = "%s..%s" % (start_revision, end_revision) if show_dates: format = "--format=%h %ci %s" else: format = "--oneline" cmd = ["git", "log", "--no-color", format, "--no-merges", git_range] stdout = run_cmd(cmd, cwd=repo_path) changes = [] for commit_line in stdout.splitlines(): commit_line = commit_line.strip() if not commit_line or is_skippable_commit(skip_requirement_merges, commit_line): continue else: changes.append(commit_line) # Filter out any requirement file changes... requirement_changes = [] requirement_files = list( glob.glob(os.path.join(repo_path, '*requirements*.txt'))) if requirement_files: cmd = ['git', 'diff', '-U0', '--no-color', git_range] cmd.extend(requirement_files) stdout = run_cmd(cmd, cwd=repo_path) requirement_changes = [ line.strip() for line in stdout.splitlines() if line.strip() ] # Get statistics about the range given... cmd = ['git', 'diff', '--stat', '--no-color', git_range] stdout = run_cmd(cmd, cwd=repo_path) diff_stats = [] for line in stdout.splitlines(): line = line.strip() if not line or line.find("tests") != -1 or line.startswith("doc"): continue diff_stats.append(line) # Extract + valdiate needed sections... sections = parse_deliverable(series, repo_name, deliverable_file=deliverable_file) change_header = ["Changes in %s %s" % (repo, git_range)] change_header.append("-" * len(change_header[0])) # Look for reno notes for this version. if not changes_only: logging.getLogger('reno').setLevel(logging.WARNING) cfg = reno_config.Config(reporoot=repo_path, ) branch = None if is_stable and series: branch = 'origin/stable/%s' % series cfg.override(branch=branch) ldr = loader.Loader(conf=cfg, ignore_cache=True) if end_revision in ldr.versions: rst_notes = formatter.format_report( loader=ldr, config=cfg, versions_to_include=[end_revision], ) reno_notes = rst2txt.convert(rst_notes).decode('utf-8') else: LOG.warning( ('Did not find revision %r in list of versions ' 'with release notes %r, skipping reno'), end_revision, ldr.versions, ) reno_notes = '' else: reno_notes = '' # The recipient for announcements should always be the # [email protected] ML (except for # release-test) email_to = '*****@*****.**' if repo_name == 'openstack-release-test': email_to = '*****@*****.**' params = dict(sections) params.update({ 'project': repo, 'description': description, 'end_rev': end_revision, 'range': git_range, 'lib': repo_path, 'skip_requirement_merges': skip_requirement_merges, 'changes': changes, 'requirement_changes': requirement_changes, 'diff_stats': diff_stats, 'change_header': "\n".join(change_header), 'emotion': random.choice(EMOTIONS), 'stable_series': is_stable, 'series': series, 'email': email, 'email_from': email_from, 'email_to': email_to, 'email_reply_to': email_reply_to, 'email_tags': email_tags, 'reno_notes': reno_notes, 'first_release': first_release, 'publishing_dir_name': publishing_dir_name, }) if include_pypi_link: params['pypi_url'] = PYPI_URL_TPL % repo_name else: params['pypi_url'] = None response = [] if changes_only: response.append(expand_template(CHANGES_ONLY_TPL, params)) else: if email: email_header = expand_template(EMAIL_HEADER_TPL.strip(), params) response.append(email_header.lstrip()) if is_release_candidate: response.append(expand_template(RELEASE_CANDIDATE_TPL, params)) else: header = expand_template(HEADER_RELEASE_TPL.strip(), params) response.append(parawrap.fill(header)) response.append(expand_template(CHANGE_RELEASE_TPL, params)) return '\n'.join(response)
def generate_release_notes(library, library_path, start_revision, end_revision, show_dates, skip_requirement_merges, is_stable, series, email, email_from, email_to, email_reply_to, email_tags, include_pypi_link, changes_only, first_release, ): """Return the text of the release notes. :param library: The name of the library. :param library_path: Path to the library repository on disk. :param start_revision: First reference for finding change log. :param end_revision: Final reference for finding change log. :param show_dates: Boolean indicating whether or not to show dates in the output. :param skip_requirement_merges: Boolean indicating whether to skip merge commits for requirements changes. :param is_stable: Boolean indicating whether this is a stable series or not. :param series: String holding the name of the series. :param email: Boolean indicating whether the output format should be an email message. :param email_from: String containing the sender email address. :param email_to: String containing the email recipient. :param email_reply_to: String containing the email reply-to address. :param email_tags: String containing the email header topic tags to add. :param include_pypi_link: Boolean indicating whether or not to include an automatically generated link to the PyPI package page. :param changes_only: Boolean indicating whether to limit output to the list of changes, without any extra data. :param first_release: Boolean indicating whether this is the first release of the project """ # Do not mention the series in independent model since there is none if series == 'independent': series = '' if not os.path.isfile(os.path.join(library_path, "setup.py")): raise RuntimeError("No 'setup.py' file found in %s\n" % library_path) if not email_from: raise RuntimeError('No email-from specified') # Get the python library/program description... cmd = [sys.executable, 'setup.py', '--description'] stdout, stderr = run_cmd(cmd, cwd=library_path) description = stdout.strip() # Get the python library/program name cmd = [sys.executable, 'setup.py', '--name'] stdout, stderr = run_cmd(cmd, cwd=library_path) library_name = stdout.strip() # Get the commits that are in the desired range... git_range = "%s..%s" % (start_revision, end_revision) if show_dates: format = "--format=%h %ci %s" else: format = "--oneline" cmd = ["git", "log", "--no-color", format, "--no-merges", git_range] stdout, stderr = run_cmd(cmd, cwd=library_path) changes = [] for commit_line in stdout.splitlines(): commit_line = commit_line.strip() if not commit_line or is_skippable_commit(skip_requirement_merges, commit_line): continue else: changes.append(commit_line) # Filter out any requirement file changes... requirement_changes = [] requirement_files = list(glob.glob(os.path.join(library_path, '*requirements*.txt'))) if requirement_files: cmd = ['git', 'diff', '-U0', '--no-color', git_range] cmd.extend(requirement_files) stdout, stderr = run_cmd(cmd, cwd=library_path) requirement_changes = [line.strip() for line in stdout.splitlines() if line.strip()] # Get statistics about the range given... cmd = ['git', 'diff', '--stat', '--no-color', git_range] stdout, stderr = run_cmd(cmd, cwd=library_path) diff_stats = [] for line in stdout.splitlines(): line = line.strip() if not line or line.find("tests") != -1 or line.startswith("doc"): continue diff_stats.append(line) # Extract + valdiate needed sections from readme... readme_sections = parse_readme(library_path) change_header = ["Changes in %s %s" % (library_name, git_range)] change_header.append("-" * len(change_header[0])) # Look for reno notes for this version. branch = None if is_stable and series: branch = 'origin/stable/%s' % series scanner_output = scanner.get_notes_by_version( reporoot=library_path, notesdir='%s/%s' % (reno_defaults.RELEASE_NOTES_SUBDIR, reno_defaults.NOTES_SUBDIR), branch=branch, ) if end_revision in scanner_output: rst_notes = formatter.format_report( reporoot=library_path, scanner_output=scanner_output, versions_to_include=[end_revision], ) reno_notes = rst2txt.convert(rst_notes) else: reno_notes = '' params = dict(readme_sections) params.update({ 'project': library_name, 'description': description, 'end_rev': end_revision, 'range': git_range, 'lib': library_path, 'skip_requirement_merges': skip_requirement_merges, 'changes': changes, 'requirement_changes': requirement_changes, 'diff_stats': diff_stats, 'change_header': "\n".join(change_header), 'emotion': random.choice(EMOTIONS), 'stable_series': is_stable, 'series': series, 'email': email, 'email_from': email_from, 'email_to': email_to, 'email_reply_to': email_reply_to, 'email_tags': email_tags, 'reno_notes': reno_notes, 'first_release': first_release, }) if include_pypi_link: params['pypi_url'] = PYPI_URL_TPL % library_name else: params['pypi_url'] = None response = [] if changes_only: response.append(expand_template(CHANGES_ONLY_TPL, params)) else: if email: email_header = expand_template(EMAIL_HEADER_TPL.strip(), params) response.append(email_header.lstrip()) header = expand_template(HEADER_RELEASE_TPL.strip(), params) response.append(parawrap.fill(header)) response.append(expand_template(CHANGE_RELEASE_TPL, params)) return '\n'.join(response)
def run(self): env = self.state.document.settings.env app = env.app def info(msg): app.info('[reno] %s' % (msg, )) title = ' '.join(self.content) branch = self.options.get('branch') reporoot_opt = self.options.get('reporoot', '.') reporoot = os.path.abspath(reporoot_opt) # When building on RTD.org the root directory may not be # the current directory, so look for it. reporoot = repo.Repo.discover(reporoot).path relnotessubdir = self.options.get('relnotessubdir', defaults.RELEASE_NOTES_SUBDIR) 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 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) info('scanning %s for %s release notes' % (os.path.join( conf.reporoot, notesdir), branch or 'current branch')) ldr = loader.Loader(conf) if version_opt is not None: versions = [v.strip() for v in version_opt.split(',')] else: versions = ldr.versions info('got versions %s' % (versions, )) text = formatter.format_report( ldr, conf, versions, title=title, ) source_name = '<%s %s>' % (__name__, branch or 'current branch') result = statemachine.ViewList() for line in text.splitlines(): result.append(line, source_name) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children