Skip to content

Commit 1656ec6

Browse files
committed
CM-44581 gradle - support restore projects and by selecting specific project
1 parent ac54f89 commit 1656ec6

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

cycode/cli/commands/scan/scan_command.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from cycode.cli.consts import (
1313
ISSUE_DETECTED_STATUS_CODE,
1414
NO_ISSUES_STATUS_CODE,
15-
SCA_SKIP_RESTORE_DEPENDENCIES_FLAG,
15+
SCA_SKIP_RESTORE_DEPENDENCIES_FLAG, SCA_GRADLE_ALL_SUB_PROJECTS_FLAG,
1616
)
1717
from cycode.cli.models import Severity
1818
from cycode.cli.sentry import add_breadcrumb
@@ -109,6 +109,14 @@
109109
type=bool,
110110
required=False,
111111
)
112+
@click.option(
113+
f'--{SCA_GRADLE_ALL_SUB_PROJECTS_FLAG}',
114+
is_flag=True,
115+
default=False,
116+
help='When specified, Cycode will run gradle restore command for all sub projects. Should run from root project directory ONLY!',
117+
type=bool,
118+
required=False,
119+
)
112120
@click.pass_context
113121
def scan_command(
114122
context: click.Context,
@@ -123,6 +131,7 @@ def scan_command(
123131
report: bool,
124132
no_restore: bool,
125133
sync: bool,
134+
gradle_all_sub_projects: bool
126135
) -> int:
127136
"""Scans for Secrets, IaC, SCA or SAST violations."""
128137
add_breadcrumb('scan')
@@ -144,6 +153,7 @@ def scan_command(
144153
context.obj['monitor'] = monitor
145154
context.obj['report'] = report
146155
context.obj[SCA_SKIP_RESTORE_DEPENDENCIES_FLAG] = no_restore
156+
context.obj[SCA_GRADLE_ALL_SUB_PROJECTS_FLAG] = gradle_all_sub_projects
147157

148158
_sca_scan_to_context(context, sca_scan)
149159

cycode/cli/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,4 @@
222222
SCA_SHORTCUT_DEPENDENCY_PATHS = 2
223223

224224
SCA_SKIP_RESTORE_DEPENDENCIES_FLAG = 'no-restore'
225+
SCA_GRADLE_ALL_SUB_PROJECTS_FLAG = 'gradle-all-sub-projects'
Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,58 @@
11
import os
2-
from typing import List
2+
import re
3+
from typing import List, Set, Optional
34

45
import click
56

7+
from cycode.cli.consts import SCA_GRADLE_ALL_SUB_PROJECTS_FLAG
68
from cycode.cli.files_collector.sca.base_restore_dependencies import BaseRestoreDependencies
79
from cycode.cli.models import Document
10+
from cycode.cli.utils.shell_executor import shell
811

912
BUILD_GRADLE_FILE_NAME = 'build.gradle'
1013
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
1114
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
15+
BUILD_GRADLE_ALL_PROJECTS_TIMEOUT = 180
16+
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
17+
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"
1218

1319

1420
class RestoreGradleDependencies(BaseRestoreDependencies):
15-
def __init__(self, context: click.Context, is_git_diff: bool, command_timeout: int) -> None:
21+
def __init__(self, context: click.Context, is_git_diff: bool, command_timeout: int,
22+
projects: Set[str] = set()) -> None:
1623
super().__init__(context, is_git_diff, command_timeout, create_output_file_manually=True)
24+
self.projects = projects
25+
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else set()
26+
27+
def is_gradle_sub_projects(self):
28+
return self.context.obj.get(SCA_GRADLE_ALL_SUB_PROJECTS_FLAG)
1729

1830
def is_project(self, document: Document) -> bool:
1931
return document.path.endswith(BUILD_GRADLE_FILE_NAME) or document.path.endswith(BUILD_GRADLE_KTS_FILE_NAME)
2032

2133
def get_commands(self, manifest_file_path: str) -> List[List[str]]:
22-
return [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
34+
return self.get_commands_for_sub_projects(manifest_file_path) if self.is_gradle_sub_projects() else [
35+
['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
2336

2437
def get_lock_file_name(self) -> str:
2538
return BUILD_GRADLE_DEP_TREE_FILE_NAME
2639

2740
def verify_restore_file_already_exist(self, restore_file_path: str) -> bool:
2841
return os.path.isfile(restore_file_path)
42+
43+
def get_working_directory(self, document: Document) -> Optional[str]:
44+
return self.context.params.get('paths')[0] if self.is_gradle_sub_projects() else None
45+
46+
def get_all_projects(self) -> List[str]:
47+
projects_output = shell(command=BUILD_GRADLE_ALL_PROJECTS_COMMAND, timeout=BUILD_GRADLE_ALL_PROJECTS_TIMEOUT,
48+
working_directory=self.context.params.get('paths')[0])
49+
50+
projects = re.findall(ALL_PROJECTS_REGEX, projects_output)
51+
52+
return set(projects)
53+
54+
def get_commands_for_sub_projects(self, manifest_file_path: str) -> List[List[str]]:
55+
project_name = os.path.basename(os.path.dirname(manifest_file_path))
56+
project_name = f':{project_name}'
57+
return [['gradle', f'{project_name}:dependencies', '-q', '--console',
58+
'plain']] if project_name in self.projects else []

0 commit comments

Comments
 (0)