diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a20c324208d..50147047032 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,6 @@ Fixes # - [ ] Pull request represents a single change (i.e. not fixing disparate/unrelated things in a single PR). - [ ] Title summarizes what is changing. -- [ ] Has a [news entry](https://github.com/Microsoft/vscode-jupyter/tree/main/news) file (remember to thank yourself!). - [ ] Appropriate comments and documentation strings in the code. - [ ] Has sufficient logging. - [ ] Has telemetry for feature-requests. diff --git a/.github/release_plan.md b/.github/release_plan.md index 5e9e2ae5fa3..9365b80bdc4 100644 --- a/.github/release_plan.md +++ b/.github/release_plan.md @@ -1,71 +1,30 @@ -# Prerequisites - -- Python 3.7 and higher -- run `python3 -m pip install --user -r news/requirements.txt` - # Get the build green (Early in endgame week) - [ ] Ensure that any CI test failures have issues assigned to that area's owner. -- [ ] Drive the build to green by fixing/disabling tests or pinging area owners to do so. - -# Move open issues (Tuesday of VS Code endgame week, XXX XX) - -- [ ] Ask the team to move all open issues to next milestone or remove milestone and put back in triage. This allows endgame champ to have a better understanding of done state. -- [ ] Schedule a bugbash if needed. - -# Release candidate (Friday of VS Code endgame week, XXX XX) +- [ ] Work with the build champ to drive the build to green by fixing/disabling tests or pinging area owners to do so. +# Release candidate (Friday of endgame week) - [ ] Review [Component Governance](https://dev.azure.com/monacotools/Monaco/_componentGovernance/191876) (Click on "microsoft/vscode-jupyter" on that page) and resolve all High/Severe issues. - - [ ] Focus on resolving `Critical` and `High` priority issues as others will be addressed in the `debt` week. - [ ] Manually add any repository dependencies (if you can't add manually, refer [here](https://docs.opensource.microsoft.com/tools/cg/features/cgmanifest/)). Only add a cgmanifest.json if the components are not NPM or are not dev only. Instructions on updating `npm` dependencies in `package.json` & `package-lock.json` can be found [here](https://github.com/microsoft/vscode-jupyter/wiki/Resolving-Component-Governance-and-Dependabot-issues-(updating-package-lock.json)). -- [ ] Create new release branch with format `release/release-YYYY.MM.100` - - [ ] Create a pull request against `release/release-YYYY.MM.100` for changes - - [ ] Bump the vscode engine version in package.json - - [ ] Run `npm install` to verify `package-lock.json` did not get updated aside from the vscode engine version. - - If there are minor changes, they can be just be updated in the release branch and later ported back to main. - - [ ] Update [`CHANGELOG.md`](https://github.com/Microsoft/vscode-jupyter/blob/main/CHANGELOG.md) - - [ ] Run [`news`](https://github.com/Microsoft/vscode-jupyter/tree/main/news) (typically `python news --final --update CHANGELOG.md | code-insiders -`) - - [ ] Update the date at the top to when the release is planned. - - [ ] Copy over the "Thanks" section from the previous release into the "Thanks" section for the new release - - [ ] Make sure the "Thanks" section is up-to-date (e.g. compare to versions in [`requirements.txt`](https://github.com/microsoft/vscode-jupyter/blob/main/requirements.txt)) - - [ ] Touch up news entries (e.g. add missing periods) - - [ ] Check the Markdown rendering to make sure everything looks good +- [ ] Create new release branch with format `release/release-YYYY.MM.100`. + - [ ] Prepare a PR to this branch with the following changes... + - [ ] Remove the `-insiders` from the vscode engine version. Run `npm install` to update this value in `package-lock.json`. - [ ] Update [`ThirdPartyNotices-Repository.txt`](https://github.com/Microsoft/vscode-jupyter/blob/main/ThirdPartyNotices-Repository.txt) as appropriate. This file is manually edited so you can check with the teams if anything needs to be added here. - - [ ] Merge pull request into `release/release-YYYY.MM.100` -- [ ] Update the [`release` branch](https://github.com/microsoft/vscode-jupyter/branches) - - [ ] If there are `release` branches that are two versions old (e.g. `release-2020.[current month - 2].100`) you can delete them at this time (you would have to un-protect the release branches temporarily to delete them). -- [ ] Update `main` after creating the release branch. (Warning: this should happen right after creating the release branch. If this is deferred till later, the `main` and `release` branches can diverge significantly, which may cause merge conflicts.) - - [ ] Merge the changes from release (Changelog, delete news, ThirdPartyNotices) into `main` branch - - [ ] Bump the version number to the next monthly ("YYYY.M.100") release in the `main` branch - - If latest is `2022.2.100`, them bump it to `2022.3.100`, - - This ensures the new new pre-release targets the next version. - - [ ] `package.json` - - [ ] `package-lock.json` - - [ ] Confirm the 3rd part of the version ends with `100`. - - [ ] Create a pull request against `main` - - [ ] Merge pull request into `main` -- [ ] GDPR bookkeeping (🤖) - - https://gdpr.datasmart.ms/ search `EntityName like 'ms-toolsai.jupyter/%' and complete = 'false'` - - Typically just update columns DataClassification, BusinessJustification, InteralOnly, Suppressed, Retired - - Suspected PII requires more -- [ ] Open appropriate [documentation issues](https://github.com/microsoft/vscode-docs/issues?q=is%3Aissue+is%3Aopen+label%3Apython) - - new features - - settings changes - - etc. (ask the team) -- [ ] Release notes from VS Code have something about Jupyter - - Example doc update [here](https://github.com/microsoft/vscode-docs/pull/5256) -- [ ] Schedule a sanity test. Aim for close after freeze so there is still time to fix release bugs before release. Ask teams before bash for specific areas that need testing. -- [ ] Ensure that closed issues targeting this release will be verfied, asking for verification steps if needed. Sanity test can be used to help with this. - - `is:issue sort:updated-desc milestone:"" label:verification-needed -label:verified` +- [ ] Create a PR to `main` with the following changes... (Warning: this should happen right after creating the release branch. If this is deferred till later, the `main` and `release` branches can diverge significantly, which may cause merge conflicts.) + - [ ] Merge the changes from release (ThirdPartyNotices) into `main` branch + - [ ] At this point, the vscode engine version should also be the same as in the release branch- will be bumped when the next release happens + - [ ] Bump the version number to the next monthly ("YYYY.M.100") version number (e.g. if the latest is `2022.2.100`, bump it to `2022.3.100`). + - [ ] Run `npm install` to update `package-lock.json` +- [ ] Schedule a sanity test. Ask team for specific areas that need testing. - [ ] Ask CTI (Python Tools CTI) to test the release candidate - Test plan document: https://github.com/microsoft/vscode-jupyter/blob/main/.github/test_plan.md -# Testing (Monday of VS Code release week, XXX XX) +# Testing (Monday of VS Code release week) -- [ ] Obtain VS Code [prebuild](https://builds.code.visualstudio.com/builds/stable) for sanity testing -- [ ] Sanity test release candidate VSIX against VS Code prebuild +- [ ] Obtain VS Code [stable RC](https://builds.code.visualstudio.com/builds/stable) for sanity testing +- [ ] Sanity test release candidate VSIX against VS Code RC - Make sure that the sanity test hits both macOS and Windows builds - [ ] Candidate bug fixes found from sanity test should be checked into `main` and cherry-picked to `release` branch @@ -73,37 +32,22 @@ ## Preparation -- [ ] Make sure the [appropriate pull requests](https://github.com/microsoft/vscode-docs/pulls) for the release notes(https://github.com/microsoft/vscode-docs/blob/vnext/release-notes/v.md, make note of the branch and file name). - - [ ] Include all new new features under a section named `Jupyter` with screenshots or animated gifs. - - [ ] Fixes, code health should remain in the Jupyter change log. - [ ] Make sure [Component Governance](https://dev.azure.com/monacotools/Monaco/_componentGovernance/191876) is happy -- [ ] Make sure there is nothing targeting this release that still needs to be validated - (`is:issue sort:updated-desc milestone:"" label:verification-needed -label:verified`) ## Release -- [ ] Publish the release - - [ ] Verify the PR Pipeline on Github actions is green against the release branch. - - [ ] Manually run the [Stable pipeline](https://dev.azure.com/monacotools/Monaco/_build?definitionId=284) against the `release/release-YYYY.MM.100` branch - - [ ] Approve the `Publish` stage - - [ ] Check if the release was automatically published here, https://github.com/microsoft/vscode-jupyter/releases - If not, publish manually: (This has been required since the move to az pipelines) - - [ ] Add a new release at https://github.com/microsoft/vscode-jupyter/releases - - Tag is version number - - Branch is release branch - - Copy contents of release branch changelog into the release (just copy the markdown) - - [ ] Publish -- [ ] Determine if a hotfix is needed - - [ ] Ensure the version in package.json is updated as follows: - * If released version is `YYYY.MM.100`, then hot fix will be `YYYY.MM.110` - * If released version is `YYYY.MM.110`, then hot fix will be `YYYY.MM.120` - -# Day of VS Code publishing (Wednesday, XXX XX) -- [ ] Go through [`info needed` issues](https://github.com/Microsoft/vscode-jupyter/issues?q=is%3Aopen+sort%3Aupdated-asc+label%3Ainfo-needed) and close any that have no activity for over a month (🤖) -- [ ] GDPR bookkeeping (🤖) +- [ ] Verify the PR Pipeline on Github actions is green against the release branch. +- [ ] Manually run the [Stable pipeline](https://dev.azure.com/monacotools/Monaco/_build?definitionId=284) against the `release/release-YYYY.MM.100` branch +- [ ] Approve the `Publish` stage +- [ ] Check if the release was automatically published here, https://github.com/microsoft/vscode-jupyter/releases - If not, publish manually: (This has been required since the move to az pipelines) + - [ ] Add a new release at https://github.com/microsoft/vscode-jupyter/releases + - Tag is version number + - Branch is release branch + - [ ] Publish - [ ] If any steps were unclear or changed in this release plan please update the `release_plan.md` file to make it clear for the next release -# Day of VS Code releasing the next insider version (Wednesday, XXX XX) -- [ ] Bump the engines.vscode version on the `main` branch to point to the next insider version. For example, from `1.58.0-insider` to `1.59.0-insider` +# Day of VS Code releasing the next insider version (Wednesday) +- [ ] Bump the engines.vscode version on the `main` branch to point to the next insider version. For example, from `1.58.0` to `1.59.0-insider` ## Prep for the _next_ release @@ -112,3 +56,10 @@ * Add the labels `endgame-plan` to this issue * Pin this issue - [ ] [(Un-)pin](https://help.github.com/en/articles/pinning-an-issue-to-your-repository) [release plan issues](https://github.com/Microsoft/vscode-jupyter/labels/release-plan) (🤖) + +# As needed + +- [ ] Determine if a hotfix is needed + - [ ] Ensure the version in package.json is updated as follows: + * If released version is `YYYY.MM.100`, then hot fix will be `YYYY.MM.110` + * If released version is `YYYY.MM.110`, then hot fix will be `YYYY.MM.120` diff --git a/.vscodeignore b/.vscodeignore index d1c8e4da353..dbf4d52ba63 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -73,7 +73,6 @@ images/**/*.gif images/**/*.png ipywidgets/** i18n/** -news/** node_modules/** obj/** logs/** diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e33b2d8afa..6b6a874f1ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Deprecated + +This changelog is deprecated. Here is where you can find details about the latest updates to this extension: +- Highlighted features for the latest release are described in the VS Code release notes, under the "Contributions to extensions" section: https://code.visualstudio.com/updates +- All issues and code changes can be found by searching our Github repo under the latest milestone. [Example from November 2022](https://github.com/microsoft/vscode-jupyter/issues?q=is%3Aclosed+milestone%3A%22November+2022%22+) + ## 2022.10.110 (2 November 2022) ### Enhancements diff --git a/news/.vscode/settings.json b/news/.vscode/settings.json deleted file mode 100644 index 2b759d72bd3..00000000000 --- a/news/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "python.languageServer": "Microsoft", - "python.formatting.provider": "black", - "editor.formatOnSave": true, - "python.testing.pytestArgs": ["."], - "python.testing.unittestEnabled": false, - "python.testing.nosetestsEnabled": false, - "python.testing.pytestEnabled": true -} diff --git a/news/1 Enhancements/README.md b/news/1 Enhancements/README.md deleted file mode 100644 index 2a159b65f4f..00000000000 --- a/news/1 Enhancements/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Changes that add new features. - diff --git a/news/2 Fixes/README.md b/news/2 Fixes/README.md deleted file mode 100644 index cc5e1020961..00000000000 --- a/news/2 Fixes/README.md +++ /dev/null @@ -1 +0,0 @@ -Changes that fix broken behaviour. diff --git a/news/3 Code Health/11761.md b/news/3 Code Health/11761.md deleted file mode 100644 index 63a4627d138..00000000000 --- a/news/3 Code Health/11761.md +++ /dev/null @@ -1 +0,0 @@ -Use Python Extension API to fetch the environment variables form the `.env` file defined in the user settings file `python.envFile`. diff --git a/news/3 Code Health/README.md b/news/3 Code Health/README.md deleted file mode 100644 index 10619f41f3a..00000000000 --- a/news/3 Code Health/README.md +++ /dev/null @@ -1 +0,0 @@ -Changes that should not be user-facing. diff --git a/news/README.md b/news/README.md deleted file mode 100644 index f26d25030fa..00000000000 --- a/news/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# News - -Our changelog is automatically generated from individual news entry files. -This alleviates the burden of having to go back and try to figure out -what changed in a release. It also helps tie pull requests back to the -issue(s) it addresses. Finally, it avoids merge conflicts between pull requests -which would occur if multiple pull requests tried to edit the changelog. - -If a change does not warrant a news entry, the `skip news` label can be added -to a pull request to signal this fact. - -## Entries - -Each news entry is represented by a Markdown file that contains the -relevant details of what changed. The file name of the news entry is -the issue that corresponds to the change along with an optional nonce in -case a single issue corresponds to multiple changes. The directory -the news entry is saved in specifies what section of the changelog the -change corresponds to. External contributors should also make sure to -thank themselves for taking the time and effort to contribute. - -As an example, a change corresponding to a bug reported in issue #42 -would be saved in the `1 Fixes` directory and named `42.md` -(or `42-nonce_value.md` if there was a need for multiple entries -regarding issue #42) and could contain the following: - -```markdown -[Answer]() -to the Ultimate Question of Life, the Universe, and Everything! -(thanks [Don Jaymanne](https://github.com/donjayamanne/)) -``` - -This would then be made into an entry in the changelog that was in the -`Fixes` section, contained the details as found in the file, and tied -to issue #42. - -## Generating the changelog - -The `announce` script can do 3 possible things: - -1. Validate that the changelog _could_ be successfully generated -2. Generate the changelog entries -3. Generate the changelog entries **and** `git-rm` the news entry files - -The first option is used in CI to make sure any added news entries -will not cause trouble at release time. The second option is for -filling in the changelog for interim releases, e.g. a beta release. -The third option is for final releases that get published to the -[VS Code marketplace](https://marketplace.visualstudio.com/VSCode). - -For options 2 & 3, the changelog is sent to stdout so it can be temporarily -saved to a file: - -```sh -python3 news > entry.txt -``` - -It can also be redirected to an editor buffer, e.g.: - -```sh -python3 news | code-insiders - -``` diff --git a/news/__main__.py b/news/__main__.py deleted file mode 100644 index b496ec1d0c8..00000000000 --- a/news/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import runpy - -runpy.run_module('announce', run_name='__main__', alter_sys=True) diff --git a/news/announce.py b/news/announce.py deleted file mode 100644 index 1c70a61908a..00000000000 --- a/news/announce.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -"""Generate the changelog. - -Usage: announce [--dry_run | --interim | --final] [--update=] [] - -""" -import dataclasses -import datetime -import enum -import json -import operator -import os -import pathlib -import re -import subprocess -import sys - -import docopt - - -FILENAME_RE = re.compile(r"(?P\d+)(?P-\S+)?\.md") - - -@dataclasses.dataclass -class NewsEntry: - """Representation of a news entry.""" - - issue_number: int - description: str - path: pathlib.Path - - -def news_entries(directory): - """Yield news entries in the directory. - - Entries are sorted by issue number. - - """ - entries = [] - for path in directory.iterdir(): - if path.name == "README.md": - continue - match = FILENAME_RE.match(path.name) - if match is None: - raise ValueError(f"{path} has a bad file name") - issue = int(match.group("issue")) - try: - entry = path.read_text("utf-8") - except UnicodeDecodeError as exc: - raise ValueError(f"'{path}' is not encoded as UTF-8") from exc - if "\ufeff" in entry: - raise ValueError(f"'{path}' contains the BOM") - entries.append(NewsEntry(issue, entry, path)) - entries.sort(key=operator.attrgetter("issue_number")) - yield from entries - - -@dataclasses.dataclass -class SectionTitle: - """Create a data object for a section of the changelog.""" - - index: int - title: str - path: pathlib.Path - - -def sections(directory): - """Yield the sections in their appropriate order.""" - found = [] - for path in directory.iterdir(): - if not path.is_dir() or path.name.startswith((".", "_")): - continue - position, sep, title = path.name.partition(" ") - if not sep: - print( - f"directory {path.name!r} is missing a ranking; skipping", - file=sys.stderr, - ) - continue - found.append(SectionTitle(int(position), title, path)) - return sorted(found, key=operator.attrgetter("index")) - - -def gather(directory): - """Gather all the entries together.""" - data = [] - for section in sections(directory): - data.append((section, list(news_entries(section.path)))) - return data - - -def entry_markdown(entry): - """Generate the Markdown for the specified entry.""" - enumerated_item = "1. " - indent = " " * len(enumerated_item) - issue_url = ( - f"https://github.com/Microsoft/vscode-jupyter/issues/{entry.issue_number}" - ) - issue_md = f"([#{entry.issue_number}]({issue_url}))" - entry_lines = entry.description.strip().splitlines() - formatted_lines = [f"{enumerated_item}{entry_lines[0]}"] - formatted_lines.extend(f"{indent}{line}" for line in entry_lines[1:]) - formatted_lines.append(f"{indent}{issue_md}") - return "\n".join(formatted_lines) - - -def changelog_markdown(data): - """Generate the Markdown for the release.""" - changelog = [] - for section, entries in data: - changelog.append(f"### {section.title}") - changelog.append("") - changelog.extend(map(entry_markdown, entries)) - changelog.append("") - return "\n".join(changelog) - - -def git_rm(path): - """Run git-rm on the path.""" - status = subprocess.run( - ["git", "rm", os.fspath(path.resolve())], - shell=False, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - try: - status.check_returncode() - except Exception: - print(status.stdout, file=sys.stderr) - raise - - -def cleanup(data): - """Remove news entries from git and disk.""" - for section, entries in data: - for entry in entries: - git_rm(entry.path) - - -class RunType(enum.Enum): - """Possible run-time options.""" - - dry_run = 0 - interim = 1 - final = 2 - - -def complete_news(version, entry, previous_news): - """Prepend a news entry to the previous news file.""" - title, _, previous_news = previous_news.partition("\n") - title = title.strip() - previous_news = previous_news.strip() - section_title = (f"## {version} ({datetime.date.today().strftime('%d %B %Y')})" - ).replace("(0", "(") - # TODO: Insert the "Thank you!" section (in monthly releases)? - return f"{title}\n\n{section_title}\n\n{entry.strip()}\n\n\n{previous_news}" - - -def main(run_type, directory, news_file=None): - directory = pathlib.Path(directory) - data = gather(directory) - markdown = changelog_markdown(data) - if news_file: - with open(news_file, "r", encoding="utf-8") as file: - previous_news = file.read() - package_config_path = pathlib.Path(news_file).parent / "package.json" - config = json.loads(package_config_path.read_text()) - new_news = complete_news(config["version"], markdown, previous_news) - if run_type == RunType.dry_run: - print(f"would be written to {news_file}:") - print() - print(new_news) - else: - with open(news_file, "w", encoding="utf-8") as file: - file.write(new_news) - else: - print(markdown) - if run_type == RunType.final: - cleanup(data) - - -if __name__ == "__main__": - arguments = docopt.docopt(__doc__) - for possible_run_type in RunType: - if arguments[f"--{possible_run_type.name}"]: - run_type = possible_run_type - break - else: - run_type = RunType.interim - directory = arguments[""] or pathlib.Path(__file__).parent - main(run_type, directory, arguments["--update"]) diff --git a/news/requirements.in b/news/requirements.in deleted file mode 100644 index ab0e1cc5187..00000000000 --- a/news/requirements.in +++ /dev/null @@ -1,2 +0,0 @@ -docopt -pytest diff --git a/news/requirements.txt b/news/requirements.txt deleted file mode 100644 index 0a24943d89b..00000000000 --- a/news/requirements.txt +++ /dev/null @@ -1,24 +0,0 @@ -# -# This file is autogenerated by pip-compile -# To update, run: -# -# pip-compile -# -attrs==19.3.0 - # via pytest -docopt==0.6.2 - # via -r requirements.in -iniconfig==1.0.1 - # via pytest -packaging==20.8 - # via pytest -pluggy==0.13.1 - # via pytest -py==1.10.0 - # via pytest -pyparsing==2.4.5 - # via packaging -pytest==6.2.2 - # via -r requirements.in -toml==0.10.1 - # via pytest diff --git a/news/test_announce.py b/news/test_announce.py deleted file mode 100644 index 29e446ab72b..00000000000 --- a/news/test_announce.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import codecs -import datetime -import pathlib - -import docopt -import pytest - -import announce as ann - - -@pytest.fixture -def directory(tmpdir): - """Fixture to create a temp directory wrapped in a pathlib.Path object.""" - return pathlib.Path(tmpdir) - - -def test_news_entry_formatting(directory): - issue = 42 - normal_entry = directory / f"{issue}.md" - nonce_entry = directory / f"{issue}-nonce.md" - body = "Hello, world!" - normal_entry.write_text(body, encoding="utf-8") - nonce_entry.write_text(body, encoding="utf-8") - results = list(ann.news_entries(directory)) - assert len(results) == 2 - for result in results: - assert result.issue_number == issue - assert result.description == body - - -def test_news_entry_sorting(directory): - oldest_entry = directory / "45.md" - newest_entry = directory / "123.md" - oldest_entry.write_text("45", encoding="utf-8") - newest_entry.write_text("123", encoding="utf-8") - results = list(ann.news_entries(directory)) - assert len(results) == 2 - assert results[0].issue_number == 45 - assert results[1].issue_number == 123 - - -def test_only_utf8(directory): - entry = directory / "42.md" - entry.write_text("Hello, world", encoding="utf-16") - with pytest.raises(ValueError): - list(ann.news_entries(directory)) - - -def test_no_bom_allowed(directory): - entry = directory / "42.md" - entry.write_bytes(codecs.BOM_UTF8 + "Hello, world".encode("utf-8")) - with pytest.raises(ValueError): - list(ann.news_entries(directory)) - - -def test_bad_news_entry_file_name(directory): - entry = directory / "bunk.md" - entry.write_text("Hello, world!") - with pytest.raises(ValueError): - list(ann.news_entries(directory)) - - -def test_news_entry_README_skipping(directory): - entry = directory / "README.md" - entry.write_text("Hello, world!") - assert len(list(ann.news_entries(directory))) == 0 - - -def test_sections_sorting(directory): - dir2 = directory / "2 Hello" - dir1 = directory / "1 World" - dir2.mkdir() - dir1.mkdir() - results = list(ann.sections(directory)) - assert [found.title for found in results] == ["World", "Hello"] - - -def test_sections_naming(directory): - (directory / "Hello").mkdir() - assert not ann.sections(directory) - - -def test_gather(directory): - fixes = directory / "2 Fixes" - fixes.mkdir() - fix1 = fixes / "1.md" - fix1.write_text("Fix 1", encoding="utf-8") - fix2 = fixes / "3.md" - fix2.write_text("Fix 2", encoding="utf-8") - enhancements = directory / "1 Enhancements" - enhancements.mkdir() - enhancement1 = enhancements / "2.md" - enhancement1.write_text("Enhancement 1", encoding="utf-8") - enhancement2 = enhancements / "4.md" - enhancement2.write_text("Enhancement 2", encoding="utf-8") - results = ann.gather(directory) - assert len(results) == 2 - section, entries = results[0] - assert section.title == "Enhancements" - assert len(entries) == 2 - assert entries[0].description == "Enhancement 1" - assert entries[1].description == "Enhancement 2" - section, entries = results[1] - assert len(entries) == 2 - assert section.title == "Fixes" - assert entries[0].description == "Fix 1" - assert entries[1].description == "Fix 2" - - -def test_entry_markdown(): - markdown = ann.entry_markdown(ann.NewsEntry(42, "Hello, world!", None)) - assert "42" in markdown - assert "Hello, world!" in markdown - assert "https://github.com/Microsoft/vscode-jupyter/issues/42" in markdown - - -def test_changelog_markdown(): - data = [ - ( - ann.SectionTitle(1, "Enhancements", None), - [ - ann.NewsEntry(2, "Enhancement 1", None), - ann.NewsEntry(4, "Enhancement 2", None), - ], - ), - ( - ann.SectionTitle(1, "Fixes", None), - [ann.NewsEntry(1, "Fix 1", None), ann.NewsEntry(3, "Fix 2", None)], - ), - ] - markdown = ann.changelog_markdown(data) - assert "### Enhancements" in markdown - assert "### Fixes" in markdown - assert "1" in markdown - assert "Fix 1" in markdown - assert "2" in markdown - assert "Enhancement 1" in markdown - assert "https://github.com/Microsoft/vscode-jupyter/issues/2" in markdown - assert "3" in markdown - assert "Fix 2" in markdown - assert "https://github.com/Microsoft/vscode-jupyter/issues/3" in markdown - assert "4" in markdown - assert "Enhancement 2" in markdown - - -def test_cleanup(directory, monkeypatch): - rm_path = None - - def fake_git_rm(path): - nonlocal rm_path - rm_path = path - - monkeypatch.setattr(ann, "git_rm", fake_git_rm) - fixes = directory / "2 Fixes" - fixes.mkdir() - fix1 = fixes / "1.md" - fix1.write_text("Fix 1", encoding="utf-8") - results = ann.gather(directory) - assert len(results) == 1 - ann.cleanup(results) - section, entries = results.pop() - assert len(entries) == 1 - assert rm_path == entries[0].path - - -TITLE = "# Our most excellent changelog" -OLD_NEWS = f"""\ -## 2018.12.0 (31 Dec 2018) - -We did things! - -## 2017.11.16 (16 Nov 2017) - -We started going stuff. -""" -NEW_NEWS = """\ -We fixed all the things! - -### Code Health - -We deleted all the code to fix all the things. ;) -""" - - -def test_complete_news(): - version = "2019.3.0" - # Remove leading `0`. - date = datetime.date.today().strftime("%d %B %Y").lstrip("0") - news = ann.complete_news(version, NEW_NEWS, f"{TITLE}\n\n\n{OLD_NEWS}") - expected = f"{TITLE}\n\n## {version} ({date})\n\n{NEW_NEWS.strip()}\n\n\n{OLD_NEWS.strip()}" - assert news == expected - - -def test_cli(): - for option in ("--" + opt for opt in ["dry_run", "interim", "final"]): - args = docopt.docopt(ann.__doc__, [option]) - assert args[option] - args = docopt.docopt(ann.__doc__, ["./news"]) - assert args[""] == "./news" - args = docopt.docopt(ann.__doc__, ["--dry_run", "./news"]) - assert args["--dry_run"] - assert args[""] == "./news" - args = docopt.docopt(ann.__doc__, ["--update", "CHANGELOG.md", "./news"]) - assert args["--update"] == "CHANGELOG.md" - assert args[""] == "./news"