Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); CM-68462 added support for gradlew by omer-roth · Pull Request #492 · cycodehq/cycode-cli · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import os
import platform
import re
from typing import Optional

Expand All@@ -12,19 +13,32 @@
BUILD_GRADLE_FILE_NAME = 'build.gradle'
BUILD_GRADLE_KTS_FILE_NAME = 'build.gradle.kts'
BUILD_GRADLE_DEP_TREE_FILE_NAME = 'gradle-dependencies-generated.txt'
BUILD_GRADLE_ALL_PROJECTS_COMMAND = ['gradle', 'projects']
ALL_PROJECTS_REGEX = r"[+-]{3} Project '(.*?)'"

GRADLE_EXECUTABLE = 'gradle'
GRADLEW_FILE_NAME = 'gradlew'
GRADLEW_BAT_FILE_NAME = 'gradlew.bat'


class RestoreGradleDependencies(BaseRestoreDependencies):
def __init__(
self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, projects: Optional[set[str]] = None
) -> None:
super().__init__(ctx, is_git_diff, command_timeout, create_output_file_manually=True)
self.gradle_executable = self._resolve_gradle_executable()
if projects is None:
projects = set()
self.projects = self.get_all_projects() if self.is_gradle_sub_projects() else projects

def _resolve_gradle_executable(self) -> str:
scan_root = get_path_from_context(self.ctx)
if scan_root:
wrapper_name = GRADLEW_BAT_FILE_NAME if platform.system() == 'Windows' else GRADLEW_FILE_NAME
wrapper_path = os.path.join(scan_root, wrapper_name)
if os.path.isfile(wrapper_path):
return wrapper_path
return GRADLE_EXECUTABLE

def is_gradle_sub_projects(self) -> bool:
return self.ctx.obj.get('gradle_all_sub_projects', False)

Expand All@@ -35,7 +49,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]:
return (
self.get_commands_for_sub_projects(manifest_file_path)
if self.is_gradle_sub_projects()
else [['gradle', 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
else [[self.gradle_executable, 'dependencies', '-b', manifest_file_path, '-q', '--console', 'plain']]
)

def get_lock_file_name(self) -> str:
Expand All@@ -49,7 +63,7 @@ def get_working_directory(self, document: Document) -> Optional[str]:

def get_all_projects(self) -> set[str]:
output = shell(
command=BUILD_GRADLE_ALL_PROJECTS_COMMAND,
command=[self.gradle_executable, 'projects'],
timeout=self.command_timeout,
working_directory=get_path_from_context(self.ctx),
)
Expand All@@ -62,7 +76,7 @@ def get_commands_for_sub_projects(self, manifest_file_path: str) -> list[list[st
project_name = os.path.basename(os.path.dirname(manifest_file_path))
project_name = f':{project_name}'
return (
[['gradle', f'{project_name}:dependencies', '-q', '--console', 'plain']]
[[self.gradle_executable, f'{project_name}:dependencies', '-q', '--console', 'plain']]
if project_name in self.projects
else []
)
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,11 +9,15 @@
BUILD_GRADLE_DEP_TREE_FILE_NAME,
BUILD_GRADLE_FILE_NAME,
BUILD_GRADLE_KTS_FILE_NAME,
GRADLE_EXECUTABLE,
GRADLEW_BAT_FILE_NAME,
GRADLEW_FILE_NAME,
RestoreGradleDependencies,
)
from cycode.cli.models import Document

_BASE_MODULE = 'cycode.cli.files_collector.sca.base_restore_dependencies'
_GRADLE_MODULE = 'cycode.cli.files_collector.sca.maven.restore_gradle_dependencies'


@pytest.fixture
Expand DownExpand Up@@ -47,6 +51,60 @@ def test_settings_gradle_does_not_match(self, restore_gradle: RestoreGradleDepen
assert restore_gradle.is_project(doc) is False


class TestResolveGradleExecutable:
def test_falls_back_to_gradle_when_no_wrapper(self, restore_gradle: RestoreGradleDependencies) -> None:
assert restore_gradle.gradle_executable == GRADLE_EXECUTABLE

def test_prefers_gradlew_wrapper_on_posix(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_prefers_gradlew_bat_on_windows(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_BAT_FILE_NAME
wrapper.write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Windows'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == str(wrapper)

def test_posix_ignores_bat_wrapper(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
(tmp_path / GRADLEW_BAT_FILE_NAME).write_text('@echo off\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
assert restore.gradle_executable == GRADLE_EXECUTABLE

def test_wrapper_is_threaded_into_get_commands(self, mock_ctx: typer.Context, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
with patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'):
restore = RestoreGradleDependencies(mock_ctx, is_git_diff=False, command_timeout=30)
commands = restore.get_commands(str(tmp_path / BUILD_GRADLE_FILE_NAME))
assert commands == [
[str(wrapper), 'dependencies', '-b', str(tmp_path / BUILD_GRADLE_FILE_NAME), '-q', '--console', 'plain']
]

def test_wrapper_is_threaded_into_sub_project_commands(self, tmp_path: Path) -> None:
wrapper = tmp_path / GRADLEW_FILE_NAME
wrapper.write_text('#!/bin/sh\n')
ctx = MagicMock(spec=typer.Context)
ctx.obj = {'monitor': False, 'gradle_all_sub_projects': True}
ctx.params = {'path': str(tmp_path)}
module_project = tmp_path / 'module-a'
module_project.mkdir()
manifest = module_project / BUILD_GRADLE_FILE_NAME

with (
patch(f'{_GRADLE_MODULE}.platform.system', return_value='Linux'),
patch.object(RestoreGradleDependencies, 'get_all_projects', return_value={':module-a'}),
):
restore = RestoreGradleDependencies(ctx, is_git_diff=False, command_timeout=30)

commands = restore.get_commands_for_sub_projects(str(manifest))
assert commands == [[str(wrapper), ':module-a:dependencies', '-q', '--console', 'plain']]


class TestCleanup:
def test_generated_dep_tree_file_is_deleted_after_restore(
self, restore_gradle: RestoreGradleDependencies, tmp_path: Path
Expand Down
Loading