Пример #1
0
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)
Пример #2
0
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)
Пример #3
0
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()
Пример #4
0
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()
Пример #5
0
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)
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
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)
Пример #9
0
 def test_fill(self):
     self.assertEqual(fill('1234567890', width=5),
                      '12345\n'
                      '67890')
Пример #10
0
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)