Skip to content
Merged
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
5 changes: 5 additions & 0 deletions src/edge-action/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
Release History
===============

1.0.0b2
++++++
* Fix 415 Unsupported Media Type error for `get-version-code` and `swap-default` POST operations by adding required Content-Type header and empty JSON body
* Add `--output-directory` parameter to `get-version-code` command to decode and save version code as zip file

1.0.0b1
++++++
* Initial release.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def _build_arguments_schema(cls, *args, **kwargs):
max_length=50,
),
)
_args_schema.output_directory = AAZStrArg(
options=["--output-directory", "-d"],
help="Output directory to save the decoded version code as a zip file. If not specified, returns the base64-encoded content.",
required=False,
)
return cls._args_schema

def _execute_operations(self):
Expand All @@ -85,6 +90,45 @@ def post_operations(self):

def _output(self, *args, **kwargs):
result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True)

# If output directory is specified, decode and save the file
output_dir = self.ctx.args.output_directory.to_serialized_data() if self.ctx.args.output_directory else None
if output_dir:
import base64
import os
from knack.log import get_logger

logger = get_logger(__name__)

# Get the base64 encoded content
content = result.get('content')
name = result.get('name', 'version_code')

if not content:
from azure.cli.core.azclierror import ValidationError
raise ValidationError("No content returned from the API")

# Decode base64 content
try:
decoded_content = base64.b64decode(content)
except Exception as e:
from azure.cli.core.azclierror import ValidationError
raise ValidationError(f"Failed to decode base64 content: {str(e)}")
Comment on lines +112 to +116
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Using bare except Exception is too broad. Consider catching specific exception types (e.g., base64.binascii.Error for base64 decoding errors) or at minimum re-raising unexpected exceptions after logging them. This will make debugging easier and prevent masking unexpected errors.

Copilot uses AI. Check for mistakes.

# Create output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)

# Save as zip file
output_file = os.path.join(output_dir, f"{name}.zip")
try:
with open(output_file, 'wb') as f:
f.write(decoded_content)
logger.warning(f"Version code saved to: {output_file}")
return {"message": f"Version code saved to: {output_file}", "file": output_file}
except Exception as e:
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Using bare except Exception is too broad here as well. Consider catching specific file I/O exceptions (e.g., IOError, OSError, PermissionError) to provide more precise error handling.

Suggested change
except Exception as e:
except (OSError, PermissionError) as e:

Copilot uses AI. Check for mistakes.
from azure.cli.core.azclierror import FileOperationError
raise FileOperationError(f"Failed to save file: {str(e)}")

return result

class EdgeActionVersionsGetVersionCode(AAZHttpOperation):
Expand All @@ -103,6 +147,7 @@ def __call__(self, *args, **kwargs):
path_format_arguments=self.url_parameters,
)
if session.http_response.status_code in [200]:
# Operation completed synchronously with data
return self.client.build_lro_polling(
self.ctx.args.no_wait,
session,
Expand Down Expand Up @@ -165,11 +210,19 @@ def query_parameters(self):
def header_parameters(self):
parameters = {
**self.serialize_header_param(
"Accept", "application/json",
"Content-Type", "application/json",
),
**self.serialize_header_param(
"Accept", "application/json, text/plain, */*",
),
}
return parameters

@property
def content(self):
# Return empty JSON object as bytes (required by the API)
return b'{}'

def on_200(self, session):
data = self.deserialize_http_content(session)
self.ctx.set_var(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ def query_parameters(self):
}
return parameters

@property
def header_parameters(self):
parameters = {
**self.serialize_header_param(
"Content-Type", "application/json",
),
**self.serialize_header_param(
"Accept", "application/json, text/plain, */*",
),
}
return parameters

@property
def content(self):
# Return empty JSON object as bytes (required by the API)
return b'{}'

def on_204(self, session):
pass

Expand Down
Loading
Loading