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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,5 @@ pip.log

az_command_coverage.txt

.venv
.local
74 changes: 48 additions & 26 deletions src/azure-cli/azure/cli/command_modules/resource/_bicep.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,16 @@ def validate_bicep_target_scope(template_schema, deployment_scope):


def run_bicep_command(cli_ctx, args, auto_install=True, custom_env=None):
if _use_binary_from_path(cli_ctx):
from shutil import which

if which("bicep") is None:
raise ValidationError(
'Could not find the "bicep" executable on PATH. To install Bicep via Azure CLI, set the "bicep.use_binary_from_path" configuration to False and run "az bicep install".' # pylint: disable=line-too-long
)

bicep_version_message = _run_command("bicep", ["--version"])
system = platform.system()
bicep_executable_path = _get_bicep_executable_path(cli_ctx, system)

if bicep_executable_path and not _is_bicep_installation_path(bicep_executable_path, system):
bicep_version_message = _get_bicep_installed_version(bicep_executable_path)
_logger.debug("Using Bicep CLI from PATH. %s", bicep_version_message)

return _run_command("bicep", args, custom_env)

installation_path = _get_bicep_installation_path(platform.system())
_logger.debug("Bicep CLI installation path: %s", installation_path)
return _run_command(bicep_executable_path, args, custom_env)

installed = os.path.isfile(installation_path)
installed = os.path.isfile(bicep_executable_path)
_logger.debug("Bicep CLI installed: %s.", installed)

check_version = cli_ctx.config.getboolean("bicep", "check_version", True)
Expand All @@ -91,7 +83,7 @@ def run_bicep_command(cli_ctx, args, auto_install=True, custom_env=None):
with suppress(ClientRequestError):
# Checking upgrade should ignore connection issues.
# Users may continue using the current installed version.
installed_version = _get_bicep_installed_version(installation_path)
installed_version = _get_bicep_installed_version(bicep_executable_path)
latest_release_tag = get_bicep_latest_release_tag() if cache_expired else latest_release_tag
latest_version = _extract_version(latest_release_tag)

Expand All @@ -104,12 +96,12 @@ def run_bicep_command(cli_ctx, args, auto_install=True, custom_env=None):
if cache_expired:
_refresh_bicep_version_check_cache(latest_release_tag)

return _run_command(installation_path, args, custom_env)
return _run_command(bicep_executable_path, args, custom_env)


def ensure_bicep_installation(cli_ctx, release_tag=None, target_platform=None, stdout=True):
system = platform.system()
installation_path = _get_bicep_installation_path(system)
installation_path = _get_bicep_executable_path(cli_ctx, system)

