sapling/addons/verify-addons-folder.py
2022-11-15 00:48:09 -08:00

167 lines
4.7 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import argparse
import asyncio
import shutil
import time
from argparse import RawTextHelpFormatter
from pathlib import Path
from typing import List
addons = Path(__file__).parent
def main():
parser = argparse.ArgumentParser(
description="""\
Verifies the contents of this folder by running tests and linters.
Requirements:
- `node` and `yarn` are on the `$PATH`
- `yarn install` has already been run in the addons/ folder
""",
formatter_class=RawTextHelpFormatter,
)
parser.add_argument(
"--use-vendored-grammars",
help=(
"Skips the codegen step for TextMate grammars that "
+ "fetches content from raw.githubusercontent.com. "
+ "Assumes TextMate codegen is already available."
),
action="store_true",
)
args = parser.parse_args()
asyncio.run(verify(use_vendored_grammars=args.use_vendored_grammars))
async def verify(*, use_vendored_grammars=False):
await asyncio.gather(
verify_prettier(),
verify_shared(),
verify_textmate(),
verify_isl(),
verify_reviewstack(use_vendored_grammars=use_vendored_grammars),
)
async def verify_prettier():
timer = Timer("verifying prettier")
await run(["yarn", "run", "prettier-check"], cwd=addons)
timer.report(ok("prettier"))
async def verify_shared():
timer = Timer("verifying shared/")
shared = addons / "shared"
await lint_and_test(shared)
timer.report(ok("shared/"))
async def verify_textmate():
timer = Timer("verifying textmate/")
textmate = addons / "textmate"
await asyncio.gather(
run(["yarn", "run", "tsc", "--noEmit"], cwd=textmate),
run(["yarn", "run", "eslint"], cwd=textmate),
)
timer.report(ok("textmate/"))
async def verify_isl():
"""Verifies isl/ and isl-server/ and vscode/ as the builds are interdependent"""
timer = Timer("verifying ISL")
isl = addons / "isl"
isl_server = addons / "isl-server"
vscode = addons / "vscode"
await run(["yarn", "codegen"], cwd=isl_server)
await asyncio.gather(
run(["yarn", "build"], cwd=isl_server),
run(["yarn", "build"], cwd=isl),
)
await asyncio.gather(
run(["yarn", "build-extension"], cwd=vscode),
run(["yarn", "build-webview"], cwd=vscode),
)
await asyncio.gather(
lint_and_test(isl),
lint_and_test(isl_server),
lint_and_test(vscode),
)
timer.report(ok("ISL"))
async def verify_reviewstack(*, use_vendored_grammars=False):
timer = Timer("verifying reviewstack/")
cwd = addons / "reviewstack"
if use_vendored_grammars:
# Normally, the full codegen step takes care of copying onig.wasm.
src_onig_wasm = (
addons / "node_modules" / "vscode-oniguruma" / "release" / "onig.wasm"
)
dest_onig_wasm = (
addons
/ "reviewstack.dev"
/ "public"
/ "generated"
/ "textmate"
/ "onig.wasm"
)
shutil.copyfile(src_onig_wasm, dest_onig_wasm)
await run(["yarn", "graphql"], cwd=cwd)
else:
await run(["yarn", "codegen"], cwd=cwd)
await asyncio.gather(lint_and_test(cwd), verify_reviewstack_dev())
timer.report(ok("reviewstack/"))
async def lint_and_test(cwd: Path):
await asyncio.gather(
run(["yarn", "run", "eslint"], cwd=cwd),
run(["yarn", "test", "--watchAll=false"], cwd=cwd),
)
async def verify_reviewstack_dev():
"""Requires codegen from reviewstack/ to have been built."""
timer = Timer("verifying reviewstack.dev/")
cwd = addons / "reviewstack.dev"
await run(["yarn", "build"], cwd=cwd)
await run(["yarn", "run", "eslint"], cwd=cwd)
await run(["yarn", "release"], cwd=cwd)
timer.report(ok("reviewstack.dev/"))
async def run(args: List[str], cwd: str):
process = await asyncio.create_subprocess_exec(
*args, cwd=cwd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
print(f"[stdout]\n{stdout.decode()}")
print(f"[stderr]\n{stderr.decode()}")
raise RuntimeError(f"command failed: {' '.join(args)}")
def ok(message: str) -> str:
return f"\033[0;32mOK\033[00m {message}"
class Timer:
def __init__(self, message):
self._start = time.time()
print(message)
def report(self, message: str):
end = time.time()
duration = end - self._start
print(f"{message} in {duration:.2f}s")
main()