Skip to content
Open
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
34 changes: 33 additions & 1 deletion bench/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,20 @@
app.install_resolved_apps(skip_assets=skip_assets, verbose=verbose)


def new_app(app, no_git=None, bench_path="."):
def new_app(

Check failure on line 862 in bench/app.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=frappe_bench&issues=AZ058pGvLQrmbX5-57nl&open=AZ058pGvLQrmbX5-57nl&pullRequest=1706
app,
no_git=None,
bench_path=".",
title=None,
description=None,
publisher=None,
email=None,
license=None,
github_workflow=None,
frontend=None,
route=None,
branch=None,
):
if bench.FRAPPE_VERSION in (0, None):
click.secho(
f"{os.path.realpath(bench_path)} is not a valid bench directory.",
Expand All @@ -883,6 +896,25 @@
return
args.append(no_git)

if title is not None:
args += ["--title", title]
if description is not None:
args += ["--description", description]
if publisher is not None:
args += ["--publisher", publisher]
if email is not None:
args += ["--email", email]
if license is not None:
args += ["--license", license]
if github_workflow is not None:
args.append("--github-workflow" if github_workflow else "--no-github-workflow")
if frontend is not None:
args.append("--frontend" if frontend else "--no-frontend")
if route is not None:
args += ["--route", route]
if branch is not None:
args += ["--branch", branch]

logger.log(f"creating new app {app}")
run_frappe_cmd(*args, bench_path=bench_path)
install_app(app, bench_path=bench_path)
Expand Down
55 changes: 51 additions & 4 deletions bench/commands/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,58 @@ def get_app(
flag_value="--no-git",
help="Do not initialize git repository for the app (available in Frappe v14+)",
)
@click.option("--title", default=None, help="App Title")
@click.option("--description", default=None, help="App Description")
@click.option("--publisher", default=None, help="App Publisher")
@click.option("--email", default=None, help="App Publisher's Email")
@click.option(
"--license",
default=None,
help="App License",
)
@click.option(
"--github-workflow/--no-github-workflow",
"github_workflow",
default=None,
help="Create GitHub Workflow action for unittests",
)
@click.option(
"--frontend/--no-frontend",
"frontend",
default=None,
help="Create frappe-ui frontend",
)
@click.option("--route", default=None, help="Frontend route for SPA when creating a frontend")
@click.option("--branch", default=None, help="Git branch name for the new app")
@click.argument("app-name")
def new_app(app_name, no_git=None):
from bench.app import new_app

new_app(app_name, no_git)
def new_app(
app_name,
no_git=None,
title=None,
description=None,
publisher=None,
email=None,
license=None,
github_workflow=None,
frontend=None,
route=None,
branch=None,
):
from bench.app import new_app as create_new_app

create_new_app(
app_name,
no_git,
title=title,
description=description,
publisher=publisher,
email=email,
license=license,
github_workflow=github_workflow,
frontend=frontend,
route=route,
branch=branch,
)


@click.command(
Expand Down
147 changes: 147 additions & 0 deletions bench/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import shutil
import subprocess
import unittest
from unittest.mock import MagicMock, patch

from bench.app import App
from bench.bench import Bench
Expand Down Expand Up @@ -104,3 +105,149 @@ def test_ssh_ports(self):
self.assertEqual(
(app.use_ssh, app.org, app.repo, app.app_name), (True, "frappe", "frappe", "frappe")
)


class TestNewAppCommand(unittest.TestCase):
"""Tests for the bench new-app command options and argument construction."""

def _make_app_args(self, app, **kwargs):
"""Call new_app() with mocked run_frappe_cmd and install_app, return captured args."""
captured = {}

def mock_run_frappe_cmd(*args, **kw):
captured["args"] = list(args)

with (
patch("bench.app.bench") as mock_bench,
patch("bench.app.run_frappe_cmd", side_effect=mock_run_frappe_cmd),
patch("bench.app.install_app"),
patch("bench.app.logger"),
):
mock_bench.FRAPPE_VERSION = 15
from bench.app import new_app

new_app(app, bench_path="/tmp/fake-bench", **kwargs)

return captured.get("args", [])

def test_new_app_basic_args(self):
"""make-app receives the apps directory and app name."""
args = self._make_app_args("my_app")
self.assertEqual(args[0], "make-app")
self.assertTrue(args[1].endswith("/apps"))
self.assertEqual(args[2], "my_app")

def test_new_app_no_extra_args_by_default(self):
"""No extra args are added when no options are passed."""
args = self._make_app_args("my_app")
self.assertEqual(len(args), 3)
self.assertEqual(args[0], "make-app")
self.assertEqual(args[2], "my_app")

def test_new_app_title(self):
args = self._make_app_args("my_app", title="My App")
self.assertIn("--title", args)
self.assertEqual(args[args.index("--title") + 1], "My App")

def test_new_app_description(self):
args = self._make_app_args("my_app", description="A great app")
self.assertIn("--description", args)
self.assertEqual(args[args.index("--description") + 1], "A great app")

def test_new_app_publisher(self):
args = self._make_app_args("my_app", publisher="ACME Corp")
self.assertIn("--publisher", args)
self.assertEqual(args[args.index("--publisher") + 1], "ACME Corp")

def test_new_app_email(self):
args = self._make_app_args("my_app", email="dev@example.com")
self.assertIn("--email", args)
self.assertEqual(args[args.index("--email") + 1], "dev@example.com")

def test_new_app_license(self):
args = self._make_app_args("my_app", license="mit")
self.assertIn("--license", args)
self.assertEqual(args[args.index("--license") + 1], "mit")

def test_new_app_create_github_workflow_flag(self):
args = self._make_app_args("my_app", github_workflow=True)
self.assertIn("--github-workflow", args)

def test_new_app_create_github_workflow_false_flag(self):
args = self._make_app_args("my_app", github_workflow=False)
self.assertIn("--no-github-workflow", args)

def test_new_app_create_github_workflow_omitted_by_default(self):
args = self._make_app_args("my_app")
self.assertNotIn("--github-workflow", args)
self.assertNotIn("--no-github-workflow", args)

def test_new_app_create_frontend_flag(self):
args = self._make_app_args("my_app", frontend=True)
self.assertIn("--frontend", args)

def test_new_app_create_frontend_false_flag(self):
args = self._make_app_args("my_app", frontend=False)
self.assertIn("--no-frontend", args)

def test_new_app_frontend_route(self):
args = self._make_app_args("my_app", route="m")
self.assertIn("--route", args)
self.assertEqual(args[args.index("--route") + 1], "m")

def test_new_app_branch_name(self):
args = self._make_app_args("my_app", branch="main")
self.assertIn("--branch", args)
self.assertEqual(args[args.index("--branch") + 1], "main")

def test_new_app_all_options_combined(self):
args = self._make_app_args(
"my_app",
title="My App",
description="A great app",
publisher="ACME Corp",
email="dev@example.com",
license="mit",
github_workflow=True,
frontend=True,
route="m",
branch="main",
)
for flag, value in (
("--title", "My App"),
("--description", "A great app"),
("--publisher", "ACME Corp"),
("--email", "dev@example.com"),
("--license", "mit"),
("--route", "m"),
("--branch", "main"),
):
self.assertIn(flag, args)
self.assertEqual(args[args.index(flag) + 1], value)
self.assertIn("--github-workflow", args)
self.assertIn("--frontend", args)

def test_new_app_cli_options_defined(self):
"""The new-app click command exposes all expected options."""
from click.testing import CliRunner
from bench.commands.make import new_app as new_app_cmd

runner = CliRunner()
result = runner.invoke(new_app_cmd, ["--help"])
help_text = result.output

for option in (
"--title",
"--description",
"--publisher",
"--email",
"--license",
"--github-workflow",
"--no-github-workflow",
"--frontend",
"--no-frontend",
"--route",
"--branch",
"--no-git",
):
self.assertIn(option, help_text, f"Expected '{option}' in --help output")
Loading
Loading