chore: fix to vsix
This commit is contained in:
@@ -1,40 +1,42 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
mkdir input report output
|
|
||||||
export NPM_RUNTIME_CHECK_VER=latest
|
|
||||||
PACKAGE_NAME=${1}
|
|
||||||
PACKAGE_VERSION=${2}
|
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
RESULT_NAME=$PACKAGE_NAME
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "Usage: $0 <publisher.extension> <version>"
|
||||||
if [ ${PACKAGE_NAME:0:1} == '@' ]
|
exit 1
|
||||||
then
|
|
||||||
POS=$(echo $PACKAGE_NAME | grep -ob "/" | grep -oE "[0-9]+" | head -n 1)
|
|
||||||
RESULT_NAME=${PACKAGE_NAME:$POS+1}
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
URL=$(npm view ${PACKAGE_NAME}@${PACKAGE_VERSION} dist.tarball)
|
PACKAGE_NAME=$1
|
||||||
|
PACKAGE_VERSION=$2
|
||||||
|
|
||||||
REPORT=$(ls ./report/git_package)
|
if [[ "$PACKAGE_NAME" != *.* ]]; then
|
||||||
REPORT_LEN=${#REPORT}
|
echo "Package name must use publisher.extension format"
|
||||||
if [ ${REPORT_LEN} != 0 ]
|
exit 1
|
||||||
then
|
fi
|
||||||
|
|
||||||
|
PUBLISHER=${PACKAGE_NAME%%.*}
|
||||||
|
EXTENSION=${PACKAGE_NAME#*.}
|
||||||
|
URL="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${PUBLISHER}/vsextensions/${EXTENSION}/${PACKAGE_VERSION}/vspackage"
|
||||||
|
RESULT_INPUT="${PACKAGE_NAME}-${PACKAGE_VERSION}.vsix"
|
||||||
|
|
||||||
|
mkdir -p input report output
|
||||||
|
export VSIX_RUNTIME_CHECK_VER=${VSIX_RUNTIME_CHECK_VER:-latest}
|
||||||
|
|
||||||
|
if [ -d ./report/git_package ]; then
|
||||||
sync
|
sync
|
||||||
rm -rf ./report/git_package
|
rm -rf ./report/git_package
|
||||||
echo "Clean git_package"
|
echo "Clean git_package"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RESULT_INPUT=${RESULT_NAME}-${PACKAGE_VERSION}.tgz
|
echo "Download ${PACKAGE_NAME}@${PACKAGE_VERSION} from ${URL}"
|
||||||
|
curl \
|
||||||
cd input
|
--fail \
|
||||||
if [ $(ls $RESULT_INPUT) ]
|
--location \
|
||||||
then
|
--header "Accept: application/octet-stream" \
|
||||||
rm $RESULT_INPUT
|
--header "Accept-Encoding: identity" \
|
||||||
fi
|
--output "input/${RESULT_INPUT}" \
|
||||||
set -x
|
"${URL}"
|
||||||
echo $URL
|
|
||||||
wget -O "${RESULT_INPUT}" "${URL}"
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
export RELOAD_CONFIG=1
|
export RELOAD_CONFIG=1
|
||||||
export ADD_METADATA_VOLUME='true'
|
export ADD_METADATA_VOLUME='true'
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# The VSIX manifest points at angular/angular, but the VS Code extension source
|
||||||
|
# lives in angular/vscode-ng-language-service. There is no v20.3.3 tag there;
|
||||||
|
# v20.3.0 is the nearest public tag for the 20.3 line.
|
||||||
|
install_dependencies: "corepack enable && corepack prepare yarn@1.22.22 --activate && yarn install --frozen-lockfile"
|
||||||
|
source_repository: "https://github.com/angular/vscode-ng-language-service.git"
|
||||||
|
source_ref: "v20.3.0"
|
||||||
|
build_vsix: "yarn package"
|
||||||
|
run_tests: "yarn test"
|
||||||
|
coverage:
|
||||||
|
enabled: false
|
||||||
|
threshold: 80
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Marketplace version 3.0.19 is tagged as pre-release/3.0.19 upstream.
|
||||||
|
install_dependencies: "npm ci"
|
||||||
|
source_ref: "pre-release/3.0.19"
|
||||||
|
build_vsix: "npx @vscode/vsce package --out source.vsix"
|
||||||
|
run_tests: "npx c8 --clean --temp-directory coverage/tmp npm test"
|
||||||
|
coverage:
|
||||||
|
enabled: true
|
||||||
|
tool: "c8"
|
||||||
|
threshold: 80
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Commands are executed from the cloned repository root.
|
||||||
|
install_dependencies: "node -e 'const [major, minor] = process.versions.node.split(`.`).map(Number); if (major < 22 || (major === 22 && minor < 18)) { console.error(`GitLens 17.12.1 requires Node >=22.18.0; current=${process.versions.node}`); process.exit(1); }' && corepack enable && corepack prepare pnpm@10.33.0 --activate && pnpm install --frozen-lockfile"
|
||||||
|
build_vsix: "pnpm exec vsce package --no-dependencies --out source.vsix"
|
||||||
|
run_tests: "npx c8 --clean --temp-directory coverage/tmp node_modules/.bin/vscode-test"
|
||||||
|
coverage:
|
||||||
|
enabled: true
|
||||||
|
tool: "c8"
|
||||||
|
threshold: 80
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
install_dependencies: "npm ci"
|
||||||
|
build_vsix: "npx vsce package --out source.vsix"
|
||||||
|
run_tests: "npm test"
|
||||||
|
coverage:
|
||||||
|
enabled: false
|
||||||
|
threshold: 80
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
install_dependencies: "corepack enable && corepack prepare yarn@1.22.22 --activate && yarn install --frozen-lockfile"
|
||||||
|
build_vsix: "npx vsce package --out source.vsix"
|
||||||
|
run_tests: "yarn test"
|
||||||
|
coverage:
|
||||||
|
enabled: false
|
||||||
|
threshold: 80
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
install_dependencies: "npm ci"
|
||||||
|
build_vsix: "npx vsce package --out source.vsix"
|
||||||
|
run_tests: "npm run build-bundle && npm run jest -- --coverage"
|
||||||
|
coverage:
|
||||||
|
enabled: true
|
||||||
|
tool: "jest"
|
||||||
|
threshold: 80
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
#!/bin/bash
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
GitPython
|
||||||
|
PyYAML
|
||||||
|
wget
|
||||||
|
scapy
|
||||||
@@ -0,0 +1,637 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os.path
|
||||||
|
import pathlib
|
||||||
|
import argparse
|
||||||
|
import tempfile
|
||||||
|
import subprocess
|
||||||
|
import zipfile
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from runtime_check.checker import T5Checker, Scanfeeder
|
||||||
|
from runtime_check.logger import get_logger
|
||||||
|
from runtime_check.monitor import Monitor
|
||||||
|
from runtime_check.config import settings
|
||||||
|
|
||||||
|
MANUAL_PROCESSING_KEY = 'MANUAL_CHECK'
|
||||||
|
MANUAL_CHECK_DETECTION_MESSAGE = 'MANUAL_CHECK_DETECTION'
|
||||||
|
|
||||||
|
|
||||||
|
class VSIX_T5Checker(T5Checker):
|
||||||
|
"""Base class to perform the whole check. We may inherit it and overwrite any part in some specific case, so don't hesitate"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
scanfeeder: Scanfeeder,
|
||||||
|
monitor: Monitor,
|
||||||
|
logger: logging.Logger,
|
||||||
|
report_dir: pathlib.Path,
|
||||||
|
package_path: pathlib.Path,
|
||||||
|
):
|
||||||
|
self.package_path = pathlib.Path(package_path)
|
||||||
|
super().__init__(scanfeeder, monitor, logger, report_dir)
|
||||||
|
|
||||||
|
def _load_yaml_config(self) -> None:
|
||||||
|
self.packages_info = dict()
|
||||||
|
yaml_base_info = dict()
|
||||||
|
yaml_specific_version = dict()
|
||||||
|
|
||||||
|
stage_name='load_yaml_config'
|
||||||
|
metadata_root = pathlib.Path(settings.get("metadata_path", "../metadata"))
|
||||||
|
coverage_tool_paths = (
|
||||||
|
metadata_root / "coverage_tools.yaml",
|
||||||
|
pathlib.Path("../meta/coverage_tools.yaml"),
|
||||||
|
)
|
||||||
|
coverage_tool_path = next(
|
||||||
|
(path for path in coverage_tool_paths if path.exists()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if coverage_tool_path:
|
||||||
|
with coverage_tool_path.open(encoding="utf-8") as coverage_file:
|
||||||
|
self.supported_coverage_tools = yaml.load(
|
||||||
|
coverage_file,
|
||||||
|
Loader=yaml.SafeLoader,
|
||||||
|
) or {}
|
||||||
|
else:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name=stage_name,
|
||||||
|
details=(
|
||||||
|
"Failed to load supported coverage tools yaml file from "
|
||||||
|
+ ", ".join(str(path) for path in coverage_tool_paths)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
package_metadata_paths = (
|
||||||
|
metadata_root / settings.package_name / "metadata.yaml",
|
||||||
|
metadata_root / f"{settings.package_name}.yml",
|
||||||
|
metadata_root / f"{settings.package_name}.yaml",
|
||||||
|
)
|
||||||
|
package_metadata_path = next(
|
||||||
|
(path for path in package_metadata_paths if path.exists()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
package_specific_version = (
|
||||||
|
metadata_root
|
||||||
|
/ settings.package_name
|
||||||
|
/ settings.package_version
|
||||||
|
/ "metadata.yaml"
|
||||||
|
)
|
||||||
|
if package_metadata_path:
|
||||||
|
with package_metadata_path.open(encoding="utf-8") as metadata_file:
|
||||||
|
yaml_base_info = yaml.load(
|
||||||
|
metadata_file,
|
||||||
|
Loader=yaml.SafeLoader,
|
||||||
|
) or {}
|
||||||
|
if package_specific_version.exists():
|
||||||
|
with package_specific_version.open(encoding="utf-8") as version_file:
|
||||||
|
yaml_specific_version = yaml.load(
|
||||||
|
version_file,
|
||||||
|
Loader=yaml.SafeLoader,
|
||||||
|
) or {}
|
||||||
|
yaml_base_info.update(yaml_specific_version)
|
||||||
|
self._normalize_vsix_metadata(yaml_base_info)
|
||||||
|
self.packages_info[settings.package_name] = yaml_base_info
|
||||||
|
else:
|
||||||
|
self.packages_info[settings.package_name] = dict()
|
||||||
|
self.logger.info("[LOAD METADATA]: not found description for package use default")
|
||||||
|
|
||||||
|
self.diff_exclude_files = []
|
||||||
|
self.diff_exclude_extensions = []
|
||||||
|
self.check_manual_processing()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_vsix_metadata(package_info: dict) -> None:
|
||||||
|
aliases = {
|
||||||
|
"install_dependencies": "install_actions",
|
||||||
|
"build_vsix": "build_actions",
|
||||||
|
"run_tests": "coverage_command",
|
||||||
|
"source_repository": "repository",
|
||||||
|
}
|
||||||
|
for source_key, target_key in aliases.items():
|
||||||
|
if source_key in package_info and target_key not in package_info:
|
||||||
|
package_info[target_key] = package_info[source_key]
|
||||||
|
|
||||||
|
coverage = package_info.get("coverage")
|
||||||
|
if isinstance(coverage, dict):
|
||||||
|
if "tool" in coverage and "coverage_tool" not in package_info:
|
||||||
|
package_info["coverage_tool"] = coverage["tool"]
|
||||||
|
if "enabled" in coverage and "coverage_enabled" not in package_info:
|
||||||
|
package_info["coverage_enabled"] = coverage["enabled"]
|
||||||
|
|
||||||
|
for value in package_info.values():
|
||||||
|
if isinstance(value, dict) and value is not coverage:
|
||||||
|
VSIX_T5Checker._normalize_vsix_metadata(value)
|
||||||
|
|
||||||
|
def check_manual_processing(self) -> None:
|
||||||
|
if self.get_version_specific_package_info(MANUAL_PROCESSING_KEY):
|
||||||
|
self.status.append_status_file(self.status.MANUAL_CHECK, '"Based on metadata info, manual check (T06) required"')
|
||||||
|
self.logger.info(MANUAL_CHECK_DETECTION_MESSAGE)
|
||||||
|
self.stage_warn_without_exit(
|
||||||
|
stage_name="manual_check_required",
|
||||||
|
details=f"Manual check is required to proceed with this package. \n{MANUAL_CHECK_DETECTION_MESSAGE}\n"
|
||||||
|
)
|
||||||
|
self.check_is_done()
|
||||||
|
|
||||||
|
def extract_package(self, archive_path: pathlib.Path, result_folder: pathlib.Path, substep_name: str) -> pathlib.Path:
|
||||||
|
try:
|
||||||
|
result_folder.mkdir(parents=True, exist_ok=False)
|
||||||
|
result_root = result_folder.resolve()
|
||||||
|
with zipfile.ZipFile(archive_path) as archive:
|
||||||
|
for member in archive.infolist():
|
||||||
|
destination = (result_folder / member.filename).resolve()
|
||||||
|
if destination != result_root and result_root not in destination.parents:
|
||||||
|
raise ValueError(f"Unsafe path in VSIX archive: {member.filename}")
|
||||||
|
archive.extractall(result_folder)
|
||||||
|
except (OSError, ValueError, zipfile.BadZipFile) as e:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name=substep_name,
|
||||||
|
details=f"Failed to extract VSIX archive {archive_path}: {e}.",
|
||||||
|
)
|
||||||
|
package_json = result_folder / "extension" / "package.json"
|
||||||
|
if not package_json.is_file():
|
||||||
|
self.stage_error(
|
||||||
|
stage_name=substep_name,
|
||||||
|
details=f"VSIX archive {archive_path} does not contain extension/package.json.",
|
||||||
|
)
|
||||||
|
self.stage_passed(stage_name=substep_name)
|
||||||
|
return result_folder
|
||||||
|
|
||||||
|
def load_extracted_package_json(self, package_extracted_path: pathlib.Path) -> None:
|
||||||
|
stage_name='load_extracted_package_json'
|
||||||
|
try:
|
||||||
|
with (package_extracted_path / "extension" / "package.json").open(
|
||||||
|
encoding="utf-8"
|
||||||
|
) as package_json:
|
||||||
|
self.extracted_package_info = json.load(package_json)
|
||||||
|
except (OSError, json.JSONDecodeError) as e:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name=stage_name,
|
||||||
|
details=f"Failed to load extension/package.json from VSIX: {e}",
|
||||||
|
)
|
||||||
|
self.stage_passed(stage_name=stage_name)
|
||||||
|
|
||||||
|
def get_git_url(self):
|
||||||
|
try:
|
||||||
|
repo_url = self.get_version_specific_package_info("repository")
|
||||||
|
if isinstance(repo_url, dict):
|
||||||
|
repo_url = repo_url.get("url")
|
||||||
|
if not repo_url:
|
||||||
|
repository = self.extracted_package_info.get("repository")
|
||||||
|
if isinstance(repository, str):
|
||||||
|
repo_url = repository
|
||||||
|
elif isinstance(repository, dict):
|
||||||
|
repo_url = repository.get("url")
|
||||||
|
|
||||||
|
if not repo_url:
|
||||||
|
self.status.append_status_file(self.status.GIT_URL_ABSENT, '"Git url is absent in package info and metadata"')
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="get_git_url",
|
||||||
|
details="Failed to fetch git url.",
|
||||||
|
)
|
||||||
|
|
||||||
|
repo_url = repo_url.removeprefix("git+")
|
||||||
|
if repo_url.startswith("git@github.com:"):
|
||||||
|
repo_url = "https://github.com/" + repo_url.removeprefix("git@github.com:")
|
||||||
|
|
||||||
|
parsed = urlparse(repo_url)
|
||||||
|
if parsed.hostname != "github.com":
|
||||||
|
self.status.append_status_file(self.status.GIT_URL_PARSE_FAILED, '"Failed to parse git url - not a github url"')
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="get_git_url",
|
||||||
|
details=f"Failed to extract package repository - {repo_url}",
|
||||||
|
)
|
||||||
|
parts = [part for part in parsed.path.split("/") if part]
|
||||||
|
if len(parts) < 2:
|
||||||
|
raise ValueError(f"GitHub repository path is incomplete: {parsed.path}")
|
||||||
|
repo_url = "https://github.com/" + "/".join(parts[:2])
|
||||||
|
except Exception as e:
|
||||||
|
self.status.append_status_file(self.status.GIT_URL_EXTRACT_FAILED, '"Failed to extract git url - not a github url"')
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="get_git_url",
|
||||||
|
details=f"Failed to extract package repository: {e}",
|
||||||
|
)
|
||||||
|
self.stage_passed(
|
||||||
|
stage_name="get_git_url",
|
||||||
|
details="git url successfully extracted"
|
||||||
|
)
|
||||||
|
self.logger.info("Git url for the project is: %s", repo_url)
|
||||||
|
return repo_url
|
||||||
|
|
||||||
|
def clone_package_and_checkout(self, working_dir: pathlib.Path) -> pathlib.Path:
|
||||||
|
stage_name = "clone_package_and_checkout"
|
||||||
|
repo_url = self.get_git_url()
|
||||||
|
project_dir = working_dir / "git_package" / self.package_name
|
||||||
|
project_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
["git", "clone", repo_url, str(project_dir)],
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
source_ref = self.get_version_specific_package_info("source_ref")
|
||||||
|
if source_ref:
|
||||||
|
subprocess.run(
|
||||||
|
["git", "fetch", "origin", str(source_ref)],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
["git", "checkout", "--detach", "FETCH_HEAD"],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
commit_id = self.get_version_specific_package_info("commit_id")
|
||||||
|
if commit_id:
|
||||||
|
subprocess.run(
|
||||||
|
["git", "checkout", "--detach", str(commit_id)],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tags = subprocess.run(
|
||||||
|
["git", "tag", "--list", self.version, f"v{self.version}"],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
).stdout.splitlines()
|
||||||
|
if tags:
|
||||||
|
preferred_tag = self.version if self.version in tags else tags[0]
|
||||||
|
subprocess.run(
|
||||||
|
["git", "checkout", "--detach", preferred_tag],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.warning(
|
||||||
|
"No tag matching %s or v%s; checking current repository HEAD",
|
||||||
|
self.version,
|
||||||
|
self.version,
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
["git", "submodule", "update", "--init", "--recursive"],
|
||||||
|
cwd=project_dir,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
except (OSError, subprocess.CalledProcessError) as e:
|
||||||
|
stderr = getattr(e, "stderr", None)
|
||||||
|
self.stage_error(
|
||||||
|
stage_name=stage_name,
|
||||||
|
details=f"Failed to clone or checkout {repo_url}: {stderr or e}",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stage_passed(stage_name=stage_name, details="Finished downloading package sources")
|
||||||
|
return project_dir
|
||||||
|
|
||||||
|
def load_repo_package_info(self, package_dir):
|
||||||
|
package_file_path = self.get_version_specific_package_info('repo_package_json_path')
|
||||||
|
if not package_file_path:
|
||||||
|
package_file_path = self.get_package_info('repo_package_json_path')
|
||||||
|
if not package_file_path:
|
||||||
|
package_file_path = "package.json"
|
||||||
|
try:
|
||||||
|
with (package_dir / package_file_path).open(encoding="utf-8") as package_json:
|
||||||
|
res = json.load(package_json)
|
||||||
|
if 'scripts' in res:
|
||||||
|
from pprint import pformat
|
||||||
|
self.logger.debug("Package Scripts: %s", pformat(res['scripts']))
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="load_repo_package_info",
|
||||||
|
details=f"Failed to load repo package info - failed to decode {package_file_path} json {e.msg}",
|
||||||
|
)
|
||||||
|
except OSError as e:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="load_repo_package_info",
|
||||||
|
details=f"Failed to load repo package info - failed to open {package_file_path}: {e}",
|
||||||
|
)
|
||||||
|
self.stage_passed(stage_name="load_repo_package_info")
|
||||||
|
return res
|
||||||
|
|
||||||
|
def install_package(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
package_dir: pathlib.Path,
|
||||||
|
env: dict,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
actions = self.get_actions_from_config("install_actions")
|
||||||
|
if actions is None:
|
||||||
|
self.install_package_general(package_dir=package_dir, env=env)
|
||||||
|
else:
|
||||||
|
self.run_actions(
|
||||||
|
"install_package",
|
||||||
|
actions,
|
||||||
|
env=env,
|
||||||
|
package_dir=package_dir,
|
||||||
|
check=True,
|
||||||
|
timeout=self.install_timeout,
|
||||||
|
)
|
||||||
|
self.stage_passed(stage_name="install_package", details="Dependencies were installed.")
|
||||||
|
|
||||||
|
def install_package_general(self, package_dir: pathlib.Path, env: dict) -> bool:
|
||||||
|
try:
|
||||||
|
if (package_dir / "pnpm-lock.yaml").is_file():
|
||||||
|
actions = [
|
||||||
|
"corepack enable",
|
||||||
|
"pnpm install --frozen-lockfile",
|
||||||
|
]
|
||||||
|
elif (package_dir / "yarn.lock").is_file():
|
||||||
|
actions = [
|
||||||
|
"corepack enable",
|
||||||
|
"yarn install --frozen-lockfile --non-interactive",
|
||||||
|
]
|
||||||
|
elif (package_dir / "package-lock.json").is_file():
|
||||||
|
actions = ["npm ci"]
|
||||||
|
else:
|
||||||
|
actions = ["npm install --no-audit"]
|
||||||
|
return self.run_actions(
|
||||||
|
"install_package_general",
|
||||||
|
actions,
|
||||||
|
env=env,
|
||||||
|
package_dir=package_dir,
|
||||||
|
check=True,
|
||||||
|
timeout=self.install_timeout,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="install_package_general",
|
||||||
|
details=f"Failed to install source dependencies: {e}",
|
||||||
|
)
|
||||||
|
|
||||||
|
def custom_prepare(self, package_dir: str | pathlib.Path, env: dict) -> bool:
|
||||||
|
"""Run prepare actions from yaml file"""
|
||||||
|
self.logger.info("Run custom package preparation")
|
||||||
|
prepare = self.get_actions_from_config('prepare')
|
||||||
|
result = self.run_actions(
|
||||||
|
'prepare',
|
||||||
|
prepare,
|
||||||
|
env=env,
|
||||||
|
package_dir=package_dir,
|
||||||
|
check=True,
|
||||||
|
timeout=self.install_timeout
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def build_package(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
package_dir: pathlib.Path,
|
||||||
|
env: dict,
|
||||||
|
**kwargs,
|
||||||
|
) -> bool:
|
||||||
|
actions = self.get_actions_from_config("build_actions")
|
||||||
|
if actions is None:
|
||||||
|
result = self.build_package_general(package_dir=package_dir, env=env)
|
||||||
|
else:
|
||||||
|
result = self.run_actions(
|
||||||
|
"build_package",
|
||||||
|
actions,
|
||||||
|
env=env,
|
||||||
|
package_dir=package_dir,
|
||||||
|
check=True,
|
||||||
|
timeout=self.build_timeout,
|
||||||
|
)
|
||||||
|
self.stage_passed(stage_name="build_package", details="VSIX was built successfully.")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def build_package_general(self, env: dict, package_dir: str | pathlib.Path) -> bool:
|
||||||
|
return self.run_actions(
|
||||||
|
'build_package_general',
|
||||||
|
["npx @vscode/vsce package --out source.vsix"],
|
||||||
|
env=env,
|
||||||
|
package_dir=package_dir,
|
||||||
|
check=True,
|
||||||
|
timeout=self.build_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
def find_built_vsix(
|
||||||
|
self,
|
||||||
|
package_dir: pathlib.Path,
|
||||||
|
existing_archives: dict[pathlib.Path, int],
|
||||||
|
) -> pathlib.Path:
|
||||||
|
configured_path = self.get_version_specific_package_info("built_vsix_path")
|
||||||
|
if configured_path:
|
||||||
|
built_vsix = package_dir / configured_path
|
||||||
|
if built_vsix.is_file():
|
||||||
|
return built_vsix
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="find_built_vsix",
|
||||||
|
details=f"Configured built VSIX was not found: {built_vsix}",
|
||||||
|
)
|
||||||
|
|
||||||
|
candidates = []
|
||||||
|
for archive in package_dir.rglob("*.vsix"):
|
||||||
|
mtime = archive.stat().st_mtime_ns
|
||||||
|
if archive not in existing_archives or existing_archives[archive] != mtime:
|
||||||
|
candidates.append(archive)
|
||||||
|
if not candidates:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="find_built_vsix",
|
||||||
|
details="Build command did not create or update a VSIX archive.",
|
||||||
|
)
|
||||||
|
built_vsix = max(candidates, key=lambda path: path.stat().st_mtime_ns)
|
||||||
|
self.stage_passed(
|
||||||
|
stage_name="find_built_vsix",
|
||||||
|
details=f"Built VSIX found at {built_vsix}",
|
||||||
|
)
|
||||||
|
return built_vsix
|
||||||
|
|
||||||
|
def count_coverage_custom(self, env: dict, package_dir: str | pathlib.Path) -> None:
|
||||||
|
coverage_actions = self.get_actions_from_config("coverage_command")
|
||||||
|
if not coverage_actions:
|
||||||
|
# No actions provided. This is weird but who to judge?
|
||||||
|
return
|
||||||
|
self.logger.info("Run custom package coverage")
|
||||||
|
self.run_actions_with_monitor(
|
||||||
|
'count_coverage_custom',
|
||||||
|
coverage_actions,
|
||||||
|
env=env,
|
||||||
|
check=False,
|
||||||
|
package_dir=package_dir,
|
||||||
|
timeout=self.test_timeout
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
def count_coverage_general(self, env: dict, package_dir: str | pathlib.Path, **kwargs) -> None:
|
||||||
|
self.status.append_status_file(self.status.COVERAGE_COMMAND_ABSENT, '"TEST_COMMAND section in metadate must be filled"')
|
||||||
|
self.stage_error(
|
||||||
|
stage_name='count_coverage_general',
|
||||||
|
details="Coverage command for the VSIX source repository is not configured."
|
||||||
|
)
|
||||||
|
|
||||||
|
def run_coverage_report(self, package_dir: pathlib.Path, env: dict) -> str:
|
||||||
|
coverage_tool_name = self.get_version_specific_package_info('coverage_tool')
|
||||||
|
|
||||||
|
if coverage_tool_name not in self.supported_coverage_tools:
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="run_coverage_report",
|
||||||
|
details=f"Unsupported coverage tool: `{coverage_tool_name}`"
|
||||||
|
)
|
||||||
|
coverage_tool = self.supported_coverage_tools[coverage_tool_name]
|
||||||
|
coverage_report_folder = coverage_tool['coverage_report_folder']
|
||||||
|
# Will travers from 'build_path' up to 'package_path' in hope to find coverage dir.
|
||||||
|
build_relative_path = self.get_version_specific_package_info('build_relative_path')
|
||||||
|
if build_relative_path:
|
||||||
|
probe_path = package_dir / build_relative_path
|
||||||
|
while probe_path != package_dir:
|
||||||
|
if (probe_path / coverage_report_folder).exists():
|
||||||
|
package_dir = probe_path
|
||||||
|
break
|
||||||
|
probe_path = probe_path.parent
|
||||||
|
|
||||||
|
if not (package_dir / coverage_report_folder).exists():
|
||||||
|
self.stage_error(
|
||||||
|
stage_name="run_coverage_report",
|
||||||
|
details=f"Failed to find coverage report dir."
|
||||||
|
)
|
||||||
|
# TODO: capture report and save in metadata
|
||||||
|
coverage_report = self.run_actions(
|
||||||
|
'run_coverage_report',
|
||||||
|
coverage_tool['report'],
|
||||||
|
env=env,
|
||||||
|
check=True,
|
||||||
|
package_dir=package_dir,
|
||||||
|
)
|
||||||
|
self.stage_passed('run_coverage_report', details=coverage_report)
|
||||||
|
coverage_report = self.run_actions(
|
||||||
|
'process_coverage_result',
|
||||||
|
coverage_tool['check'],
|
||||||
|
env=env,
|
||||||
|
check=True,
|
||||||
|
package_dir=package_dir,
|
||||||
|
)
|
||||||
|
self.stage_passed('process_coverage_result', details=coverage_report)
|
||||||
|
|
||||||
|
|
||||||
|
def run_tests_coverage(self, env: dict, package_dir: str | pathlib.Path, **kwargs) -> None:
|
||||||
|
if self.get_version_specific_package_info("coverage_enabled") is False:
|
||||||
|
self.stage_passed(
|
||||||
|
stage_name="count_coverage",
|
||||||
|
details="Coverage verification is disabled for this VSIX package.",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
coverage_actions = self.get_actions_from_config("coverage_command")
|
||||||
|
if coverage_actions is None:
|
||||||
|
self.count_coverage_general(env=env, package_dir=package_dir, **kwargs)
|
||||||
|
else:
|
||||||
|
self.count_coverage_custom(env, package_dir)
|
||||||
|
|
||||||
|
self.run_coverage_report(package_dir, env)
|
||||||
|
self.stage_passed(
|
||||||
|
stage_name="count_coverage",
|
||||||
|
details=f"Package {self.package_name} {self.version} was processed."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_package_env():
|
||||||
|
env = os.environ.copy()
|
||||||
|
new_env_path = []
|
||||||
|
for path in env['PATH'].split(os.pathsep):
|
||||||
|
if path.endswith('venv/bin'):
|
||||||
|
# erase current venv
|
||||||
|
continue
|
||||||
|
new_env_path.append(path)
|
||||||
|
env['PATH'] = os.pathsep.join(new_env_path)
|
||||||
|
env.pop('PYTHONHOME', None)
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
def run_check(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
tmpdir_path = pathlib.Path(tmpdir)
|
||||||
|
marketplace_extracted_path = self.extract_package(
|
||||||
|
archive_path=self.package_path,
|
||||||
|
result_folder=tmpdir_path / "marketplace_vsix",
|
||||||
|
substep_name="extract_marketplace_vsix",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.load_extracted_package_json(marketplace_extracted_path)
|
||||||
|
self.logger.info("Working on VSIX package %s@%s", self.package_name, self.version)
|
||||||
|
|
||||||
|
git_project_path = self.clone_package_and_checkout(
|
||||||
|
working_dir=pathlib.Path(self.report_dir)
|
||||||
|
)
|
||||||
|
self.repo_package_info = self.load_repo_package_info(git_project_path)
|
||||||
|
|
||||||
|
package_env = self.get_package_env()
|
||||||
|
self.custom_prepare(package_dir=git_project_path, env=package_env)
|
||||||
|
self.install_package(package_dir=git_project_path, env=package_env)
|
||||||
|
|
||||||
|
existing_archives = {
|
||||||
|
archive: archive.stat().st_mtime_ns
|
||||||
|
for archive in git_project_path.rglob("*.vsix")
|
||||||
|
}
|
||||||
|
self.build_package(package_dir=git_project_path, env=package_env)
|
||||||
|
built_vsix = self.find_built_vsix(git_project_path, existing_archives)
|
||||||
|
source_extracted_path = self.extract_package(
|
||||||
|
archive_path=built_vsix,
|
||||||
|
result_folder=tmpdir_path / "source_vsix",
|
||||||
|
substep_name="extract_source_vsix",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.check_diff(marketplace_extracted_path, source_extracted_path)
|
||||||
|
self.run_tests_coverage(package_dir=git_project_path, env=package_env)
|
||||||
|
self.check_is_done()
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
report_folder = args.report_path
|
||||||
|
package_file_name = settings.package_file
|
||||||
|
logger = get_logger(
|
||||||
|
"vsix_package_processing",
|
||||||
|
log_file=pathlib.Path(report_folder) / f"processing_{package_file_name}.log",
|
||||||
|
log_level_name=settings.log_level.upper()
|
||||||
|
)
|
||||||
|
logger.info("Start processing %s", package_file_name)
|
||||||
|
|
||||||
|
scanfeeder = Scanfeeder(logger)
|
||||||
|
|
||||||
|
monitor = Monitor(
|
||||||
|
tcpdump_enable=settings.monitor_enable,
|
||||||
|
sysdig_enable=settings.monitor_enable,
|
||||||
|
scanfeeder=scanfeeder,
|
||||||
|
logger=logger,
|
||||||
|
pipe_path=settings.sysdig_pipe_path,
|
||||||
|
report_folder=report_folder,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
vsix_checker = VSIX_T5Checker(
|
||||||
|
scanfeeder=scanfeeder,
|
||||||
|
monitor=monitor,
|
||||||
|
logger=logger,
|
||||||
|
report_dir=pathlib.Path(args.report_path),
|
||||||
|
package_path=pathlib.Path(args.file_path),
|
||||||
|
)
|
||||||
|
vsix_checker.run_check()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
projdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
parser = argparse.ArgumentParser(prog="T005 checker", description="does t005 check")
|
||||||
|
parser.add_argument("--file_path", help="full path to the archive to be check", required=False, default=os.path.join(projdir, 'input', settings.package_file))
|
||||||
|
parser.add_argument("--report_path", help="full path to the directory where report will be generated", required=False, default=os.path.join(projdir, 'report'))
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
main(args)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Host github.com
|
||||||
|
User git
|
||||||
|
IdentityFile ~/.ssh/github_rsa
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgGp47LrHXo6Ghtx1ESc4AlPT/SalJL2y+le4Vf/KIUIB7PRI5bbFV1VUOM8jLPyK0WETHG0mZmaOn64hBTh9hqvOQSdAEcaa2ZAksa9ELTgK+OgovOOaTINXxib1uZjiGHx91LfAweOD4lopYA31/ffiCklponq4G8OwUYLjUZg3YRZd3VyKDcRjwhDPOpmMLSHJZztAek2PM8eMf8h09fMESMgSFI3T6z9IIpfnRwIkFwK7XujqdS5qNJARX4VsI4TFay8JWn813b3x6IexCEHvVmstS2xa7e0fgWHk+CUui9ut63fM/O/Uap8LTdAm7dnlfTXVCIYXZLofiBGML1Hmc0//8649w28mbd9cXBcBDrFnnFRObhwYK7cgJGk4lfveLLQJHeIV0IjpK+UE70LMoChF1x9eWc+8DW6w7KxjpqXsy1/s51D5lMAjZ9p6PpCZDeogVH0eI2qezbK10dBTqH9KUZvrGnDuC9QQAfHhvvTtme/YkJy8zK+jkQ/ohQ== x@x
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||||
|
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||||
|
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
|
||||||
Reference in New Issue
Block a user