Skip to content

Commit b8a0163

Browse files
committed
Merge remote-tracking branch 'origin/main' into deploy-dmo-package
2 parents 89bcb1e + fb05a4f commit b8a0163

5 files changed

Lines changed: 72 additions & 52 deletions

File tree

src/datacustomcode/cli.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,7 @@ def zip(path: str, network: str):
198198
default=None,
199199
help="SF CLI org alias or username. Fetches credentials via `sf org display`.",
200200
)
201-
@click.option(
202-
"--use-in-feature",
203-
default="SearchIndexChunking",
204-
help="Feature where this function will be used.",
205-
)
201+
@click.option("--use-in-feature", default=None, hidden=True, deprecated=True)
206202
def deploy(
207203
path: str,
208204
name: str,
@@ -248,17 +244,20 @@ def deploy(
248244
)
249245

250246
if package_type == "function":
251-
# Try to infer use_in_feature from function signature; fall back to
252-
# the explicit flag value (defaults to SearchIndexChunking)
247+
# Infer use_in_feature from function signature
253248
entrypoint_path = os.path.join(path, ENTRYPOINT_FILE)
254-
inferred = infer_use_in_feature(entrypoint_path)
255-
if inferred:
256-
use_in_feature = inferred
249+
use_in_feature = infer_use_in_feature(entrypoint_path)
250+
if use_in_feature:
257251
logger.info(f"Inferred use_in_feature: {use_in_feature}")
258252
else:
259-
logger.info(f"Using use_in_feature: {use_in_feature}")
253+
click.secho(
254+
"Error: Function signature does not match a supported type. "
255+
"Use SearchIndexChunkingV1Request and "
256+
"SearchIndexChunkingV1Response in function signature.",
257+
fg="red",
258+
)
259+
raise click.Abort()
260260

261-
assert use_in_feature is not None
262261
# Map feature names to Connect API names
263262
mapped_feature = USE_IN_FEATURE_MAPPING_FOR_CONNECT_API.get(
264263
use_in_feature, use_in_feature

src/datacustomcode/token_provider.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -140,37 +140,44 @@ def _run_sf_command(args: list[str], description: str) -> dict:
140140
)
141141
return dict(data)
142142

143-
# Get instanceUrl from sf org display
143+
# Get org info from sf org display
144144
display_data = _run_sf_command(
145145
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
146146
"sf org display",
147147
)
148-
instance_url = display_data.get("result", {}).get("instanceUrl")
148+
result_data = display_data.get("result", {})
149+
instance_url = result_data.get("instanceUrl")
149150
if not instance_url:
150151
raise RuntimeError(
151152
f"'sf org display' did not return an instance URL "
152153
f"for org '{self.sf_cli_org}'"
153154
)
154155

155-
# Get access token via show-access-token (newer SF CLI versions
156-
# redact the token in sf org display)
157-
token_data = _run_sf_command(
158-
[
159-
"sf",
160-
"org",
161-
"auth",
162-
"show-access-token",
163-
"--target-org",
164-
self.sf_cli_org,
165-
"--json",
166-
],
167-
"sf org auth show-access-token",
168-
)
169-
access_token = token_data.get("result", {}).get("accessToken")
156+
# Try show-access-token first (SF CLI >= 2.136.6); fall back to the
157+
# token from sf org display (older CLIs don't redact it).
158+
access_token = None
159+
try:
160+
token_data = _run_sf_command(
161+
[
162+
"sf",
163+
"org",
164+
"auth",
165+
"show-access-token",
166+
"--target-org",
167+
self.sf_cli_org,
168+
"--json",
169+
],
170+
"sf org auth show-access-token",
171+
)
172+
access_token = token_data.get("result", {}).get("accessToken")
173+
except RuntimeError:
174+
# Command not available on older SF CLI versions
175+
access_token = result_data.get("accessToken")
176+
170177
if not access_token:
171178
raise RuntimeError(
172-
f"'sf org auth show-access-token' did not return an access token "
173-
f"for org '{self.sf_cli_org}'"
179+
f"Could not obtain an access token for org '{self.sf_cli_org}'. "
180+
f"Upgrade SF CLI to 2.136.6+ or ensure the org is authenticated."
174181
)
175182

176183
return AccessTokenResponse(access_token=access_token, instance_url=instance_url)

tests/io/reader/test_sf_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def test_missing_access_token_raises_runtime_error(self, reader):
175175
token_result = MagicMock()
176176
token_result.stdout = json.dumps({"status": 0, "result": {}})
177177
with patch("subprocess.run", side_effect=[display_result, token_result]):
178-
with pytest.raises(RuntimeError, match="did not return an access token"):
178+
with pytest.raises(RuntimeError, match="Could not obtain an access token"):
179179
reader._get_token()
180180

181181
def test_missing_instance_url_raises_runtime_error(self, reader):

tests/test_sf_cli_contract.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -188,26 +188,6 @@ def test_accepts_network_flag(
188188
result = runner.invoke(deploy, [*self._BASE_ARGS, "--network", "custom"])
189189
assert result.exit_code != 2, result.output
190190

191-
@patch("datacustomcode.token_provider.SFCLITokenProvider")
192-
@patch("datacustomcode.deploy.deploy_full")
193-
@patch("datacustomcode.cli.find_base_directory")
194-
@patch("datacustomcode.cli.get_package_type")
195-
def test_accepts_use_in_feature_flag(
196-
self, mock_pkg_type, mock_find_base, mock_deploy_full, mock_sf_cli_provider
197-
):
198-
mock_find_base.return_value = "payload"
199-
mock_pkg_type.return_value = "function"
200-
mock_provider_instance = mock_sf_cli_provider.return_value
201-
mock_provider_instance.get_token.return_value = AccessTokenResponse(
202-
access_token="tok", instance_url="https://example.com"
203-
)
204-
runner = CliRunner()
205-
result = runner.invoke(
206-
deploy,
207-
[*self._BASE_ARGS, "--use-in-feature", "SearchIndexChunking"],
208-
)
209-
assert result.exit_code != 2, result.output
210-
211191

212192
class TestRunArgContract:
213193
"""

tests/test_token_provider.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,40 @@ def test_successful_token_retrieval(self):
197197
assert "org" in display_call[0][0] and "display" in display_call[0][0]
198198
assert "show-access-token" in token_call[0][0]
199199

200+
def test_fallback_to_display_token_on_older_cli(self):
201+
"""Test fallback to sf org display token when show-access-token unavailable."""
202+
import json
203+
import subprocess
204+
205+
provider = SFCLITokenProvider("test_org")
206+
207+
display_output = json.dumps(
208+
{
209+
"status": 0,
210+
"result": {
211+
"accessToken": "display_token",
212+
"instanceUrl": "https://cli.salesforce.com",
213+
},
214+
}
215+
)
216+
217+
def side_effect(*args, **kwargs):
218+
cmd = args[0]
219+
if "show-access-token" in cmd:
220+
raise subprocess.CalledProcessError(
221+
returncode=2, cmd="sf", stderr="not a sf command"
222+
)
223+
mock = MagicMock()
224+
mock.stdout = display_output
225+
return mock
226+
227+
with patch("subprocess.run", side_effect=side_effect):
228+
result = provider.get_token()
229+
230+
assert isinstance(result, AccessTokenResponse)
231+
assert result.access_token == "display_token"
232+
assert result.instance_url == "https://cli.salesforce.com"
233+
200234
def test_sf_command_not_found(self):
201235
"""Test that FileNotFoundError is wrapped in RuntimeError."""
202236
provider = SFCLITokenProvider("test_org")

0 commit comments

Comments
 (0)