if os.path.isfile(installation_path):
if not release_tag:
Expand All @@ -120,6 +112,9 @@ def ensure_bicep_installation(cli_ctx, release_tag=None, target_platform=None, s
if installed_version and target_version and installed_version == target_version:
return

if not _is_bicep_installation_path(installation_path, system):
installation_path = _get_bicep_installation_path(system)

installation_dir = os.path.dirname(installation_path)
if not os.path.exists(installation_dir):
os.makedirs(installation_dir)
Expand Down Expand Up @@ -156,10 +151,14 @@ def ensure_bicep_installation(cli_ctx, release_tag=None, target_platform=None, s

def remove_bicep_installation(cli_ctx):
system = platform.system()
installation_path = _get_bicep_installation_path(system)
bicep_executable_path = _get_bicep_executable_path(cli_ctx, system)

if os.path.exists(installation_path):
os.remove(installation_path)
if not _is_bicep_installation_path(bicep_executable_path, system):
raise ValidationError(
f'The bicep executable "{bicep_executable_path}" is not managed by Azure CLI. To install Bicep via Azure CLI, set the "bicep.use_binary_from_path" configuration to False and run "az bicep install".' # pylint: disable=line-too-long
)
if os.path.exists(bicep_executable_path):
os.remove(bicep_executable_path)
if os.path.exists(_bicep_version_check_file_path):
os.remove(_bicep_version_check_file_path)

Expand Down Expand Up @@ -196,10 +195,10 @@ def get_bicep_latest_release_tag():
raise ClientRequestError(f"Error while attempting to retrieve the latest Bicep version: {err}.")


def bicep_version_greater_than_or_equal_to(version):
def bicep_version_greater_than_or_equal_to(cli_ctx, version):
system = platform.system()
installation_path = _get_bicep_installation_path(system)
installed_version = _get_bicep_installed_version(installation_path)
bicep_executable_path = _get_bicep_executable_path(cli_ctx, system)
installed_version = _get_bicep_installed_version(bicep_executable_path)
parsed_version = semver.VersionInfo.parse(version)
return installed_version >= parsed_version

Expand Down Expand Up @@ -282,11 +281,34 @@ def _get_bicep_download_url(system, release_tag, target_platform=None):
return download_url.format("bicep-linux-musl-x64")
return download_url.format("bicep-linux-x64")
if system == "Darwin":
return download_url.format("bicep-osx-x64")
return download_url.format("bicep-osx-arm64") if platform.processor() == 'arm' else download_url.format("bicep-osx-x64")

raise ValidationError(f'The platform "{system}" is not supported.')


def _get_bicep_executable_path(cli_ctx, system):
if _use_binary_from_path(cli_ctx):
from shutil import which

bicep_executable_path = which("bicep")

if bicep_executable_path is None:
raise ValidationError(
'Could not find the "bicep" executable on PATH. To install Bicep via Azure CLI, set the "bicep.use_binary_from_path" configuration to False and run "az bicep install".' # pylint: disable=line-too-long
)

return bicep_executable_path

bicep_executable_path = _get_bicep_installation_path(system)
_logger.debug("Bicep CLI installation path: %s", bicep_executable_path)

return bicep_executable_path


def _is_bicep_installation_path(bicep_executable_path, system):
return bicep_executable_path == _get_bicep_installation_path(system)


def _get_bicep_installation_path(system):
if system == "Windows":
return os.path.join(_bicep_installation_dir, "bicep.exe")
Expand All @@ -301,9 +323,9 @@ def _extract_version(text):
return semver.VersionInfo.parse(semver_match.group(0)) if semver_match else None


def _run_command(bicep_installation_path, args, custom_env=None):
def _run_command(bicep_executable_path, args, custom_env=None):
process = subprocess.run(
[rf"{bicep_installation_path}"] + args,
[rf"{bicep_executable_path}"] + args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=custom_env)
Expand Down
22 changes: 11 additions & 11 deletions src/azure-cli/azure/cli/command_modules/resource/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,11 +1062,11 @@ def _parse_bicepparam_file(cmd, template_file, parameters):
ensure_bicep_installation(cmd.cli_ctx, stdout=False)

minimum_supported_version_bicepparam_compilation = "0.14.85"
if not bicep_version_greater_than_or_equal_to(minimum_supported_version_bicepparam_compilation):
if not bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version_bicepparam_compilation):
raise ArgumentUsageError(f"Unable to compile .bicepparam file with the current version of Bicep CLI. Please upgrade Bicep CLI to {minimum_supported_version_bicepparam_compilation} or later.")

minimum_supported_version_supplemental_param = "0.22.6"
if len(parameters) > 1 and not bicep_version_greater_than_or_equal_to(minimum_supported_version_supplemental_param):
if len(parameters) > 1 and not bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version_supplemental_param):
raise ArgumentUsageError(f"Current version of Bicep CLI does not support supplemental parameters with .bicepparam file. Please upgrade Bicep CLI to {minimum_supported_version_supplemental_param} or later.")

