The document provides instructions and guidelines on how to author command modules. For other help, please see the following:
On-boarding Guide:
https://github.com/Azure/azure-cli/blob/dev/doc/onboarding_guide.md
Module Authoring:
You are here!
Command Authoring:
https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md
Command Guidelines:
https://github.com/Azure/azure-cli/blob/dev/doc/command_guidelines.md
Help Authoring:
https://github.com/Azure/azure-cli/blob/dev/doc/authoring_help.md
Test Authoring:
https://github.com/Azure/azure-cli/blob/dev/doc/authoring_tests.md
Generating Documentation:
https://review.docs.microsoft.com/help/onboard/admin/reference/cli/azure-cli-ci?branch=master#documenting-a-new-azure-cli-module
Create you dev environment if you haven't already. This is how to do that.
Clone the repo, enter the repo directory then create your virtual environment.
For example:
git clone https://github.com/Azure/azure-cli.git
cd azure-cli
virtualenv env
source env/bin/activate
python scripts/dev_setup.py
After this, you should be able to run the CLI with az
.
Now, install your command module into the environment with pip in editable mode.
Where <path_to_your_command_module>
is the path to the directory containing your setup.py
file.
pip install -e <path_to_your_command_module>
If installation was successful, you should be able to run pip list
and see your command module.
$ pip list
...
azure-cli-example (0.0.1, /Users/myuser/Repos/azure-cli-example)
...
Also, you can run az
and if your command module contributes any commands, they should appear.
If your commands aren't showing with az
, use az --debug
to help debug. There could have been an exception
thrown whilst attempting to load your module.
Currently, all command modules should start with azure-cli-
.
When the CLI loads, it search for packages installed that start with that prefix.
The example_module_template
directory gives an example command module with other useful examples.
Command modules should have the following structure:
.
|-- README.rst
|-- azure
| |-- __init__.py
| `-- cli
| |-- __init__.py
| `-- command_modules
| |-- __init__.py
| `-- <MODULE_NAME>
| `-- __init__.py
`-- setup.py
`-- HISTORY.rst
Create an __init__.py for your module
In the __init__ file, you will declare a command loader class that inherits from AzCommandsLoader. You will typically override the following three methods:
__init__
- Useful for setting metadata that applies to the entire module. For performance reasons, no heavy processing should be done here. See command authoring for more info.load_commands_table
- Register command groups and commands here. It is common to store the implementation of this method in a file namedcommands.py
but for very small modules this may not be necessary. See command authoring for more info.load_arguments
- Apply metadata to your command arguments. It is common to store the implementation of this method in a file named_params.py
but for very small modules this may not be necessary. See command authoring for more info.
init.py
from azure.cli.core import AzCommandsLoader
from azure.cli.command_modules.mymod._help import helps # pylint: disable=unused-import
class MyModCommandsLoader(AzCommandsLoader):
def load_command_table(self, args):
from azure.cli.core.commands import CliCommandType
mymod_custom = CliCommandType(
operations_tmpl='azure.mgmt.mymod.operations#MyModOperations.{}',
)
with self.command_group('myfoo', mymod_custom) as g:
g.command('create', 'create_myfoo')
COMMAND_LOADER_CLS = MyModCommandsLoader
custom.py
def create_myfoo(cmd, myfoo_name, resource_group_name, location=None):
from azure.mgmt.example.models import MyFoo
from azure.cli.command_modules.example._client_factory import cf_mymod
client = cf_mymod(cmd.cli_ctx)
foo = MyFoo(location=location)
return client.create_or_update(myfoo_name, resource_group_name, foo)
The snippet above shows what it takes to author a basic command.
- Create a CliCommandType which holds the metadata for your command.
- Create a command group in which your command will exist, passing the command type created in the previous step.
- Register your command with the
command
method, defining first the name of the command and then the name of the method which will execute. - Define the callable that will execute:
The CLI inspects the callable to determine required params, defaults and help text and more.
Try out the example to see these in action!
When running the command with the --help
flag, you should see the command.
You can also now execute the command for yourself.
$ az myfoo create --help
Command
az myfoo create
Arguments
--myfoo-name [Required]: The argument that is required.
--resource-group-name [Required]: Also required.
--location : Optional arg.
...
$ az myfoo create --myfoo-name foo --resource-group-name myrg
{
"name": "foo",
"resourceGroup": "myrg",
"location": None
}
Discover tests
azdev test --discover
Run all tests in a module:
azdev test MODULE [--live] [--series] [--discover] [--dest-file FILENAME]
Run an individual test:
azdev test TEST [TEST ...] [--live] [--series] [--discover] [--dest-file FILENAME]
For example azdev test test_myfoo
Run a test when there is a conflict (for example, both 'azure-cli-core' and 'azure-cli-network' have 'test_foo'):
azdev test MODULE.TEST [--live]
The list of failed tests are displayed at the end of a run and dumped to the file specified with --dest-file
or test_failures.txt
if nothing is provided. This allows for conveniently replaying failed tests:
azdev test --src-file test_failures.txt [--live] [--series] [--discover]
Relying on the default filename, the list of failed tests should grow shorter as you fix the cause of the failures until there are no more failing tests.
azdev style --module <module> [--pylint] [--pep8]
History notes are auto-generated based on PR titles and descriptions starting from S165. Starting from 01/30/2020, we require all the PR titles to follow the below format:
- [Mandatory] Each PR title MUST start with
[Component Name]
or{Component Name}
.Component Name
shall be replaced by the real ones such asStorage
,Compute
. It could be the name of a command module, but in title case with necessary spaces for better readability, such asAPI Management
,Managed Service
. Other possible component names include but are not limited to:Packaging
,Misc.
,Aladdin
.[]
means this change is customer-facing and the message will be put intoHISTORY.rst
.{}
means this change is not customer-facing and the message will NOT be included inHISTORY.rst
.- If the component name is
Core
, the message will be written insrc/azure-cli-core/HISTORY.rst
. Otherwise, the message will be written insrc/azure-cli/HISTORY.rst
.
- [Mandatory] If it's a breaking change, the second part should be
BREAKING CHANGE
followed by a colon. In the case of hotfix, putHotfix
in this part. If it's related to fixing an issue, putFix #number
in this part. For other cases, this part could be empty. - [Recommendation] If the change can be mapped into a command, then the next part could be the command name starting with
az
, followed by a colon. - [Recommendation] Use the right verb with present-tense in base form and capitalized first letter to describe what is done:
- Add for new features.
- Change for changes in existing functionality.
- Deprecate for once-stable features removed in upcoming releases.
- Remove for deprecated features removed in this release.
- Fix for any bug fixes.
Examples of customer-facing change PR title:
[Storage] BREAKING CHANGE: az storage remove: Remove --auth-mode argument
[ARM] Fix #10246: az resource tag crashes when the parameter --ids passed in is resource group ID
An example of non-customer-facing change PR title:
{Aladdin} Add help example for dns
Please follow the instruction in the PR template to provide a description of the PR and the testing guide if possible.
If you would like to write multiple history notes for one PR or overwrite the message in the PR title as a history note, please write the notes under History Notes
section in the PR description, following the same format described above. The PR template already contains the history note template, just change it if needed. In this case, the PR title could be a summary of all the changes in this PR and will not be put into HISTORY.rst
in our pipeline. The PR title still needs to start with [Component Name]
. You can delete the History Notes
section if not needed.
Step 1: Create a hotfix branch based on release branch, then submit a PR to merge hotfix into release.
In this PR, the second part of the PR title should be Hotfix
. If you have customer-facing changes, you need to manually modify HISTORY.rst
to add history notes. The auto generated history notes for the next regular release will ignore the PR that contains Hotfix
.
Step 2: Submit a PR to merge the release branch back into dev branch after the hotfix release.
Do NOT squash and merge this PR. After the PR gets approved by code owners, you should fast forward dev to release on your local machine and then push dev to upstream repository.
An example title of hotfix change PR:
{Packaging} Hotfix: Fix dependency error