Beispiel #1
0
def main(fname=None):
    if not fname:
        fname = os.path.join(rfcs.root_folder, 'index.md')
    # Load all metadata
    all = [rfc for rfc in rfcs.walk()]
    all.sort(key=lambda x: x.num)
    tmp_fname = fname + '.tmp'
    with open(tmp_fname, 'w', encoding='utf-8') as out:
        out.write("# Aries RFCs by Status\n")
        for status in rfcs.status_list:
            out.write(f"\n## [{status}](README.md#{status.lower()})\n")
            with_status = [rfc for rfc in all if rfc.status == status]
            for rfc in with_status:
                line = f"* [{rfc.num}: {rfc.title}]({rfc.relpath})"
                tags = [f"[`{x}`](/tags.md#{x})" for x in rfc.tags]
                line += f" ({rfc.since}"
                if rfc.impl_count:
                    line += f", [{rfc.impl_count} impl"
                    if rfc.impl_count > 1:
                        line += 's'
                    line += '](' + rfc.relpath + '#implementations)'
                line += ' — ' + ' '.join(tags) + ')'
                out.write(line + '\n')
        out.write(
            "\n\n>(This file is machine-generated; see [code/generate_index.py](code/generate_index.py).)\n"
        )
    update(fname, tmp_fname)
Beispiel #2
0
def test_rfc_metadata():
    errors = []

    def e(rfc, msg):
        errors.append(rfc.relpath.replace('README.md', '') + ': ' + msg)

    for rfc in rfcs.walk():
        if not bool(rfc.title): e(rfc, 'no title found')
        if rfc.category not in rfc.relpath:
            e(rfc, 'category does not match path')
        if rfc.category[:-1] not in rfc.tags: e(rfc, 'category not in tags')
        opposite_category = 'feature' if rfc.category == 'concepts' else 'concept'
        if opposite_category in rfc.tags: e(rfc, 'opposite category in tags')
        if rfc.status not in rfcs.status_list:
            e(rfc, 'status is not canonical')
        if not re.match(r'\d{4}$', rfc.num): e(rfc, 'num is not 4 digits')
        if not re.search(r'\d{4}-\d{2}-\d{2}', rfc.since):
            e(rfc, 'since does not contain yyyy-mm-dd')
        if rfc.start_date:
            if not re.search(r'\d{4}-\d{2}-\d{2}', rfc.start_date):
                e(rfc, 'start_date does not contain yyyy-mm-dd')
        if bool(rfc.authors):
            if '@' in rfc.authors:
                if not re.search(r'\[.*?\]\([^)]+@.*?\)', rfc.authors):
                    e(rfc, 'email is not clickable')
        else:
            e(rfc, 'no authors found')
        if ','.join(rfc.tags) != ','.join(rfc.tags).lower():
            e(rfc, 'tags are case-sensitive')
        if rfc.supersedes:
            if not re.search(r'\[.*?\]\(.*?\)', rfc.supersedes):
                e(rfc, 'supersedes does not contain hyperlink')
        if rfc.superseded_by:
            if not re.search(r'\[.*?\]\(.*?\)', rfc.superseded_by):
                e(rfc, 'superseded_by does not contain hyperlink')
        if rfc.impl_count > 0:
            if rfc.status == 'PROPOSED':
                e(rfc, 'should not be PROPOSED if it has an impl')
    if errors:
        msg = '\n' + '\n'.join(errors)
        raise BaseException(msg)
