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
6 changes: 6 additions & 0 deletions .changes/unreleased/added-20260210-123451.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: added
body: Update import command interface to support ci/cd flow
time: 2026-02-10T12:34:51.783593963Z
custom:
Author: aviatco
AuthorLink: https://github.com/aviatco
4 changes: 3 additions & 1 deletion src/fabric_cli/commands/fs/fab_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ def get_command(args: Namespace) -> None:
@set_command_context()
def import_command(args: Namespace) -> None:
context = handle_context.get_command_context(args.path, raise_error=False)
context.check_command_support(Command.FS_IMPORT)
if hasattr(args, 'path') and args.path:
# In CICD flow - no path elements involved, skip command support check
context.check_command_support(Command.FS_IMPORT)
fs_import.exec_command(args, context)


Expand Down
17 changes: 13 additions & 4 deletions src/fabric_cli/commands/fs/fab_fs_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@

from argparse import Namespace

from fabric_cli.commands.fs.impor import fab_fs_import_item as import_item
from fabric_cli.commands.fs.impor import fab_fs_import_direct_api as import_direct_api
from fabric_cli.commands.fs.impor import fab_fs_import_cicd as import_cicd
from fabric_cli.core.hiearchy.fab_hiearchy import FabricElement, Item
from fabric_cli.utils import fab_util as utils


def exec_command(args: Namespace, context: FabricElement) -> None:
args.input = utils.process_nargs(args.input)
if hasattr(args, 'validate_args'):
args.validate_args(args)

if isinstance(context, Item):
import_item.import_single_item(context, args)
# Direct API flow
if args.path and args.input:
args.input = utils.process_nargs(args.input)
if isinstance(context, Item):
import_direct_api.import_single_item(context, args)

# CI/CD flow
elif args.config_file:
import_cicd.import_with_config_file(args)
4 changes: 4 additions & 0 deletions src/fabric_cli/commands/fs/impor/fab_fs_import_cicd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from argparse import Namespace

def import_with_config_file(args: Namespace) -> None:
"""Import using config file and environment parameters - delegates to CICD library."""
1 change: 1 addition & 0 deletions src/fabric_cli/core/fab_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@
ERROR_UNIVERSAL_SECURITY_DISABLED = "UniversalSecurityDisabled"
ERROR_SPN_AUTH_MISSING = "ServicePrincipalAuthMissing"
ERROR_JOB_FAILED = "JobFailed"
ERROR_IMPORT_VALIDATION = "ImportValidationError"

# Exit codes
EXIT_CODE_SUCCESS = 0
Expand Down
6 changes: 4 additions & 2 deletions src/fabric_cli/core/hiearchy/fab_base_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ def check_command_support(self, commmand: Command) -> bool:
is_supported = self.item_type in cmd.get_supported_items(commmand)
if is_unsupported:
raise FabricCLIError(
ErrorMessages.Hierarchy.command_not_supported(commmand.value),
ErrorMessages.Hierarchy.command_not_supported(
commmand.value, str(self.item_type)),
fab_constant.ERROR_UNSUPPORTED_COMMAND,
)
if is_supported:
Expand All @@ -109,7 +110,8 @@ def check_command_support(self, commmand: Command) -> bool:
super().check_command_support(commmand)
except FabricCLIError:
raise FabricCLIError(
ErrorMessages.Hierarchy.command_not_supported(commmand.value),
ErrorMessages.Hierarchy.command_not_supported(
commmand.value, str(self.item_type)),
fab_constant.ERROR_UNSUPPORTED_COMMAND,
)
return True
3 changes: 2 additions & 1 deletion src/fabric_cli/core/hiearchy/fab_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def check_command_support(self, commmand: Command) -> bool:
is_supported = self.type in cmd.get_supported_elements(commmand)
if not is_supported:
raise FabricCLIError(
ErrorMessages.Hierarchy.command_not_supported(commmand.value),
ErrorMessages.Hierarchy.command_not_supported(
commmand.value, self.type.value),
fab_constant.ERROR_UNSUPPORTED_COMMAND,
)
return True
Expand Down
12 changes: 12 additions & 0 deletions src/fabric_cli/errors/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ def gateway_property_not_supported_for_type(
property_name: str, gateway_type: str
) -> str:
return f"Setting '{property_name}' is not supported for Gateway type '{gateway_type}'"

@staticmethod
def import_required_param_missing(param_display_name: str, flow_name: str, flow_syntax: str) -> str:
return f"{param_display_name} is required for {flow_name} flow.\nCorrect syntax: {flow_syntax}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure it actually break into a new line.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is - I test it.
but I see not the string is wrong - I wanted it without the "correct" - will remove it


@staticmethod
def import_mixed_flows_error() -> str:
return "cannot mix Direct API flow parameters (path, -i, --format) with CICD flow parameters (--config-file, --env, -P)"

@staticmethod
def import_no_flow_specified_error() -> str:
return "either -i/--input (with path) or --config-file (with --env) must be specified"

@staticmethod
def query_not_supported_for_set(query: str) -> str:
Expand Down
4 changes: 2 additions & 2 deletions src/fabric_cli/errors/hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def invalid_type(name: str) -> str:
return f"Invalid type '{name}'"

@staticmethod
def command_not_supported(command: str) -> str:
return f"not supported for command '{command}'"
def command_not_supported(command: str, item_type: str) -> str:
return f"Command '{command}' is not supported for item type '{item_type}'"