bicepparam_file = _get_bicepparam_file_path(parameters)
Expand Down Expand Up @@ -4462,7 +4462,7 @@ def format_bicep_file(cmd, file, stdout=None, outdir=None, outfile=None, newline
ensure_bicep_installation(cmd.cli_ctx, stdout=False)

minimum_supported_version = "0.12.1"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["format", file]
if outdir:
args += ["--outdir", outdir]
Expand Down Expand Up @@ -4491,23 +4491,23 @@ def publish_bicep_file(cmd, file, target, documentationUri=None, with_source=Non
ensure_bicep_installation(cmd.cli_ctx)

minimum_supported_version = "0.4.1008"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["publish", file, "--target", target]
if documentationUri:
minimum_supported_version_for_documentationUri_parameter = "0.14.46"
if bicep_version_greater_than_or_equal_to(minimum_supported_version_for_documentationUri_parameter):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version_for_documentationUri_parameter):
args += ["--documentationUri", documentationUri]
else:
logger.error("az bicep publish with --documentationUri/-d parameter could not be executed with the current version of Bicep CLI. Please upgrade Bicep CLI to v%s or later.", minimum_supported_version_for_documentationUri_parameter)
if with_source:
minimum_supported_version_for_publish_with_source = "0.23.1"
if bicep_version_greater_than_or_equal_to(minimum_supported_version_for_publish_with_source):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version_for_publish_with_source):
args += ["--with-source"]
else:
logger.error("az bicep publish with --with-source/-s parameter could not be executed with the current version of Bicep CLI. Please upgrade Bicep CLI to v%s or later.", minimum_supported_version_for_publish_with_source)
if force:
minimum_supported_version_for_publish_force = "0.17.1"
if bicep_version_greater_than_or_equal_to(minimum_supported_version_for_publish_force):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version_for_publish_force):
args += ["--force"]
else:
logger.error("az bicep publish with --force parameter could not be executed with the current version of Bicep CLI. Please upgrade Bicep CLI to v%s or later.", minimum_supported_version_for_publish_force)
Expand All @@ -4520,7 +4520,7 @@ def restore_bicep_file(cmd, file, force=None):
ensure_bicep_installation(cmd.cli_ctx)

minimum_supported_version = "0.4.1008"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["restore", file]
if force:
args += ["--force"]
Expand All @@ -4540,7 +4540,7 @@ def decompileparams_bicep_file(cmd, file, bicep_file=None, outdir=None, outfile=
ensure_bicep_installation(cmd.cli_ctx)

minimum_supported_version = "0.18.4"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["decompile-params", file]
if bicep_file:
args += ["--bicep-file", bicep_file]
Expand Down Expand Up @@ -4571,7 +4571,7 @@ def generate_params_file(cmd, file, no_restore=None, outdir=None, outfile=None,
ensure_bicep_installation(cmd.cli_ctx, stdout=False)

minimum_supported_version = "0.7.4"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["generate-params", file]
if no_restore:
args += ["--no-restore"]
Expand All @@ -4598,7 +4598,7 @@ def lint_bicep_file(cmd, file, no_restore=None, diagnostics_format=None):
ensure_bicep_installation(cmd.cli_ctx, stdout=False)

minimum_supported_version = "0.7.4"
if bicep_version_greater_than_or_equal_to(minimum_supported_version):
if bicep_version_greater_than_or_equal_to(cmd.cli_ctx, minimum_supported_version):
args = ["lint", file]
if no_restore:
args += ["--no-restore"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ def test_format_bicep_file(self, mock_print, mock_run_bicep_command, mock_bicep_
format_bicep_file(cmd, file_path, stdout=stdout)

# Assert.
mock_bicep_version_greater_than_or_equal_to.assert_called_once_with("0.12.1")
mock_bicep_version_greater_than_or_equal_to.assert_called_once_with(cmd.cli_ctx, "0.12.1")
mock_run_bicep_command.assert_called_once_with(cmd.cli_ctx, ["format", file_path, "--stdout"])

class TestPublishWithSource(unittest.TestCase):
Expand All @@ -688,7 +688,7 @@ def test_publish_withsource(self, mock_run_bicep_command, mock_bicep_version_gre

# Assert.
mock_bicep_version_greater_than_or_equal_to.assert_has_calls([
mock.call("0.4.1008"), # Min version for 'bicep publish'
mock.call(cmd.cli_ctx, "0.4.1008"), # Min version for 'bicep publish'
])
mock_run_bicep_command.assert_called_once_with(cmd.cli_ctx, ['publish', file_path, '--target', 'br:contoso.azurecr.io/bicep/mymodule:v1'])

Expand All @@ -704,8 +704,8 @@ def test_publish_without_source(self, mock_run_bicep_command, mock_bicep_version

# Assert.
mock_bicep_version_greater_than_or_equal_to.assert_has_calls([
mock.call("0.4.1008"), # Min version for 'bicep publish'
mock.call("0.23.1") # Min version for 'bicep publish --with-source'
mock.call(cmd.cli_ctx, "0.4.1008"), # Min version for 'bicep publish'
mock.call(cmd.cli_ctx, "0.23.1") # Min version for 'bicep publish --with-source'
])
mock_run_bicep_command.assert_called_once_with(cmd.cli_ctx, ['publish', file_path, '--target', 'br:contoso.azurecr.io/bicep/mymodule:v1', '--with-source'])

Expand Down
Loading