def config_web_parser(parser: argparse.ArgumentParser, is_primary=False): """Configure the argument parser for the web command Args: parser: The parser to configure is_primary: True if configuring as the main command. False if configuring as a sub-command. """ parser.description = parawrap.fill( 'Run builtin dev server or print a command that would run the server ' 'if the command were evaluated. Although the production server will ' 'not be run directly, it could be run with:\n' '\n' '\t\'eval $({}{} web [OPTIONS] <production-server>)\'' ''.format(cfg.PKG_NAME, '' if is_primary else ' web') ) parser.formatter_class = MixedHelpFormatter parser.add_argument('--debug', '-d', action='store_true', help='Run the dev server with debug web iface and ' 'reload server on source file changes') parser.add_argument('--host', default=cfg.WEB_HOST, help='Server host/name') parser.add_argument('--port', '-p', type=int, default=cfg.WEB_PORT, help='Port on which the server listens') parser.add_argument('server', choices=('builtin', 'eventlet', 'gunicorn'), default='builtin', help='Run builtin dev server or print command ' 'related to running a specific production server') parser.set_defaults(func=web_cmd)
def wrap_text(): """ Open LICENSE file, wrap it to max 75 char width, and write it back out. """ with open('LICENSE', 'r') as license_file: strings = license_file.read() file_string = ''.join(strings) wrapped_text = parawrap.fill(text=file_string, width=75) with open('LICENSE', 'w') as license_file: license_file.write(wrapped_text)
def generate_email(args): params = { 'FULL_NAME': args.who, 'HE_SHE': args.gender.title(), 'TEAM_CORE': '%s-core' % args.team, 'ME': args.sender, } params['TEAM'] = args.team.strip().lower() params['HE_SHE_LOWER'] = params['HE_SHE'].lower() params['FIRST_NAME'] = params['FULL_NAME'].split()[0] contents = expand_template(CORE_TPL, params) contents = parawrap.fill(contents.strip(), width=75) # Put the links on after so they are not affected by the wrapping... links = [ 'https://launchpad.net/~%s' % args.who_launchpad_id, 'https://launchpad.net/%s' % params['TEAM'], ] contents += "\n\n" for i, link in enumerate(links, 1): contents += "[%s] %s\n" % (i, link) return contents.rstrip()
responsibility of being a new core member[1] in project {{project}}). What do you think, are you able (and willing) to accept? If you have any questions, please feel free to respond or jump on freenode and chat with the team on channel #openstack-oslo (one of the other cores in oslo usually around). This message will self-destruct in 5 seconds. Sincerely, The Oslo Team [1] http://docs.openstack.org/infra/manual/core.html """ firstname = sys.argv[1] lastname = sys.argv[2] tpl_args = { 'firstname': firstname, 'project': sys.argv[3], 'lastname': lastname, 'firstname_title': firstname.title(), 'lastname_title': lastname.title(), 'chosen_how': random.choice(chosen_how), } tpl_value = expand_template(new_oslo_core_tpl.lstrip(), tpl_args) tpl_value = parawrap.fill(tpl_value) print(tpl_value)
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 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)
responsibility of being a new core member[1] in project {{project}}). What do you think, are you able (and willing) to accept? If you have any questions, please feel free to respond or jump on freenode and chat with the team on channel #openstack-oslo (one of the other cores in oslo usually around). This message will self-destruct in 5 seconds. Sincerely, The Oslo Team [1] http://docs.openstack.org/infra/manual/core.html """ firstname = sys.argv[1] lastname = sys.argv[2] tpl_args = { "firstname": firstname, "project": sys.argv[3], "lastname": lastname, "firstname_title": firstname.title(), "lastname_title": lastname.title(), "chosen_how": random.choice(chosen_how), } tpl_value = expand_template(new_oslo_core_tpl.lstrip(), tpl_args) tpl_value = parawrap.fill(tpl_value) print(tpl_value)
def test_fill(self): self.assertEqual(fill('1234567890', width=5), '12345\n' '67890')
def generate_release_notes(library, library_path, start_revision, end_revision, show_dates, skip_requirement_merges, notable_changes, is_stable, series, email, email_from, email_to, email_reply_to, email_tags, include_pypi_link, changes_only, ): """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 notable_changes: Highlights from the release. :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. """ if not os.path.isfile(os.path.join(library_path, "setup.py")): raise RuntimeError("No 'setup.py' file found in %s\n" % library_path) # 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) bug_url = readme_sections['bug_url'] if bug_url: lp_url = bug_url.replace("bugs.", "").rstrip("/") milestone_url = lp_url + "/+milestone/%s" % end_revision else: lp_url = '' milestone_url = '' change_header = ["Changes in %s %s" % (library_name, git_range)] change_header.append("-" * len(change_header[0])) if not email_from: raise RuntimeError('No email-from specified') params = dict(readme_sections) params.update({ 'project': os.path.basename(library_path), 'description': description, 'end_rev': end_revision, 'range': git_range, 'lib': library_path, 'milestone_url': milestone_url, 'skip_requirement_merges': skip_requirement_merges, 'changes': changes, 'requirement_changes': requirement_changes, 'diff_stats': diff_stats, 'notables': notable_changes, '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, }) 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)