Beispiel #3
0
def test_rfc_metadata():
    errors = []

    def e(rfc, msg):
        errors.append(rfc.relpath.replace('README.md', '') + ': ' + msg)

    def warn(rfc, msg):
        sys.stderr.write('Warning: ' + rfc.relpath.replace('README.md', '') +
                         ': ' + msg + '\n')

    for rfc in rfcs.walk():
        if not bool(rfc.title): e(rfc, 'no title found')
        if rfc.category not in rfc.relpath:
            e(rfc, 'category does not match path')
        if rfc.category[:-1] not in rfc.tags: e(rfc, 'category not in tags')
        opposite_category = 'feature' if rfc.category == 'concepts' else 'concept'
        if opposite_category in rfc.tags: e(rfc, 'opposite category in tags')
        if rfc.status not in rfcs.status_list:
            e(rfc, 'status is not canonical')
        if not re.match(r'\d{4}$', rfc.num): e(rfc, 'num is not 4 digits')
        if not re.search(r'\d{4}-\d{2}-\d{2}', rfc.since):
            e(rfc, 'since does not contain yyyy-mm-dd')
        if rfc.start_date:
            if not re.search(r'\d{4}-\d{2}-\d{2}', rfc.start_date):
                e(rfc, 'start_date does not contain yyyy-mm-dd')
        if bool(rfc.authors):
            if '@' in rfc.authors:
                if not re.search(r'\[.*?\]\([^)]+@.*?\)', rfc.authors):
                    e(rfc, 'email is not clickable')
        else:
            e(rfc, 'no authors found')
        if ','.join(rfc.tags) != ','.join(rfc.tags).lower():
            e(rfc, 'tags are case-sensitive')
        if rfc.supersedes:
            if not re.search(r'\[.*?\]\(.*?\)', rfc.supersedes):
                e(rfc, 'supersedes does not contain hyperlink')
        if rfc.superseded_by:
            if not re.search(r'\[.*?\]\(.*?\)', rfc.superseded_by):
                e(rfc, 'superseded_by does not contain hyperlink')
        if rfc.status == 'PROPOSED':
            for impl in rfcs.test_suite_impls(rfc, False):
                e(rfc,
                  'should not be PROPOSED if it has a non-test-suite impl')
                break
        # Should this RFC have links to test results?
        elif rfc.status in [
                'ACCEPTED', 'ADOPTED'
        ] and 'feature' in rfc.tags and ('protocol' in rfc.tags
                                         or 'decorator' in rfc.tags):
            found_test_suite_in_impls = False
            for row in rfcs.test_suite_impls(rfc, True):
                found_test_suite_in_impls = True
                break
            if not found_test_suite_in_impls:
                msg = 'Test suite must be an impl for any protocol- or decorator-related RFC beyond DEMONSTRATED status.'
                if 'test-anomaly' in rfc.tags:
                    warn(rfc, msg)
                else:
                    e(rfc,
                      msg + ' Tag "test-anomaly" to temporarily override.')
            for row in rfcs.test_suite_impls(rfc, False):
                m = rfcs.get_test_results_link(row)
                # If we lack a link entirely, this is an error, period.
                # If we have tagged the RFC with "test-anomaly", then it becomes possible to link
                # the ugly text "MISSING test results" to the test-anomaly tag and have the result
                # be only a warning. This ugly text+link should only be accepted when the 'test-anomaly'
                # tag is present.
                desc = rfcs.describe_impl_row(row)
                if m is None:
                    e(
                        rfc,
                        'Impl "%s" needs a link to test results in its Notes column. Format = [test results](...) or, if RFC is tagged "test-anomaly", [MISSING test results](/tags.md#test-anomaly).'
                        % desc)
                # Are test results explicitly declared to be missing?
                elif ('MISSING' in m.group(1)
                      and '/tags.md#test-anomaly' in m.group(2)):
                    if 'test-anomaly' in rfc.tags:
                        warn(
                            rfc,
                            'Impl "%s" needs to replace missing test results with something meaningful.'
                            % desc)
                    else:
                        e(
                            rfc,
                            'Can\'t declare missing tests without the "test-anomaly" tag to make the RFC ugly, so impl "%s" needs a link to test results in its Notes column. Format = [test results](...).'
                            % desc)

    if errors:
        msg = '\n' + '\n'.join(errors)
        raise BaseException(msg)