···3333and the name of the extension you want to package as `extension`:
34343535```sh
3636-./query-extension-index.sh --cli-version=2.61.0 --extension=azure-devops --download
3636+nix run .#azure-cli.extension-tool -- \
3737+ --cli-version=2.61.0 \
3838+ --extension=azure-devops \
3939+ --init
3740```
38413942The output should look something like this:
···4144```json
4245{
4346 "pname": "azure-devops",
4444- "description": "Tools for managing Azure DevOps.",
4545- "version": "1.0.1",
4646- "url": "https://github.com/Azure/azure-devops-cli-extension/releases/download/20240514.1/azure_devops-1.0.1-py2.py3-none-any.whl",
4747- "sha256": "f300d0288f017148514ebe6f5912aef10c7a6f29bdc0c916b922edf1d75bc7db",
4747+ "version": "1.0.2",
4848+ "url": "https://github.com/Azure/azure-devops-cli-extension/releases/download/20250624.2/azure_devops-1.0.2-py2.py3-none-any.whl",
4949+ "hash": "sha256-4rDeAqOnRRKMP26MJxG4u9vBuos6/SQIoVgfNbBpulk=",
5050+ "description": "Tools for managing Azure DevOps",
4851 "license": "MIT",
4949- "requires": [
5050- "distro (==1.3.0)",
5151- "distro==1.3.0"
5252+ "requirements": [
5353+ "distro (>=1.6.0)"
5254 ]
5355}
5456```
···5860```nix
5961 azure-devops = mkAzExtension {
6062 pname = "azure-devops";
6161- version = "1.0.0";
6262- url = "https://github.com/Azure/azure-devops-cli-extension/releases/download/20240206.1/azure_devops-${version}-py2.py3-none-any.whl";
6363- sha256 = "658a2854d8c80f874f9382d421fa45abf6a38d00334737dda006f8dec64cf70a";
6363+ version = "1.0.2";
6464+ url = "https://github.com/Azure/azure-devops-cli-extension/releases/download/20250624.2/azure_devops-${version}-py2.py3-none-any.whl";
6565+ hash = "sha256-4rDeAqOnRRKMP26MJxG4u9vBuos6/SQIoVgfNbBpulk=";
6466 description = "Tools for managing Azure DevOps";
6567 propagatedBuildInputs = with python3Packages; [
6668 distro
···71737274* The attribute name should be the same as `pname`.
7375* Replace the version in `url` with `${version}`.
7474-* The json output `requires` must be transformed into `propagetedBuildInputs`.
7676+* The json output `requirements` must be transformed into package `requirements`.
7577* If `license` is `"MIT"`, it can be left out in the nix expression, as the builder defaults to that license.
7678* Add yourself as maintainer in `meta.maintainers`.
7779
+55-4
pkgs/by-name/az/azure-cli/extensions-tool.py
···174174 return max(versions, key=lambda e: parse(e["metadata"]["version"]), default=None)
175175176176177177-def processExtension(
177177+def find_extension_version(
178178 extVersions: dict,
179179 cli_version: Version,
180180 ext_name: Optional[str] = None,
181181 requirements: bool = False,
182182-) -> Optional[Ext]:
182182+) -> Optional[Dict[str, Any]]:
183183 versions = filter(_filter_invalid, extVersions)
184184 versions = filter(lambda v: _filter_compatible(v, cli_version), versions)
185185 latest = _get_latest_version(versions)
···188188 if ext_name and latest["metadata"]["name"] != ext_name:
189189 return None
190190 if not requirements and "run_requires" in latest["metadata"]:
191191+ return None
192192+ return latest
193193+194194+195195+def find_and_transform_extension_version(
196196+ extVersions: dict,
197197+ cli_version: Version,
198198+ ext_name: Optional[str] = None,
199199+ requirements: bool = False,
200200+) -> Optional[Ext]:
201201+ latest = find_extension_version(extVersions, cli_version, ext_name, requirements)
202202+ if not latest:
191203 return None
192204193205 return _transform_dict_to_obj(latest)
···335347 action=argparse.BooleanOptionalAction,
336348 help="whether to commit changes to git",
337349 )
350350+ parser.add_argument(
351351+ "--init",
352352+ action=argparse.BooleanOptionalAction,
353353+ help="whether you want to init a new extension",
354354+ )
338355 args = parser.parse_args()
339356 cli_version = parse(args.cli_version)
340357···348365 assert index["formatVersion"] == "1" # only support formatVersion 1
349366 extensions_remote = index["extensions"]
350367368368+ # init just prints the json of the extension version that matches the cli version.
369369+ if args.init:
370370+ if not args.extension:
371371+ logger.error("extension name is required for --init")
372372+ exit(1)
373373+374374+ for ext_name, ext_versions in extensions_remote.items():
375375+ if ext_name != args.extension:
376376+ continue
377377+ ext = find_extension_version(
378378+ ext_versions,
379379+ cli_version,
380380+ args.extension,
381381+ requirements=True,
382382+ )
383383+ break
384384+ if not ext:
385385+ logger.error(f"Extension {args.extension} not found in index")
386386+ exit(1)
387387+388388+ ext_translated = {
389389+ "pname": ext["metadata"]["name"],
390390+ "version": ext["metadata"]["version"],
391391+ "url": ext["downloadUrl"],
392392+ "hash": _convert_hash_digest_from_hex_to_b64_sri(ext["sha256Digest"]),
393393+ "description": ext["metadata"]["summary"].rstrip("."),
394394+ "license": ext["metadata"]["license"],
395395+ "requirements": ext["metadata"]["run_requires"][0]["requires"],
396396+ }
397397+ print(json.dumps(ext_translated, indent=2))
398398+ return
399399+351400 if args.extension:
352401 logger.info(f"updating extension: {args.extension}")
353402354403 ext = Optional[Ext]
355404 for _ext_name, extension in extensions_remote.items():
356356- extension = processExtension(
405405+ extension = find_and_transform_extension_version(
357406 extension, cli_version, args.extension, requirements=True
358407 )
359408 if extension:
···402451403452 extensions_remote_filtered = set()
404453 for _ext_name, extension in extensions_remote.items():
405405- extension = processExtension(extension, cli_version, args.extension)
454454+ extension = find_and_transform_extension_version(
455455+ extension, cli_version, args.extension
456456+ )
406457 if extension:
407458 extensions_remote_filtered.add(extension)
408459