From bf15b16f02d92f065f5b26d30f92dc0f5596db18 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 23 Dec 2022 14:47:38 -0500 Subject: [PATCH] Enable nightly pre-release builds --- .github/workflows/ci.yaml | 3 +- .github/workflows/release.yaml | 66 ++++++++++++++++++++++--- LICENSE | 24 +++++++++ README.md | 3 +- build/generate_build_id.py | 70 ++++++++++++++++++++++++++ build/update_ext_version.py | 90 ++++++++++++++++++++++++++++++++++ noxfile.py | 18 +++---- package.json | 2 +- pyproject.toml | 4 +- 9 files changed, 253 insertions(+), 27 deletions(-) create mode 100644 build/generate_build_id.py create mode 100644 build/update_ext_version.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ddeff80..b818805 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,6 +21,5 @@ jobs: - uses: wntrblm/nox@2022.11.21 with: python-versions: '3.7, 3.8, 3.9, 3.10' - - run: nox --session lint - - run: nox --session typecheck + - run: nox --session check - run: nox --session test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4c544c4..713d160 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,12 +4,39 @@ on: create: tags: - v* + pull_request: + branches: [main] env: - FETCH_DEPTH: 0 # pull in the tags for the version string + FETCH_DEPTH: 0 jobs: - dist: + build-id: + name: "Build ID" + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: ${{ env.FETCH_DEPTH }} + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Generate Build ID (release) + if: "startsWith(github.ref, 'refs/tags/')" + id: release-build-id-generator + run: | + export BUILD_ID=$(python -m build.generate_build_id --release) + echo "BUILD_ID=$BUILD_ID" >> $GITHUB_OUTPUT + - name: Generate Build ID (nightly) + if: "!startsWith(github.ref, 'refs/tags/')" + id: nightly-build-id-generator + run: | + export BUILD_ID=$(python -m build.generate_build_id) + echo "BUILD_ID=$BUILD_ID" >> $GITHUB_OUTPUT + - run: 'echo "BUILD_ID: $BUILD_ID"' + + build: strategy: matrix: include: @@ -35,7 +62,8 @@ jobs: target: aarch64-apple-darwin code-target: darwin-arm64 - name: dist (${{ matrix.target }}) + name: Build (${{ matrix.target }}) + needs: ['build-id'] runs-on: ${{ matrix.os }} container: ${{ matrix.container }} @@ -60,10 +88,25 @@ jobs: # Install Node dependencies. - run: npm ci + # Set the Build ID. + - name: Set Build ID (release) + if: "startsWith(github.ref, 'refs/tags/')" + run: | + python -m build.update_ext_version --build-id ${{ steps.release-build-id-generator.outputs.BUILD_ID }} --for-publishing --release + - name: Set Build ID (nightly) + if: "!startsWith(github.ref, 'refs/tags/')" + run: | + python -m build.update_ext_version --build-id ${{ steps.nightly-build-id-generator.outputs.BUILD_ID }} --for-publishing + # Build the extension. - - name: Package Extension + - name: Package Extension (release) + if: "startsWith(github.ref, 'refs/tags/')" run: npx vsce package -o "./dist/ruff-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} + - name: Package Extension (nightly) + if: "!startsWith(github.ref, 'refs/tags/')" + run: npx vsce package -o "./dist/ruff-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release + # Upload the extension. - name: Upload artifacts uses: actions/upload-artifact@v1 with: @@ -71,9 +114,9 @@ jobs: path: ./dist publish: - name: publish + name: "Publish" + needs: ['build'] runs-on: ubuntu-latest - needs: ['dist'] steps: - name: Install Nodejs uses: actions/setup-node@v3 @@ -120,12 +163,19 @@ jobs: - run: npm ci # Publish to the Code Marketplace. - - name: Publish Extension (Code Marketplace) + - name: Publish Extension (Code Marketplace, release) if: "startsWith(github.ref, 'refs/tags/')" run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ./dist/ruff-*.vsix + - name: Publish Extension (Code Marketplace, nightly) + if: "!startsWith(github.ref, 'refs/tags/')" + run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ./dist/ruff-*.vsix --pre-release # Publish to OpenVSX. - - name: Publish Extension (OpenVSX) + - name: Publish Extension (OpenVSX, release) if: "startsWith(github.ref, 'refs/tags/')" run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ./dist/ruff-*.vsix timeout-minutes: 2 + - name: Publish Extension (OpenVSX, nightly) + if: "!startsWith(github.ref, 'refs/tags/')" + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ./dist/ruff-*.vsix --pre-release + timeout-minutes: 2 diff --git a/LICENSE b/LICENSE index c46de9a..bdab8c8 100644 --- a/LICENSE +++ b/LICENSE @@ -19,3 +19,27 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +MIT License + +# TODO: Copyright (c) Microsoft Corporation. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE diff --git a/README.md b/README.md index da95257..ab9901d 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,7 @@ This extension is based on the [Template for VS Code Python tools extensions](ht ### Development - `nox --session fmt` -- `nox --session lint` -- `nox --session typecheck` +- `nox --session check` - `nox --session test` ### Packaging and Publishing diff --git a/build/generate_build_id.py b/build/generate_build_id.py new file mode 100644 index 0000000..60b1637 --- /dev/null +++ b/build/generate_build_id.py @@ -0,0 +1,70 @@ +"""Generate a build ID for a release or pre-release version.""" + +import argparse +import datetime +import json +import pathlib +from typing import Tuple, Union + +EXT_ROOT = pathlib.Path(__file__).parent.parent +PACKAGE_JSON_PATH = EXT_ROOT / "package.json" + + +def is_even(v: Union[int, str]) -> bool: + """Returns `True` if `v` is even.""" + return not int(v) % 2 + + +def micro_build_number() -> str: + """Generates the micro build number. + + The format is `1`. + """ + return f"1{datetime.datetime.now(tz=datetime.timezone.utc).strftime('%j%H%M')}" + + +def parse_version(version: str) -> Tuple[str, str, str, str]: + """Parse a version string into a tuple of version parts.""" + major, minor, parts = version.split(".", maxsplit=2) + try: + micro, suffix = parts.split("-", maxsplit=1) + except ValueError: + micro = parts + suffix = "" + return major, minor, micro, suffix + + +def main(package_json: pathlib.Path, *, release: bool) -> None: + package = json.loads(package_json.read_text(encoding="utf-8")) + + major, minor, micro, suffix = parse_version(package["version"]) + + if release and not is_even(minor): + raise ValueError( + f"Release version should have EVEN numbered minor version: " + f"{package['version']}" + ) + elif not release and is_even(minor): + raise ValueError( + f"Pre-Release version should have ODD numbered minor version: " + f"{package['version']}" + ) + + if release: + print(micro) + else: + print(micro_build_number()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generate a build ID for a release or pre-release version." + ) + parser.add_argument( + "--release", + action="store_true", + help="Treats the current build as a release build.", + ) + args = parser.parse_args() + + main(PACKAGE_JSON_PATH, release=args.release) diff --git a/build/update_ext_version.py b/build/update_ext_version.py new file mode 100644 index 0000000..269d8ee --- /dev/null +++ b/build/update_ext_version.py @@ -0,0 +1,90 @@ +"""Update the Python extension micro version based on a build ID.""" + +import argparse +import json +import pathlib +from typing import Tuple, Union + +EXT_ROOT = pathlib.Path(__file__).parent.parent +PACKAGE_JSON_PATH = EXT_ROOT / "package.json" + + +def is_even(v: Union[int, str]) -> bool: + """Returns True if `v` is even.""" + return not int(v) % 2 + + +def parse_version(version: str) -> Tuple[str, str, str, str]: + """Parse a version string into a tuple of version parts.""" + major, minor, parts = version.split(".", maxsplit=2) + try: + micro, suffix = parts.split("-", maxsplit=1) + except ValueError: + micro = parts + suffix = "" + return major, minor, micro, suffix + + +def main( + package_json: pathlib.Path, *, release: bool, build_id: int, for_publishing: bool +) -> None: + package = json.loads(package_json.read_text(encoding="utf-8")) + + major, minor, micro, suffix = parse_version(package["version"]) + + if release and not is_even(minor): + raise ValueError( + f"Release version should have EVEN numbered minor version: " + f"{package['version']}" + ) + elif not release and is_even(minor): + raise ValueError( + f"Pre-Release version should have ODD numbered minor version: " + f"{package['version']}" + ) + + # The build ID should fall within the 0-INT32 max range allowed by the Marketplace. + if build_id < 0 or (for_publishing and build_id > ((2**32) - 1)): + raise ValueError(f"Build ID must be within [0, {(2**32) - 1}]") + + print(f"Updating build FROM: {package['version']}") + package["version"] = ".".join((major, minor, str(build_id))) + if not for_publishing and not release and len(suffix): + package["version"] += "-" + suffix + print(f"Updating build TO: {package['version']}") + + # Overwrite package.json with new data. + package_json.write_text( + json.dumps(package, indent=4, ensure_ascii=False) + "\n", encoding="utf-8" + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Update the Python extension micro version based on a build ID." + ) + parser.add_argument( + "--release", + action="store_true", + help="Treats the current build as a release build.", + ) + parser.add_argument( + "--build-id", + action="store", + type=int, + help="Micro version to use.", + required=True, + ) + parser.add_argument( + "--for-publishing", + action="store_true", + help="Removes `-dev` or `-rc` suffix.", + ) + args = parser.parse_args() + + main( + PACKAGE_JSON_PATH, + release=args.release, + build_id=args.build_id, + for_publishing=args.for_publishing, + ) diff --git a/noxfile.py b/noxfile.py index 3ebdf27..68a5b71 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,6 +1,3 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - import json import pathlib import urllib.request as url_lib @@ -125,7 +122,7 @@ def test(session: nox.Session) -> None: @nox.session(python="3.10") -def lint(session: nox.Session) -> None: +def check(session: nox.Session) -> None: """Lint the Python and TypeScript source files.""" session.install("-r", "./requirements.txt") session.install("-r", "./requirements-dev.txt") @@ -133,23 +130,18 @@ def lint(session: nox.Session) -> None: # Check Python lint with Ruff. session.run("ruff", "./noxfile.py") session.run("ruff", "./bundled/tool") + session.run("ruff", "./build") session.run("ruff", "./src/test/python_tests") # Check Python formatting with Black. session.run("black", "--check", "./noxfile.py") session.run("black", "--check", "./bundled/tool") + session.run("black", "--check", "./build") session.run("black", "--check", "./src/test/python_tests") # Check TypeScript code. session.run("npm", "run", "lint", external=True) - -@nox.session(python="3.10") -def typecheck(session: nox.Session) -> None: - """Typecheck the Python and TypeScript source files.""" - session.install("-r", "./requirements.txt") - session.install("-r", "./requirements-dev.txt") - # Check Python types with Mypy. session.run("mypy") @@ -166,11 +158,13 @@ def fmt(session: nox.Session) -> None: # Sort imports with Ruff. session.run("ruff", "--select", "I001", "--fix", "./noxfile.py") session.run("ruff", "--select", "I001", "--fix", "./bundled/tool") + session.run("ruff", "--select", "I001", "--fix", "./build") session.run("ruff", "--select", "I001", "--fix", "./src/test/python_tests") # Format Python with Black. session.run("black", "./noxfile.py") session.run("black", "./bundled/tool") + session.run("black", "./build") session.run("black", "./src/test/python_tests") # Format TypeScript with Prettier. @@ -193,4 +187,4 @@ def update_packages(session: nox.Session) -> None: _update_npm_packages(session) -nox.options.sessions = ["test", "lint", "typecheck"] +nox.options.sessions = ["test", "check"] diff --git a/package.json b/package.json index 93cbd0f..6f92a42 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ruff", "displayName": "Ruff", "description": "A Visual Studio Code extension with support for the Ruff linter.", - "version": "2022.0.26", + "version": "2022.1.0-dev", "serverInfo": { "name": "Ruff", "module": "ruff" diff --git a/pyproject.toml b/pyproject.toml index 5613b4f..ace6831 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,8 +16,8 @@ extend-exclude = ["bundled/libs", "src/test/python_tests/test_data"] line-length = 88 [tool.mypy] -files = "bundled/tool" -mypy_path = "bundled/tool" +files = ["bundled/tool", "build"] +mypy_path = ["bundled/tool", "build"] namespace_packages = true explicit_package_bases = true no_implicit_optional = true