Skip to content
Draft
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: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
schematics~=2.1.1
pyyaml~=6.0.2
fuzzywuzzy~=0.18.0
inflect~=5.6.2
azure-mgmt-core~=1.3.0
pluralizer~=1.2.0
lxml~=4.9.4
flask~=3.0.3
cachelib~=0.13.0
Expand Down
3 changes: 2 additions & 1 deletion src/aaz_dev/cli/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

def register_blueprints(app):
from . import az, portal, _cmds
from . import az, ps, portal, _cmds
app.register_blueprint(_cmds.bp)
app.register_blueprint(az.bp)
app.register_blueprint(ps.bp)
app.register_blueprint(portal.bp)
129 changes: 129 additions & 0 deletions src/aaz_dev/cli/api/_cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import logging
from flask import Blueprint
import sys
import subprocess
import os

from utils.config import Config

Expand Down Expand Up @@ -237,3 +239,130 @@ def _build_profile(profile_name, commands_map):
group_names = parent_group_names

return profile


@bp.cli.command("generate-powershell", short_help="Generate powershell code based on selected azure cli module.")
@click.option(
"--aaz-path", '-a',
type=click.Path(file_okay=False, dir_okay=True, writable=True, readable=True, resolve_path=True),
default=Config.AAZ_PATH,
required=not Config.AAZ_PATH,
callback=Config.validate_and_setup_aaz_path,
expose_value=False,
help="The local path of aaz repo."
)
@click.option(
"--cli-path", '-c',
type=click.Path(file_okay=False, dir_okay=True, writable=True, readable=True, resolve_path=True),
callback=Config.validate_and_setup_cli_path,
help="The local path of azure-cli repo. Only required when generate from azure-cli module."
)
@click.option(
"--cli-extension-path", '-e',
type=click.Path(file_okay=False, dir_okay=True, writable=True, readable=True, resolve_path=True),
callback=Config.validate_and_setup_cli_extension_path,
help="The local path of azure-cli-extension repo. Only required when generate from azure-cli extension."
)
@click.option(
"--powershell-path", '-p',
type=click.Path(file_okay=False, dir_okay=True, writable=True, readable=True, resolve_path=True),
required=True,
help="The local path of azure-powershell repo."
)
@click.option(
"--extension-or-module-name", '--name',
required=True,
help="Name of the module in azure-cli or the extension in azure-cli-extensions"
)
@click.option(
"--swagger-path", '-s',
type=click.Path(file_okay=False, dir_okay=True, readable=True, resolve_path=True),
default=Config.SWAGGER_PATH,
required=not Config.SWAGGER_PATH,
callback=Config.validate_and_setup_swagger_path,
expose_value=False,
help="The local path of azure-rest-api-specs repo. Official repo is https://github.com/Azure/azure-rest-api-specs"
)
def generate_powershell(extension_or_module_name, cli_path=None, cli_extension_path=None, powershell_path=None):
from cli.controller.ps_config_generator import PSAutoRestConfigurationGenerator
from cli.controller.az_module_manager import AzMainManager, AzExtensionManager
from cli.templates import get_templates

# Module path in azure-powershell repo

powershell_path = os.path.join(powershell_path, "src")
if not os.path.exists(powershell_path):
logger.error(f"Path `{powershell_path}` not exist")
sys.exit(1)

if cli_path is not None:
assert Config.CLI_PATH is not None
manager = AzMainManager()
else:
assert cli_extension_path is not None
assert Config.CLI_EXTENSION_PATH is not None
manager = AzExtensionManager()

if not manager.has_module(extension_or_module_name):
logger.error(f"Cannot find module or extension `{extension_or_module_name}`")
sys.exit(1)

# generate README.md for powershell from CLI, ex, for Oracle, README.md should be generated in src/Oracle/Oracle.Autorest/README.md in azure-powershell repo
ps_generator = PSAutoRestConfigurationGenerator(manager, extension_or_module_name)
ps_cfg = ps_generator.generate_config()

autorest_module_path = os.path.join(powershell_path, ps_cfg.module_name, f"{ps_cfg.module_name}.Autorest")
if not os.path.exists(autorest_module_path):
os.makedirs(autorest_module_path)
readme_file = os.path.join(autorest_module_path, "README.md")
if os.path.exists(readme_file):
# read until to the "### AutoRest Configuration"
with open(readme_file, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.startswith("### AutoRest Configuration"):
lines = lines[:i]
break
else:
lines = []

tmpl = get_templates()['powershell']['configuration']
data = tmpl.render(cfg=ps_cfg)
lines.append(data)
with open(readme_file, "w") as f:
f.writelines(lines)

print(f"Generated {readme_file}")
# Generate and build PowerShell module from the README.md file generated above
print("Start to generate the PowerShell module from the README.md file in " + autorest_module_path)

# Execute autorest to generate the PowerShell module
original_cwd = os.getcwd()
os.chdir(autorest_module_path)
exit_code = os.system("pwsh -Command autorest")

# Print the output of the generation
if (exit_code != 0):
print("Failed to generate the module")
os.chdir(original_cwd)
sys.exit(1)
else:
print("Code generation succeeded.")
# print(result.stdout)

os.chdir(original_cwd)
# Execute autorest to generate the PowerShell module
print("Start to build the generated PowerShell module")
result = subprocess.run(
["pwsh", "-File", 'build-module.ps1'],
capture_output=True,
text=True,
cwd=autorest_module_path
)

if (result.returncode != 0):
print("Failed to build the module, please see following output for details:")
print(result.stderr)
sys.exit(1)
else:
print("Module build succeeds, and you may run the generated module by executing the following command: `./run-module.ps1` in " + autorest_module_path)
14 changes: 14 additions & 0 deletions src/aaz_dev/cli/api/ps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from flask import Blueprint, jsonify, request, url_for

from utils.config import Config
from utils import exceptions
from cli.controller.az_module_manager import AzMainManager, AzExtensionManager
from cli.controller.portal_cli_generator import PortalCliGenerator
from cli.model.view import CLIModule
from command.controller.specs_manager import AAZSpecsManager
import logging

logging.basicConfig(level="INFO")

bp = Blueprint('ps', __name__, url_prefix='/CLI/PS')

Loading