2727
2828from datacustomcode import AuthType
2929from datacustomcode .auth import configure_oauth_tokens
30+ from datacustomcode .constants import (
31+ CONFIG_FILE ,
32+ ENTRYPOINT_FILE ,
33+ PAYLOAD_DIR ,
34+ TEST_FILE ,
35+ TESTS_DIR ,
36+ )
3037from datacustomcode .scan import find_base_directory , get_package_type
3138
3239
@@ -74,6 +81,30 @@ def _configure_client_credentials(
7481 )
7582
7683
84+ def _generate_function_test_file (entrypoint_path : str ) -> Optional [str ]:
85+ """Generate test.json file for a function.
86+
87+ Args:
88+ entrypoint_path: Path to the function's entrypoint.py
89+
90+ Returns:
91+ Path to generated test.json, or None if generation failed
92+ """
93+ from datacustomcode .function_utils import generate_test_json
94+
95+ tests_dir = os .path .join (os .path .dirname (entrypoint_path ), TESTS_DIR )
96+ os .makedirs (tests_dir , exist_ok = True )
97+ test_json_path = os .path .join (tests_dir , TEST_FILE )
98+
99+ try :
100+ generate_test_json (entrypoint_path , test_json_path )
101+ logger .debug (f"Generated test JSON at { test_json_path } " )
102+ return test_json_path
103+ except Exception as e :
104+ logger .warning (f"Could not generate test.json: { e } " )
105+ return None
106+
107+
77108@cli .command ()
78109@click .option ("--profile" , default = "default" , help = "Credential profile name" )
79110@click .option (
@@ -162,7 +193,6 @@ def zip(path: str, network: str):
162193
163194 Choose based on your workload requirements.""" ,
164195)
165- @click .option ("--function-invoke-opt" )
166196@click .option (
167197 "--sf-cli-org" ,
168198 default = None ,
@@ -176,13 +206,14 @@ def deploy(
176206 cpu_size : str ,
177207 profile : str ,
178208 network : str ,
179- function_invoke_opt : str ,
180209 sf_cli_org : Optional [str ],
181210):
211+ from datacustomcode .constants import USE_IN_FEATURE_MAPPING_FOR_CONNECT_API
182212 from datacustomcode .deploy import (
183213 COMPUTE_TYPES ,
184214 CodeExtensionMetadata ,
185215 deploy_full ,
216+ infer_use_in_feature ,
186217 )
187218 from datacustomcode .token_provider import (
188219 CredentialsTokenProvider ,
@@ -211,15 +242,24 @@ def deploy(
211242 )
212243
213244 if package_type == "function" :
214- if not function_invoke_opt :
245+ # Infer use_in_feature from function signature
246+ entrypoint_path = os .path .join (path , ENTRYPOINT_FILE )
247+ use_in_feature = infer_use_in_feature (entrypoint_path )
248+ if use_in_feature :
249+ logger .info (f"Inferred use_in_feature: { use_in_feature } " )
250+ else :
215251 click .secho (
216- "Error: Function invoke options are required for function package type" ,
252+ "Error: Could not infer function invoke options. "
253+ "Please provide --use-in-feature" ,
217254 fg = "red" ,
218255 )
219256 raise click .Abort ()
220- else :
221- function_invoke_options = function_invoke_opt .split ("," )
222- metadata .functionInvokeOptions = function_invoke_options
257+
258+ # Map user-provided feature names to API names
259+ mapped_feature = USE_IN_FEATURE_MAPPING_FOR_CONNECT_API .get (
260+ use_in_feature , use_in_feature
261+ )
262+ metadata .functionInvokeOptions = [mapped_feature ]
223263
224264 try :
225265 if sf_cli_org :
@@ -238,7 +278,12 @@ def deploy(
238278@click .option (
239279 "--code-type" , default = "script" , type = click .Choice (["script" , "function" ])
240280)
241- def init (directory : str , code_type : str ):
281+ @click .option (
282+ "--use-in-feature" ,
283+ default = "SearchIndexChunking" ,
284+ help = "Feature where this function will be used (only applicable for function)." ,
285+ )
286+ def init (directory : str , code_type : str , use_in_feature : Optional [str ]):
242287 from datacustomcode .scan import (
243288 dc_config_json_from_file ,
244289 update_config ,
@@ -250,9 +295,9 @@ def init(directory: str, code_type: str):
250295 if code_type == "script" :
251296 copy_script_template (directory )
252297 elif code_type == "function" :
253- copy_function_template (directory )
254- entrypoint_path = os .path .join (directory , "payload" , "entrypoint.py" )
255- config_location = os .path .join (os .path .dirname (entrypoint_path ), "config.json" )
298+ copy_function_template (directory , use_in_feature )
299+ entrypoint_path = os .path .join (directory , PAYLOAD_DIR , ENTRYPOINT_FILE )
300+ config_location = os .path .join (os .path .dirname (entrypoint_path ), CONFIG_FILE )
256301
257302 # Write package type to SDK-specific config
258303 sdk_config = {"type" : code_type }
@@ -265,6 +310,7 @@ def init(directory: str, code_type: str):
265310 updated_config_json = update_config (entrypoint_path )
266311 with open (config_location , "w" ) as f :
267312 json .dump (updated_config_json , f , indent = 2 )
313+
268314 click .echo (
269315 "Start developing by updating the code in "
270316 + click .style (entrypoint_path , fg = "blue" , bold = True )
@@ -275,6 +321,24 @@ def init(directory: str, code_type: str):
275321 + " to automatically update config.json when you make changes to your code"
276322 )
277323
324+ # Generate test.json for functions
325+ if code_type == "function" :
326+ test_json_path = _generate_function_test_file (entrypoint_path )
327+ if test_json_path :
328+ click .echo (
329+ "Generated test file at "
330+ + click .style (test_json_path , fg = "blue" , bold = True )
331+ )
332+ click .echo (
333+ "Test your function locally with "
334+ + click .style (
335+ f"datacustomcode run { entrypoint_path } "
336+ f"--test-with { test_json_path } " ,
337+ fg = "blue" ,
338+ bold = True ,
339+ )
340+ )
341+
278342
279343@cli .command ()
280344@click .argument ("filename" )
@@ -286,7 +350,7 @@ def init(directory: str, code_type: str):
286350def scan (filename : str , config : str , dry_run : bool , no_requirements : bool ):
287351 from datacustomcode .scan import update_config , write_requirements_file
288352
289- config_location = config or os .path .join (os .path .dirname (filename ), "config.json" )
353+ config_location = config or os .path .join (os .path .dirname (filename ), CONFIG_FILE )
290354 click .echo (
291355 "Dumping scan results to config file: "
292356 + click .style (config_location , fg = "blue" , bold = True )
@@ -312,6 +376,12 @@ def scan(filename: str, config: str, dry_run: bool, no_requirements: bool):
312376@click .option ("--config-file" , default = None )
313377@click .option ("--dependencies" , default = [], multiple = True )
314378@click .option ("--profile" , default = "default" )
379+ @click .option (
380+ "--test-with" ,
381+ default = None ,
382+ type = click .Path (exists = True ),
383+ help = "Path to test JSON file for function testing" ,
384+ )
315385@click .option (
316386 "--sf-cli-org" ,
317387 default = None ,
@@ -322,10 +392,16 @@ def run(
322392 config_file : Union [str , None ],
323393 dependencies : List [str ],
324394 profile : str ,
395+ test_with : Optional [str ],
325396 sf_cli_org : Optional [str ],
326397):
327398 from datacustomcode .run import run_entrypoint
328399
329400 run_entrypoint (
330- entrypoint , config_file , dependencies , profile , sf_cli_org = sf_cli_org
401+ entrypoint ,
402+ config_file ,
403+ dependencies ,
404+ profile ,
405+ test_file = test_with ,
406+ sf_cli_org = sf_cli_org ,
331407 )
0 commit comments