@staticmethod
def item_type_not_valid(item_type: str) -> str:
Expand Down
55 changes: 47 additions & 8 deletions src/fabric_cli/parsers/fab_fs_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,14 @@ def register_get_parser(subparsers: _SubParsersAction) -> None:
# Command for 'import'
def register_import_parser(subparsers: _SubParsersAction) -> None:
import_examples = [
"# import a notebook from a local directory",
"# import a notebook from a local directory (Direct API call flow)",
"$ import imp.Notebook -i /tmp/nb1.Notebook\n",
"# import a pipeline from a local directory",
"$ import pip.Notebook -i /tmp/pip1.DataPipeline -f",
"# import a pipeline from a local directory (Direct API call flow)",
"$ import pip.Notebook -i /tmp/pip1.DataPipeline -f\n",
"# import using config file and environment (CI/CD flow - no path needed)",
"$ import --config-file config.yml --env dev\n",
"# import with config file, environment, and CICD parameters (CI/CD flow)",
"$ import --config-file config.yml --env prod -P '[{\"param1\":\"value1\"}]' -f",
]

import_parser = subparsers.add_parser(
Expand All @@ -402,27 +406,62 @@ def register_import_parser(subparsers: _SubParsersAction) -> None:
fab_examples=import_examples,
fab_learnmore=["_"],
)

# Create mutually exclusive groups for the two import flows
flow_group = import_parser.add_mutually_exclusive_group(required=True)

#CI/CD flow parameters
flow_group.add_argument(
"--config-file",
metavar="PATH",
type=str,
help="Path to local config file. When used, --env is required. Only used in CI/CD flow.",
)

import_parser.add_argument(
"path", nargs="+", type=str, help="Directory path (item name to import)"
"--env",
metavar="ENV_NAME",
type=str,
help="Environment name as defined in config file. Required when using --config-file. Only used in CI/CD flow.",
)

import_parser.add_argument(
"-P",
"--params",
metavar="JSON",
type=str,
help="Optional parameters for CICD in JSON format (e.g., '[{\"p1\":\"v1\",\"p2\":\"v2\"}]'). Only used in CI/CD flow.",
)

# Direct API flow parameters
flow_group.add_argument(
"path",
nargs="*", # Changed from "+" to "*" to make it optional
type=str,
help="Directory path (item name to import). When used, -i/--input is required. Only used in Direct API call flow."
)

import_parser.add_argument(
"-i",
"--input",
nargs="+",
required=True,
help="Input path for import",
help="Input path for import. When used, path argument is required. Only used in Direct API call flow.",
)

import_parser.add_argument(
"--format",
metavar="",
help="Input format. Optional, supported for notebooks (.ipynb, .py)",
help="Input format for current flow only. Optional, supported for notebooks (.ipynb, .py). Only used in Direct API call flow.",
)

import_parser.add_argument(
"-f", "--force", required=False, action="store_true", help="Force. Optional"
)

from fabric_cli.parsers.fab_parser_validators import validate_import_args

import_parser.set_defaults(func=fs.import_command, validate_args=lambda args: validate_import_args(args))
import_parser.usage = f"{utils_error_parser.get_usage_prog(import_parser)}"
import_parser.set_defaults(func=fs.import_command)


# Command for 'set'
Expand Down
46 changes: 45 additions & 1 deletion src/fabric_cli/parsers/fab_parser_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
# Licensed under the MIT License.

import argparse
from fabric_cli.core import fab_constant
from fabric_cli.core.fab_exceptions import FabricCLIError
from fabric_cli.errors import ErrorMessages


def validate_positive_int(value):
Expand All @@ -12,4 +15,45 @@ def validate_positive_int(value):
raise argparse.ArgumentTypeError(f"'{value}' must be a positive integer")
return ivalue
except ValueError:
raise argparse.ArgumentTypeError(f"'{value}' is not a valid integer")
raise argparse.ArgumentTypeError(f"'{value}' is not a valid integer")


def validate_import_args(args):
"""
Validate import command arguments based on two distinct flows:

Flow 1 (Direct API): path + input (--format optional)
Flow 2 (CICD): config-file + env (-P optional)
"""

def _check_required_param(args, attr_name, param_display_name, flow_name, flow_syntax):
"""Check if required parameter is provided for the specified flow."""
param_value = getattr(args, attr_name, None)
if not param_value:
error_message = ErrorMessages.Common.import_required_param_missing(param_display_name, flow_name, flow_syntax)
raise FabricCLIError(error_message, fab_constant.ERROR_IMPORT_VALIDATION)

is_direct_api_flow = args.path or args.input or args.format
is_cicd_flow = args.config_file or args.env or args.params

if is_direct_api_flow and is_cicd_flow:
error_message = ErrorMessages.Common.import_mixed_flows_error()
raise FabricCLIError(error_message, fab_constant.ERROR_IMPORT_VALIDATION)

if is_direct_api_flow:
flow_syntax = "fab import <path> -i <input_path> [--format <format>]"
_check_required_param(args, 'path', 'path', 'Direct API', flow_syntax)
_check_required_param(args, 'input', '-i/--input',
'Direct API', flow_syntax)

elif is_cicd_flow:
flow_syntax = "fab import --config-file <config_path> --env <env_name> [-P <params>]"
_check_required_param(args, 'config_file',
'--config-file', 'CICD', flow_syntax)
_check_required_param(args, 'env', '--env', 'CICD', flow_syntax)

else:
error_message = ErrorMessages.Common.import_no_flow_specified_error()
raise FabricCLIError(error_message, fab_constant.ERROR_IMPORT_VALIDATION)

return args
Loading