From 0bddc7b9bd21f85b21c5461b3aab6e5087afeda2 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 12 Jan 2023 17:03:08 -0500 Subject: [PATCH 1/4] Clean up GitHub statistics script This clears up the flake8 exception, and corrects the title and trailing whitespace that I always need to clean up when committing the file. --- .flake8 | 1 - tools/github_stats.py | 241 ++++++++++++++++++++++++------------------ 2 files changed, 137 insertions(+), 105 deletions(-) diff --git a/.flake8 b/.flake8 index 490ea57d9891..1041b27b8be2 100644 --- a/.flake8 +++ b/.flake8 @@ -36,7 +36,6 @@ exclude = doc/tutorials # External files. tools/gh_api.py - tools/github_stats.py .tox .eggs diff --git a/tools/github_stats.py b/tools/github_stats.py index f6e190324194..b5263eebad7a 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -1,13 +1,13 @@ #!/usr/bin/env python """Simple tools to query github.com and gather stats about issues. -To generate a report for IPython 2.0, run: +To generate a report for Matplotlib 3.0.0, run: - python github_stats.py --milestone 2.0 --since-tag rel-1.0.0 + python github_stats.py --milestone 3.0.0 --since-tag v2.0.0 """ -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # Imports -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- import sys @@ -19,33 +19,72 @@ get_paged_request, make_auth_header, get_pull_request, is_pull_request, get_milestone_id, get_issues_list, get_authors, ) -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # Globals -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- ISO8601 = "%Y-%m-%dT%H:%M:%SZ" PER_PAGE = 100 -#----------------------------------------------------------------------------- +REPORT_TEMPLATE = """\ +.. _github-stats: + +{title} +{title_underline} + +GitHub statistics for {since_day} (tag: {tag}) - {today} + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed {n_issues} issues and merged {n_pulls} pull requests. +{milestone} +The following {nauthors} authors contributed {ncommits} commits. + +{unique_authors} +{links} + +Previous GitHub statistics +-------------------------- + +.. toctree:: + :maxdepth: 1 + :glob: + :reversed: + + prev_whats_new/github_stats_*""" +MILESTONE_TEMPLATE = ( + 'The full list can be seen `on GitHub ' + '`__\n') +LINKS_TEMPLATE = """ +GitHub issues and pull requests: + +Pull Requests ({n_pulls}): + +{pull_request_report} + +Issues ({n_issues}): + +{issue_report} +""" + +# ----------------------------------------------------------------------------- # Functions -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + def round_hour(dt): - return dt.replace(minute=0,second=0,microsecond=0) + return dt.replace(minute=0, second=0, microsecond=0) + def _parse_datetime(s): """Parse dates in the format returned by the GitHub API.""" - if s: - return datetime.strptime(s, ISO8601) - else: - return datetime.fromtimestamp(0) + return datetime.strptime(s, ISO8601) if s else datetime.fromtimestamp(0) + def issues2dict(issues): """Convert a list of issues to a dict, keyed by issue number.""" - idict = {} - for i in issues: - idict[i['number']] = i - return idict + return {i['number']: i for i in issues} + def split_pulls(all_issues, project="matplotlib/matplotlib"): """Split a list of closed issues into non-PR Issues and Pull Requests.""" @@ -60,9 +99,12 @@ def split_pulls(all_issues, project="matplotlib/matplotlib"): return issues, pulls -def issues_closed_since(period=timedelta(days=365), project="matplotlib/matplotlib", pulls=False): - """Get all issues closed since a particular point in time. period - can either be a datetime object, or a timedelta object. In the +def issues_closed_since(period=timedelta(days=365), + project='matplotlib/matplotlib', pulls=False): + """ + Get all issues closed since a particular point in time. + + *period* can either be a datetime object, or a timedelta object. In the latter case, it is used as a time before the present. """ @@ -72,60 +114,73 @@ def issues_closed_since(period=timedelta(days=365), project="matplotlib/matplotl since = round_hour(datetime.utcnow() - period) else: since = period - url = "https://api.github.com/repos/%s/%s?state=closed&sort=updated&since=%s&per_page=%i" % (project, which, since.strftime(ISO8601), PER_PAGE) + url = ( + f'https://api.github.com/repos/{project}/{which}' + f'?state=closed' + f'&sort=updated' + f'&since={since.strftime(ISO8601)}' + f'&per_page={PER_PAGE}') allclosed = get_paged_request(url, headers=make_auth_header()) - filtered = [ i for i in allclosed if _parse_datetime(i['closed_at']) > since ] + filtered = (i for i in allclosed + if _parse_datetime(i['closed_at']) > since) if pulls: - filtered = [ i for i in filtered if _parse_datetime(i['merged_at']) > since ] + filtered = (i for i in filtered + if _parse_datetime(i['merged_at']) > since) # filter out PRs not against main (backports) - filtered = [ i for i in filtered if i['base']['ref'] == 'main' ] + filtered = (i for i in filtered if i['base']['ref'] == 'main') else: - filtered = [ i for i in filtered if not is_pull_request(i) ] + filtered = (i for i in filtered if not is_pull_request(i)) - return filtered + return list(filtered) def sorted_by_field(issues, field='closed_at', reverse=False): """Return a list of issues sorted by closing date date.""" - return sorted(issues, key = lambda i:i[field], reverse=reverse) + return sorted(issues, key=lambda i: i[field], reverse=reverse) def report(issues, show_urls=False): """Summary report about a list of issues, printing number and title.""" + lines = [] if show_urls: for i in issues: role = 'ghpull' if 'merged_at' in i else 'ghissue' - print('* :%s:`%d`: %s' % (role, i['number'], - i['title'].replace('`', '``'))) + number = i['number'] + title = i['title'].replace('`', '``').strip() + lines.append(f'* :{role}:`{number}`: {title}') else: for i in issues: - print('* %d: %s' % (i['number'], i['title'].replace('`', '``'))) + number = i['number'] + title = i['title'].replace('`', '``').strip() + lines.append('* {number}: {title}') + return '\n'.join(lines) -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # Main script -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- if __name__ == "__main__": # Whether to add reST urls for all issues in printout. show_urls = True parser = ArgumentParser() - parser.add_argument('--since-tag', type=str, - help="The git tag to use for the starting point (typically the last major release)." - ) - parser.add_argument('--milestone', type=str, - help="The GitHub milestone to use for filtering issues [optional]." - ) - parser.add_argument('--days', type=int, - help="The number of days of data to summarize (use this or --since-tag)." - ) - parser.add_argument('--project', type=str, default="matplotlib/matplotlib", - help="The project to summarize." - ) - parser.add_argument('--links', action='store_true', default=False, - help="Include links to all closed Issues and PRs in the output." - ) + parser.add_argument( + '--since-tag', type=str, + help='The git tag to use for the starting point ' + '(typically the last major release).') + parser.add_argument( + '--milestone', type=str, + help='The GitHub milestone to use for filtering issues [optional].') + parser.add_argument( + '--days', type=int, + help='The number of days of data to summarize (use this or --since-tag).') + parser.add_argument( + '--project', type=str, default='matplotlib/matplotlib', + help='The project to summarize.') + parser.add_argument( + '--links', action='store_true', default=False, + help='Include links to all closed Issues and PRs in the output.') opts = parser.parse_args() tag = opts.since_tag @@ -135,9 +190,10 @@ def report(issues, show_urls=False): since = datetime.utcnow() - timedelta(days=opts.days) else: if not tag: - tag = check_output(['git', 'describe', '--abbrev=0']).strip().decode('utf8') + tag = check_output(['git', 'describe', '--abbrev=0'], + encoding='utf8').strip() cmd = ['git', 'log', '-1', '--format=%ai', tag] - tagday, tz = check_output(cmd).strip().decode('utf8').rsplit(' ', 1) + tagday, tz = check_output(cmd, encoding='utf8').strip().rsplit(' ', 1) since = datetime.strptime(tagday, "%Y-%m-%d %H:%M:%S") h = int(tz[1:3]) m = int(tz[3:]) @@ -152,21 +208,19 @@ def report(issues, show_urls=False): milestone = opts.milestone project = opts.project - print("fetching GitHub stats since %s (tag: %s, milestone: %s)" % (since, tag, milestone), file=sys.stderr) + print(f'fetching GitHub stats since {since} (tag: {tag}, milestone: {milestone})', + file=sys.stderr) if milestone: milestone_id = get_milestone_id(project=project, milestone=milestone, - auth=True) - issues_and_pulls = get_issues_list(project=project, - milestone=milestone_id, - state='closed', - auth=True, - ) + auth=True) + issues_and_pulls = get_issues_list(project=project, milestone=milestone_id, + state='closed', auth=True) issues, pulls = split_pulls(issues_and_pulls, project=project) else: issues = issues_closed_since(since, project=project, pulls=False) pulls = issues_closed_since(since, project=project, pulls=True) - # For regular reports, it's nice to show them in reverse chronological order + # For regular reports, it's nice to show them in reverse chronological order. issues = sorted_by_field(issues, reverse=True) pulls = sorted_by_field(pulls, reverse=True) @@ -175,71 +229,50 @@ def report(issues, show_urls=False): since_day = since.strftime("%Y/%m/%d") today = datetime.today() - # Print summary report we can directly include into release notes. - print('.. _github-stats:') - print() - title = 'GitHub statistics ' + today.strftime('(%b %d, %Y)') - print(title) - print('=' * len(title)) - - print() - print("GitHub statistics for %s (tag: %s) - %s" % (since_day, tag, today.strftime("%Y/%m/%d"), )) - print() - print("These lists are automatically generated, and may be incomplete or contain duplicates.") - print() + title = (f'GitHub statistics for {milestone.lstrip("v")} ' + f'{today.strftime("(%b %d, %Y)")}') ncommits = 0 all_authors = [] if tag: # print git info, in addition to GitHub info: - since_tag = tag+'..' + since_tag = f'{tag}..' cmd = ['git', 'log', '--oneline', since_tag] ncommits += len(check_output(cmd).splitlines()) - author_cmd = ['git', 'log', '--use-mailmap', "--format=* %aN", since_tag] - all_authors.extend(check_output(author_cmd).decode('utf-8', 'replace').splitlines()) + author_cmd = ['git', 'log', '--use-mailmap', '--format=* %aN', since_tag] + all_authors.extend( + check_output(author_cmd, encoding='utf-8', errors='replace').splitlines()) pr_authors = [] for pr in pulls: pr_authors.extend(get_authors(pr)) ncommits = len(pr_authors) + ncommits - len(pulls) author_cmd = ['git', 'check-mailmap'] + pr_authors - with_email = check_output(author_cmd).decode('utf-8', 'replace').splitlines() + with_email = check_output(author_cmd, + encoding='utf-8', errors='replace').splitlines() all_authors.extend(['* ' + a.split(' <')[0] for a in with_email]) unique_authors = sorted(set(all_authors), key=lambda s: s.lower()) - print("We closed %d issues and merged %d pull requests." % (n_issues, n_pulls)) if milestone: - print("The full list can be seen `on GitHub `__" - % (project, milestone_id) - ) - - print() - print("The following %i authors contributed %i commits." % (len(unique_authors), ncommits)) - print() - print('\n'.join(unique_authors)) + milestone_str = MILESTONE_TEMPLATE.format(project=project, + milestone_id=milestone_id) + else: + milestone_str = '' if opts.links: - print() - print("GitHub issues and pull requests:") - print() - print('Pull Requests (%d):\n' % n_pulls) - report(pulls, show_urls) - print() - print('Issues (%d):\n' % n_issues) - report(issues, show_urls) - print() - print() - print("""\ -Previous GitHub statistics --------------------------- - - -.. toctree:: - :maxdepth: 1 - :glob: - :reversed: - - prev_whats_new/github_stats_* + links = LINKS_TEMPLATE.format(n_pulls=n_pulls, + pull_request_report=report(pulls, show_urls), + n_issues=n_issues, + issue_report=report(issues, show_urls)) + else: + links = '' -""") + # Print summary report we can directly include into release notes. + print(REPORT_TEMPLATE.format(title=title, title_underline='=' * len(title), + since_day=since_day, tag=tag, + today=today.strftime('%Y/%m/%d'), + n_issues=n_issues, n_pulls=n_pulls, + milestone=milestone_str, + nauthors=len(unique_authors), ncommits=ncommits, + unique_authors='\n'.join(unique_authors), links=links)) From cf6f76d1e70611e322722f10e1a0ad35cffeaac1 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 17 Jan 2023 20:05:33 -0500 Subject: [PATCH 2/4] Fix extra line in Zenodo cache script Every run of the script adds an extra newline at the end. --- tools/cache_zenodo_svg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py index 4f441d960197..f5bd4a7ecf1a 100644 --- a/tools/cache_zenodo_svg.py +++ b/tools/cache_zenodo_svg.py @@ -125,7 +125,7 @@ def _get_xdg_cache_dir(): target = None if ln.strip() == ".. END OF AUTOGENERATED": target = footer - target.append(ln) + target.append(ln.rstrip()) with open(citing, "w") as fout: fout.write("\n".join(header)) From 9d5837faf1e889adf41078d79d9227bda78af9b0 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 18 Jan 2023 05:10:24 -0500 Subject: [PATCH 3/4] Update release guide for current practices --- doc/devel/release_guide.rst | 240 +++++++++++++++--------------------- 1 file changed, 98 insertions(+), 142 deletions(-) diff --git a/doc/devel/release_guide.rst b/doc/devel/release_guide.rst index 3f49631d00d8..3f4b17d15231 100644 --- a/doc/devel/release_guide.rst +++ b/doc/devel/release_guide.rst @@ -35,45 +35,41 @@ In addition the following test should be run and manually inspected:: python tools/memleak.py agg 1000 agg.pdf -In addition the following should be run and manually inspected, but -is currently broken:: - - pushd examples/tests/ - python backend_driver_sgskip.py - popd - - .. _release_ghstats: GitHub statistics ================= +We automatically extract GitHub issue, PRs, and authors from GitHub via the API. To +prepare this list: -We automatically extract GitHub issue, PRs, and authors from GitHub via the -API. Copy the current :file:`doc/users/github_stats.rst` to -:file:`doc/users/prev_whats_new/github_stats_X.Y.Z.rst`, changing the link -target at the top of the file, and removing the "Previous GitHub Stats" section -at the end. +1. Archive the existing GitHub statistics page. -For example, when updating from v3.2.0 to v3.2.1:: + a. Copy the current :file:`doc/users/github_stats.rst` to + :file:`doc/users/prev_whats_new/github_stats_{X}.{Y}.{Z}.rst`. + b. Change the link target at the top of the file. + c. Remove the "Previous GitHub Stats" section at the end. - cp doc/users/github_stats.rst doc/users/prev_whats_new/github_stats_3.2.0.rst - $EDITOR doc/users/prev_whats_new/github_stats_3.2.0.rst - # Change contents as noted above. - git add doc/users/prev_whats_new/github_stats_3.2.0.rst + For example, when updating from v3.2.0 to v3.2.1:: -Then re-generate the updated stats:: + cp doc/users/github_stats.rst doc/users/prev_whats_new/github_stats_3.2.0.rst + $EDITOR doc/users/prev_whats_new/github_stats_3.2.0.rst + # Change contents as noted above. + git add doc/users/prev_whats_new/github_stats_3.2.0.rst - python tools/github_stats.py --since-tag v3.2.0 --milestone=v3.2.1 --project 'matplotlib/matplotlib' --links > doc/users/github_stats.rst +2. Re-generate the updated stats:: -Review and commit changes. Some issue/PR titles may not be valid reST (the -most common issue is ``*`` which is interpreted as unclosed markup). + python tools/github_stats.py --since-tag v3.2.0 --milestone=v3.2.1 \ + --project 'matplotlib/matplotlib' --links > doc/users/github_stats.rst + +3. Review and commit changes. Some issue/PR titles may not be valid reST (the most + common issue is ``*`` which is interpreted as unclosed markup). .. note:: - Make sure you authenticate against the GitHub API. If you - do not you will get blocked by GitHub for going over the API rate - limits. You can authenticate in one of two ways: + Make sure you authenticate against the GitHub API. If you do not, you will get + blocked by GitHub for going over the API rate limits. You can authenticate in one of + two ways: * using the ``keyring`` package; ``pip install keyring`` and then when running the stats script, you will be prompted for user name and password, @@ -97,9 +93,16 @@ are going to tag on and delete the doc branch on GitHub. Update supported versions in Security Policy -------------------------------------------- -When making major or minor releases, update the supported versions in the -Security Policy in :file:`SECURITY.md`. Commonly, this may be one or two -previous minor releases, but is dependent on release managers. +When making major or minor releases, update the supported versions in the Security +Policy in :file:`SECURITY.md`. + +For minor version release update the table in :file:`SECURITY.md` to specify that the +two most recent minor releases in the current major version series are supported. + +For a major version release update the table in :file:`SECURITY.md` to specify that the +last minor version in the previous major version series is still supported. Dropping +support for the last version of a major version series will be handled on an ad-hoc +basis. Update release notes -------------------- @@ -110,9 +113,9 @@ What's new *Only needed for major and minor releases. Bugfix releases should not have new features.* -Merge the contents of all the files in :file:`doc/users/next_whats_new/` -into a single file :file:`doc/users/prev_whats_new/whats_new_X.Y.0.rst` -and delete the individual files. +Merge the contents of all the files in :file:`doc/users/next_whats_new/` into a single +file :file:`doc/users/prev_whats_new/whats_new_{X}.{Y}.0.rst` and delete the individual +files. API changes ~~~~~~~~~~~ @@ -120,9 +123,9 @@ API changes *Primarily needed for major and minor releases. We may sometimes have API changes in bugfix releases.* -Merge the contents of all the files in :file:`doc/api/next_api_changes/` -into a single file :file:`doc/api/prev_api_changes/api_changes_X.Y.Z.rst` -and delete the individual files. +Merge the contents of all the files in :file:`doc/api/next_api_changes/` into a single +file :file:`doc/api/prev_api_changes/api_changes_{X}.{Y}.{Z}.rst` and delete the +individual files. Release notes TOC ~~~~~~~~~~~~~~~~~ @@ -152,69 +155,52 @@ Update :file:`doc/users/release_notes.rst`: Update version switcher ~~~~~~~~~~~~~~~~~~~~~~~ -Update ``doc/_static/switcher.json``. If a minor release, ``X.Y.Z``, create -a new entry ``version: X.Y.(Z-1)``, and change the name of stable -``name: stable/X.Y.Z``. If a major release, ``X.Y.0``, change the name -of ``name: devel/X.(Y+1)`` and ``name: stable/X.Y.0`` as well as adding -a new version for the previous stable. +Update ``doc/_static/switcher.json``: + +- If a bugfix release, :samp:`{X}.{Y}.{Z}`, no changes are needed. +- If a major release, :samp:`{X}.{Y}.0`, change the name of :samp:`name: {X}.{Y+1} + (dev)` and :samp:`name: {X}.{Y} (stable)` as well as adding a new version for the + previous stable (:samp:`name: {X}.{Y-1}`). Verify that docs build ---------------------- -Finally, make sure that the docs build cleanly :: +Finally, make sure that the docs build cleanly:: make -Cdoc O=-j$(nproc) html latexpdf -After the docs are built, check that all of the links, internal and external, -are still valid. We use ``linkchecker`` for this, which has not been ported to -Python3 yet. You will need to create a Python2 environment with -``requests==2.9.0`` and linkchecker :: +After the docs are built, check that all of the links, internal and external, are still +valid. We use ``linkchecker`` for this:: - conda create -p /tmp/lnkchk python=2 requests==2.9.0 - source activate /tmp/lnkchk pip install linkchecker pushd doc/build/html linkchecker index.html --check-extern popd -Address any issues which may arise. The internal links are checked on Circle -CI, this should only flag failed external links. - - -Update supported versions in SECURITY.md ----------------------------------------- - -For minor version release update the table in :file:`SECURITY.md` to specify -that the 2 most recent minor releases in the current major version series are -supported. +Address any issues which may arise. The internal links are checked on Circle CI, so this +should only flag failed external links. -For a major version release update the table in :file:`SECURITY.md` to specify -that the last minor version in the previous major version series is still -supported. Dropping support for the last version of a major version series -will be handled on an ad-hoc basis. .. _release_tag: Create release commit and tag ============================= -To create the tag, first create an empty commit with a very terse set of the release notes -in the commit message :: +To create the tag, first create an empty commit with a very terse set of the release +notes in the commit message:: git commit --allow-empty -and then create a signed, annotated tag with the same text in the body -message :: +and then create a signed, annotated tag with the same text in the body message:: git tag -a -s v2.0.0 -which will prompt you for your GPG key password and an annotation. For pre -releases it is important to follow :pep:`440` so that the build artifacts will -sort correctly in PyPI. +which will prompt you for your GPG key password and an annotation. For pre-releases it +is important to follow :pep:`440` so that the build artifacts will sort correctly in +PyPI. -To prevent issues with any down-stream builders which download the -tarball from GitHub it is important to move all branches away from the commit -with the tag [#]_:: +To prevent issues with any down-stream builders which download the tarball from GitHub +it is important to move all branches away from the commit with the tag [#]_:: git commit --allow-empty @@ -233,11 +219,11 @@ Congratulations, the scariest part is done! based on the git tag, when users install from the tarball. However, if there is a branch pointed at the tagged commit, then the branch name will also be included in the tarball. - When the branch eventually moves, anyone how checked the hash + When the branch eventually moves, anyone who checked the hash of the tarball before the branch moved will have an incorrect hash. - To generate the file that GitHub does use :: + To generate the file that GitHub does use:: git archive v2.0.0 -o matplotlib-2.0.0.tar.gz --prefix=matplotlib-2.0.0/ @@ -260,28 +246,22 @@ On this branch un-comment the globs from :ref:`release_chkdocs`. And then :: git push DANGER v2.0.x - - .. _release_DOI: Release management / DOI ======================== -Via the `GitHub UI -`__, turn the newly -pushed tag into a release. If this is a pre-release remember to mark -it as such. - -For final releases, also get the DOI from `zenodo -`__ (which will automatically produce one once -the tag is pushed). Add the doi post-fix and version to the dictionary in -:file:`tools/cache_zenodo_svg.py` and run the script. +Via the `GitHub UI `__, turn the +newly pushed tag into a release. If this is a pre-release remember to mark it as such. +For final releases, also get the DOI from `Zenodo `__ (which will +automatically produce one once the tag is pushed). Add the DOI post-fix and version to +the dictionary in :file:`tools/cache_zenodo_svg.py` and run the script. -This will download the new svg to the :file:`_static` directory in the -docs and edit :file:`doc/citing.rst`. Commit the new svg, the change -to :file:`tools/cache_zenodo_svg.py`, and the changes to -:file:`doc/citing.rst` to the VER-doc branch and push to GitHub. :: +This will download the new SVG to :file:`doc/_static/zenodo_cache/{postfix}.svg` and +edit :file:`doc/citing.rst`. Commit the new SVG, the change to +:file:`tools/cache_zenodo_svg.py`, and the changes to :file:`doc/citing.rst` to the +VER-doc branch and push to GitHub. :: git checkout v2.0.0-doc $EDITOR tools/cache_zenodo_svg.py @@ -290,43 +270,26 @@ to :file:`tools/cache_zenodo_svg.py`, and the changes to git commit -a git push DANGER v2.0.0-doc:v2.0.0-doc + .. _release_bld_bin: Building binaries ================= -We distribute macOS, Windows, and many Linux wheels as well as a source tarball -via PyPI. Most builders should trigger automatically once the tag is pushed to -GitHub: - -* Windows, macOS and manylinux wheels are built on GitHub Actions. Builds are - triggered by the GitHub Action defined in - :file:`.github/workflows/cibuildwheel.yml`, and wheels will be available as - artifacts of the build. -* Alternative Windows wheels are built by Christoph Gohlke automatically and - will be `available at his site - `__ once built. +We distribute macOS, Windows, and many Linux wheels as well as a source tarball via +PyPI. Most builders should trigger automatically once the tag is pushed to GitHub: + +* Windows, macOS and manylinux wheels are built on GitHub Actions. Builds are triggered + by the GitHub Action defined in :file:`.github/workflows/cibuildwheel.yml`, and wheels + will be available as artifacts of the build. * The auto-tick bot should open a pull request into the `conda-forge feedstock - `__. Review and merge - (if you have the power to). + `__. Review and merge (if you + have the power to). .. warning:: - Because this is automated, it is extremely important to bump all branches - away from the tag as discussed in :ref:`release_tag`. - -If this is a final release the following downstream packagers should be contacted: - -- Debian -- Fedora -- Arch -- Gentoo -- Macports -- Homebrew -- Continuum -- Enthought - -This can be done ahead of collecting all of the binaries and uploading to pypi. + Because this is automated, it is extremely important to bump all branches away from + the tag as discussed in :ref:`release_tag`. .. _release_upload_bin: @@ -334,19 +297,19 @@ This can be done ahead of collecting all of the binaries and uploading to pypi. Make distribution and upload to PyPI ==================================== -Once you have collected all of the wheels (expect this to take about a -day), generate the tarball :: +Once you have collected all of the wheels (expect this to take a few hours), generate +the tarball:: git checkout v2.0.0 git clean -xfd - python setup.py sdist + python -m build --sdist -and copy all of the wheels into :file:`dist` directory. First, check -that the dist files are OK :: +and copy all of the wheels into :file:`dist` directory. First, check that the dist files +are OK:: twine check dist/* -and then use ``twine`` to upload all of the files to pypi :: +and then use ``twine`` to upload all of the files to PyPI :: twine upload -s dist/matplotlib*tar.gz twine upload dist/*whl @@ -368,34 +331,31 @@ build the docs from the ``ver-doc`` branch. An easy way to arrange this is:: git clean -xfd make -Cdoc O="-t release -j$(nproc)" html latexpdf LATEXMKOPTS="-silent -f" -which will build both the html and pdf version of the documentation. - +which will build both the HTML and PDF version of the documentation. The built documentation exists in the `matplotlib.github.com `__ repository. Pushing changes to main automatically updates the website. -The documentation is organized by version. At the root of the tree is always -the documentation for the latest stable release. Under that, there are -directories containing the documentation for older versions. The documentation -for current main is built on Circle CI and pushed to the `devdocs -`__ repository. These are available at +The documentation is organized in subdirectories by version. The latest stable release +is symlinked from the :file:`stable` directory. The documentation for current main is +built on Circle CI and pushed to the `devdocs +`__ repository. These are available at `matplotlib.org/devdocs `__. Assuming you have this repository checked out in the same directory as matplotlib :: cd ../matplotlib.github.com - mkdir 2.0.0 - rsync -a ../matplotlib/doc/build/html/* 2.0.0 + cp -a ../matplotlib/doc/build/html 2.0.0 + rm 2.0.0/.buildinfo cp ../matplotlib/doc/build/latex/Matplotlib.pdf 2.0.0 which will copy the built docs over. If this is a final release, link the ``stable`` subdirectory to the newest version:: - rsync -a 2.0.0/* ./ rm stable - ln -s 2.0.0/ stable + ln -s 2.0.0 stable You will need to manually edit :file:`versions.html` to show the last 3 tagged versions. You will also need to edit :file:`sitemap.xml` to include @@ -407,10 +367,10 @@ the newly released version. Now commit and push everything to GitHub :: Congratulations you have now done the third scariest part! -If you have access, clear the Cloudflare caches. +If you have access, clear the CloudFlare caches. -It typically takes about 5-10 minutes for GitHub to process the push -and update the live web page (remember to clear your browser cache). +It typically takes about 5-10 minutes for the website to process the push and update the +live web page (remember to clear your browser cache). Announcing @@ -423,13 +383,9 @@ version of the release notes along with acknowledgments should be sent to - matplotlib-devel@python.org - matplotlib-announce@python.org -For final releases announcements should also be sent to the -numpy/scipy/scikit-image mailing lists. - -In addition, announcements should be made on social networks (twitter -via the ``@matplotlib`` account, any other via personal accounts). -`NumFOCUS `__ should be contacted for -inclusion in their newsletter. +In addition, announcements should be made on social networks (e.g., Twitter via the +``@matplotlib`` account, any other via personal accounts). `NumFOCUS +`__ should be contacted for inclusion in their newsletter. Conda packages From 06cf2f3962d4a01246df35ade5472f8ba6a5413d Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Thu, 26 Jan 2023 17:50:42 -0600 Subject: [PATCH 4/4] STY: start docstring on second line --- tools/github_stats.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/github_stats.py b/tools/github_stats.py index b5263eebad7a..bffa1c296954 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -"""Simple tools to query github.com and gather stats about issues. +""" +Simple tools to query github.com and gather stats about issues. To generate a report for Matplotlib 3.0.0, run: