From 91a6bfb0e2b7da0ddac0436c08d4e30f34b08622 Mon Sep 17 00:00:00 2001 From: Ray Chen Date: Mon, 25 Nov 2024 15:00:59 -0800 Subject: [PATCH] Deprecated code and update dependencies (#9379) * Removed dependencies Removed swagger-validation-common dep; Removed part of references from azure-js-dev-tools. * [change1] Remove azure js dev tool (#9365) * revert githubUtils.ts * delete test file and fix some change about azure-js-dev-tools * Removed unused codes and refactoring * changing the order of code execution (#9374) * Removed unused tests and refactor the code * Update dependencies * Refine dependencies and resolve vulnerabilities * Update version to the first version * Updated eslint config and tsconfig * Added pipeline definitions * Added flag to control publish * Reference parameter * Updated pipeline yml and added codeowner --------- Co-authored-by: Tianen --- .github/CODEOWNERS | 1 + tools/spec-gen-sdk/CHANGELOG.md | 3 + tools/spec-gen-sdk/azure-pipelines.yml | 104 - tools/spec-gen-sdk/ci.yml | 73 + tools/spec-gen-sdk/eslint.config.mjs | 34 +- .../integrationTest/clearGithubTestRepos.ts | 46 - .../integrationTest/fixtures/index.ts | 26 - .../fixtures/schm-arm-test/.gitignore | 1 - .../schemas/common/definitions.json | 0 .../schm-arm-test/swagger_to_sdk_config.json | 18 - .../fixtures/sdk-go-test/.gitignore | 34 - .../fixtures/sdk-go-test/Gopkg.lock | 427 - .../fixtures/sdk-go-test/Gopkg.toml | 56 - .../sdk-go-test/swagger_to_sdk_config.json | 28 - .../testservice/arm-testservice/LICENSE.txt | 21 - .../sdk/testservice/arm-testservice/README.md | 99 - .../arm-testservice/rollup.config.js | 37 - .../arm-testservice/src/models/index.ts | 50 - .../arm-testservice/src/models/mappers.ts | 29 - .../arm-testservice/src/models/parameters.ts | 32 - .../arm-testservice/src/models/testMappers.ts | 12 - .../arm-testservice/src/operations/index.ts | 11 - .../arm-testservice/src/operations/test.ts | 74 - .../arm-testservice/src/testServiceClient.ts | 41 - .../src/testServiceClientContext.ts | 56 - .../testservice/arm-testservice/tsconfig.json | 19 - .../sdk-js-test/swagger_to_sdk_config.json | 19 - .../swagger_to_sdk_custom_config.json | 19 - .../fixtures/sdk-py-test/.gitignore | 99 - .../fixtures/sdk-py-test/build_package.py | 33 - .../sdk-py-test/scripts/analyze_deps.py | 417 - .../fixtures/sdk-py-test/scripts/deps.html.j2 | 284 - .../fixtures/sdk-py-test/scripts/dev_setup.py | 173 - .../scripts/devops_tasks/build_packages.py | 87 - .../scripts/devops_tasks/common_tasks.py | 412 - .../scripts/devops_tasks/find_change_log.ps1 | 106 - .../scripts/devops_tasks/git_helper.py | 107 - .../devops_tasks/setup_execute_tests.py | 311 - .../scripts/devops_tasks/test_regression.py | 389 - .../scripts/devops_tasks/tox_harness.py | 389 - .../scripts/devops_tasks/verify_change_log.py | 132 - .../scripts/multi_api_readme_help.py | 122 - .../sdk-py-test/scripts/multiapi_init_gen.py | 545 -- .../scripts/pylint_custom_plugin/README.md | 60 - .../scripts/pylint_custom_plugin/__init__.py | 0 .../pylint_guidelines_checker.py | 1653 ---- .../scripts/pylint_custom_plugin/setup.py | 12 - .../pylint_custom_plugin/tests/__init__.py | 0 .../tests/test_pylint_custom_plugins.py | 2343 ------ .../scripts/templates/_multiapi_client.py | 105 - .../scripts/templates/_operations_mixin.py | 34 - .../sdk-py-test/scripts/templates/models.py | 9 - .../fixtures/sdk-py-test/scripts/trim_aio.py | 19 - .../sdk-py-test/swagger_to_sdk_config.json | 20 - .../azure-sdk-tools/dev_requirements.txt | 1 - .../packaging_tools/__init__.py | 126 - .../packaging_tools/__main__.py | 54 - .../packaging_tools/change_log.py | 201 - .../packaging_tools/code_report.py | 298 - .../azure-sdk-tools/packaging_tools/conf.py | 43 - .../packaging_tools/drop_tools.py | 141 - .../packaging_tools/generate_package.py | 50 - .../packaging_tools/generate_sdk.py | 133 - .../swaggertosdk/SwaggerToSdkCore.py | 289 - .../swaggertosdk/SwaggerToSdkNewCLI.py | 311 - .../swaggertosdk/autorest_tools.py | 150 - .../packaging_tools/templates/MANIFEST.in | 6 - .../packaging_tools/templates/README.md | 21 - .../packaging_tools/templates/__init__.py | 1 - .../packaging_tools/templates/setup.cfg | 2 - .../packaging_tools/templates/setup.py | 96 - .../packaging_tools/update_pr.py | 100 - .../packaging_tools/venvtools.py | 46 - .../azure-sdk-tools/pypi_tools/__init__.py | 1 - .../tools/azure-sdk-tools/pypi_tools/pypi.py | 58 - .../tools/azure-sdk-tools/sdk_packaging.toml | 2 - .../tools/azure-sdk-tools/setup.py | 45 - .../sdk-tf-test/swagger_to_sdk_config.json | 29 - .../stable/2020-01-01/TestService.json | 168 - .../stable/2020-01-01/examples/TestGet.json | 10 - .../stable/2020-01-01/examples/TestPut.json | 10 - .../readme.azureresourceschema.md | 19 - .../testservice/resource-manager/readme.md | 75 - .../resource-manager/readme.python.md | 38 - .../stable/2020-02-01/TestService.json | 132 - .../stable/2020-02-01/examples/TestGet.json | 10 - .../scenarios/shouldbeexcluded.json | 1 - .../testservice/resource-manager/readme.md | 82 - .../resource-manager/readme.python.md | 51 - .../resource-manager/readme.no-lang.md | 3 - .../stable/2020-01-01/AnotherService.json | 125 - .../stable/2020-01-01/examples/TestGet.json | 10 - .../anotherservice/resource-manager/readme.md | 73 - .../stable/2020-01-01/TestService.json | 125 - .../stable/2020-01-01/examples/TestGet.json | 10 - .../testservice/resource-manager/readme.md | 73 - .../specificationRepositoryConfiguration.json | 33 - .../integrationTest/jest.setupAfterEnv.js | 5 - .../test/L0-armschm-open.spec.ts | 28 - .../integrationTest/test/L0-js-open.spec.ts | 26 - .../integrationTest/test/L0-py-open.spec.ts | 29 - .../test/L0-py-t2-open.spec.ts | 27 - .../integrationTest/test/L0-tf-open.spec.ts | 27 - .../integrationTest/test/L1-js-merge.spec.ts | 27 - .../test/L1-js-multi-merge-empty.spec.ts | 29 - .../test/L1-js-multi-merge-open.spec.ts | 29 - .../test/L1-js-open-second-run.spec.ts | 34 - .../test/L1-js-open-two-readme.spec.ts | 26 - .../L0-armschm-open.spec.ts.snap | 111 - .../__snapshots__/L0-js-open.spec.ts.snap | 137 - .../__snapshots__/L0-py-open.spec.ts.snap | 190 - .../__snapshots__/L0-py-t2-open.spec.ts.snap | 215 - .../__snapshots__/L0-tf-open.spec.ts.snap | 132 - .../__snapshots__/L1-js-merge.spec.ts.snap | 139 - .../L1-js-multi-merge-empty.spec.ts.snap | 141 - .../L1-js-multi-merge-open.spec.ts.snap | 145 - .../L1-js-open-second-run.spec.ts.snap | 160 - .../L1-js-open-two-readme.spec.ts.snap | 220 - .../integrationTest/test/lang-common.ts | 210 - tools/spec-gen-sdk/integrationTest/utils.ts | 256 - tools/spec-gen-sdk/jest.config.integration.js | 32 - tools/spec-gen-sdk/package-lock.json | 7440 +++++++++++++++++ tools/spec-gen-sdk/package.json | 112 + .../spec-gen-sdk/src/automation/entrypoint.ts | 59 +- tools/spec-gen-sdk/src/automation/legacy.ts | 435 - tools/spec-gen-sdk/src/automation/logging.ts | 2 +- .../src/automation/reportStatus.ts | 8 +- .../{ => automation}/sdkAutomationState.ts | 33 - .../automation/updateBreakingChangesLabels.ts | 5 +- tools/spec-gen-sdk/src/automation/workflow.ts | 79 +- .../src/automation/workflowPackage.ts | 26 +- tools/spec-gen-sdk/src/blobProxy.ts | 20 - tools/spec-gen-sdk/src/cli/cli.ts | 11 +- tools/spec-gen-sdk/src/cli/main.ts | 158 - tools/spec-gen-sdk/src/fakeBlobProxy.ts | 15 - tools/spec-gen-sdk/src/index.ts | 12 - .../langSpecs/generateBreakingChnageReport.ts | 11 - .../src/langSpecs/installationInstructions.ts | 36 - .../langSpecs/langs/azureresourceschema.ts | 56 - tools/spec-gen-sdk/src/langSpecs/langs/cli.ts | 100 - .../src/langSpecs/langs/dotnet.ts | 87 - .../src/langSpecs/langs/dotnetTrack2.ts | 17 - tools/spec-gen-sdk/src/langSpecs/langs/go.ts | 134 - .../spec-gen-sdk/src/langSpecs/langs/java.ts | 75 - .../src/langSpecs/langs/javascript.ts | 83 - .../src/langSpecs/langs/python.ts | 179 - .../src/langSpecs/langs/pythonTrack2.ts | 20 - .../spec-gen-sdk/src/langSpecs/langs/ruby.ts | 133 - .../src/langSpecs/langs/trenton.ts | 183 - .../src/langSpecs/languageConfiguration.ts | 113 - .../src/langSpecs/packageCommand.ts | 108 - .../src/langSpecs/packageCommandOptions.ts | 34 - .../src/langSpecs/repositoryCommand.ts | 64 - .../src/langSpecs/repositoryCommandOptions.ts | 29 - .../src/langSpecs/sdkRepositoryPackage.ts | 233 - tools/spec-gen-sdk/src/realBlobProxy.ts | 40 - tools/spec-gen-sdk/src/runnerReportLogger.ts | 26 - tools/spec-gen-sdk/src/sdkAutomation.ts | 752 -- tools/spec-gen-sdk/src/sdkRepository.ts | 1442 ---- .../spec-gen-sdk/src/sdkRepositoryMapping.ts | 56 - .../spec-gen-sdk/src/specificationPREvent.ts | 31 - .../src/specificationPullRequest.ts | 1012 --- .../src/specificationPullRequestGeneration.ts | 482 -- .../src/specificationReadmeMdFile.ts | 85 - .../specificationRepositoryConfiguration.ts | 156 - .../src/swaggerToSDKConfiguration.ts | 230 - .../spec-gen-sdk/src/types/GenerateOutput.ts | 2 +- tools/spec-gen-sdk/src/types/Message.ts | 100 + tools/spec-gen-sdk/src/types/PackageData.ts | 113 +- .../spec-gen-sdk/src/types/sdkSuppressions.ts | 87 + tools/spec-gen-sdk/src/types/sdks.ts | 66 + tools/spec-gen-sdk/src/types/validator.ts | 31 +- tools/spec-gen-sdk/src/utils/arrays.ts | 38 + tools/spec-gen-sdk/src/utils/fsUtils.ts | 702 ++ tools/spec-gen-sdk/src/utils/githubUtils.ts | 150 +- .../src/utils/handleSuppressionLines.ts | 2 +- tools/spec-gen-sdk/src/utils/readme.ts | 81 + tools/spec-gen-sdk/src/utils/reportFormat.ts | 2 +- .../src/utils/resolveChangedTags.ts | 26 - tools/spec-gen-sdk/src/utils/runScript.ts | 4 +- tools/spec-gen-sdk/src/utils/typespecUtils.ts | 6 +- tools/spec-gen-sdk/src/utils/utils.ts | 229 +- tools/spec-gen-sdk/test/dotnetTests.ts | 23 - tools/spec-gen-sdk/test/fakeBlobProxyTests.ts | 45 - tools/spec-gen-sdk/test/goTests.ts | 20 - tools/spec-gen-sdk/test/javaTests.ts | 23 - tools/spec-gen-sdk/test/javascriptTests.ts | 23 - .../spec-gen-sdk/test/packageCommandTests.ts | 257 - tools/spec-gen-sdk/test/pythonTests.ts | 93 - tools/spec-gen-sdk/test/realBlobProxyTests.ts | 79 - .../test/repositoryCommandTests.ts | 296 - tools/spec-gen-sdk/test/rubyTests.ts | 48 - tools/spec-gen-sdk/test/sdkAutomationTests.ts | 703 -- tools/spec-gen-sdk/test/sdkRepositoryTests.ts | 2368 ------ ...specificationPullRequestGenerationTests.ts | 607 -- .../test/specificationPullRequestTests.ts | 1773 ---- .../test/specificationReadmeMdFileTests.ts | 219 - ...ecificationRepositoryConfigurationTests.ts | 180 - tools/spec-gen-sdk/test/test.ts | 1105 --- tools/spec-gen-sdk/tsconfig.integration.json | 6 - tools/spec-gen-sdk/tsconfig.json | 3 +- 201 files changed, 9108 insertions(+), 29682 deletions(-) create mode 100644 tools/spec-gen-sdk/CHANGELOG.md delete mode 100644 tools/spec-gen-sdk/azure-pipelines.yml create mode 100644 tools/spec-gen-sdk/ci.yml delete mode 100644 tools/spec-gen-sdk/integrationTest/clearGithubTestRepos.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/index.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/.gitignore delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/schemas/common/definitions.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/swagger_to_sdk_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/.gitignore delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.lock delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.toml delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/swagger_to_sdk_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/LICENSE.txt delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/README.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/rollup.config.js delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/index.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/mappers.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/parameters.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/testMappers.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/index.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/test.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClient.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClientContext.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/tsconfig.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test/swagger_to_sdk_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test-patch0-track2/swagger_to_sdk_custom_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/.gitignore delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/build_package.py delete mode 100755 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/analyze_deps.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/deps.html.j2 delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/dev_setup.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/build_packages.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/common_tasks.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/find_change_log.ps1 delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/git_helper.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/setup_execute_tests.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/test_regression.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/tox_harness.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/verify_change_log.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multi_api_readme_help.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multiapi_init_gen.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/README.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/__init__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/pylint_guidelines_checker.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/setup.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/__init__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/test_pylint_custom_plugins.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_multiapi_client.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_operations_mixin.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/models.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/trim_aio.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/swagger_to_sdk_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/dev_requirements.txt delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__init__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__main__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/change_log.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/code_report.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/conf.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/drop_tools.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_package.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_sdk.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkCore.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkNewCLI.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/autorest_tools.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/MANIFEST.in delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/README.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/__init__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.cfg delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/update_pr.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/venvtools.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/__init__.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/pypi.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/sdk_packaging.toml delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/setup.py delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/sdk-tf-test/swagger_to_sdk_config.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.azureresourceschema.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.python.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/TestService.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/examples/TestGet.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/scenarios/shouldbeexcluded.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.python.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch2-empty-update/specification/testservice/resource-manager/readme.no-lang.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/AnotherService.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/examples/TestGet.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/readme.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/readme.md delete mode 100644 tools/spec-gen-sdk/integrationTest/fixtures/spec-test/specificationRepositoryConfiguration.json delete mode 100644 tools/spec-gen-sdk/integrationTest/jest.setupAfterEnv.js delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L0-armschm-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L0-js-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L0-py-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L0-py-t2-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L0-tf-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L1-js-merge.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-empty.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-open.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L1-js-open-second-run.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/L1-js-open-two-readme.spec.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-armschm-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-js-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-t2-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-tf-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-merge.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-empty.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-open.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-second-run.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-two-readme.spec.ts.snap delete mode 100644 tools/spec-gen-sdk/integrationTest/test/lang-common.ts delete mode 100644 tools/spec-gen-sdk/integrationTest/utils.ts delete mode 100644 tools/spec-gen-sdk/jest.config.integration.js create mode 100644 tools/spec-gen-sdk/package-lock.json create mode 100644 tools/spec-gen-sdk/package.json delete mode 100644 tools/spec-gen-sdk/src/automation/legacy.ts rename tools/spec-gen-sdk/src/{ => automation}/sdkAutomationState.ts (55%) delete mode 100644 tools/spec-gen-sdk/src/blobProxy.ts delete mode 100644 tools/spec-gen-sdk/src/cli/main.ts delete mode 100644 tools/spec-gen-sdk/src/fakeBlobProxy.ts delete mode 100644 tools/spec-gen-sdk/src/index.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/generateBreakingChnageReport.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/installationInstructions.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/azureresourceschema.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/cli.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/dotnet.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/dotnetTrack2.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/go.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/java.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/javascript.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/python.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/pythonTrack2.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/ruby.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/langs/trenton.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/languageConfiguration.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/packageCommand.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/packageCommandOptions.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/repositoryCommand.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/repositoryCommandOptions.ts delete mode 100644 tools/spec-gen-sdk/src/langSpecs/sdkRepositoryPackage.ts delete mode 100644 tools/spec-gen-sdk/src/realBlobProxy.ts delete mode 100644 tools/spec-gen-sdk/src/runnerReportLogger.ts delete mode 100644 tools/spec-gen-sdk/src/sdkAutomation.ts delete mode 100644 tools/spec-gen-sdk/src/sdkRepository.ts delete mode 100644 tools/spec-gen-sdk/src/sdkRepositoryMapping.ts delete mode 100644 tools/spec-gen-sdk/src/specificationPREvent.ts delete mode 100644 tools/spec-gen-sdk/src/specificationPullRequest.ts delete mode 100644 tools/spec-gen-sdk/src/specificationPullRequestGeneration.ts delete mode 100644 tools/spec-gen-sdk/src/specificationReadmeMdFile.ts delete mode 100644 tools/spec-gen-sdk/src/specificationRepositoryConfiguration.ts delete mode 100644 tools/spec-gen-sdk/src/swaggerToSDKConfiguration.ts create mode 100644 tools/spec-gen-sdk/src/types/Message.ts create mode 100644 tools/spec-gen-sdk/src/types/sdkSuppressions.ts create mode 100644 tools/spec-gen-sdk/src/types/sdks.ts create mode 100644 tools/spec-gen-sdk/src/utils/arrays.ts create mode 100644 tools/spec-gen-sdk/src/utils/readme.ts delete mode 100644 tools/spec-gen-sdk/src/utils/resolveChangedTags.ts delete mode 100644 tools/spec-gen-sdk/test/dotnetTests.ts delete mode 100644 tools/spec-gen-sdk/test/fakeBlobProxyTests.ts delete mode 100644 tools/spec-gen-sdk/test/goTests.ts delete mode 100644 tools/spec-gen-sdk/test/javaTests.ts delete mode 100644 tools/spec-gen-sdk/test/javascriptTests.ts delete mode 100644 tools/spec-gen-sdk/test/packageCommandTests.ts delete mode 100644 tools/spec-gen-sdk/test/pythonTests.ts delete mode 100644 tools/spec-gen-sdk/test/realBlobProxyTests.ts delete mode 100644 tools/spec-gen-sdk/test/repositoryCommandTests.ts delete mode 100644 tools/spec-gen-sdk/test/rubyTests.ts delete mode 100644 tools/spec-gen-sdk/test/sdkAutomationTests.ts delete mode 100644 tools/spec-gen-sdk/test/sdkRepositoryTests.ts delete mode 100644 tools/spec-gen-sdk/test/specificationPullRequestGenerationTests.ts delete mode 100644 tools/spec-gen-sdk/test/specificationPullRequestTests.ts delete mode 100644 tools/spec-gen-sdk/test/specificationReadmeMdFileTests.ts delete mode 100644 tools/spec-gen-sdk/test/specificationRepositoryConfigurationTests.ts delete mode 100644 tools/spec-gen-sdk/test/test.ts delete mode 100644 tools/spec-gen-sdk/tsconfig.integration.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 59b51e51d61..5f30ef01ba9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,6 +44,7 @@ /tools/pipeline-witness/ @hallipr /tools/sdk-ai-bots/ @raych1 /tools/sdk-testgen/ @lirenhe @tadelesh +/tools/spec-gen-sdk/ @raych1 @chidozieononiwu /tools/test-proxy/ @scbedd @mikeharder @benbp /tools/tsp-client/ @catalinaperalta /tools/webhook-router/ @praveenkuttappan @weshaggard diff --git a/tools/spec-gen-sdk/CHANGELOG.md b/tools/spec-gen-sdk/CHANGELOG.md new file mode 100644 index 00000000000..90f9448e962 --- /dev/null +++ b/tools/spec-gen-sdk/CHANGELOG.md @@ -0,0 +1,3 @@ +## 2024-11-14 - 0.1.0 + +- Initial Release \ No newline at end of file diff --git a/tools/spec-gen-sdk/azure-pipelines.yml b/tools/spec-gen-sdk/azure-pipelines.yml deleted file mode 100644 index 2539f231427..00000000000 --- a/tools/spec-gen-sdk/azure-pipelines.yml +++ /dev/null @@ -1,104 +0,0 @@ -trigger: - - master - -pool: - name: AzurePipelines-EO - demands: - - ImageOverride -equals AzurePipelinesUbuntu20.04compliant - -variables: - DOCKER_BUILDKIT: 1 - -jobs: - - job: Build_Verfication - steps: - - task: npmAuthenticate@0 - inputs: - workingFile: .npmrc - - - script: cp .npmrc .npmrc-registry - displayName: Disable .npmrc-registry - - - script: sed -i -E 's/"version":\s*"([0-9\.]+)",/"version":"\1.$(Build.BuildNumber)",/' package.json - displayName: Set version in package.json - - - task: Docker@2 - displayName: Build Image - inputs: - command: build - repository: openapi/sdk-automation - tags: $(Build.BuildNumber) - Dockerfile: ./Dockerfile - containerRegistry: openapi_test_docker_connection - arguments: --build-arg UBUNTU_MIRROR=$(UBUNTU_MIRROR) - - - task: Docker@2 - displayName: Push Image - condition: notIn(variables['Build.Reason'], 'PullRequest') - inputs: - command: push - repository: openapi/sdk-automation - containerRegistry: openapi_test_docker_connection - tags: $(Build.BuildNumber) - - - task: ComponentGovernanceComponentDetection@0 - displayName: Dependencies Compliance Analysis - inputs: - verbosity: Verbose - snapshotForceEnabled: true - useDefaultDetectors: false - detectorsToRun: Npm - - - job: Integration_Test - variables: - SDK_REPO_NAME: PLACEHOLDER - steps: - - task: NodeTool@0 - inputs: - versionSpec: '18.x' - - - task: npmAuthenticate@0 - inputs: - workingFile: .npmrc - - - script: npm ci - displayName: NPM Install - - - script: | - git config --global user.email "sdkautomation@microsoft.com" - git config --global user.name "SDK Automation" - rm .npmrc - - npm config set audit false - sudo npm install -g npm@latest - - sudo apt update - sudo apt install python3-setuptools python3-venv - /usr/bin/python3 -m venv work/pyenv - node ./node_modules/.bin/autorest --typescript - - TEST_RUN_ID=`node -e "console.log(Math.random().toString(36).substring(2, 8))"` - echo "##vso[task.setvariable variable=TEST_RUN_ID]$TEST_RUN_ID" - echo "TEST_RUN_ID=$TEST_RUN_ID" - displayName: Init - - - script: | - source work/pyenv/bin/activate - npm run test-ci - displayName: Integration Test - timeoutInMinutes: 30 - env: - SPEC_REPO: $(spec-repo) - GITHUB_COMMENT_AUTHOR_NAME: $(github-comment-author-name) - GITHUBAPP_ID: $(githubapp-id) - GITHUBAPP_PRIVATE_KEY: $(githubapp-private-key) - - - script: | - [ -z $TEST_RUN_ID ] || npm run clear-github-test-repos - displayName: Clean Up - condition: always() - env: - SPEC_REPO: $(spec-repo) - GITHUB_COMMENT_AUTHOR_NAME: $(github-comment-author-name) - GITHUBAPP_ID: $(githubapp-id) - GITHUBAPP_PRIVATE_KEY: $(githubapp-private-key) diff --git a/tools/spec-gen-sdk/ci.yml b/tools/spec-gen-sdk/ci.yml new file mode 100644 index 00000000000..73f9a31bc6f --- /dev/null +++ b/tools/spec-gen-sdk/ci.yml @@ -0,0 +1,73 @@ +trigger: + branches: + include: + - main + paths: + include: + - tools/spec-gen-sdk + +pr: + branches: + include: + - main + paths: + include: + - tools/spec-gen-sdk + +extends: + template: /eng/pipelines/templates/stages/archetype-sdk-publish-js.yml + parameters: + BuildStageName: InstallAndBuild + ArtifactName: drop + PackageJsonPath: $(Build.SourcesDirectory)/tools/spec-gen-sdk + BuildStages: + - stage: InstallAndBuild + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + - name: NodeVersion + value: '20.x' + - name: VAR_ARTIFACT_NAME + value: 'drop' + - name: VAR_BUILD_ARTIFACT_STAGING_DIRECTORY + value: $(Build.ArtifactStagingDirectory) + jobs: + - job: Build_Linux + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + steps: + - task: NodeTool@0 + inputs: + versionSpec: '$(NodeVersion)' + displayName: 'Install Node.js' + + - bash: | + npm ci + displayName: 'npm ci' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/spec-gen-sdk + + - bash: | + npm run build-test + displayName: 'build and test' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/spec-gen-sdk + + - bash: | + npm pack + displayName: 'npm pack' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/spec-gen-sdk + + - bash: 'cp azure-tools-spec-gen-sdk-*.tgz $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' + displayName: 'copy to staging directory' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/spec-gen-sdk + + - pwsh: | + Get-ChildItem -Path $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY) ` + | ForEach-Object { Write-Host "npm install $($_.FullName)"; npm install $_.FullName } + displayName: Smoke test a package installation + + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: '$(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' + artifactName: '$(VAR_ARTIFACT_NAME)' \ No newline at end of file diff --git a/tools/spec-gen-sdk/eslint.config.mjs b/tools/spec-gen-sdk/eslint.config.mjs index 4a6ddc615d7..865fdf4f5df 100644 --- a/tools/spec-gen-sdk/eslint.config.mjs +++ b/tools/spec-gen-sdk/eslint.config.mjs @@ -1,10 +1,32 @@ import globals from "globals"; -import tseslint from "typescript-eslint"; - +import pluginJs from "@eslint/js"; +import tsPlugin from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; +/** @type {import('eslint').Linter.Config[]} */ export default [ - {files: ["**/*.{js,mjs,cjs,ts}"]}, - {files: ["**/*.js"], languageOptions: {sourceType: "commonjs"}}, - {languageOptions: { globals: globals.node }}, - ...tseslint.configs.recommended, + { + files: ["**/*.{js,mjs,cjs,ts}"], + languageOptions: { + globals: { + ...globals.node + }, + parser: tsParser, + parserOptions: { + ecmaVersion: "latest", // Use the latest ECMAScript features + sourceType: "module", + project: "./tsconfig.json", // Ensure this points to your tsconfig file + }, + }, + ignores: ["test/**/*", "jest.config.js", "eslint.config.mjs"], + plugins: { + "@typescript-eslint": tsPlugin, + }, + rules: { + ...pluginJs.configs.recommended.rules, + ...tsPlugin.configs.recommended.rules, + "@typescript-eslint/ban-ts-comment": "error", + "@typescript-eslint/no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true }] + }, + }, ]; \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/clearGithubTestRepos.ts b/tools/spec-gen-sdk/integrationTest/clearGithubTestRepos.ts deleted file mode 100644 index 7c5e6d1af3c..00000000000 --- a/tools/spec-gen-sdk/integrationTest/clearGithubTestRepos.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { getTestGithubClient, repoOwner } from './utils'; -import { sdkAutomationCliConfig } from '../src/cli/config'; -import { Octokit, RestEndpointMethodTypes } from '@octokit/rest'; - -type ReposListForOrgResponse = RestEndpointMethodTypes['repos']['listForOrg']['response']['data'] - -const cleanGithubTestRepos = async () => { - const github = await getTestGithubClient(); - const reposRsp: ReposListForOrgResponse = await github.paginate(github.repos.listForOrg.endpoint.merge({ - org: repoOwner - })); - - const runId = sdkAutomationCliConfig.testRunId; - const prefixToMatch = runId ? `test-${runId}` : 'test'; - - let repos = reposRsp.map(repo => repo.name); - console.log(`Repos in ${repoOwner}:`); - console.log(repos.join('\n')); - - console.log(`\nFilter: ${prefixToMatch}`); - repos = repos.filter(name => name.startsWith(prefixToMatch)); - console.log(`Repos after filter:`); - console.log(repos.join('\n')); - - const parallelCount = 4; - const promises: Promise[] = []; - for (let i = 0; i < parallelCount; ++i) { - promises.push(cleanReposWorker(github, repos)); - } - await Promise.all(promises); -}; - -const cleanReposWorker = async (github: Octokit, repos: string[]) => { - while (repos.length > 0) { - const repoName = repos.shift() as string; - console.log(`Cleaning up ${repoOwner}/${repoName}`); - try { - await github.repos.delete({ owner: repoOwner, repo: repoName }); - } catch (e) { - console.log(`Failed to delete ${repoOwner}/${repoName}: ${e.message} ${e.stack}`); - } - } -}; - -// tslint:disable-next-line: no-floating-promises -cleanGithubTestRepos(); diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/index.ts b/tools/spec-gen-sdk/integrationTest/fixtures/index.ts deleted file mode 100644 index 476f86dcffa..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -export const fixtures = { - specTest: { - name: 'spec-test', - patch0_AddService: 'spec-test-patch0-add-service', - patch1_Add_02_01: 'spec-test-patch1-add-02-01', // Depends on patch0 - patch2_Empty: 'spec-test-patch2-empty-update', // Depends on patch0 - patch3_TwoReadme: 'spec-test-patch3-two-readme' - }, - sdkGo: { - name: 'sdk-go-test' - }, - sdkJs: { - name: 'sdk-js-test', - patch0_AddServiceGen: 'sdk-js-test-patch0-add-service-gen' // CodeGen result after spec patch0 - }, - sdkPy: { - name: 'sdk-py-test', - patch0_Track2: 'sdk-py-test-patch0-track2' // Track2 config - }, - sdkTf: { - name: 'sdk-tf-test' - }, - schmARM: { - name: 'schm-arm-test' - } -} as const; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/.gitignore b/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/.gitignore deleted file mode 100644 index 4b297a4f604..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -schemas/code-model-v1 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/schemas/common/definitions.json b/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/schemas/common/definitions.json deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/swagger_to_sdk_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/swagger_to_sdk_config.json deleted file mode 100644 index ae8776d6bcb..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/schm-arm-test/swagger_to_sdk_config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://openapistorageprod.blob.core.windows.net/sdkautomation/prod/schemas/swagger_to_sdk_config.schema.json", - "meta": { - "autorest_options": { - "use": "@autorest/azureresourceschema@3.0.79", - "azureresourceschema": "", - "multiapi": "", - "sdkrel:azureresourceschema-folder": ".", - "title": "none", - "pass-thru:subset-reducer": "" - }, - "advanced_options": { - "create_sdk_pull_requests": true, - "sdk_generation_pull_request_base": "integration_branch" - }, - "version": "0.2.0" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/.gitignore b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/.gitignore deleted file mode 100644 index bccadb649df..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -# *.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -*.zip - -# Editor swap files -*.swp -*~ -.DS_Store -.vscode - -# ignore vendor/ -vendor/ diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.lock b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.lock deleted file mode 100644 index ba530e8934e..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.lock +++ /dev/null @@ -1,427 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:6b1426cad7057b717351eacf5b6fe70f053f11aac1ce254bbf2fd72c031719eb" - name = "contrib.go.opencensus.io/exporter/ocagent" - packages = ["."] - pruneopts = "UT" - revision = "dcb33c7f3b7cfe67e8a2cea10207ede1b7c40764" - version = "v0.4.12" - -[[projects]] - digest = "1:a4431dd9598c9926ff12356c100ed73807815112de703322564f76d60c5294a4" - name = "github.com/Azure/go-autorest" - packages = [ - "autorest", - "autorest/adal", - "autorest/azure", - "autorest/azure/auth", - "autorest/azure/cli", - "autorest/date", - "autorest/to", - "autorest/validation", - "logger", - "tracing", - ] - pruneopts = "UT" - revision = "2913f263500c4a5b23dada1b46ccd22ac972315f" - version = "v12.3.0" - -[[projects]] - digest = "1:55388fd080150b9a072912f97b1f5891eb0b50df43401f8b75fb4273d3fec9fc" - name = "github.com/Masterminds/semver" - packages = ["."] - pruneopts = "UT" - revision = "c7af12943936e8c39859482e61f0574c2fd7fc75" - version = "v1.4.2" - -[[projects]] - digest = "1:8f5acd4d4462b5136af644d25101f0968a7a94ee90fcb2059cec5b7cc42e0b20" - name = "github.com/census-instrumentation/opencensus-proto" - packages = [ - "gen-go/agent/common/v1", - "gen-go/agent/metrics/v1", - "gen-go/agent/trace/v1", - "gen-go/metrics/v1", - "gen-go/resource/v1", - "gen-go/trace/v1", - ] - pruneopts = "UT" - revision = "d89fa54de508111353cb0b06403c00569be780d8" - version = "v0.2.1" - -[[projects]] - digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55" - name = "github.com/dgrijalva/jwt-go" - packages = ["."] - pruneopts = "UT" - revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" - version = "v3.2.0" - -[[projects]] - digest = "1:cf0d2e435fd4ce45b789e93ef24b5f08e86be0e9807a16beb3694e2d8c9af965" - name = "github.com/dimchansky/utfbom" - packages = ["."] - pruneopts = "UT" - revision = "d2133a1ce379ef6fa992b0514a77146c60db9d1c" - version = "v1.1.0" - -[[projects]] - branch = "master" - digest = "1:052aa482c25b2d76f432c16c4b404a6a3cb9cc205a95818c7680fcec501a43b7" - name = "github.com/dnaeon/go-vcr" - packages = [ - "cassette", - "recorder", - ] - pruneopts = "UT" - revision = "ac8906116758e03208f043a52754f16f2982f26d" - -[[projects]] - branch = "master" - digest = "1:78102ee4d536347316bc42e818340cc50902e45dbd7fdd524c5a1fc0cb07b588" - name = "github.com/globalsign/mgo" - packages = [ - ".", - "bson", - "internal/json", - "internal/sasl", - "internal/scram", - ] - pruneopts = "UT" - revision = "eeefdecb41b842af6dc652aaea4026e8403e62df" - -[[projects]] - digest = "1:b532ee3f683c057e797694b5bfeb3827d89e6adf41c53dbc80e549bca76364ea" - name = "github.com/golang/protobuf" - packages = [ - "jsonpb", - "proto", - "protoc-gen-go/descriptor", - "protoc-gen-go/generator", - "protoc-gen-go/generator/internal/remap", - "protoc-gen-go/plugin", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/struct", - "ptypes/timestamp", - "ptypes/wrappers", - ] - pruneopts = "UT" - revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7" - version = "v1.3.2" - -[[projects]] - digest = "1:3b341cd71012c63aacddabfc70b9110be8e30c553349552ad3f77242843f2d03" - name = "github.com/grpc-ecosystem/grpc-gateway" - packages = [ - "internal", - "runtime", - "utilities", - ] - pruneopts = "UT" - revision = "ad529a448ba494a88058f9e5be0988713174ac86" - version = "v1.9.5" - -[[projects]] - digest = "1:7fae9ec96d10b2afce0da23c378c8b3389319b7f92fa092f2621bba3078cfb4b" - name = "github.com/hashicorp/golang-lru" - packages = ["simplelru"] - pruneopts = "UT" - revision = "7f827b33c0f158ec5dfbba01bb0b14a4541fd81d" - version = "v0.5.3" - -[[projects]] - digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" - name = "github.com/inconshreveable/mousetrap" - packages = ["."] - pruneopts = "UT" - revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" - version = "v1.0" - -[[projects]] - digest = "1:ca955a9cd5b50b0f43d2cc3aeb35c951473eeca41b34eb67507f1dbcc0542394" - name = "github.com/kr/pretty" - packages = ["."] - pruneopts = "UT" - revision = "73f6ac0b30a98e433b289500d779f50c1a6f0712" - version = "v0.1.0" - -[[projects]] - digest = "1:15b5cc79aad436d47019f814fde81a10221c740dc8ddf769221a65097fb6c2e9" - name = "github.com/kr/text" - packages = ["."] - pruneopts = "UT" - revision = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f" - version = "v0.1.0" - -[[projects]] - digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79" - name = "github.com/mitchellh/go-homedir" - packages = ["."] - pruneopts = "UT" - revision = "af06845cf3004701891bf4fdb884bfe4920b3727" - version = "v1.1.0" - -[[projects]] - digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" - name = "github.com/pkg/errors" - packages = ["."] - pruneopts = "UT" - revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" - version = "v0.8.1" - -[[projects]] - digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925" - name = "github.com/satori/go.uuid" - packages = ["."] - pruneopts = "UT" - revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" - version = "v1.2.0" - -[[projects]] - digest = "1:81e02c4edb639c80559c0650f9401d3e2dcc3256d1fa215382bb7c83c1db9126" - name = "github.com/shopspring/decimal" - packages = ["."] - pruneopts = "UT" - revision = "cd690d0c9e2447b1ef2a129a6b7b49077da89b8e" - version = "1.1.0" - -[[projects]] - digest = "1:e096613fb7cf34743d49af87d197663cfccd61876e2219853005a57baedfa562" - name = "github.com/spf13/cobra" - packages = ["."] - pruneopts = "UT" - revision = "f2b07da1e2c38d5f12845a4f607e2e1018cbb1f5" - version = "v0.0.5" - -[[projects]] - digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" - name = "github.com/spf13/pflag" - packages = ["."] - pruneopts = "UT" - revision = "298182f68c66c05229eb03ac171abe6e309ee79a" - version = "v1.0.3" - -[[projects]] - digest = "1:4c93890bbbb5016505e856cb06b5c5a2ff5b7217584d33f2a9071ebef4b5d473" - name = "go.opencensus.io" - packages = [ - ".", - "internal", - "internal/tagencoding", - "metric/metricdata", - "metric/metricproducer", - "plugin/ocgrpc", - "plugin/ochttp", - "plugin/ochttp/propagation/b3", - "plugin/ochttp/propagation/tracecontext", - "resource", - "stats", - "stats/internal", - "stats/view", - "tag", - "trace", - "trace/internal", - "trace/propagation", - "trace/tracestate", - ] - pruneopts = "UT" - revision = "43463a80402d8447b7fce0d2c58edf1687ff0b58" - version = "v0.19.3" - -[[projects]] - branch = "master" - digest = "1:994c4915a59f821705d08ea77b117ec7a3e6a46cc867fd194d887500dac1c3c2" - name = "golang.org/x/crypto" - packages = [ - "pkcs12", - "pkcs12/internal/rc2", - ] - pruneopts = "UT" - revision = "4def268fd1a49955bfb3dda92fe3db4f924f2285" - -[[projects]] - branch = "master" - digest = "1:d2aa096fe6b539afe74dd6ab8e9a160304707f1477b01c637b4bbe20d262a25c" - name = "golang.org/x/net" - packages = [ - "context", - "http/httpguts", - "http2", - "http2/hpack", - "idna", - "internal/timeseries", - "trace", - ] - pruneopts = "UT" - revision = "ca1201d0de80cfde86cb01aea620983605dfe99b" - -[[projects]] - branch = "master" - digest = "1:382bb5a7fb4034db3b6a2d19e5a4a6bcf52f4750530603c01ca18a172fa3089b" - name = "golang.org/x/sync" - packages = ["semaphore"] - pruneopts = "UT" - revision = "112230192c580c3556b8cee6403af37a4fc5f28c" - -[[projects]] - branch = "master" - digest = "1:ec99dad7924bf972656818f5d62216fb987b7e077d401deb86b3c1e5e1b1d4d6" - name = "golang.org/x/sys" - packages = ["unix"] - pruneopts = "UT" - revision = "fc99dfbffb4e5ed5758a37e31dd861afe285406b" - -[[projects]] - digest = "1:8d8faad6b12a3a4c819a3f9618cb6ee1fa1cfc33253abeeea8b55336721e3405" - name = "golang.org/x/text" - packages = [ - "collate", - "collate/build", - "internal/colltab", - "internal/gen", - "internal/language", - "internal/language/compact", - "internal/tag", - "internal/triegen", - "internal/ucd", - "language", - "secure/bidirule", - "transform", - "unicode/bidi", - "unicode/cldr", - "unicode/norm", - "unicode/rangetable", - ] - pruneopts = "UT" - revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475" - version = "v0.3.2" - -[[projects]] - branch = "master" - digest = "1:87f3ab7c6341b1be840c580bdf23dcce036916bf1859e8ab8667033a09ae6097" - name = "golang.org/x/tools" - packages = [ - "go/ast/astutil", - "go/gcexportdata", - "go/internal/gcimporter", - "go/internal/packagesdriver", - "go/packages", - "go/types/typeutil", - "imports", - "internal/fastwalk", - "internal/gopathwalk", - "internal/imports", - "internal/module", - "internal/semver", - ] - pruneopts = "UT" - revision = "fc6e2057e7f6701ef9b5ef49a089bff4da7f4610" - -[[projects]] - digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643" - name = "google.golang.org/api" - packages = ["support/bundler"] - pruneopts = "UT" - revision = "02490b97dff7cfde1995bd77de808fd27053bc87" - version = "v0.7.0" - -[[projects]] - branch = "master" - digest = "1:3565a93b7692277a5dea355bc47bd6315754f3246ed07a224be6aec28972a805" - name = "google.golang.org/genproto" - packages = [ - "googleapis/api/httpbody", - "googleapis/rpc/status", - "protobuf/field_mask", - ] - pruneopts = "UT" - revision = "c506a9f9061087022822e8da603a52fc387115a8" - -[[projects]] - digest = "1:581c9b0fe9354faf730ff231cf3682089e0b703073cf10e3976219609d27a9ea" - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "binarylog/grpc_binarylog_v1", - "codes", - "connectivity", - "credentials", - "credentials/internal", - "encoding", - "encoding/proto", - "grpclog", - "internal", - "internal/backoff", - "internal/balancerload", - "internal/binarylog", - "internal/channelz", - "internal/envconfig", - "internal/grpcrand", - "internal/grpcsync", - "internal/syscall", - "internal/transport", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "serviceconfig", - "stats", - "status", - "tap", - ] - pruneopts = "UT" - revision = "045159ad57f3781d409358e3ade910a018c16b30" - version = "v1.22.1" - -[[projects]] - branch = "v1" - digest = "1:af715ae33cc1f5695c4b2a4e4b21d008add8802a99e15bb467ac7c32edb5000d" - name = "gopkg.in/check.v1" - packages = ["."] - pruneopts = "UT" - revision = "788fd78401277ebd861206a03c884797c6ec5541" - -[[projects]] - digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" - name = "gopkg.in/yaml.v2" - packages = ["."] - pruneopts = "UT" - revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" - version = "v2.2.2" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/Azure/go-autorest/autorest", - "github.com/Azure/go-autorest/autorest/adal", - "github.com/Azure/go-autorest/autorest/azure", - "github.com/Azure/go-autorest/autorest/azure/auth", - "github.com/Azure/go-autorest/autorest/date", - "github.com/Azure/go-autorest/autorest/to", - "github.com/Azure/go-autorest/autorest/validation", - "github.com/Azure/go-autorest/tracing", - "github.com/Masterminds/semver", - "github.com/dnaeon/go-vcr/cassette", - "github.com/dnaeon/go-vcr/recorder", - "github.com/globalsign/mgo", - "github.com/pkg/errors", - "github.com/satori/go.uuid", - "github.com/shopspring/decimal", - "github.com/spf13/cobra", - "golang.org/x/crypto/pkcs12", - "golang.org/x/tools/imports", - "gopkg.in/check.v1", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.toml b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.toml deleted file mode 100644 index d418e65a101..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/Gopkg.toml +++ /dev/null @@ -1,56 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - -[prune] - unused-packages = true - go-tests = true - -[[constraint]] - name = "github.com/Azure/go-autorest" - version = "12.3.0" - -[[constraint]] - branch = "master" - name = "github.com/dnaeon/go-vcr" - -[[constraint]] - branch = "master" - name = "github.com/globalsign/mgo" - -[[constraint]] - name = "github.com/satori/go.uuid" - version = "1.2.0" - -[[constraint]] - name = "github.com/shopspring/decimal" - version = "1.0.0" - -[[constraint]] - branch = "master" - name = "golang.org/x/crypto" - -[[constraint]] - branch = "master" - name = "golang.org/x/tools" - -[[constraint]] - branch = "v1" - name = "gopkg.in/check.v1" diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/swagger_to_sdk_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/swagger_to_sdk_config.json deleted file mode 100644 index 377fede6beb..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-go-test/swagger_to_sdk_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://openapistorageprod.blob.core.windows.net/sdkautomation/prod/schemas/swagger_to_sdk_config.schema.json", - "meta": { - "after_scripts_in_repo": ["gofmt -w ./services/"], - "autorest_options": { - "use": "@microsoft.azure/autorest.go@2.1.137", - "version": "2.0.4407", - "go": "", - "verbose": "", - "sdkrel:go-sdk-folder": ".", - "multiapi": "", - "preview-chk": "", - "go.clear-output-folder": false, - "stage": "", - "gomod-root": "github.com/Azure/azure-sdk-for-go" - }, - "repotag": "azure-sdk-for-go", - "envs": { - "sdkrel:GOPATH": "../../../.." - }, - "advanced_options": { - "clone_dir": "./src/github.com/Azure/azure-sdk-for-go", - "sdk_generation_pull_request_base": "integration_branch", - "create_sdk_pull_requests": true - }, - "version": "0.2.0" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/LICENSE.txt b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/LICENSE.txt deleted file mode 100644 index e611c1979e3..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2020 Microsoft - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/README.md b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/README.md deleted file mode 100644 index b8494358595..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/README.md +++ /dev/null @@ -1,99 +0,0 @@ -## Azure TestServiceClient SDK for JavaScript - -This package contains an isomorphic SDK for TestServiceClient. - -### Currently supported environments - -- Node.js version 6.x.x or higher -- Browser JavaScript - -### How to Install - -```bash -npm install @azure/test-service -``` - -### How to use - -#### nodejs - Authentication, client creation and get test as an example written in TypeScript. - -##### Install @azure/ms-rest-nodeauth - -- Please install minimum version of `"@azure/ms-rest-nodeauth": "^3.0.0"`. -```bash -npm install @azure/ms-rest-nodeauth@"^3.0.0" -``` - -##### Sample code - -```typescript -import * as msRest from "@azure/ms-rest-js"; -import * as msRestAzure from "@azure/ms-rest-azure-js"; -import * as msRestNodeAuth from "@azure/ms-rest-nodeauth"; -import { TestServiceClient, TestServiceModels, TestServiceMappers } from "@azure/test-service"; -const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"]; - -msRestNodeAuth.interactiveLogin().then((creds) => { - const client = new TestServiceClient(creds, subscriptionId); - client.test.get().then((result) => { - console.log("The result is:"); - console.log(result); - }); -}).catch((err) => { - console.error(err); -}); -``` - -#### browser - Authentication, client creation and get test as an example written in JavaScript. - -##### Install @azure/ms-rest-browserauth - -```bash -npm install @azure/ms-rest-browserauth -``` - -##### Sample code - -See https://github.com/Azure/ms-rest-browserauth to learn how to authenticate to Azure in the browser. - -- index.html -```html - - - - @azure/test-service sample - - - - - - - - -``` - -## Related projects - -- [Microsoft Azure SDK for Javascript](https://github.com/Azure/azure-sdk-for-js) - -![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js/sdk/README.png) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/rollup.config.js b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/rollup.config.js deleted file mode 100644 index e2015cce051..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/rollup.config.js +++ /dev/null @@ -1,37 +0,0 @@ -import rollup from "rollup"; -import nodeResolve from "rollup-plugin-node-resolve"; -import sourcemaps from "rollup-plugin-sourcemaps"; - -/** - * @type {rollup.RollupFileOptions} - */ -const config = { - input: "./esm/testServiceClient.js", - external: [ - "@azure/ms-rest-js", - "@azure/ms-rest-azure-js" - ], - output: { - file: "./dist/test-service.js", - format: "umd", - name: "Azure.TestService", - sourcemap: true, - globals: { - "@azure/ms-rest-js": "msRest", - "@azure/ms-rest-azure-js": "msRestAzure" - }, - banner: `/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */` - }, - plugins: [ - nodeResolve({ mainFields: ['module', 'main'] }), - sourcemaps() - ] -}; - -export default config; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/index.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/index.ts deleted file mode 100644 index 59f3673efba..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -import { BaseResource, CloudError, AzureServiceClientOptions } from "@azure/ms-rest-azure-js"; -import * as msRest from "@azure/ms-rest-js"; - -export { BaseResource, CloudError }; - -/** - * Mocked result. - * @summary Test Get. - */ -export interface TestGetResult { - /** - * Test result. Test result. - */ - value?: string; -} - -/** - * An interface representing TestServiceClientOptions. - */ -export interface TestServiceClientOptions extends AzureServiceClientOptions { - baseUri?: string; -} - -/** - * Contains response data for the get operation. - */ -export type TestGetResponse = TestGetResult & { - /** - * The underlying HTTP response. - */ - _response: msRest.HttpResponse & { - /** - * The response body as text (string format) - */ - bodyAsText: string; - - /** - * The response body as parsed JSON or XML - */ - parsedBody: TestGetResult; - }; -}; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/mappers.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/mappers.ts deleted file mode 100644 index 019da829c92..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/mappers.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -import { CloudErrorMapper, BaseResourceMapper } from "@azure/ms-rest-azure-js"; -import * as msRest from "@azure/ms-rest-js"; - -export const CloudError = CloudErrorMapper; -export const BaseResource = BaseResourceMapper; - -export const TestGetResult: msRest.CompositeMapper = { - serializedName: "TestGetResult", - type: { - name: "Composite", - className: "TestGetResult", - modelProperties: { - value: { - serializedName: "value", - type: { - name: "String" - } - } - } - } -}; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/parameters.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/parameters.ts deleted file mode 100644 index 0d109216640..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/parameters.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is - * regenerated. - */ - -import * as msRest from "@azure/ms-rest-js"; - -export const acceptLanguage: msRest.OperationParameter = { - parameterPath: "acceptLanguage", - mapper: { - serializedName: "accept-language", - defaultValue: 'en-US', - type: { - name: "String" - } - } -}; -export const apiVersion: msRest.OperationQueryParameter = { - parameterPath: "apiVersion", - mapper: { - required: true, - serializedName: "api-version", - type: { - name: "String" - } - } -}; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/testMappers.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/testMappers.ts deleted file mode 100644 index 5528580bc4e..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/models/testMappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -export { - CloudError, - TestGetResult -} from "../models/mappers"; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/index.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/index.ts deleted file mode 100644 index 1fdfd80232c..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is - * regenerated. - */ - -export * from "./test"; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/test.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/test.ts deleted file mode 100644 index 84fb7cae6f7..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/operations/test.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is - * regenerated. - */ - -import * as msRest from "@azure/ms-rest-js"; -import * as Models from "../models"; -import * as Mappers from "../models/testMappers"; -import * as Parameters from "../models/parameters"; -import { TestServiceClientContext } from "../testServiceClientContext"; - -/** Class representing a Test. */ -export class Test { - private readonly client: TestServiceClientContext; - - /** - * Create a Test. - * @param {TestServiceClientContext} client Reference to the service client. - */ - constructor(client: TestServiceClientContext) { - this.client = client; - } - - /** - * Get test. - * @param [options] The optional parameters - * @returns Promise - */ - get(options?: msRest.RequestOptionsBase): Promise; - /** - * @param callback The callback - */ - get(callback: msRest.ServiceCallback): void; - /** - * @param options The optional parameters - * @param callback The callback - */ - get(options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; - get(options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { - return this.client.sendOperationRequest( - { - options - }, - getOperationSpec, - callback) as Promise; - } -} - -// Operation Specifications -const serializer = new msRest.Serializer(Mappers); -const getOperationSpec: msRest.OperationSpec = { - httpMethod: "GET", - path: "providers/Microsoft.TestService/test", - queryParameters: [ - Parameters.apiVersion - ], - headerParameters: [ - Parameters.acceptLanguage - ], - responses: { - 200: { - bodyMapper: Mappers.TestGetResult - }, - default: { - bodyMapper: Mappers.CloudError - } - }, - serializer -}; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClient.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClient.ts deleted file mode 100644 index 49fe923e7c7..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClient.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is - * regenerated. - */ - -import * as msRest from "@azure/ms-rest-js"; -import * as Models from "./models"; -import * as Mappers from "./models/mappers"; -import * as operations from "./operations"; -import { TestServiceClientContext } from "./testServiceClientContext"; - - -class TestServiceClient extends TestServiceClientContext { - // Operation groups - test: operations.Test; - - /** - * Initializes a new instance of the TestServiceClient class. - * @param credentials Credentials needed for the client to connect to Azure. - * @param [options] The parameter options - */ - constructor(credentials: msRest.ServiceClientCredentials, options?: Models.TestServiceClientOptions) { - super(credentials, options); - this.test = new operations.Test(this); - } -} - -// Operation Specifications - -export { - TestServiceClient, - TestServiceClientContext, - Models as TestServiceModels, - Mappers as TestServiceMappers -}; -export * from "./operations"; diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClientContext.ts b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClientContext.ts deleted file mode 100644 index 5e8eb39a0f6..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/src/testServiceClientContext.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is - * regenerated. - */ - -import * as Models from "./models"; -import * as msRest from "@azure/ms-rest-js"; -import * as msRestAzure from "@azure/ms-rest-azure-js"; - -const packageName = "@azure/test-service"; -const packageVersion = "1.0.0"; - -export class TestServiceClientContext extends msRestAzure.AzureServiceClient { - credentials: msRest.ServiceClientCredentials; - apiVersion?: string; - - /** - * Initializes a new instance of the TestServiceClient class. - * @param credentials Credentials needed for the client to connect to Azure. - * @param [options] The parameter options - */ - constructor(credentials: msRest.ServiceClientCredentials, options?: Models.TestServiceClientOptions) { - if (credentials == undefined) { - throw new Error('\'credentials\' cannot be null.'); - } - - if (!options) { - options = {}; - } - if(!options.userAgent) { - const defaultUserAgent = msRestAzure.getDefaultUserAgentValue(); - options.userAgent = `${packageName}/${packageVersion} ${defaultUserAgent}`; - } - - super(credentials, options); - - this.apiVersion = '2020-01-01'; - this.acceptLanguage = 'en-US'; - this.longRunningOperationRetryTimeout = 30; - this.baseUri = options.baseUri || this.baseUri || "https://management.azure.com"; - this.requestContentType = "application/json; charset=utf-8"; - this.credentials = credentials; - - if(options.acceptLanguage !== null && options.acceptLanguage !== undefined) { - this.acceptLanguage = options.acceptLanguage; - } - if(options.longRunningOperationRetryTimeout !== null && options.longRunningOperationRetryTimeout !== undefined) { - this.longRunningOperationRetryTimeout = options.longRunningOperationRetryTimeout; - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/tsconfig.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/tsconfig.json deleted file mode 100644 index 422b584abd5..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test-patch0-add-service-gen/sdk/testservice/arm-testservice/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "es6", - "moduleResolution": "node", - "strict": true, - "target": "es5", - "sourceMap": true, - "declarationMap": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "lib": ["es6", "dom"], - "declaration": true, - "outDir": "./esm", - "importHelpers": true - }, - "include": ["./src/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test/swagger_to_sdk_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test/swagger_to_sdk_config.json deleted file mode 100644 index f9f937c179d..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-js-test/swagger_to_sdk_config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "meta": { - "autorest_options": { - "version": "V2", - "typescript": "", - "license-header": "MICROSOFT_MIT_NO_VERSION", - "sdkrel:typescript-sdks-folder": ".", - "use": "@microsoft.azure/autorest.typescript@4.4.4" - }, - "advanced_options": { - "create_sdk_pull_requests": true, - "sdk_generation_pull_request_base": "integration_branch" - }, - "version": "0.2.0" - }, - "advancedOptions": { - "generationCallMode": "one-per-config" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test-patch0-track2/swagger_to_sdk_custom_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test-patch0-track2/swagger_to_sdk_custom_config.json deleted file mode 100644 index 3dc7aabbdb5..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test-patch0-track2/swagger_to_sdk_custom_config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://openapistorageprod.blob.core.windows.net/sdkautomation/prod/schemas/swagger_to_sdk_config.schema.json", - "meta": { - "autorest_options": { - "use": "@autorest/python@5.3.0", - "python": "", - "python-mode": "update", - "sdkrel:python-sdks-folder": "./sdk/.", - "multiapi": "", - "track2": "" - }, - "advanced_options": { - "create_sdk_pull_requests": true, - "sdk_generation_pull_request_base": "integration_branch" - }, - "repotag": "azure-sdk-for-python", - "version": "0.2.0" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/.gitignore b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/.gitignore deleted file mode 100644 index d357979f797..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/.gitignore +++ /dev/null @@ -1,99 +0,0 @@ -# Python cache -__pycache__/ -*.pyc -.pytest_cache -.mypy_cache -.cache - -# Virtual environment -env*/ - -# PTVS analysis -.ptvs/ - -# Coverage report -**/.coverage -_coverage - -# Build results -bin/ -obj/ -dist/ -MANIFEST -_docs - -# Result of running python setup.py install/pip install -e -RECORD.txt -build/ -*.egg-info/ -.tox_pip_cache*/ - -# Test results -TestResults/ - -# tox generated artifacts -test-junit-*.xml -pylint-*.out.txt -coverage-*.xml -stderr.txt -stdout.txt - -# tox environment folders -.tox/ - -# Credentials -credentials_real.json -testsettings_local.json -testsettings_local.cfg -servicebus_settings_real.py -storage_settings_real.py -legacy_mgmt_settings_real.py -mgmt_settings_real.py -app_creds_real.py - -# User-specific files -*.suo -*.user -*.sln.docstates -.vs/ -.vscode/ - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac desktop service store files -.DS_Store - -.idea -src/build -*.iml -/doc/_build -/doc/sphinx/examples -/doc/sphinx/tests -/.vs/config/applicationhost.config - -# Azure deployment credentials -*.pubxml - -# [begoldsm] ignore virtual env if it exists. -adlEnv/ - -code_reports - -# Azure Storage test credentials -sdk/storage/azure-storage-blob/tests/settings_real.py -sdk/storage/azure-storage-queue/tests/settings_real.py -sdk/storage/azure-storage-file-share/tests/settings_real.py -sdk/storage/azure-storage-file-datalake/tests/settings_real.py -*.code-workspace -sdk/cosmos/azure-cosmos/test/test_config.py - -# temp path to to run regression test -.tmp_code_path/ \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/build_package.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/build_package.py deleted file mode 100644 index cb0064c33d7..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/build_package.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python - -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -#-------------------------------------------------------------------------- - -import argparse -import os -import glob -from subprocess import check_call - - -DEFAULT_DEST_FOLDER = "./dist" - -def create_package(name, dest_folder=DEFAULT_DEST_FOLDER): - # a package will exist in either one, or the other folder. this is why we can resolve both at the same time. - absdirs = [os.path.dirname(package) for package in (glob.glob('{}/setup.py'.format(name)) + glob.glob('sdk/*/{}/setup.py'.format(name)))] - - absdirpath = os.path.abspath(absdirs[0]) - check_call(['python', 'setup.py', 'bdist_wheel', '-d', dest_folder], cwd=absdirpath) - check_call(['python', 'setup.py', "sdist", "--format", "zip", '-d', dest_folder], cwd=absdirpath) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Build Azure package.') - parser.add_argument('name', help='The package name') - parser.add_argument('--dest', '-d', default=DEFAULT_DEST_FOLDER, - help='Destination folder. Relative to the package dir. [default: %(default)s]') - - args = parser.parse_args() - create_package(args.name, args.dest) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/analyze_deps.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/analyze_deps.py deleted file mode 100755 index 1425eed6371..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/analyze_deps.py +++ /dev/null @@ -1,417 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function, unicode_literals -import argparse -import ast -from datetime import datetime -import glob -import io -import json -import os -from pkg_resources import Requirement -import re -import sys -import textwrap - -# Todo: This should use a common omit logic once ci scripts are refactored into ci_tools -skip_pkgs = [ - 'azure-mgmt-documentdb', # deprecated - 'azure-sdk-for-python', # top-level package - 'azure-sdk-tools', # internal tooling for automation - 'azure-servicemanagement-legacy', # legacy (not officially deprecated) - 'azure-common', - 'azure', - 'azure-keyvault' -] - -def report_should_skip_lib(lib_name): - return lib_name in skip_pkgs or lib_name.endswith('-nspkg') - -def dump_should_skip_lib(lib_name): - return report_should_skip_lib(lib_name) or '-mgmt' in lib_name or not lib_name.startswith('azure') - -def locate_libs(base_dir): - packages = [os.path.dirname(p) for p in (glob.glob(os.path.join(base_dir, 'azure*', 'setup.py')) + glob.glob(os.path.join(base_dir, 'sdk/*/azure*', 'setup.py')))] - return sorted(packages) - -def locate_wheels(base_dir): - wheels = glob.glob(os.path.join(base_dir, '*.whl')) - return sorted(wheels) - -def parse_req(req): - try: - req_object = Requirement.parse(req) - req_name = req_object.key - spec = str(req_object).replace(req_name, '') - return (req_name, spec) - except: - print('Failed to parse requirement %s' % (req)) - -def record_dep(dependencies, req_name, spec, lib_name): - if not req_name in dependencies: - dependencies[req_name] = {} - if not spec in dependencies[req_name]: - dependencies[req_name][spec] = [] - dependencies[req_name][spec].append(lib_name) - - -def get_lib_deps(base_dir): - packages = {} - dependencies = {} - for lib_dir in locate_libs(base_dir): - try: - setup_path = os.path.join(lib_dir, 'setup.py') - lib_name, version, requires = parse_setup(setup_path) - - packages[lib_name] = { - 'version': version, - 'source': lib_dir, - 'deps': [] - } - - for req in requires: - req_name, spec = parse_req(req) - packages[lib_name]['deps'].append({ - 'name': req_name, - 'version': spec - }) - if not report_should_skip_lib(lib_name): - record_dep(dependencies, req_name, spec, lib_name) - except: - print('Failed to parse %s' % (setup_path)) - return packages, dependencies - -def get_wheel_deps(wheel_dir): - from wheel.pkginfo import read_pkg_info_bytes - from wheel.wheelfile import WheelFile - - packages = {} - dependencies = {} - for whl_path in locate_wheels(wheel_dir): - try: - with WheelFile(whl_path) as whl: - pkg_info = read_pkg_info_bytes(whl.read(whl.dist_info_path + '/METADATA')) - lib_name = pkg_info.get('Name') - - packages[lib_name] = { - 'version': pkg_info.get('Version'), - 'source': whl_path, - 'deps': [] - } - - requires = pkg_info.get_all('Requires-Dist') - for req in requires: - req = req.split(';')[0] # Extras conditions appear after a semicolon - req = re.sub(r'[\s\(\)]', '', req) # Version specifiers appear in parentheses - req_name, spec = parse_req(req) - packages[lib_name]['deps'].append({ - 'name': req_name, - 'version': spec - }) - if not report_should_skip_lib(lib_name): - record_dep(dependencies, req_name, spec, lib_name) - except: - print('Failed to parse METADATA from %s' % (whl_path)) - return packages, dependencies - -def parse_setup(setup_filename): - mock_setup = textwrap.dedent('''\ - def setup(*args, **kwargs): - __setup_calls__.append((args, kwargs)) - ''') - parsed_mock_setup = ast.parse(mock_setup, filename=setup_filename) - with io.open(setup_filename, 'r', encoding='utf-8-sig') as setup_file: - parsed = ast.parse(setup_file.read()) - for index, node in enumerate(parsed.body[:]): - if ( - not isinstance(node, ast.Expr) or - not isinstance(node.value, ast.Call) or - not hasattr(node.value.func, 'id') or - node.value.func.id != 'setup' - ): - continue - parsed.body[index:index] = parsed_mock_setup.body - break - - fixed = ast.fix_missing_locations(parsed) - codeobj = compile(fixed, setup_filename, 'exec') - local_vars = {} - global_vars = {'__setup_calls__': []} - current_dir = os.getcwd() - working_dir = os.path.dirname(setup_filename) - os.chdir(working_dir) - exec(codeobj, global_vars, local_vars) - os.chdir(current_dir) - _, kwargs = global_vars['__setup_calls__'][0] - - version = kwargs['version'] - name = kwargs['name'] - requires = [] - if 'install_requires' in kwargs: - requires += kwargs['install_requires'] - if 'extras_require' in kwargs: - for extra in kwargs['extras_require'].values(): - requires += extra - return name, version, requires - -def dict_compare(d1, d2): - d1_keys = set(d1.keys()) - d2_keys = set(d2.keys()) - intersect_keys = d1_keys.intersection(d2_keys) - added = d1_keys - d2_keys - removed = d2_keys - d1_keys - modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]} - return added, removed, modified - -def render_report(output_path, report_context): - env = Environment( - loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))) - ) - template = env.get_template('deps.html.j2') - with io.open(output_path, 'w', encoding='utf-8') as output: - output.write(template.render(report_context)) - -def get_dependent_packages(data_pkgs): - # Get unique set of Azure SDK packages that are added as required package - deps = [] - for v in data_pkgs.values(): - deps.extend([dep['name'] for dep in v['deps'] if not dump_should_skip_lib(dep['name'])]) - return set(deps) - -def dump_packages(data_pkgs): - dump_data = {} - unique_dependent_packages = get_dependent_packages(data_pkgs) - for p_name, p_data in data_pkgs.items(): - p_id = p_name + ':' + p_data['version'] - dep = [p for p in p_data['deps'] if not dump_should_skip_lib(p['name'])] - # Add package if it requires other azure sdk package or if it is added as required by other sdk package - if len(dep) > 0 or p_name in unique_dependent_packages: - dump_data[p_id] = { - 'name': p_name, - 'version': p_data['version'], - 'type': 'internal', - 'deps': dep - } - - return dump_data - -def resolve_lib_deps(dump_data, data_pkgs, pkg_id): - for dep in dump_data[pkg_id]['deps']: - dep_req = Requirement.parse(dep['name'] + dep['version']) - if dep['name'] in data_pkgs and data_pkgs[dep['name']]['version'] in dep_req: - # If the internal package version matches the dependency spec, - # rewrite the dep version to match the internal package version - dep['version'] = data_pkgs[dep['name']]['version'] - else: - dep_id = dep['name'] + ':' + dep['version'] - if not dep_id in dump_data: - dump_data[dep_id] = { - 'name': dep['name'], - 'version': dep['version'], - 'type': 'internalbinary' if dep['name'] in data_pkgs else 'external', - 'deps': [] - } - -if __name__ == '__main__': - base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - - parser = argparse.ArgumentParser(description='''\ - Analyze dependencies in Python packages. First, all declared dependencies - and the libraries that declare them will be discovered (visible with - --verbose). Next, all declared dependency version specs will be analyzed to - ensure they are consistent across all libraries. Finally, all declared - dependency version specs will be compared to the frozen version specs in - shared_requirements.txt, or if --freeze is provided, all declared dependency - version specs will be frozen to shared_requirements.txt. - ''') - parser.add_argument('--verbose', help='verbose output', action='store_true') - parser.add_argument('--freeze', help='freeze dependencies after analyzing (otherwise, validate dependencies against frozen list)', action='store_true') - parser.add_argument('--out', metavar='FILE', help='write HTML-formatted report to FILE') - parser.add_argument('--dump', metavar='FILE', help='write JSONP-formatted dependency data to FILE') - parser.add_argument('--wheeldir', metavar='DIR', help='analyze wheels in DIR rather than source packages in this repository') - args = parser.parse_args() - - if args.out: - try: - from jinja2 import Environment, FileSystemLoader - except: - print("Jinja2 is required to render the dependency report. Please install with 'pip install Jinja2' to use this option.") - sys.exit(1) - - if args.wheeldir: - all_packages, dependencies = get_wheel_deps(args.wheeldir) - else: - all_packages, dependencies = get_lib_deps(base_dir) - - packages = {k: v for k,v in all_packages.items() if not report_should_skip_lib(k)} - - if args.verbose: - print('Packages analyzed') - print('=================') - for package in sorted(packages.keys()): - info = packages[package] - print("%s %s" % (package, info['version'])) - print(" from %s" % (info['source'])) - - print('\n\nRequirements discovered') - print('=======================') - for requirement in sorted(dependencies.keys()): - specs = dependencies[requirement] - libs = [] - print('%s' % (requirement)) - for spec in specs.keys(): - print('%s' % (spec if spec else '(empty)')) - for lib in specs[spec]: - print(' * %s' % (lib)) - print('') - - inconsistent = [] - for requirement in sorted(dependencies.keys()): - specs = dependencies[requirement] - num_specs = len(specs) - if num_specs == 1: - continue - - if not inconsistent and args.verbose: - print('\nInconsistencies detected') - print('========================') - - inconsistent.append(requirement) - if args.verbose: - print("Requirement '%s' has %s unique specifiers:" % (requirement, num_specs)) - for spec in sorted(specs.keys()): - libs = specs[spec] - friendly_spec = '(none)' if spec == '' else spec - print(" '%s'" % (friendly_spec)) - print(' ' + ('-' * (len(friendly_spec) + 2))) - for lib in sorted(libs): - print(' * %s' % (lib)) - print('') - - frozen_filename = os.path.join(base_dir, 'shared_requirements.txt') - if args.freeze: - if inconsistent: - print('Unable to freeze requirements due to incompatible dependency versions') - sys.exit(1) - else: - with io.open(frozen_filename, 'w', encoding='utf-8') as frozen_file: - for requirement in sorted(dependencies.keys()): - spec = list(dependencies[requirement].keys())[0] - if spec == '': - print("Requirement '%s' being frozen with no version spec" % requirement) - frozen_file.write(requirement + spec + '\n') - print('Current requirements frozen to %s' % (frozen_filename)) - sys.exit(0) - - frozen = {} - overrides = {} - override_count = 0 - try: - with io.open(frozen_filename, 'r', encoding='utf-8-sig') as frozen_file: - for line in frozen_file: - if line.startswith('#override'): - _, lib_name, req_override = line.split(' ', 2) - req_override_name, override_spec = parse_req(req_override) - record_dep(overrides, req_override_name, override_spec, lib_name) - override_count += 1 - elif not line.startswith('#'): - req_name, spec = parse_req(line) - frozen[req_name] = [spec] - except: - print('Unable to open shared_requirements.txt, shared requirements have not been validated') - - missing_reqs, new_reqs, changed_reqs = {}, {}, {} - non_overridden_reqs_count = 0 - exitcode = 0 - if frozen: - flat_deps = {req: sorted(dependencies[req].keys()) for req in dependencies} - missing_reqs, new_reqs, changed_reqs = dict_compare(frozen, flat_deps) - if args.verbose and len(overrides) > 0: - print('\nThe following requirement overrides are in place:') - for overridden_req in overrides: - for spec in overrides[overridden_req]: - libs = ', '.join(sorted(overrides[overridden_req][spec])) - print(' * %s is allowed for %s' % (overridden_req + spec, libs)) - if args.verbose and len(missing_reqs) > 0: - print('\nThe following requirements are frozen but do not exist in any current library:') - for missing_req in missing_reqs: - [spec] = frozen[missing_req] - print(' * %s' % (missing_req + spec)) - if len(new_reqs) > 0: - exitcode = 1 - if args.verbose: - for new_req in new_reqs: - for spec in dependencies[new_req]: - libs = dependencies[new_req][spec] - print("\nRequirement '%s' is declared in the following libraries but has not been frozen:" % (new_req + spec)) - for lib in libs: - print(" * %s" % (lib)) - if len(changed_reqs) > 0: - for changed_req in changed_reqs: - frozen_specs, current_specs = changed_reqs[changed_req] - unmatched_specs = set(current_specs) - set(frozen_specs) - override_specs = overrides.get(changed_req, []) - - for spec in unmatched_specs: - if spec in override_specs: - non_overridden_libs = set(dependencies[changed_req][spec]) - set(override_specs[spec]) - else: - non_overridden_libs = dependencies[changed_req][spec] - - if len(non_overridden_libs) > 0: - exitcode = 1 - non_overridden_reqs_count += 1 - if args.verbose: - print("\nThe following libraries declare requirement '%s' which does not match the frozen requirement '%s':" % (changed_req + spec, changed_req + frozen_specs[0])) - for lib in non_overridden_libs: - print(" * %s" % (lib)) - if exitcode == 0: - if args.verbose: - print('') - print('All library dependencies validated against frozen requirements') - elif not args.verbose: - print('Library dependencies do not match frozen requirements, run this script with --verbose for details') - elif inconsistent: - exitcode = 1 - - if exitcode == 1: - if not args.verbose: - print('\nIncompatible dependency versions detected in libraries, run this script with --verbose for details') - else: - print('\nAll library dependencies verified, no incompatible versions detected') - - if args.out: - external = [k for k in dependencies if k not in packages and not report_should_skip_lib(k)] - def display_order(k): - if k in inconsistent: - return 'a' + k if k in external else 'b' + k - else: - return 'c' + k if k in external else 'd' + k - - render_report(args.out, { - 'changed_reqs': changed_reqs, - 'curtime': datetime.utcnow(), - 'dependencies': dependencies, - 'env': os.environ, - 'external': external, - 'frozen': frozen, - 'inconsistent': inconsistent, - 'missing_reqs': missing_reqs, - 'new_reqs': new_reqs, - 'non_overridden_reqs_count': non_overridden_reqs_count, - 'ordered_deps': sorted(dependencies.keys(), key=display_order), - 'override_count': override_count, - 'overrides': overrides, - 'packages': packages, - 'repo_name': 'azure-sdk-for-python' - }) - - if args.dump: - data_pkgs = {k: v for k, v in all_packages.items() if not dump_should_skip_lib(k)} - dump_data = dump_packages(data_pkgs) - pkg_ids = [k for k in dump_data.keys()] - for pkg_id in pkg_ids: - resolve_lib_deps(dump_data, data_pkgs, pkg_id) - with io.open(args.dump, 'w', encoding='utf-8') as dump_file: - dump_file.write('const data = ' + json.dumps(dump_data) + ';') - - sys.exit(exitcode) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/deps.html.j2 b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/deps.html.j2 deleted file mode 100644 index 26ad9a21edd..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/deps.html.j2 +++ /dev/null @@ -1,284 +0,0 @@ -{% set branch = env.get('SYSTEM_PULLREQUEST_SOURCEBRANCH') if env.get('SYSTEM_PULLREQUEST_SOURCEBRANCH') else env.get('BUILD_SOURCEBRANCHNAME') %} -{% set build = env.get('BUILD_BUILDNUMBER') %} -{% set build_url = '%s%s/_build/results?buildId=%s' % (env.get('SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'), env.get('SYSTEM_TEAMPROJECT'), env.get('BUILD_BUILDID')) %} -{% set commit = env.get('BUILD_SOURCEVERSION') %} -{% set isfork = env.get('SYSTEM_PULLREQUEST_ISFORK') == 'True' %} -{% set rel_url = env.get('RELEASE_RELEASEWEBURL') %} -{% set release = env.get('RELEASE_RELEASENAME') %} -{% set repo = env.get('BUILD_REPOSITORY_NAME') if isfork else ('Azure/' + repo_name) %} -{% macro pluralize(num, singular, plural) -%} -{% if num == 1 %}{{ singular }}{% else %}{{ plural }}{% endif %} -{%- endmacro %} - - - - {{ repo_name|capitalize }} Dependency Report - - - - -
-

{{ repo_name|capitalize }} Dependency Report

-

- Generated at {{ curtime.replace(microsecond=0).isoformat() }}Z - {% if release %} - for release {{ release }} - {% elif build %} - for build {{ build }} - {% if branch %} -
from branch {{ branch }} - {% if isfork %} - in repo {{ repo }} - {% endif %} - {% endif %} - {% if commit %} - ({{ commit[:7] }}) - {% endif %} - {% endif %} -

-

- {{ dependencies|length - external|length }} internal and {{ external|length }} external package {{ pluralize(dependencies|length,'dependency was','dependencies were') }} analyzed to determine if any packages declare inconsistent dependency versions.
- {% if inconsistent %} - {{ inconsistent|length }} inconsistent package dependency {{ pluralize(inconsistent|length,'version was','versions were') }} discovered.

- {% else %} - No inconsistent package dependency versions were discovered.

- {% endif %} - {% if frozen %} - {{ frozen|length }} dependency {{ pluralize(frozen|length,'version was','versions were') }} discovered in the lockfile.
- {% if override_count %} - {{ override_count }} dependency version {{ pluralize(override_count,'override is','overrides are') }} present, causing dependency versions to differ from the version in the lockfile.
- {% endif %} - {% if new_reqs %} - {{ new_reqs|length }} {{ pluralize(new_reqs|length,'dependency is','dependencies are') }} missing from the lockfile.
- {% endif %} - {% if non_overridden_reqs_count %} - {{ non_overridden_reqs_count }} dependency {{ pluralize(non_overridden_reqs_count,'version does','versions do') }} not match the version in the lockfile.
- {% endif %} - {% if not new_reqs and not non_overridden_reqs_count %} - All declared dependency versions were validated against those in the lockfile.
- {% endif %} - {% else %} - No lockfile is present in the repo, declared dependency versions were not able to be validated.
- {% endif %} -
This report scanned {{ packages|length }} {{ pluralize(packages|length,'package','packages') }}. -

- - {% for dep_name in ordered_deps %} - - - - {% if loop.index == 1 %} - - {% endif %} - - {% if dep_name in external %} - {% set dep_type = "external" %} - {% else %} - {% set dep_type = "internal" %} - {% endif %} - {% if dep_name in inconsistent %} - {% set dep_type = "inconsistent " + dep_type %} - {% endif %} - - - - {% for requirement, packages in dependencies[dep_name]|dictsort %} - - - - - {% endfor %} - -
Dependencies Discovered in Packages
{{ dep_type|title }} Dependency: {{ dep_name }}
{{ requirement if requirement else '(empty)' }} - {% for package_name in packages|sort %} - {{ package_name }} - {% if dep_name in overrides and requirement in overrides[dep_name] and package_name in overrides[dep_name][requirement] %} - override - {% endif %} -
- {% endfor %} -
-
- {% endfor %} -




-
- - - - {% if frozen %} - - {% endif %} - - - {% for name, versions in frozen|dictsort %} - - - - {% if name in missing_reqs %} - - {% elif name in changed_reqs %} - - {% else %} - - {% endif %} - - {% endfor %} - {% if not frozen %} - - {% endif %} - -
Dependencies Frozen in Lockfile
DependencyFrozen VersionDependency State
{{ name }}{{ versions[0] if versions[0] else '(empty)' }}⚠️ No packages reference this dependency -
❌ One or more packages reference a different version of this dependency - - {% for spec, libs in dependencies[name]|dictsort %} - {% if spec != versions[0] %} - {% for package in libs|sort %} - {{ package }} ({{ spec }}) -
- {% endfor %} - {% endif %} - {% endfor %} -
-
-
✅ All packages validated against this dependency and version
Unable to open shared_requirements.txt, shared requirements have not been validated
- {% if frozen and new_reqs %} -
- {% for name in new_reqs|sort %} - - - {% if loop.index == 1 %} - - {% endif %} - - - - {% for requirement, packages in dependencies[name]|dictsort %} - - - - - {% endfor %} - -
Dependencies Missing from Lockfile
Missing Dependency: {{ name }}
{{ requirement if requirement else '(empty)' }} - {% for package_name in packages|sort %} - {{ package_name }}
- {% endfor %} -
- {% endfor %} - {% endif %} -




-
- - - - - - - {% for name, info in packages|dictsort %} - - - - - - {% endfor %} - -
Packages Scanned for this Report
Package AnalyzedPackage VersionPackage Source
{{ name }}{{ info.version }}{{ info.source }}
-
- - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/dev_setup.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/dev_setup.py deleted file mode 100644 index cd5aef43159..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/dev_setup.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -from __future__ import print_function - -import sys -import glob -import os -import argparse -from collections import Counter -from subprocess import check_call, CalledProcessError - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..")) - - -def pip_command(command, additional_dir=".", error_ok=False): - try: - print("Executing: {} from {}".format(command, additional_dir)) - check_call( - [sys.executable, "-m", "pip"] + command.split(), - cwd=os.path.join(root_dir, additional_dir), - ) - print() - except CalledProcessError as err: - print(err, file=sys.stderr) - if not error_ok: - sys.exit(1) - -def select_install_type(pkg, run_develop, exceptions): - # the default for disable_develop will be false, which means `run_develop` will be true - argument = "" - if run_develop: - argument = "-e" - - if pkg in exceptions: - # opposite of whatever our decision was - if argument == "": - argument = "-e" - elif argument == "-e": - argument = "" - - return argument - -# optional argument in a situation where we want to build a variable subset of packages -parser = argparse.ArgumentParser( - description="Set up the dev environment for selected packages." -) -parser.add_argument( - "--packageList", - "-p", - dest="packageList", - default="", - help="Comma separated list of targeted packages. Used to limit the number of packages that dependencies will be installed for.", -) -parser.add_argument( - "--disabledevelop", - dest="install_in_develop_mode", - default=True, - action="store_false", - help="Add this argument if you would prefer to install the package with a simple `pip install` versus `pip install -e`", -) -# this is a hack to support generating docs for the single package that doesn't support develop mode. It will be removed when we -# migrate to generating docs on a per-package cadence. -parser.add_argument( - "--exceptionlist", - "-e", - dest="exception_list", - default="", - help="Comma separated list of packages that we want to take the 'opposite' installation method for.", -) - -args = parser.parse_args() - -packages = { - tuple(os.path.dirname(f).rsplit(os.sep, 1)) - for f in glob.glob("sdk/*/azure-*/setup.py") + glob.glob("tools/azure-*/setup.py") -} -# [(base_folder, package_name), ...] to {package_name: base_folder, ...} -packages = {package_name: base_folder for (base_folder, package_name) in packages} - -exceptions = [p.strip() for p in args.exception_list.split(',')] - -# keep targeted packages separate. python2 needs the nspkgs to work properly. -if not args.packageList: - targeted_packages = list(packages.keys()) -else: - targeted_packages = [ - os.path.relpath(x.strip()) for x in args.packageList.split(",") - ] - -# Extract nspkg and sort nspkg by number of "-" -nspkg_packages = [p for p in packages.keys() if "nspkg" in p] -nspkg_packages.sort(key=lambda x: len([c for c in x if c == "-"])) - -# Manually push meta-packages at the end, in reverse dependency order -meta_packages = ["azure-keyvault", "azure-mgmt", "azure"] - -content_packages = sorted( - [ - p - for p in packages.keys() - if p not in nspkg_packages + meta_packages and p in targeted_packages - ] -) - -# Install tests dep first -if "azure-devtools" in content_packages: - content_packages.remove("azure-devtools") -content_packages.insert(0, "azure-devtools") - -if "azure-sdk-tools" in content_packages: - content_packages.remove("azure-sdk-tools") -content_packages.insert(1, "azure-sdk-tools") - -# Put azure-common in front of content package -if "azure-common" in content_packages: - content_packages.remove("azure-common") -content_packages.insert(2, "azure-common") - -if 'azure-core' in content_packages: - content_packages.remove('azure-core') -content_packages.insert(3, 'azure-core') - - -print("Running dev setup...") -print("Root directory '{}'\n".format(root_dir)) - -# install private whls if there are any -privates_dir = os.path.join(root_dir, "privates") -if os.path.isdir(privates_dir) and os.listdir(privates_dir): - whl_list = " ".join( - [os.path.join(privates_dir, f) for f in os.listdir(privates_dir)] - ) - pip_command("install {}".format(whl_list)) - -# install nspkg only on py2, but in wheel mode (not editable mode) -if sys.version_info < (3,): - for package_name in nspkg_packages: - pip_command("install {}/{}/".format(packages[package_name], package_name)) - - - -# install packages -print("Packages to install: {}".format(content_packages)) -for package_name in content_packages: - print("\nInstalling {}".format(package_name)) - # if we are running dev_setup with no arguments. going after dev_requirements will be a pointless exercise - # and waste of cycles as all the dependencies will be installed regardless. - if os.path.isfile( - "{}/{}/dev_requirements.txt".format(packages[package_name], package_name) - ): - pip_command( - "install -r dev_requirements.txt", - os.path.join(packages[package_name], package_name), - ) - - pip_command( - "install --ignore-requires-python {} {}".format( - select_install_type(package_name, args.install_in_develop_mode, exceptions), - os.path.join(packages[package_name], package_name) - ) - ) - -# On Python 3, uninstall azure-nspkg if he got installed -if sys.version_info >= (3,): - pip_command("uninstall -y azure-nspkg", error_ok=True) - -print("Finished dev setup.") - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/build_packages.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/build_packages.py deleted file mode 100644 index 2cd5dab475d..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/build_packages.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# Normally, this module will be executed as referenced as part of the devops build definitions. -# An enterprising user can easily glance over this and leverage for their own purposes. - -import argparse -import sys -import os - -from common_tasks import process_glob_string, run_check_call - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) -build_packing_script_location = os.path.join(root_dir, "build_package.py") - - -def build_packages(targeted_packages, distribution_directory): - # run the build and distribution - for package_name in targeted_packages: - print(package_name) - print("Generating Package Using Python {}".format(sys.version)) - run_check_call( - [ - "python", - build_packing_script_location, - "--dest", - distribution_directory, - package_name, - ], - root_dir, - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Build Azure Packages, Called from DevOps YAML Pipeline" - ) - parser.add_argument( - "-d", - "--distribution-directory", - dest="distribution_directory", - help="The path to the distribution directory. Should be passed $(Build.ArtifactStagingDirectory) from the devops yaml definition.", - required=True, - ) - - parser.add_argument( - "glob_string", - nargs="?", - help=( - "A comma separated list of glob strings that will target the top level directories that contain packages. " - 'Examples: All == "azure-*", Single = "azure-keyvault"' - ), - ) - - parser.add_argument( - "--service", - help=( - "Name of service directory (under sdk/) to build." - "Example: --service applicationinsights" - ), - ) - - parser.add_argument( - "--pkgfilter", - default="", - dest="package_filter_string", - help=( - "An additional string used to filter the set of artifacts by a simple CONTAINS clause. This filters packages AFTER the set is built with compatibility and omission lists accounted." - ), - ) - - args = parser.parse_args() - - # We need to support both CI builds of everything and individual service - # folders. This logic allows us to do both. - if args.service: - service_dir = os.path.join("sdk", args.service) - target_dir = os.path.join(root_dir, service_dir) - else: - target_dir = root_dir - - targeted_packages = process_glob_string(args.glob_string, target_dir, args.package_filter_string) - build_packages(targeted_packages, args.distribution_directory) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/common_tasks.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/common_tasks.py deleted file mode 100644 index dc1380a1177..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/common_tasks.py +++ /dev/null @@ -1,412 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# Below are common methods for the devops build steps. This is the common location that will be updated with -# package targeting during release. - -import glob -from subprocess import check_call, CalledProcessError -import os -import errno -import shutil -import sys -import logging -import ast -import textwrap -import io -import re -import pdb - -# Assumes the presence of setuptools -from pkg_resources import parse_version, parse_requirements, Requirement - -# this assumes the presence of "packaging" -from packaging.specifiers import SpecifierSet -from packaging.version import Version - - -DEV_REQ_FILE = "dev_requirements.txt" -NEW_DEV_REQ_FILE = "new_dev_requirements.txt" - -logging.getLogger().setLevel(logging.INFO) - -OMITTED_CI_PACKAGES = [ - "azure-mgmt-documentdb", - "azure-servicemanagement-legacy", - "azure-mgmt-scheduler", -] -MANAGEMENT_PACKAGE_IDENTIFIERS = [ - "mgmt", - "azure-cognitiveservices", - "azure-servicefabric", - "nspkg", - "azure-keyvault", - "azure-synapse" -] -META_PACKAGES = ["azure", "azure-mgmt", "azure-keyvault"] -REGRESSION_EXCLUDED_PACKAGES = [ - "azure-common", -] - -MANAGEMENT_PACKAGES_FILTER_EXCLUSIONS = [ - "azure-mgmt-core", -] - -omit_regression = ( - lambda x: "nspkg" not in x - and "mgmt" not in x - and os.path.basename(x) not in MANAGEMENT_PACKAGE_IDENTIFIERS - and os.path.basename(x) not in META_PACKAGES - and os.path.basename(x) not in REGRESSION_EXCLUDED_PACKAGES -) -omit_docs = lambda x: "nspkg" not in x and os.path.basename(x) not in META_PACKAGES -omit_build = lambda x: x # Dummy lambda to match omit type -lambda_filter_azure_pkg = lambda x: x.startswith("azure") and "-nspkg" not in x -omit_mgmt = lambda x: "mgmt" not in x or os.path.basename(x) in MANAGEMENT_PACKAGES_FILTER_EXCLUSIONS - -# dict of filter type and filter function -omit_funct_dict = { - "Build": omit_build, - "Docs": omit_docs, - "Regression": omit_regression, - "Omit_management": omit_mgmt, -} - -def log_file(file_location, is_error=False): - with open(file_location, "r") as file: - for line in file: - sys.stdout.write(line) - sys.stdout.write("\n") - sys.stdout.flush() - - -def read_file(file_location): - str_buffer = "" - with open(file_location, "r") as file: - for line in file: - str_buffer += line - return str_buffer - - -def cleanup_folder(target_folder): - for file in os.listdir(target_folder): - file_path = os.path.join(target_folder, file) - try: - if os.path.isfile(file_path): - os.remove(file_path) - except Exception as e: - logging.error(e) - - -# helper functions -def clean_coverage(coverage_dir): - try: - os.mkdir(coverage_dir) - except OSError as e: - if e.errno == errno.EEXIST: - logging.info("Coverage dir already exists. Cleaning.") - cleanup_folder(coverage_dir) - else: - raise - - -def parse_setup(setup_path): - setup_filename = os.path.join(setup_path, "setup.py") - mock_setup = textwrap.dedent( - """\ - def setup(*args, **kwargs): - __setup_calls__.append((args, kwargs)) - """ - ) - parsed_mock_setup = ast.parse(mock_setup, filename=setup_filename) - with io.open(setup_filename, "r", encoding="utf-8-sig") as setup_file: - parsed = ast.parse(setup_file.read()) - for index, node in enumerate(parsed.body[:]): - if ( - not isinstance(node, ast.Expr) - or not isinstance(node.value, ast.Call) - or not hasattr(node.value.func, "id") - or node.value.func.id != "setup" - ): - continue - parsed.body[index:index] = parsed_mock_setup.body - break - - fixed = ast.fix_missing_locations(parsed) - codeobj = compile(fixed, setup_filename, "exec") - local_vars = {} - global_vars = {"__setup_calls__": []} - current_dir = os.getcwd() - working_dir = os.path.dirname(setup_filename) - os.chdir(working_dir) - exec(codeobj, global_vars, local_vars) - os.chdir(current_dir) - _, kwargs = global_vars["__setup_calls__"][0] - - try: - python_requires = kwargs["python_requires"] - # most do not define this, fall back to what we define as universal - except KeyError as e: - python_requires = ">=2.7" - - version = kwargs["version"] - name = kwargs["name"] - - requires = [] - if "install_requires" in kwargs: - requires = kwargs["install_requires"] - - return name, version, python_requires, requires - - -def parse_requirements_file(file_location): - with open(file_location, "r") as f: - reqs = f.read() - - return dict((req.name, req) for req in parse_requirements(reqs)) - - -def parse_setup_requires(setup_path): - _, _, python_requires, _ = parse_setup(setup_path) - - return python_requires - - -def filter_for_compatibility(package_set): - collected_packages = [] - v = sys.version_info - running_major_version = Version(".".join([str(v[0]), str(v[1]), str(v[2])])) - - for pkg in package_set: - spec_set = SpecifierSet(parse_setup_requires(pkg)) - - if running_major_version in spec_set: - collected_packages.append(pkg) - - return collected_packages - - -# this function is where a glob string gets translated to a list of packages -# It is called by both BUILD (package) and TEST. In the future, this function will be the central location -# for handling targeting of release packages -def process_glob_string( - glob_string, - target_root_dir, - additional_contains_filter="", - filter_type="Build", -): - if glob_string: - individual_globs = glob_string.split(",") - else: - individual_globs = "azure-*" - collected_top_level_directories = [] - - for glob_string in individual_globs: - globbed = glob.glob( - os.path.join(target_root_dir, glob_string, "setup.py") - ) + glob.glob(os.path.join(target_root_dir, "sdk/*/", glob_string, "setup.py")) - collected_top_level_directories.extend([os.path.dirname(p) for p in globbed]) - - # dedup, in case we have double coverage from the glob strings. Example: "azure-mgmt-keyvault,azure-mgmt-*" - collected_directories = list( - set( - [ - p - for p in collected_top_level_directories - if additional_contains_filter in p - ] - ) - ) - - # if we have individually queued this specific package, it's obvious that we want to build it specifically - # in this case, do not honor the omission list - if len(collected_directories) == 1: - pkg_set_ci_filtered = filter_for_compatibility(collected_directories) - # however, if there are multiple packages being built, we should honor the omission list and NOT build the omitted - # packages - else: - allowed_package_set = remove_omitted_packages(collected_directories) - pkg_set_ci_filtered = filter_for_compatibility(allowed_package_set) - - # Apply filter based on filter type. for e.g. Docs, Regression, Management - pkg_set_ci_filtered = list(filter(omit_funct_dict.get(filter_type, omit_build), pkg_set_ci_filtered)) - logging.info( - "Target packages after filtering by CI: {}".format( - pkg_set_ci_filtered - ) - ) - logging.info( - "Package(s) omitted by CI filter: {}".format( - list(set(collected_directories) - set(pkg_set_ci_filtered)) - ) - ) - return sorted(pkg_set_ci_filtered) - - -def remove_omitted_packages(collected_directories): - packages = [ - package_dir - for package_dir in collected_directories - if os.path.basename(package_dir) not in OMITTED_CI_PACKAGES - ] - - return packages - - -def run_check_call( - command_array, - working_directory, - acceptable_return_codes=[], - run_as_shell=False, - always_exit=True, -): - try: - if run_as_shell: - logging.info( - "Command Array: {0}, Target Working Directory: {1}".format( - " ".join(command_array), working_directory - ) - ) - check_call(" ".join(command_array), cwd=working_directory, shell=True) - else: - logging.info( - "Command Array: {0}, Target Working Directory: {1}".format( - command_array, working_directory - ) - ) - check_call(command_array, cwd=working_directory) - except CalledProcessError as err: - if err.returncode not in acceptable_return_codes: - logging.error(err) # , file = sys.stderr - if always_exit: - exit(1) - else: - return err - - -# This function generates code coverage parameters -def create_code_coverage_params(parsed_args, package_name): - coverage_args = [] - if parsed_args.disablecov: - logging.info("Code coverage disabled as per the flag(--disablecov)") - coverage_args.append("--no-cov") - else: - current_package_name = package_name.replace("-", ".") - coverage_args.append("--cov={}".format(current_package_name)) - logging.info( - "Code coverage is enabled for package {0}, pytest arguements: {1}".format( - current_package_name, coverage_args - ) - ) - return coverage_args - - -# This function returns if error code 5 is allowed for a given package -def is_error_code_5_allowed(target_pkg, pkg_name): - if ( - all( - map( - lambda x: any( - [pkg_id in x for pkg_id in MANAGEMENT_PACKAGE_IDENTIFIERS] - ), - [target_pkg], - ) - ) - or pkg_name in MANAGEMENT_PACKAGE_IDENTIFIERS - ): - return True - else: - return False - - -# This function parses requirement and return package name and specifier -def parse_require(req): - req_object = Requirement.parse(req) - pkg_name = req_object.key - spec = SpecifierSet(str(req_object).replace(pkg_name, "")) - return [pkg_name, spec] - -def find_whl(package_name, version, whl_directory): - if not os.path.exists(whl_directory): - logging.error("Whl directory is incorrect") - exit(1) - - logging.info("Searching whl for package {}".format(package_name)) - whl_name = "{0}-{1}*.whl".format(package_name.replace("-", "_"), version) - paths = glob.glob(os.path.join(whl_directory, whl_name)) - if not paths: - logging.error( - "whl is not found in whl directory {0} for package {1}".format( - whl_directory, package_name - ) - ) - exit(1) - - return paths[0] - -# This method installs package from a pre-built whl -def install_package_from_whl( - package_whl_path, working_dir, python_sym_link=sys.executable -): - commands = [python_sym_link, "-m", "pip", "install", package_whl_path] - run_check_call(commands, working_dir) - logging.info("Installed package from {}".format(package_whl_path)) - - -def filter_dev_requirements(pkg_root_path, packages_to_exclude, dest_dir): - # This method returns list of requirements from dev_requirements by filtering out packages in given list - dev_req_path = os.path.join(pkg_root_path, DEV_REQ_FILE) - if not os.path.exists(dev_req_path): - logging.info("{0} is not found in package root {1}".format(DEV_REQ_FILE, pkg_root_path)) - return "" - - requirements = [] - with open(dev_req_path, "r") as dev_req_file: - requirements = dev_req_file.readlines() - - # filter any package given in excluded list - requirements = [ - req - for req in requirements - if os.path.basename(req.replace("\n", "")) not in packages_to_exclude - ] - - logging.info("Filtered dev requirements: {}".format(requirements)) - # create new dev requirements file with different name for filtered requirements - new_dev_req_path = os.path.join(dest_dir, NEW_DEV_REQ_FILE) - with open(new_dev_req_path, "w") as dev_req_file: - dev_req_file.writelines(requirements) - - return new_dev_req_path - -def is_required_version_on_pypi(package_name, spec): - from pypi_tools.pypi import PyPIClient - client = PyPIClient() - versions = [] - try: - versions = [str(v) for v in client.get_ordered_versions(package_name) if str(v) in spec] - except: - logging.error("Package {} is not found on PyPI", package_name) - return versions - -def find_packages_missing_on_pypi(path): - import pkginfo - requires = [] - if path.endswith(".whl"): - requires = list(filter(lambda_filter_azure_pkg, pkginfo.get_metadata(path).requires_dist)) - else: - _, _, _, requires = parse_setup(path) - - # parse pkg name and spec - pkg_spec_dict = dict(parse_require(req) for req in requires) - logging.info("Package requirement: {}".format(pkg_spec_dict)) - # find if version is available on pypi - missing_packages = ["{0}{1}".format(pkg, pkg_spec_dict[pkg]) for pkg in pkg_spec_dict.keys() if not is_required_version_on_pypi(pkg, pkg_spec_dict[pkg])] - if missing_packages: - logging.error("Packages not found on PyPI: {}".format(missing_packages)) - return missing_packages - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/find_change_log.ps1 b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/find_change_log.ps1 deleted file mode 100644 index f3eaa4f1767..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/find_change_log.ps1 +++ /dev/null @@ -1,106 +0,0 @@ - -param ( - $workingDir, - $version -) -$RELEASE_TITLE_REGEX = "(?^\#+.*(?\b\d+\.\d+\.\d+([^0-9\s][^\s:]+)?))" - - -function ExtractReleaseNotes($changeLogLocation) -{ - $releaseNotes = @{} - $contentArrays = @{} - if ($changeLogLocation.Length -eq 0) - { - return $releaseNotes - } - - try { - $contents = Get-Content $changeLogLocation - - # walk the document, finding where the version specifiers are and creating lists - $version = "" - Write-Host "Versions in change log $changeLogLocation" - foreach($line in $contents){ - if ($line -match $RELEASE_TITLE_REGEX) - { - Write-Host $line - $version = $matches["version"] - $contentArrays[$version] = @() - } - - $contentArrays[$version] += $line - } - - # resolve each of discovered version specifier string arrays into real content - foreach($key in $contentArrays.Keys) - { - $releaseNotes[$key] = New-Object PSObject -Property @{ - ReleaseVersion = $key - ReleaseContent = $contentArrays[$key] -join [Environment]::NewLine - } - } - } - catch - { - Write-Host "Error parsing $changeLogLocation." - Write-Host $_.Exception.Message - } - - return $releaseNotes -} - - -function VerifyPackages($rootDirectory) -{ - #This function verifies version in CHANGELOG.md for a given package - try - { - $historyFiles = Get-ChildItem -Path $rootDirectory -Recurse -Include "CHANGELOG.md" - if ($historyFiles -eq $null) - { - Write-Host "Change log file is missing for package" - exit(1) - } - - #Find current version of package from _version.py and package name from setup.py - $changeFile = @($historyFiles)[0] - #Get Version and release notes in each change log files - $releaseNotes = ExtractReleaseNotes -changeLogLocation $changeFile - if ($releaseNotes.Count -gt 0) - { - #Log package if it doesn't have current version in change log - if ( $releaseNotes.Contains($version)) - { - $content = $releaseNotes[$version] - Write-Host "Change log [$changeFile] is updated with current version $version" - Write-Host "Release notes for version $version" - Write-Host "****************************************************************************************************" - Write-Host $content.ReleaseContent - Write-Host "****************************************************************************************************" - } - else - { - Write-Host "Change log [$changeFile] does not have current version $version" - exit(1) - } - } - } - catch - { - Write-Host "Error verifying version in change log" - Write-Host $_.Exception.Message - exit(1) - } - -} - - -if (($workingDir -eq $null) -or ($version -eq $null)) -{ - Write-Host "Invalid arguements. workingDir and version are mandatory arguements" - exit(1) -} - -VerifyPackages -rootDirectory $workingDir - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/git_helper.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/git_helper.py deleted file mode 100644 index 189872ac3cb..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/git_helper.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -import sys -import os -import logging -from packaging.version import parse -from common_tasks import run_check_call - -logging.getLogger().setLevel(logging.INFO) - -# Oldest release of SDK packages that should be skipped -EXCLUDED_PACKAGE_VERSIONS = { - 'azure-storage-file-share': ['12.0.0', '12.0.0b5'], - 'azure-storage-queue': ['0.37.0', '1.0.0', '1.1.0', '1.2.0rc1', '1.3.0', '1.4.0', '2.0.0', '2.0.1', '2.1.0'], - 'azure-storage-file': ['0.37.0', '1.0.0', '1.1.0', '1.2.0rc1', '1.3.0', '1.3.1', '1.4.0', '2.0.0', '2.0.1', '2.1.0'], - 'azure-storage-blob': ['0.37.0', '0.37.1', '1.0.0', '1.1.0', '1.2.0rc1', '1.3.0', '1.3.1', '1.4.0', '1.5.0', '2.0.0', '2.0.1', '2.1.0',], - 'azure-eventhub': ['0.2.0', '1.0.0', '1.1.0', '1.1.1', '1.2.0rc1', '1.2.0', '1.3.0', '1.3.1', '1.3.2', '1.3.3',], - 'azure-cosmos': ['3.0.0', '3.0.1', '3.0.2', '3.1.0', '3.1.1', '3.1.2'], -} - -# This method identifies release tag for latest or oldest released version of a given package -def get_release_tag(dep_pkg_name, isLatest): - # get versions from pypi and find latest - # delayed import until sdk tools are installed on virtual env - from pypi_tools.pypi import PyPIClient - - client = PyPIClient() - versions = [] - try: - versions = [str(v) for v in client.get_ordered_versions(dep_pkg_name)] - logging.info("Versions available on PyPI for {0} are: {1}".format(dep_pkg_name, versions)) - except: - logging.error("Package {} is not available on PyPI".format(dep_pkg_name)) - return None - - # filter excluded versions - if dep_pkg_name in EXCLUDED_PACKAGE_VERSIONS: - versions = [v for v in versions if v not in EXCLUDED_PACKAGE_VERSIONS[dep_pkg_name]] - logging.info("Filtered versions for {0} is: {1}".format(dep_pkg_name, versions)) - - if not versions: - logging.info( - "Released version info for package {} is not available".format(dep_pkg_name) - ) - # This is not a hard error. We can run into this situation when a new package is added to repo and not yet released - return - - # find latest version - logging.info("Looking for {} released version".format("Latest" if isLatest == True else "Oldest")) - if isLatest == True: - versions.reverse() - else: - # find oldest GA version by filtering out all preview versions - versions = [ v for v in versions if parse(v).is_prerelease == False] - if(len(versions) <2): - logging.info("Only one or no released GA version found for package {}".format(dep_pkg_name)) - return - - version = versions[0] - - # create tag in _version format - tag_name = "{0}_{1}".format(dep_pkg_name, version) - logging.info( - "Release tag for package [{0}] is [{1}]".format(dep_pkg_name, tag_name) - ) - return tag_name - - -# This method checkouts a given tag of sdk repo -def git_checkout_tag(tag_name, working_dir): - # fetch tags - run_check_call(["git", "fetch", "origin", "tag", tag_name], working_dir) - - logging.info("checkout git repo with tag {}".format(tag_name)) - commands = ["git", "checkout", "tags/{}".format(tag_name)] - run_check_call(commands, working_dir) - logging.info("Code with tag {} is checked out successfully".format(tag_name)) - - -# This method checkouts a given tag of sdk repo -def git_checkout_branch(branch_name, working_dir): - # fetch tags - run_check_call(["git", "fetch", "origin", branch_name], working_dir) - try: - run_check_call(["git", "branch", branch_name, "FETCH_HEAD"], working_dir) - except: - logging.error("Failed to create branch. But this can happen if a branch already exists so ignoring this error") - logging.info("checkout git repo with branch {}".format(branch_name)) - commands = ["git", "checkout", branch_name] - run_check_call(commands, working_dir) - logging.info("Repo with branch name {} is checked out successfully".format(branch_name)) - - -def clone_repo(dest_dir, repo_url): - if not os.path.isdir(dest_dir): - logging.error( - "Invalid destination directory to clone git repo:[{}]".format(dest_dir) - ) - sys.exit(1) - - logging.info("cloning git repo using url {}".format(repo_url)) - run_check_call(["git", "clone", "--depth=1", repo_url], dest_dir) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/setup_execute_tests.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/setup_execute_tests.py deleted file mode 100644 index e928f33fdd6..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/setup_execute_tests.py +++ /dev/null @@ -1,311 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# This script is the primary entry point for the azure-sdk-for-python Devops CI commands -# Primarily, it figures out which packages need to be built by combining the targeting string with the servicedir argument. -# After this, it either executes a global install of all packages followed by a test, or a tox invocation per package collected. - - -import argparse -import sys -import os -import errno -import shutil -import glob -import logging -import pdb -from common_tasks import ( - process_glob_string, - run_check_call, - cleanup_folder, - clean_coverage, - is_error_code_5_allowed, - create_code_coverage_params, -) -from tox_harness import prep_and_run_tox - -logging.getLogger().setLevel(logging.INFO) - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) -coverage_dir = os.path.join(root_dir, "_coverage/") -dev_setup_script_location = os.path.join(root_dir, "scripts/dev_setup.py") - -def combine_coverage_files(coverage_files): - # find tox.ini file. tox.ini is used to combine coverage paths to generate formatted report - tox_ini_file = os.path.join(root_dir, "eng", "tox", "tox.ini") - config_file_flag = "--rcfile={}".format(tox_ini_file) - - if os.path.isfile(tox_ini_file): - # for every individual coverage file, run coverage combine to combine path - for coverage_file in coverage_files: - cov_cmd_array = [sys.executable, "-m", "coverage", "combine"] - # tox.ini file has coverage paths to combine - # Pas tox.ini as coverage config file - cov_cmd_array.extend([config_file_flag, coverage_file]) - run_check_call(cov_cmd_array, root_dir) - else: - # not a hard error at this point - # this combine step is required only for modules if report has package name starts with .tox - logging.error("tox.ini is not found in path {}".format(root_dir)) - -def collect_pytest_coverage_files(targeted_packages): - coverage_files = [] - # generate coverage files - for package_dir in [package for package in targeted_packages]: - coverage_file = os.path.join( - coverage_dir, ".coverage_{}".format(os.path.basename(package_dir)) - ) - if os.path.isfile(coverage_file): - coverage_files.append(coverage_file) - - logging.info("Visible uncombined .coverage files: {}".format(coverage_files)) - - if len(coverage_files): - cov_cmd_array = ["coverage", "combine"] - cov_cmd_array.extend(coverage_files) - - # merge them with coverage combine and copy to root - run_check_call(cov_cmd_array, coverage_dir) - - source = os.path.join(coverage_dir, "./.coverage") - dest = os.path.join(root_dir, ".coverage") - - shutil.move(source, dest) - - -def prep_tests(targeted_packages): - logging.info("running test setup for {}".format(targeted_packages)) - run_check_call( - [ - sys.executable, - dev_setup_script_location, - "--disabledevelop", - "-p", - ",".join([os.path.basename(p) for p in targeted_packages]) - ], - root_dir, - ) - - -def run_tests(targeted_packages, test_output_location, test_res, parsed_args): - err_results = [] - - clean_coverage(coverage_dir) - - # base command array without a targeted package - command_array = [sys.executable, "-m", "pytest"] - command_array.extend(test_res) - - # loop through the packages - logging.info("Running pytest for {}".format(targeted_packages)) - - for index, target_package in enumerate(targeted_packages): - logging.info( - "Running pytest for {}. {} of {}.".format( - target_package, index, len(targeted_packages) - ) - ) - - package_name = os.path.basename(target_package) - source_coverage_file = os.path.join(root_dir, ".coverage") - target_coverage_file = os.path.join( - coverage_dir, ".coverage_{}".format(package_name) - ) - target_package_options = [] - allowed_return_codes = [] - - local_command_array = command_array[:] - - # Get code coverage params for current package - coverage_commands = create_code_coverage_params(parsed_args, package_name) - # Create local copy of params to pass to execute - local_command_array.extend(coverage_commands) - - # if we are targeting only packages that are management plane, it is a possibility - # that no tests running is an acceptable situation - # we explicitly handle this here. - if is_error_code_5_allowed(target_package, package_name): - allowed_return_codes.append(5) - - # format test result output location - if test_output_location: - target_package_options.extend( - [ - "--junitxml", - os.path.join( - "TestResults/{}/".format(package_name), test_output_location - ), - ] - ) - - target_package_options.append(target_package) - err_result = run_check_call( - local_command_array + target_package_options, - root_dir, - allowed_return_codes, - True, - False, - ) - if err_result: - logging.error("Errors present in {}".format(package_name)) - err_results.append(err_result) - - if os.path.isfile(source_coverage_file): - shutil.move(source_coverage_file, target_coverage_file) - - if not parsed_args.disablecov: - collect_pytest_coverage_files(targeted_packages) - - # if any of the packages failed, we should get exit with errors - if err_results: - exit(1) - - -def execute_global_install_and_test( - parsed_args, targeted_packages, extended_pytest_args -): - if parsed_args.mark_arg: - extended_pytest_args.extend(["-m", '"{}"'.format(parsed_args.mark_arg)]) - - if parsed_args.runtype == "setup" or parsed_args.runtype == "all": - prep_tests(targeted_packages) - - if parsed_args.runtype == "execute" or parsed_args.runtype == "all": - run_tests( - targeted_packages, - parsed_args.test_results, - extended_pytest_args, - parsed_args, - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Install Dependencies, Install Packages, Test Azure Packages, Called from DevOps YAML Pipeline" - ) - - parser.add_argument( - "glob_string", - nargs="?", - help=( - "A comma separated list of glob strings that will target the top level directories that contain packages." - 'Examples: All = "azure-*", Single = "azure-keyvault", Targeted Multiple = "azure-keyvault,azure-mgmt-resource"' - ), - ) - - parser.add_argument( - "--junitxml", - dest="test_results", - help=( - "The folder where the test results will be stored in xml format." - 'Example: --junitxml="junit/test-results.xml"' - ), - ) - - parser.add_argument( - "--mark_arg", - dest="mark_arg", - help=( - 'The complete argument for `pytest -m ""`. This can be used to exclude or include specific pytest markers.' - '--mark_arg="not cosmosEmulator"' - ), - ) - - parser.add_argument( - "--disablecov", help=("Flag that disables code coverage."), action="store_true" - ) - - parser.add_argument( - "--tparallel", - default=False, - help=("Flag that enables parallel tox invocation."), - action="store_true", - ) - - parser.add_argument( - "--tenvparallel", - default=False, - help=("Run individual tox env for each package in parallel."), - action="store_true", - ) - - parser.add_argument( - "--service", - help=( - "Name of service directory (under sdk/) to test." - "Example: --service applicationinsights" - ), - ) - - parser.add_argument( - "-r", "--runtype", choices=["setup", "execute", "all", "none"], default="none" - ) - - parser.add_argument( - "-t", - "--toxenv", - dest="tox_env", - help="Specific set of named environments to execute", - ) - - parser.add_argument( - "-w", - "--wheel_dir", - dest="wheel_dir", - help="Location for prebuilt artifacts (if any)", - ) - - parser.add_argument( - "-x", - "--xdist", - default=False, - help=("Flag that enables xdist (requires pip install)"), - action="store_true" - ) - - parser.add_argument( - "-i", - "--injected-packages", - dest="injected_packages", - default="", - help="Comma or space-separated list of packages that should be installed prior to dev_requirements. If local path, should be absolute.", - ) - - parser.add_argument( - "--omit-management", - dest="omit_management", - default=False, - action="store_true", - help="Flag that indicates to omit any management packages except any management packages that should not be filtered. for e.g azure-mgmt-core", - ) - - args = parser.parse_args() - - # We need to support both CI builds of everything and individual service - # folders. This logic allows us to do both. - if args.service: - service_dir = os.path.join("sdk", args.service) - target_dir = os.path.join(root_dir, service_dir) - else: - target_dir = root_dir - - if args.omit_management: - targeted_packages = process_glob_string(args.glob_string, target_dir, "", "Omit_management") - else: - targeted_packages = process_glob_string(args.glob_string, target_dir) - extended_pytest_args = [] - - if len(targeted_packages) == 0: - exit(0) - - if args.xdist: - extended_pytest_args.extend(["-n", "8", "--dist=loadscope"]) - - if args.runtype != "none": - execute_global_install_and_test(args, targeted_packages, extended_pytest_args) - else: - prep_and_run_tox(targeted_packages, args, extended_pytest_args) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/test_regression.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/test_regression.py deleted file mode 100644 index 849a6d8fe9c..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/test_regression.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# This script will run regression test for packages which are added as required package by other packages -# Regression test ensures backword compatibility with released dependent package versions - -import argparse -import glob -import sys -import os -import logging -from common_tasks import ( - process_glob_string, - parse_setup, - run_check_call, - parse_require, - install_package_from_whl, - filter_dev_requirements, - find_packages_missing_on_pypi, - find_whl -) -from git_helper import get_release_tag, git_checkout_tag, git_checkout_branch, clone_repo -from pip._internal.operations import freeze - -AZURE_GLOB_STRING = "azure*" - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) -test_tools_req_file = os.path.abspath(os.path.join(root_dir, "eng", "test_tools.txt")) - -GIT_REPO_NAME = "azure-sdk-for-python" -GIT_MASTER_BRANCH = "master" -VENV_NAME = "regressionenv" -AZURE_SDK_FOR_PYTHON_GIT_URL = "https://github.com/Azure/azure-sdk-for-python.git" -TEMP_FOLDER_NAME = ".tmp_code_path" - -logging.getLogger().setLevel(logging.INFO) - - -class CustomVirtualEnv: - def __init__(self, path): - self.path = os.path.join(path, VENV_NAME) - - def create(self): - logging.info("Creating virtual environment [{}]".format(self.path)) - run_check_call([sys.executable, "-m", "venv", "ENV_DIR", self.path], root_dir) - self.python_executable = self._find_python_executable() - self.lib_paths = self._find_lib_paths() - - def clear_venv(self): - # clear any previously installed packages - run_check_call( - [sys.executable, "-m", "venv", "--clear", "ENV_DIR", self.path], root_dir - ) - - def _find_python_executable(self): - paths = glob.glob(os.path.join(self.path, "*", "python")) + glob.glob(os.path.join(self.path, "*", "python.exe")) - if not paths: - logging.error("Failed to find path to python executable in virtual env:{}".format(self.path)) - sys.exit(1) - return paths[0] - - def _find_lib_paths(self): - paths = glob.glob(os.path.join(self.path, "*", "site-packages")) + glob.glob(os.path.join(self.path, "lib", "*", "site-packages")) - if not paths: - logging.error("Failed to find site-packages directory in virtual env:{}".format(self.path)) - sys.exit(1) - return paths - - -class RegressionContext: - def __init__(self, whl_dir, tmp_path, is_latest, pytest_mark_arg): - self.whl_directory = whl_dir - self.temp_path = tmp_path - self.is_latest_depend_test = is_latest - self.venv = CustomVirtualEnv(self.temp_path) - self.pytest_mark_arg = pytest_mark_arg - self.venv.create() - - def init_for_pkg(self, pkg_root): - # This method is called each time context is switched to test regression for new package - self.package_root_path = pkg_root - self.package_name, self.pkg_version, _, _ = parse_setup(self.package_root_path) - - def initialize(self, dep_pkg_root_path): - self.dep_pkg_root_path = dep_pkg_root_path - self.venv.clear_venv() - - def deinitialize(self, dep_pkg_root_path): - # This function can be used to reset code repo to master branch - # Revert to master branch - run_check_call(["git", "clean", "-fd"], dep_pkg_root_path) - run_check_call(["git", "checkout", GIT_MASTER_BRANCH], dep_pkg_root_path) - - -class RegressionTest: - def __init__(self, context, package_dependency_dict): - self.context = context - self.package_dependency_dict = package_dependency_dict - - def run(self): - pkg_name = self.context.package_name - if pkg_name in self.package_dependency_dict: - logging.info("Running regression test for {}".format(pkg_name)) - self.whl_path = find_whl(pkg_name, self.context.pkg_version, self.context.whl_directory) - if find_packages_missing_on_pypi(self.whl_path): - logging.error("Required packages are not available on PyPI. Skipping regression test") - exit(0) - - dep_packages = self.package_dependency_dict[pkg_name] - logging.info("Dependent packages for [{0}]: {1}".format(pkg_name, dep_packages)) - for dep_pkg_path in dep_packages: - dep_pkg_name, _, _, _ = parse_setup(dep_pkg_path) - logging.info( - "Starting regression test of {0} against released {1}".format( - pkg_name, dep_pkg_name - ) - ) - self._run_test(dep_pkg_path) - logging.info( - "Completed regression test of {0} against released {1}".format( - pkg_name, dep_pkg_name - ) - ) - - logging.info("Completed regression test for {}".format(pkg_name)) - else: - logging.info( - "Package {} is not added as required by any package".format(pkg_name) - ) - - def _run_test(self, dep_pkg_path): - self.context.initialize(dep_pkg_path) - - # find GA released tags for package and run test using that code base - dep_pkg_name, version, _, _ = parse_setup(dep_pkg_path) - release_tag = get_release_tag(dep_pkg_name, self.context.is_latest_depend_test) - if not release_tag: - logging.error("Release tag is not available. Skipping package {} from test".format(dep_pkg_name)) - return - - test_branch_name = "{0}_tests".format(release_tag) - try: - git_checkout_branch(test_branch_name, dep_pkg_path) - except: - # If git checkout failed for "tests" branch then checkout branch with release tag - logging.info("Failed to checkout branch {}. Checking out release tagged git repo".format(test_branch_name)) - git_checkout_tag(release_tag, dep_pkg_path) - - try: - # install packages required to run tests - run_check_call( - [ - self.context.venv.python_executable, - "-m", - "pip", - "install", - "-r", - test_tools_req_file, - ], - dep_pkg_path - ) - - # Install pre-built whl for current package - install_package_from_whl( - self.whl_path, - self.context.temp_path, - self.context.venv.python_executable, - ) - # install package to be tested and run pytest - self._execute_test(dep_pkg_path) - finally: - self.context.deinitialize(dep_pkg_path) - - def _execute_test(self, dep_pkg_path): - # install dependent package from source - self._install_packages(dep_pkg_path, self.context.package_name) - - # Ensure correct version of package is installed - if not self._is_package_installed(self.context.package_name, self.context.pkg_version): - logging.error("Incorrect version of package {0} is installed. Expected version {1}".format(self.context.package_name, self.context.pkg_version)) - sys.exit(1) - - logging.info("Running test for {}".format(dep_pkg_path)) - commands = [ - self.context.venv.python_executable, - "-m", - "pytest", - "--verbose", - "--durations", - "10", - ] - - # add any pytest mark arg if present. for e.g. 'not cosmosEmulator' - if self.context.pytest_mark_arg: - commands.extend(["-m", self.context.pytest_mark_arg]) - - commands.append(self._get_package_test_dir(dep_pkg_path)) - run_check_call(commands, self.context.temp_path) - - def _get_package_test_dir(self, pkg_root_path): - # Returns path to test or tests folder within package root directory. - paths = glob.glob(os.path.join(pkg_root_path, "test")) + glob.glob(os.path.join(pkg_root_path, "tests")) - if paths is None: - # We will run into this situation only if test and tests are missing in repo. - # For now, running test for package repo itself to keep it same as regular CI in such cases - logging.error("'test' folder is not found in {}".format(pkg_root_path)) - return pkg_root_path - return paths[0] - - def _install_packages(self, dependent_pkg_path, pkg_to_exclude): - python_executable = self.context.venv.python_executable - working_dir = self.context.package_root_path - temp_dir = self.context.temp_path - - list_to_exclude = [pkg_to_exclude,] - installed_pkgs = [p.split('==')[0] for p in list(freeze.freeze(paths=self.context.venv.lib_paths)) if p.startswith('azure-')] - logging.info("Installed azure sdk packages:{}".format(installed_pkgs)) - list_to_exclude.extend(installed_pkgs) - # install dev requirement but skip already installed package which is being tested or present in dev requirement - filtered_dev_req_path = filter_dev_requirements( - dependent_pkg_path, list_to_exclude, dependent_pkg_path - ) - - if filtered_dev_req_path: - logging.info( - "Installing filtered dev requirements from {}".format(filtered_dev_req_path) - ) - run_check_call( - [python_executable, "-m", "pip", "install", "-r", filtered_dev_req_path], - dependent_pkg_path, - ) - else: - logging.info("dev requirements is not found to install") - - # install dependent package which is being verified - run_check_call( - [python_executable, "-m", "pip", "install", dependent_pkg_path], temp_dir - ) - - def _is_package_installed(self, package, version): - # find env root and pacakge locations - venv_root = self.context.venv.path - site_packages = self.context.venv.lib_paths - logging.info("Searching for packages in :{}".format(site_packages)) - installed_pkgs = list(freeze.freeze(paths=site_packages)) - logging.info("Installed packages: {}".format(installed_pkgs)) - # Verify installed package version - # Search for exact version or dev build version of current version. - pkg_search_string = "{0}=={1}".format(package, version) - dev_build_search_string = "{0}=={1}.dev".format(package, version) - return any(p == pkg_search_string or p.startswith(dev_build_search_string) for p in installed_pkgs) - - -# This method identifies package dependency map for all packages in azure sdk -def find_package_dependency(glob_string, repo_root_dir): - package_paths = process_glob_string( - glob_string, repo_root_dir, "", "Regression" - ) - dependency_map = {} - for pkg_root in package_paths: - _, _, _, requires = parse_setup(pkg_root) - - # Get a list of package names from install requires - required_pkgs = [parse_require(r)[0] for r in requires] - required_pkgs = [p for p in required_pkgs if p.startswith("azure")] - - for req_pkg in required_pkgs: - if req_pkg not in dependency_map: - dependency_map[req_pkg] = [] - dependency_map[req_pkg].append(pkg_root) - - logging.info("Package dependency: {}".format(dependency_map)) - return dependency_map - - -# This is the main function which identifies packages to test, find dependency matrix and trigger test -def run_main(args): - - temp_dir = "" - if args.temp_dir: - temp_dir = args.temp_dir - else: - temp_dir = os.path.abspath(os.path.join(root_dir, "..", TEMP_FOLDER_NAME)) - - code_repo_root = os.path.join(temp_dir, GIT_REPO_NAME) - # Make sure root_dir where script is running is not same as code repo which will be reverted to old released branch to run test - if root_dir == code_repo_root: - logging.error( - "Invalid path to clone github code repo. Temporary path can not be same as current source root directory" - ) - exit(1) - - # Make sure temp path exists - if not os.path.exists(temp_dir): - os.mkdir(temp_dir) - - if args.service: - service_dir = os.path.join("sdk", args.service) - target_dir = os.path.join(root_dir, service_dir) - else: - target_dir = root_dir - - targeted_packages = process_glob_string(args.glob_string, target_dir, "", "Regression") - if len(targeted_packages) == 0: - exit(0) - - # clone code repo only if it doesn't exists - if not os.path.exists(code_repo_root): - clone_repo(temp_dir, AZURE_SDK_FOR_PYTHON_GIT_URL) - else: - logging.info( - "Path {} already exists. Skipping step to clone github repo".format( - code_repo_root - ) - ) - - # find package dependency map for azure sdk - pkg_dependency = find_package_dependency(AZURE_GLOB_STRING, code_repo_root) - - # Create regression text context. One context object will be reused for all packages - context = RegressionContext( - args.whl_dir, temp_dir, args.verify_latest, args.mark_arg - ) - - for pkg_path in targeted_packages: - context.init_for_pkg(pkg_path) - RegressionTest(context, pkg_dependency).run() - logging.info("Regression test is completed successfully") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Run regression test for a package against released dependent packages" - ) - - parser.add_argument( - "glob_string", - nargs="?", - help=( - "A comma separated list of glob strings that will target the top level directories that contain packages." - 'Examples: All = "azure*", Single = "azure-keyvault", Targeted Multiple = "azure-keyvault,azure-mgmt-resource"' - ), - ) - - parser.add_argument( - "--service", - help=( - "Name of service directory (under sdk/) to test." - "Example: --service applicationinsights" - ), - ) - - parser.add_argument( - "--whl-dir", - required=True, - help=("Directory in which whl is pre built for all eligible package"), - ) - - parser.add_argument( - "--verify-latest", - default=True, - help=( - "Set this parameter to true to verify regression against latest released version." - "Default behavior is to test regression for oldest released version of dependent packages" - ), - ) - - parser.add_argument( - "--temp-dir", - help=( - "Temporary path to clone github repo of azure-sdk-for-python to run tests. Any changes in this path will be overwritten" - ), - ) - - parser.add_argument( - "--mark-arg", - dest="mark_arg", - help=( - 'The complete argument for `pytest -m ""`. This can be used to exclude or include specific pytest markers.' - '--mark_arg="not cosmosEmulator"' - ), - ) - - args = parser.parse_args() - run_main(args) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/tox_harness.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/tox_harness.py deleted file mode 100644 index 6229663f556..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/tox_harness.py +++ /dev/null @@ -1,389 +0,0 @@ -import sys -import os -import errno -import shutil -import re -import multiprocessing - -if sys.version_info < (3, 0): - from Queue import Queue -else: - from queue import Queue -from threading import Thread - -from subprocess import Popen, PIPE, STDOUT -from common_tasks import ( - process_glob_string, - run_check_call, - cleanup_folder, - clean_coverage, - log_file, - read_file, - is_error_code_5_allowed, - create_code_coverage_params, - find_whl, - parse_setup -) - -from pkg_resources import parse_requirements, RequirementParseError -import logging - -logging.getLogger().setLevel(logging.INFO) - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) -coverage_dir = os.path.join(root_dir, "_coverage/") -pool_size = multiprocessing.cpu_count() * 2 -DEFAULT_TOX_INI_LOCATION = os.path.join(root_dir, "eng/tox/tox.ini") -IGNORED_TOX_INIS = ["azure-cosmos"] - - -class ToxWorkItem: - def __init__(self, target_package_path, tox_env, options_array): - self.target_package_path = target_package_path - self.tox_env = tox_env - self.options_array = options_array - - -class Worker(Thread): - def __init__(self, tasks): - Thread.__init__(self) - self.tasks = tasks - self.daemon = True - self.start() - - def run(self): - while True: - func, args, kargs = self.tasks.get() - try: - func(*args, **kargs) - except Exception as e: - logging.error(e) - finally: - self.tasks.task_done() - - -def in_ci(): - return os.getenv("TF_BUILD", False) - - -class ThreadPool: - def __init__(self, num_threads): - self.tasks = Queue(num_threads) - for _ in range(num_threads): - Worker(self.tasks) - - def add_task(self, func, *args, **kargs): - self.tasks.put((func, args, kargs)) - - def map(self, func, args_list): - for args in args_list: - self.add_task(func, args) - - def wait_completion(self): - self.tasks.join() - - -def combine_coverage_files(targeted_packages): - # find tox.ini file. tox.ini is used to combine coverage paths to generate formatted report - tox_ini_file = os.path.join(root_dir, "eng", "tox", "tox.ini") - config_file_flag = "--rcfile={}".format(tox_ini_file) - - if os.path.isfile(tox_ini_file): - # for every individual coverage file, run coverage combine to combine path - for package_dir in [package for package in targeted_packages]: - coverage_file = os.path.join(package_dir, ".coverage") - if os.path.isfile(coverage_file): - cov_cmd_array = [sys.executable, "-m", "coverage", "combine"] - # tox.ini file has coverage paths to combine - # Pas tox.ini as coverage config file - cov_cmd_array.extend([config_file_flag, coverage_file]) - run_check_call(cov_cmd_array, package_dir) - else: - # not a hard error at this point - # this combine step is required only for modules if report has package name starts with .tox - logging.error("tox.ini is not found in path {}".format(root_dir)) - - -def collect_tox_coverage_files(targeted_packages): - root_coverage_dir = os.path.join(root_dir, "_coverage/") - - clean_coverage(coverage_dir) - - # coverage report has paths starting .tox and azure - # coverage combine fixes this with the help of tox.ini[coverage:paths] - combine_coverage_files(targeted_packages) - - coverage_files = [] - # generate coverage files - for package_dir in [package for package in targeted_packages]: - coverage_file = os.path.join(package_dir, ".coverage") - if os.path.isfile(coverage_file): - destination_file = os.path.join( - root_coverage_dir, ".coverage_{}".format(os.path.basename(package_dir)) - ) - shutil.copyfile(coverage_file, destination_file) - coverage_files.append(destination_file) - - logging.info("Visible uncombined .coverage files: {}".format(coverage_files)) - - if len(coverage_files): - cov_cmd_array = [sys.executable, "-m", "coverage", "combine"] - cov_cmd_array.extend(coverage_files) - - # merge them with coverage combine and copy to root - run_check_call(cov_cmd_array, os.path.join(root_dir, "_coverage/")) - - source = os.path.join(coverage_dir, "./.coverage") - dest = os.path.join(root_dir, ".coverage") - - shutil.move(source, dest) - - -def individual_workload(tox_command_tuple, workload_results): - pkg = os.path.basename(tox_command_tuple[1]) - stdout = os.path.join(tox_command_tuple[1], "stdout.txt") - stderr = os.path.join(tox_command_tuple[1], "stderr.txt") - tox_dir = os.path.join(tox_command_tuple[1], "./.tox/") - - with open(stdout, "w") as f_stdout, open(stderr, "w") as f_stderr: - proc = Popen( - tox_command_tuple[0], - stdout=f_stdout, - stderr=f_stderr, - cwd=tox_command_tuple[1], - env=os.environ.copy(), - ) - - logging.info("POpened task for for {}".format(pkg)) - proc.wait() - - return_code = proc.returncode - - if proc.returncode != 0: - logging.error("{} returned with code {}".format(pkg, proc.returncode)) - else: - logging.info( - "{} returned with code 0, output will be printed after the test run completes.".format( - pkg - ) - ) - - if read_file(stderr): - logging.error("Package {} had stderror output. Logging.".format(pkg)) - return_code = "StdErr output detected" - - workload_results[tox_command_tuple[1]] = (return_code, stdout, stderr) - - if in_ci(): - shutil.rmtree(tox_dir) - - -def execute_tox_parallel(tox_command_tuples): - pool = ThreadPool(pool_size) - workload_results = {} - run_result = 0 - - for index, cmd_tuple in enumerate(tox_command_tuples): - pool.add_task(individual_workload, cmd_tuple, workload_results) - - pool.wait_completion() - - for key in workload_results.keys(): - log_file(workload_results[key][1]) - - if workload_results[key][0] != 0: - logging.error( - "{} tox invocation exited with returncode {}".format( - os.path.basename(key), workload_results[key][0] - ) - ) - run_result = 1 - - return run_result - - -def compare_req_to_injected_reqs(parsed_req, injected_packages): - if parsed_req is None: - return False - - return any(parsed_req.name in req for req in injected_packages) - - -def inject_custom_reqs(file, injected_packages, package_dir): - req_lines = [] - injected_packages = [p for p in re.split("[\s,]", injected_packages) if p] - - if injected_packages: - logging.info( - "Adding custom packages to requirements for {}".format(package_dir) - ) - with open(file, "r") as f: - for line in f: - try: - parsed_req = [req for req in parse_requirements(line)] - except RequirementParseError as e: - parsed_req = [None] - req_lines.append((line, parsed_req)) - - if req_lines: - all_adjustments = injected_packages + [ - line_tuple[0].strip() - for line_tuple in req_lines - if line_tuple[0].strip() - and not compare_req_to_injected_reqs( - line_tuple[1][0], injected_packages - ) - ] - else: - all_adjustments = injected_packages - - with open(file, "w") as f: - # note that we directly use '\n' here instead of os.linesep due to how f.write() actually handles this stuff internally - # If a file is opened in text mode (the default), during write python will accidentally double replace due to "\r" being - # replaced with "\r\n" on Windows. Result: "\r\n\n". Extra line breaks! - f.write("\n".join(all_adjustments)) - - -def build_whl_for_req(req, package_path): - if ".." in req: - # Create temp path if it doesn't exist - temp_dir = os.path.join(package_path, ".tmp_whl_dir") - if not os.path.exists(temp_dir): - os.mkdir(temp_dir) - - req_pkg_path = os.path.abspath(os.path.join(package_path, req.replace("\n", ""))) - pkg_name, version, _, _ = parse_setup(req_pkg_path) - logging.info("Building wheel for package {}".format(pkg_name)) - run_check_call([sys.executable, "setup.py", "bdist_wheel", "-d", temp_dir], req_pkg_path) - - whl_path = find_whl(pkg_name, version, temp_dir) - logging.info("Wheel for package {0} is {1}".format(pkg_name, whl_path)) - logging.info("Replacing dev requirement. Old requirement:{0}, New requirement:{1}".format(req, whl_path)) - return whl_path - else: - return req - -def replace_dev_reqs(file): - adjusted_req_lines = [] - - with open(file, "r") as f: - for line in f: - args = [ - part.strip() - for part in line.split() - if part and not part.strip() == "-e" - ] - amended_line = " ".join(args) - adjusted_req_lines.append(amended_line) - - logging.info("Old dev requirements:{}".format(adjusted_req_lines)) - adjusted_req_lines = list(map(lambda x: build_whl_for_req(x, os.path.dirname(file)), adjusted_req_lines)) - logging.info("New dev requirements:{}".format(adjusted_req_lines)) - - with open(file, "w") as f: - # note that we directly use '\n' here instead of os.linesep due to how f.write() actually handles this stuff internally - # If a file is opened in text mode (the default), during write python will accidentally double replace due to "\r" being - # replaced with "\r\n" on Windows. Result: "\r\n\n". Extra line breaks! - f.write("\n".join(adjusted_req_lines)) - - -def execute_tox_serial(tox_command_tuples): - return_code = 0 - - for index, cmd_tuple in enumerate(tox_command_tuples): - tox_dir = os.path.abspath(os.path.join(cmd_tuple[1], "./.tox/")) - - logging.info( - "Running tox for {}. {} of {}.".format( - os.path.basename(cmd_tuple[1]), index + 1, len(tox_command_tuples) - ) - ) - - result = run_check_call(cmd_tuple[0], cmd_tuple[1], always_exit=False) - - if result is not None and result != 0: - return_code = result - - if in_ci(): - shutil.rmtree(tox_dir) - - return return_code - - -def prep_and_run_tox(targeted_packages, parsed_args, options_array=[]): - if parsed_args.wheel_dir: - os.environ["PREBUILT_WHEEL_DIR"] = parsed_args.wheel_dir - - if parsed_args.mark_arg: - options_array.extend(["-m", "{}".format(parsed_args.mark_arg)]) - - tox_command_tuples = [] - - for index, package_dir in enumerate(targeted_packages): - destination_tox_ini = os.path.join(package_dir, "tox.ini") - destination_dev_req = os.path.join(package_dir, "dev_requirements.txt") - - tox_execution_array = [sys.executable, "-m", "tox"] - - local_options_array = options_array[:] - - # Get code coverage params for current package - package_name = os.path.basename(package_dir) - coverage_commands = create_code_coverage_params(parsed_args, package_name) - local_options_array.extend(coverage_commands) - - pkg_egg_info_name = "{}.egg-info".format(package_name.replace("-", "_")) - local_options_array.extend(["--ignore", pkg_egg_info_name]) - - # if we are targeting only packages that are management plane, it is a possibility - # that no tests running is an acceptable situation - # we explicitly handle this here. - if is_error_code_5_allowed(package_dir, package_name): - local_options_array.append("--suppress-no-test-exit-code") - - # if not present, re-use base - if not os.path.exists(destination_tox_ini) or ( - os.path.exists(destination_tox_ini) - and os.path.basename(package_dir) in IGNORED_TOX_INIS - ): - logging.info( - "No customized tox.ini present, using common eng/tox/tox.ini for {}".format( - os.path.basename(package_dir) - ) - ) - tox_execution_array.extend(["-c", DEFAULT_TOX_INI_LOCATION]) - - # handle empty file - if not os.path.exists(destination_dev_req): - logging.info("No dev_requirements present.") - with open(destination_dev_req, "w+") as file: - file.write("\n") - - if in_ci(): - replace_dev_reqs(destination_dev_req) - os.environ["TOX_PARALLEL_NO_SPINNER"] = "1" - - inject_custom_reqs( - destination_dev_req, parsed_args.injected_packages, package_dir - ) - - if parsed_args.tox_env: - tox_execution_array.extend(["-e", parsed_args.tox_env]) - - if parsed_args.tenvparallel: - tox_execution_array.extend(["-p", "all"]) - - if local_options_array: - tox_execution_array.extend(["--"] + local_options_array) - - tox_command_tuples.append((tox_execution_array, package_dir)) - - if parsed_args.tparallel: - return_code = execute_tox_parallel(tox_command_tuples) - else: - return_code = execute_tox_serial(tox_command_tuples) - - if not parsed_args.disablecov: - collect_tox_coverage_files(targeted_packages) - - sys.exit(return_code) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/verify_change_log.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/verify_change_log.py deleted file mode 100644 index 63480b4d457..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/devops_tasks/verify_change_log.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python - -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# Normally, this module will be executed as referenced as part of the devops build definitions. -# An enterprising user can easily glance over this and leverage for their own purposes. - -import argparse -import sys -import os -import logging - -from common_tasks import process_glob_string, parse_setup, run_check_call - - -logging.getLogger().setLevel(logging.INFO) - -root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) -psscript = os.path.join(root_dir, "scripts", "devops_tasks", "find_change_log.ps1") - -# Service fabric change log has non standard versioning for e.g 7.0.0.0 -# Verify change log should skip this package since this script looks for standard version format of x.y.z -NON_STANDARD_CHANGE_LOG_PACKAGES = ["azure-servicefabric",] - -def find_change_log(targeted_package, version): - # Execute powershell script to find a matching version in change log - command_array = ["pwsh"] - command_array.append("-File {}".format(psscript)) - command_array.append("-workingDir {}".format(targeted_package)) - command_array.append("-version {}".format(version)) - command_array.append("set-ExecutionPolicy Unrestricted") - - allowed_return_codes = [] - - # Execute powershell script to verify version - er_result = run_check_call( - command_array, root_dir, allowed_return_codes, True, False - ) - - if er_result: - logging.error( - "Failed to find version in change log for package {}".format( - targeted_package - ) - ) - return False - - return True - - -def verify_packages(targeted_packages): - # run the build and distribution - change_log_missing = {} - - for package in targeted_packages: - # Parse setup.py using common helper method to get version and package name - pkg_name, version, _, _ = parse_setup(package) - - # Skip management packages and any explicitly excluded packages - if "-mgmt" in pkg_name or pkg_name in NON_STANDARD_CHANGE_LOG_PACKAGES: - logging.info("Skipping {} due to known exclusion in change log verification".format(pkg_name)) - continue - - if not find_change_log(package, version): - logging.error( - "Change log is not updated for package {0}, version {1}".format( - pkg_name, version - ) - ) - change_log_missing[pkg_name] = version - - return change_log_missing - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Verifies latest version is updated in change log, Called from DevOps YAML Pipeline" - ) - - parser.add_argument( - "glob_string", - nargs="?", - help=( - "A comma separated list of glob strings that will target the top level directories that contain packages. " - 'Examples: All == "azure-*", Single = "azure-keyvault"' - ), - ) - - parser.add_argument( - "--service", - help=( - "Name of service directory (under sdk/) to build." - "Example: --service applicationinsights" - ), - ) - - parser.add_argument( - "--pkgfilter", - default="", - dest="package_filter_string", - help=( - "An additional string used to filter the set of artifacts by a simple CONTAINS clause." - ), - ) - - args = parser.parse_args() - - # We need to support both CI builds of everything and individual service - # folders. This logic allows us to do both. - if args.service: - service_dir = os.path.join("sdk", args.service) - target_dir = os.path.join(root_dir, service_dir) - else: - target_dir = root_dir - - # Skip nspkg and metapackage from version check. - # Change log file may be missing for these two types - # process glob helper methods filter nspkg and metapackages with filter type "Docs" - targeted_packages = process_glob_string( - args.glob_string, target_dir, args.package_filter_string, "Docs" - ) - change_missing = verify_packages(targeted_packages) - if len(change_missing) > 0: - logging.error("Below packages do not have change log") - logging.error("***************************************************") - for pkg_name in change_missing.keys(): - logging.error("{0} - {1}".format(pkg_name, change_missing[pkg_name])) - - sys.exit(1) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multi_api_readme_help.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multi_api_readme_help.py deleted file mode 100644 index c73744f32fd..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multi_api_readme_help.py +++ /dev/null @@ -1,122 +0,0 @@ -import json -import logging -from pathlib import Path -import sys - - -_LOGGER = logging.getLogger(__name__) - -_TAG_PREFIX = """### Tag: package-{api_version}-only - -These settings apply only when `--tag=package-{api_version}-only` is specified on the command line. - -```yaml $(tag) == 'package-{api_version}-only' -input-file:""" -_TAG_SUFFIX = "```\n\n" - -_BATCH_PREFIX = """```yaml $(python) && $(multiapi) -batch:""" -_BATCH_SUFFIX = "```\n\n" - -_PY_NAMESPACE = """### Tag: package-{api_version}-only and python - -These settings apply only when `--tag=package-{api_version}-only --python` is specified on the command line. -Please also specify `--python-sdks-folder=`. - -``` yaml $(tag) == 'package-{api_version}-only' && $(python) -python: - namespace: $(python-base-namespace).{ns} - output-folder: $(python-sdks-folder)/$(python-base-folder)/{ns} -``` -""" - -def get_api_versions(root): - - api_versions = {} - prefixes_per_path = {} - - rp_folders = root.glob("Microsoft.*") - for rp_folder in rp_folders: - _LOGGER.info(f"Parsing folder {rp_folder}") - for preview_stable in rp_folder.iterdir(): - _LOGGER.info(f"Currently in {preview_stable}") - for api_version in preview_stable.iterdir(): - _LOGGER.info(f"Currently in {api_version}") - for swagger in api_version.glob("*.json"): - prefixes_per_path[swagger] = parse_swagger(swagger) - api_versions.setdefault(api_version.name, []).append(swagger.relative_to(root).as_posix()) - - # Try to detect when it's problematic. That's tough, the following logic is definitely - # not handling all the touch parts yet... - - # 1- If a file declare several prefixes, let's warning - for swagger_path, prefixed_used in prefixes_per_path.items(): - if len(prefixed_used) == 1: - _LOGGER.info(f"File {swagger_path} uses only one prefix: {prefixed_used}") - else: - _LOGGER.warn(f"File {swagger_path} uses several prefixes: {prefixed_used}") - - - # Let's print - print_tags(api_versions) - print_batch(api_versions) - print_python_namespace(api_versions) - -def print_tags(api_versions): - for api_version in sorted(api_versions.keys(), reverse=True): - swagger_files = api_versions[api_version] - print(_TAG_PREFIX.format(api_version=api_version)) - for swagger_file in swagger_files: - print("- {}".format(swagger_file)) - print(_TAG_SUFFIX) - - -def print_batch(api_versions): - print(_BATCH_PREFIX) - for api_version in sorted(api_versions.keys(), reverse=True): - print(f" - tag: package-{api_version}-only") - print(_BATCH_SUFFIX) - -def print_python_namespace(api_versions): - for api_version in sorted(api_versions.keys(), reverse=True): - swagger_files = api_versions[api_version] - print(_PY_NAMESPACE.format( - api_version=api_version, - ns="v"+api_version.replace("-", "_")) - ) - -def parse_swagger(swagger_path): - _LOGGER.info(f"Parsing {swagger_path}") - with swagger_path.open() as swagger: - parsed_swagger = json.load(swagger) - - api_version = parsed_swagger["info"]["version"] - - operations = operation_finder(parsed_swagger) - - prefixed_used = {op.split("_")[0] for op in operations if "_" in op} - return prefixed_used - -def operation_finder(swagger_root): - result = set() - for key, node in swagger_root.items(): - if key == "definitions": # Skipping some node - return result - if key == "operationId": - result.add(node) - # Can skip it now, only one operationId per node - return result - if isinstance(node, dict): - result |= operation_finder(node) - return result - - -if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG if "--debug" in sys.argv else logging.WARNING) - - root = Path(__file__).parent - - root = Path(sys.argv[1]).relative_to(root) - - _LOGGER.info(f"My root: {root}") - get_api_versions(root) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multiapi_init_gen.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multiapi_init_gen.py deleted file mode 100644 index e8cd28f6243..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/multiapi_init_gen.py +++ /dev/null @@ -1,545 +0,0 @@ -import argparse -import ast -import importlib -import inspect -import logging -import os -import pkgutil -import re -import sys -import shutil -from pathlib import Path - -from typing import List, Tuple, Any, Union - -try: - import msrestazure -except: # Install msrestazure. Would be best to mock it, since we don't need it, but all scenarios I know are fine with a pip install for now - import subprocess - - subprocess.call( - sys.executable + " -m pip install msrestazure --index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/", shell=True - ) # Use shell to use venv if available - -try: - from jinja2 import Template, FileSystemLoader, Environment -except: - import subprocess - - subprocess.call( - sys.executable + " -m pip install jinja2 --index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/", shell=True - ) # Use shell to use venv if available - from jinja2 import Template, FileSystemLoader, Environment - - -try: - import azure.common -except: - sys.path.append( - str((Path(__file__).parents[1] / "sdk" / "core" / "azure-common").resolve()) - ) - import azure.common - -import pkg_resources - -pkg_resources.declare_namespace("azure") - -_LOGGER = logging.getLogger(__name__) - - -def parse_input(input_parameter): - """From a syntax like package_name#submodule, build a package name - and complete module name. - """ - split_package_name = input_parameter.split("#") - package_name = split_package_name[0] - module_name = package_name.replace("-", ".") - if len(split_package_name) >= 2: - module_name = ".".join([module_name, split_package_name[1]]) - return package_name, module_name - - -# given an input of a name, we need to return the appropriate relative diff between the sdk_root and the actual package directory -def resolve_package_directory(package_name, sdk_root=None): - packages = [ - p.parent - for p in ( - list(sdk_root.glob("{}/setup.py".format(package_name))) - + list(sdk_root.glob("sdk/*/{}/setup.py".format(package_name))) - ) - ] - - if len(packages) > 1: - print( - "There should only be a single package matched in either repository structure. The following were found: {}".format( - packages - ) - ) - sys.exit(1) - - return str(packages[0].relative_to(sdk_root)) - - -def get_versioned_modules( - package_name: str, module_name: str, sdk_root: Path = None -) -> List[Tuple[str, Any]]: - """Get (label, submodule) where label starts with "v20" and submodule is the corresponding imported module. - """ - if not sdk_root: - sdk_root = Path(__file__).parents[1] - - path_to_package = resolve_package_directory(package_name, sdk_root) - azure.__path__.append(str((sdk_root / path_to_package / "azure").resolve())) - - # Doesn't work with namespace package - # sys.path.append(str((sdk_root / package_name).resolve())) - module_to_generate = importlib.import_module(module_name) - return { - label: importlib.import_module("." + label, module_to_generate.__name__) - for (_, label, ispkg) in pkgutil.iter_modules(module_to_generate.__path__) - if label.startswith("v20") and ispkg - } - - -class ApiVersionExtractor(ast.NodeVisitor): - def __init__(self, *args, **kwargs): - self.api_version = None - super(ApiVersionExtractor, self).__init__(*args, **kwargs) - - def visit_Assign(self, node): - try: - if node.targets[0].id == "api_version": - self.api_version = node.value.s - except Exception: - pass - - -def extract_api_version_from_code(function): - """Will extract from __code__ the API version. Should be use if you use this is an operation group with no constant api_version. - """ - try: - srccode = inspect.getsource(function) - try: - ast_tree = ast.parse(srccode) - except IndentationError: - ast_tree = ast.parse("with 0:\n" + srccode) - - api_version_visitor = ApiVersionExtractor() - api_version_visitor.visit(ast_tree) - return api_version_visitor.api_version - except Exception: - raise - - -def get_client_class_name_from_module(module): - """Being a module that is an Autorest generation, get the client name.""" - # Using the fact that Client is always the first element in __all__ - # I externalize that code in a class in case we need to be smarter later - return module.__all__[0] - - -def build_operation_meta(versioned_modules): - """Introspect the client: - - version_dict => { - 'application_gateways': [ - ('v2018_05_01', 'ApplicationGatewaysOperations') - ] - } - mod_to_api_version => {'v2018_05_01': '2018-05-01'} - """ - - version_dict = {} - mod_to_api_version = {} - for versionned_label, versionned_mod in versioned_modules.items(): - extracted_api_versions = set() - client_doc = versionned_mod.__dict__[ - get_client_class_name_from_module(versionned_mod) - ].__doc__ - operations = list( - re.finditer( - r":ivar (?P[a-z_0-9]+): \w+ operations\n\s+:vartype (?P=attr): .*.operations.(?P\w+)\n", - client_doc, - ) - ) - for operation in operations: - attr, clsname = operation.groups() - _LOGGER.debug("Class name: %s", clsname) - version_dict.setdefault(attr, []).append((versionned_label, clsname)) - - # Create a fake operation group to extract easily the real api version - extracted_api_version = None - try: - extracted_api_version = versionned_mod.operations.__dict__[clsname]( - None, None, None, None - ).api_version - _LOGGER.debug("Found an obvious API version: %s", extracted_api_version) - if extracted_api_version: - extracted_api_versions.add(extracted_api_version) - except Exception: - _LOGGER.debug( - "Should not happen. I guess it mixed operation groups like VMSS Network..." - ) - for func_name, function in versionned_mod.operations.__dict__[ - clsname - ].__dict__.items(): - if not func_name.startswith("__"): - _LOGGER.debug("Try to extract API version from: %s", func_name) - extracted_api_version = extract_api_version_from_code(function) - _LOGGER.debug( - "Extracted API version: %s", extracted_api_version - ) - if extracted_api_version: - extracted_api_versions.add(extracted_api_version) - - if not extracted_api_versions: - sys.exit( - "Was not able to extract api_version of {}".format(versionned_label) - ) - if len(extracted_api_versions) >= 2: - # Mixed operation group, try to figure out what we want to use - final_api_version = None - _LOGGER.warning( - "Found too much API version: {} in label {}".format( - extracted_api_versions, versionned_label - ) - ) - for candidate_api_version in extracted_api_versions: - if ( - "v{}".format(candidate_api_version.replace("-", "_")) - == versionned_label - ): - final_api_version = candidate_api_version - _LOGGER.warning( - "Guessing you want {} based on label {}".format( - final_api_version, versionned_label - ) - ) - break - else: - sys.exit( - "Unble to match {} to label {}".format( - extracted_api_versions, versionned_label - ) - ) - extracted_api_versions = {final_api_version} - mod_to_api_version[versionned_label] = extracted_api_versions.pop() - - # latest: api_version=mod_to_api_version[versions[-1][0]] - - return version_dict, mod_to_api_version - - -def build_operation_mixin_meta(versioned_modules): - """Introspect the client: - - version_dict => { - 'check_dns_name_availability': { - 'doc': 'docstring', - 'signature': '(self, p1, p2, **operation_config), - 'call': 'p1, p2', - 'available_apis': [ - 'v2018_05_01' - ] - } - } - """ - mixin_operations = {} - - for versionned_label, versionned_mod in sorted(versioned_modules.items()): - - client_name = get_client_class_name_from_module(versionned_mod) - client_class = versionned_mod.__dict__[client_name] - - # Detect if this client is using an operation mixin (Network) - # Operation mixins are available since Autorest.Python 4.x - operations_mixin = next( - (c for c in client_class.__mro__ if "OperationsMixin" in c.__name__), None - ) - if not operations_mixin: - continue - - for func_name, func in operations_mixin.__dict__.items(): - # Work only on functions - if func_name.startswith("_"): - continue - - signature = inspect.signature(func) - mixin_operations.setdefault(func_name, {}).setdefault( - "available_apis", [] - ).append(versionned_label) - mixin_operations[func_name]["doc"] = func.__doc__ - mixin_operations[func_name]["signature"] = str(signature) - mixin_operations[func_name]["call"] = ", ".join( - list(signature.parameters)[1:-1] - ) - - return mixin_operations - - -def build_last_rt_list( - versioned_operations_dict, mixin_operations, last_api_version, preview_mode -): - """Build the a mapping RT => API version if RT doesn't exist in latest detected API version. - - Example: - last_rt_list = { - 'check_dns_name_availability': '2018-05-01' - } - - There is one subtle scenario if PREVIEW mode is disabled: - - RT1 available on 2019-05-01 and 2019-06-01-preview - - RT2 available on 2019-06-01-preview - - RT3 available on 2019-07-01-preview - - Then, if I put "RT2: 2019-06-01-preview" in the list, this means I have to make - "2019-06-01-preview" the default for models loading (otherwise "RT2: 2019-06-01-preview" won't work). - But this likely breaks RT1 default operations at "2019-05-01", with default models at "2019-06-01-preview" - since "models" are shared for the entire set of operations groups (I wished models would be split by operation groups, but meh, that's not the case) - - So, until we have a smarter Autorest to deal with that, only preview RTs which do not share models with a stable RT can be added to this map. - In this case, RT2 is out, RT3 is in. - """ - - def there_is_a_rt_that_contains_api_version(rt_dict, api_version): - "Test in the given api_version is is one of those RT." - for rt_api_version in rt_dict.values(): - if api_version in rt_api_version: - return True - return False - - last_rt_list = {} - # Operation groups - versioned_dict = { - operation_name: [meta[0] for meta in operation_metadata] - for operation_name, operation_metadata in versioned_operations_dict.items() - } - # Operations at client level - versioned_dict.update( - { - operation_name: operation_metadata["available_apis"] - for operation_name, operation_metadata in mixin_operations.items() - } - ) - - for operation, api_versions_list in versioned_dict.items(): - local_last_api_version = get_floating_latest(api_versions_list, preview_mode) - if local_last_api_version == last_api_version: - continue - # If some others RT contains "local_last_api_version", and it's greater than the future default, danger, don't profile it - if ( - there_is_a_rt_that_contains_api_version( - versioned_dict, local_last_api_version - ) - and local_last_api_version > last_api_version - ): - continue - last_rt_list[operation] = local_last_api_version - - return last_rt_list - - -def get_floating_latest(api_versions_list, preview_mode): - """Get the floating latest, from a random list of API versions. - """ - api_versions_list = list(api_versions_list) - absolute_latest = sorted(api_versions_list)[-1] - trimmed_preview = [ - version for version in api_versions_list if "preview" not in version - ] - - # If there is no preview, easy: the absolute latest is the only latest - if not trimmed_preview: - return absolute_latest - - # If preview mode, let's use the absolute latest, I don't care preview or stable - if preview_mode: - return absolute_latest - - # If not preview mode, and there is preview, take the latest known stable - return sorted(trimmed_preview)[-1] - - -def find_module_folder(package_name, module_name): - sdk_root = Path(__file__).parents[1] - _LOGGER.debug("SDK root is: %s", sdk_root) - path_to_package = resolve_package_directory(package_name, sdk_root) - module_path = ( - sdk_root / Path(path_to_package) / Path(module_name.replace(".", os.sep)) - ) - _LOGGER.debug("Module path is: %s", module_path) - return module_path - - -def find_client_file(package_name, module_name): - module_path = find_module_folder(package_name, module_name) - return next(module_path.glob("*_client.py")) - - -def patch_import(file_path: Union[str, Path]) -> None: - """If multi-client package, we need to patch import to be - from ..version - and not - from .version - - That should probably means those files should become a template, but since right now - it's literally one dot, let's do it the raw way. - """ - # That's a dirty hack, maybe it's worth making configuration a template? - with open(file_path, "rb") as read_fd: - conf_bytes = read_fd.read() - conf_bytes = conf_bytes.replace( - b" .version", b" ..version" - ) # Just a dot right? Worth its own template for that? :) - with open(file_path, "wb") as write_fd: - write_fd.write(conf_bytes) - - -def has_subscription_id(client_class): - return "subscription_id" in inspect.signature(client_class).parameters - - -def main(input_str, default_api=None): - - # If True, means the auto-profile will consider preview versions. - # If not, if it exists a stable API version for a global or RT, will always be used - preview_mode = default_api and "preview" in default_api - - # The only known multi-client package right now is azure-mgmt-resource - is_multi_client_package = "#" in input_str - - package_name, module_name = parse_input(input_str) - versioned_modules = get_versioned_modules(package_name, module_name) - versioned_operations_dict, mod_to_api_version = build_operation_meta( - versioned_modules - ) - - client_folder = find_module_folder(package_name, module_name) - last_api_version = get_floating_latest(mod_to_api_version.keys(), preview_mode) - - # I need default_api to be v2019_06_07_preview shaped if it exists, let's be smart - # and change it automatically so I can take both syntax as input - if default_api and not default_api.startswith("v"): - last_api_version = [ - mod_api - for mod_api, real_api in mod_to_api_version.items() - if real_api == default_api - ][0] - _LOGGER.info("Default API version will be: %s", last_api_version) - - last_api_path = client_folder / last_api_version - - # In case we are transitioning from a single api generation, clean old folders - shutil.rmtree(str(client_folder / "operations"), ignore_errors=True) - shutil.rmtree(str(client_folder / "models"), ignore_errors=True) - - shutil.copy( - str(client_folder / last_api_version / "_configuration.py"), - str(client_folder / "_configuration.py"), - ) - shutil.copy( - str(client_folder / last_api_version / "__init__.py"), - str(client_folder / "__init__.py"), - ) - if is_multi_client_package: - _LOGGER.warning("Patching multi-api client basic files") - patch_import(client_folder / "_configuration.py") - patch_import(client_folder / "__init__.py") - - versionned_mod = versioned_modules[last_api_version] - client_name = get_client_class_name_from_module(versionned_mod) - client_class = versionned_mod.__dict__[client_name] - - # Detect if this client is using an operation mixin (Network) - # Operation mixins are available since Autorest.Python 4.x - mixin_operations = build_operation_mixin_meta(versioned_modules) - - # If we get a StopIteration here, means the API version folder is broken - client_file_name = next(last_api_path.glob("*_client.py")).name - - # versioned_operations_dict => { - # 'application_gateways': [ - # ('v2018-05-01', 'ApplicationGatewaysOperations') - # ] - # } - # mod_to_api_version => {'v2018-05-01': '2018-05-01'} - # mixin_operations => { - # 'check_dns_name_availability': { - # 'doc': 'docstring', - # 'signature': '(self, p1, p2, **operation_config), - # 'call': 'p1, p2', - # 'available_apis': [ - # 'v2018_05_01' - # ] - # } - # } - # last_rt_list = { - # 'check_dns_name_availability': '2018-05-01' - # } - - last_rt_list = build_last_rt_list( - versioned_operations_dict, mixin_operations, last_api_version, preview_mode - ) - - conf = { - "client_name": client_name, - "has_subscription_id": has_subscription_id(client_class), - "module_name": module_name, - "operations": versioned_operations_dict, - "mixin_operations": mixin_operations, - "mod_to_api_version": mod_to_api_version, - "last_api_version": mod_to_api_version[last_api_version], - "client_doc": client_class.__doc__.split("\n")[0], - "last_rt_list": last_rt_list, - "default_models": sorted( - {last_api_version} | {versions for _, versions in last_rt_list.items()} - ), - } - - env = Environment( - loader=FileSystemLoader(str(Path(__file__).parents[0] / "templates")), - keep_trailing_newline=True, - ) - - for template_name in env.list_templates(): - # Don't generate files if they is not operations mixins - if template_name == "_operations_mixin.py" and not mixin_operations: - continue - - # Some file doesn't use the template name - if template_name == "_multiapi_client.py": - output_filename = client_file_name - else: - output_filename = template_name - - future_filepath = client_folder / output_filename - - template = env.get_template(template_name) - result = template.render(**conf) - - with future_filepath.open("w") as fd: - fd.write(result) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Multi-API client generation for Azure SDK for Python" - ) - parser.add_argument( - "--debug", dest="debug", action="store_true", help="Verbosity in DEBUG mode" - ) - parser.add_argument( - "--default-api-version", - dest="default_api", - default=None, - help="Force default API version, do not detect it. [default: %(default)s]", - ) - parser.add_argument("package_name", help="The package name.") - - args = parser.parse_args() - - main_logger = logging.getLogger() - logging.basicConfig() - main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) - - main(args.package_name, default_api=args.default_api) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/README.md b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/README.md deleted file mode 100644 index 7e2b912c62b..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/README.md +++ /dev/null @@ -1,60 +0,0 @@ -## Linting the Guidelines - -In order to lint for the guidelines, you must make sure you are using the pylintrc file. -It is recommended you run pylint at the library package level to be consistent with how the CI runs pylint. - -Check that you are running pylint version >=2.31 and astroid version >=2.25. - -**How to run pylint locally using the pylintrc:** - -1. Run pylint at the root of the repo and it will automatically find the pylintrc: - ```bash - C:\azure-sdk-for-python>pylint sdk/storage/azure-storage-blob/azure - ``` -2. Add the --rcfile command line argument with a relative path to the pylintrc from your current directory: - ```bash - C:\azure-sdk-for-python\sdk\storage>pylint --rcfile="../../pylintrc" azure-storage-blob - ``` -3. Set the environment variable PYLINTRC to the absolute path of the pylintrc file: - ```bash - set PYLINTRC=C:\azure-sdk-for-python\pylintrc - ``` - Run pylint: - ```bash - C:\azure-sdk-for-python\sdk\storage>pylint azure-storage-blob - ``` -4. Run pylint at the package level using tox and it will find the pylintrc file: - ```bash - C:\azure-sdk-for-python\sdk\storage\azure-storage-blob>tox -c ../../../eng/tox/tox.ini -e lint - ``` -5. If you use the pylint extension for VS code or Pycharm it *should* find the pylintrc automatically. - -**How to disable a pylint error:** -```bash -# pylint:disable=connection-string-should-not-be-constructor-param -``` - -The pylint custom checkers for SDK guidelines fall into messages range C4717 - C4738. -You will know you came across a custom checker if it contains a link to the guidelines. - -In the case of a false positive, use the disable command to remove the pylint error. - -**Guidelines that are currently linted:** - -| Pylint checker name | How to fix this | How to disable this rule | Link to python guideline | -|----------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| -| client-method-should-not-use-static-method | Use module level functions instead. | # pylint:disable=connection-string-should-not-be-constructor-param | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| missing-client-constructor-parameter-credential | Add a credential parameter to the client constructor. Do not use plural form "credentials". | # pylint:disable=missing-client-constructor-parameter-credential | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| missing-client-constructor-parameter-kwargs | Add a **kwargs parameter to the client constructor. | # pylint:disable=missing-client-constructor-parameter-kwargs | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| client-method-has-more-than-5-positional-arguments | Use keyword arguments to reduce number of positional arguments. | # pylint:disable=client-method-has-more-than-5-positional-arguments | [link](https://azure.github.io/azure-sdk/python_introduction.html#method-signatures) | -| client-method-missing-type-annotations | Check that param/return type comments are present or that param/return type annotations are present. Check that you did not mix type comments with type annotations. | # pylint:disable=client-method-missing-type-annotations | [link](https://azure.github.io/azure-sdk/python_introduction.html#types-or-not) | -| client-incorrect-naming-convention | Check that you use... snake_case for variable, function, and method names. Pascal case for types. ALL CAPS for constants. | # pylint:disable=client-incorrect-naming-convention | [link](https://azure.github.io/azure-sdk/python_introduction.html#naming-conventions) | -| client-method-missing-kwargs | Check that any methods that make network calls have a **kwargs parameter. | # pylint:disable=client-method-missing-kwargs | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| config-missing-kwargs-in-policy | Check that the policies in your configuration function contain a **kwargs parameter. | # pylint:disable=config-missing-kwargs-in-policy | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| async-client-bad-name | Remove "Async" from your service client's name. | # pylint:disable=async-client-bad-name | [link](https://azure.github.io/azure-sdk/python_design.html#async-support) | -| file-needs-copyright-header | Add a copyright header to the top of your file. | # pylint:disable=file-needs-copyright-header | [link](https://azure.github.io/azure-sdk/policies_opensource.html) | -| client-method-name-no-double-underscore | Don't use method names prefixed with "__". | # pylint:disable=client-method-name-no-double-underscore | [link](https://azure.github.io/azure-sdk/python_introduction.html#public-vs-private) | -| specify-parameter-names-in-call | Specify the parameter names when calling methods with more than 2 required positional parameters. e.g. self.get_foo(one, two, three=three, four=four, five=five) | # pylint:disable=specify-parameter-names-in-call | [link](https://azure.github.io/azure-sdk/python_introduction.html#method-signatures) | -| connection-string-should-not-be-constructor-param | Remove connection string parameter from client constructor. Create a method that creates the client using a connection string. | # pylint:disable=connection-string-should-not-be-constructor-param | [link](https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods) | -| package-name-incorrect | Change your distribution package name to only include dashes, e.g. azure-storage-file-share | # pylint:disable=package-name-incorrect | [link](https://azure.github.io/azure-sdk/python_implementation.html#packaging) | -| client-suffix-needed | Service client types should use a "Client" suffix, e.g. BlobClient. | # pylint:disable=client-suffix-needed | [link](https://azure.github.io/azure-sdk/python_design.html#clients) | \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/__init__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/pylint_guidelines_checker.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/pylint_guidelines_checker.py deleted file mode 100644 index 24e7b75064e..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/pylint_guidelines_checker.py +++ /dev/null @@ -1,1653 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ - -""" -Pylint custom checkers for SDK guidelines: C4717 - C4738 -""" - -import logging -import astroid -from pylint.checkers import BaseChecker -from pylint.interfaces import IAstroidChecker -logger = logging.getLogger(__name__) - - -class ClientConstructorTakesCorrectParameters(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-constructor" - priority = -1 - msgs = { - "C4717": ( - "Client constructor is missing a credential parameter. See details:" - " https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods", - "missing-client-constructor-parameter-credential", - "All client types should accept a credential parameter.", - ), - "C4718": ( - "Client constructor is missing a **kwargs parameter. See details:" - " https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods", - "missing-client-constructor-parameter-kwargs", - "All client types should accept a **kwargs parameter.", - ) - } - options = ( - ( - "ignore-missing-client-constructor-parameter-credential", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client constructors without a credential parameter", - }, - ), - ( - "ignore-missing-client-constructor-parameter-kwargs", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client constructors without a **kwargs parameter", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientConstructorTakesCorrectParameters, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits the constructor within a client class and checks that it has - credential and kwargs parameters. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.name == "__init__" and node.parent.name.endswith("Client") and \ - node.parent.name not in self.ignore_clients: - arg_names = [argument.name for argument in node.args.args] - if "credential" not in arg_names: - self.add_message( - msg_id="missing-client-constructor-parameter-credential", node=node, confidence=None - ) - if not node.args.kwarg: - self.add_message( - msg_id="missing-client-constructor-parameter-kwargs", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if constructor has correct parameters.") - pass - - -class ClientHasKwargsInPoliciesForCreateConfigurationMethod(BaseChecker): - __implements__ = IAstroidChecker - - name = "configuration-policies-kwargs" - priority = -1 - msgs = { - "C4719": ( - "A policy in the create_configuration() function is missing a **kwargs argument. See details:" - " https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods", - "config-missing-kwargs-in-policy", - "All policies should take a **kwargs parameter.", - ) - } - options = ( - ( - "ignore-config-missing-kwargs-in-policy", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow clients instantiate a policy without a kwargs parameter.", - }, - ), - ) - - def __init__(self, linter=None): - super(ClientHasKwargsInPoliciesForCreateConfigurationMethod, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits the any method called `create_configuration` or `create_config` and checks - that every policy in the method contains a kwargs parameter. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.name == "create_configuration" or node.name == "create_config": - node.decorators = None - for idx in range(len(node.body)): - # Gets each line of the method as a string - line = list(node.get_children())[idx].as_string() - if line.find("Policy") != -1: - if line.find("**kwargs") == -1: - self.add_message( - msg_id="config-missing-kwargs-in-policy", - node=list(node.get_children())[idx], - confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if kwargs parameter in policies.") - pass - - -class ClientHasApprovedMethodNamePrefix(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-approved-method-name-prefix" - priority = -1 - msgs = { - "C4720": ( - "Client is not using an approved method name prefix. See details:" - " https://azure.github.io/azure-sdk/python_design.html#service-operations", - "unapproved-client-method-name-prefix", - "All clients should use the preferred verbs for method names.", - ) - } - options = ( - ( - "ignore-unapproved-client-method-name-prefix", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow clients to not use preferred method name prefixes", - }, - ), - ) - - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientHasApprovedMethodNamePrefix, self).__init__(linter) - - def visit_classdef(self, node): - """Visits every class in file and checks if it is a client. If it is a client, checks - that approved method name prefixes are present. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - try: - if node.name.endswith("Client") and node.name not in self.ignore_clients: - client_methods = [child for child in node.get_children() if child.is_function] - - approved_prefixes = ["get", "list", "create", "upsert", "set", "update", "replace", "append", "add", - "delete", "remove", "begin"] - for idx, method in enumerate(client_methods): - if method.name.startswith("__") or "_exists" in method.name or method.name.startswith("_") \ - or method.name.startswith("from"): - continue - prefix = method.name.split("_")[0] - if prefix.lower() not in approved_prefixes: - self.add_message( - msg_id="unapproved-client-method-name-prefix", - node=client_methods[idx], - confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client has approved method name prefix.") - pass - - -class ClientMethodsUseKwargsWithMultipleParameters(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-method-multiple-parameters" - priority = -1 - msgs = { - "C4721": ( - "Client has too many positional arguments. Use keyword-only arguments." - " See details: https://azure.github.io/azure-sdk/python_introduction.html#method-signatures", - "client-method-has-more-than-5-positional-arguments", - "Client method should use keyword-only arguments for some parameters.", - ) - } - options = ( - ( - "ignore-client-method-has-more-than-5-positional-arguments", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method to have more than 5 positional arguments", - }, - ), - ) - - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientMethodsUseKwargsWithMultipleParameters, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that it doesn't have more than 5 - positional arguments. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and node.parent.name not in self.ignore_clients: - # Only bother checking method signatures with > 6 parameters (don't include self/cls/etc) - if len(node.args.args) > 6: - positional_args = len(node.args.args) - len(node.args.defaults) - if positional_args > 6: - self.add_message( - msg_id="client-method-has-more-than-5-positional-arguments", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if kwargs is used for multiple parameters.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class ClientMethodsHaveTypeAnnotations(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-method-type-annotations" - priority = -1 - msgs = { - "C4722": ( - "Client method is missing type annotations/comments, return type annotations/comments, or " - "mixing type annotations and comments. See details: " - " https://azure.github.io/azure-sdk/python_introduction.html#types-or-not", - "client-method-missing-type-annotations", - "Client method should use type annotations.", - ) - } - options = ( - ( - "ignore-client-method-missing-type-annotations", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method without type annotations", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientMethodsHaveTypeAnnotations, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that all type comments/annotations - and type returns are present. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and node.parent.name not in self.ignore_clients: - if not node.name.startswith("_") or node.name == "__init__": - # Checks that method has python 2/3 type comments or annotations as shown here: - # https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code - - # check for type comments - if node.type_comment_args is None or node.type_comment_returns is None: - - # type annotations default to a list of None when not present, - # so need extra logic here to check for any hints that may be present - type_annotations = [type_hint for type_hint in node.args.annotations if type_hint is not None] - - # check for type annotations - # node.args.args is a list of ast.AssignName arguments - # node.returns is the type annotation return - # Note that if the method returns nothing it will be of type ast.Const.NoneType - if (type_annotations == [] and len(node.args.args) > 1) or node.returns is None: - self.add_message( - msg_id="client-method-missing-type-annotations", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client methods missing type annotations.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class ClientMethodsHaveTracingDecorators(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-method-has-tracing-decorator" - priority = -1 - msgs = { - "C4723": ( - "Client method is missing the distributed tracing decorator - `distributed_trace`. See details:" - " https://azure.github.io/azure-sdk/python_implementation.html#distributed-tracing", - "client-method-missing-tracing-decorator", - "Client method should support distributed tracing.", - ), - "C4724": ( - "Client async method is missing the distributed tracing decorator - `distributed_trace_async`. " - " See details: https://azure.github.io/azure-sdk/python_implementation.html#distributed-tracing", - "client-method-missing-tracing-decorator-async", - "Client method should support distributed tracing.", - ), - } - options = ( - ( - "ignore-client-method-missing-tracing-decorator", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method without tracing decorator.", - }, - ), - ( - "ignore-client-method-missing-tracing-decorator-async", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method without tracing decorator.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientMethodsHaveTracingDecorators, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that a distributed tracing decorator is present. - Ignores private methods, from_connection_string, and methods that retrieve child clients. - - node.decoratornames() returns a set of the method's decorator names. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and not node.name.startswith("_") and \ - node.parent.name not in self.ignore_clients: - if node.args.kwarg and "azure.core.tracing.decorator.distributed_trace" not in node.decoratornames() \ - and "builtins.classmethod" not in node.decoratornames(): - self.add_message( - msg_id="client-method-missing-tracing-decorator", node=node, confidence=None - ) - except AttributeError: - pass - - def visit_asyncfunctiondef(self, node): - """Visits every method in the client and checks that a distributed tracing decorator is present. - Ignores private methods, from_connection_string, and methods that retrieve child clients. - - node.decoratornames() returns a set of the method's decorator names. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and not node.name.startswith("_") and \ - node.parent.name not in self.ignore_clients: - if node.args.kwarg and "azure.core.tracing.decorator_async.distributed_trace_async" not in \ - node.decoratornames() and "builtins.classmethod" not in node.decoratornames(): - self.add_message( - msg_id="client-method-missing-tracing-decorator-async", node=node, confidence=None - ) - except AttributeError: - pass - - -class ClientsDoNotUseStaticMethods(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-does-not-use-static-methods" - priority = -1 - msgs = { - "C4725": ( - "Client should not use static methods (staticmethod). See details:" - " https://azure.github.io/azure-sdk/python_introduction.html#method-signatures", - "client-method-should-not-use-static-method", - "Client method should not use staticmethod.", - ), - } - options = ( - ( - "ignore-client-method-should-not-use-static-method", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method to use staticmethod.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientsDoNotUseStaticMethods, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that it does not use staticmethod. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and node.parent.name not in self.ignore_clients: - # ignores private methods or methods that don't have any decorators - if not node.name.startswith("_") and node.decorators is not None: - if "builtins.staticmethod" in node.decoratornames(): - self.add_message( - msg_id="client-method-should-not-use-static-method", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client methods do not use staticmethods.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class FileHasCopyrightHeader(BaseChecker): - __implements__ = IAstroidChecker - - name = "file-has-copyright-header" - priority = -1 - msgs = { - "C4726": ( - "File is missing a copyright header. See details:" - " https://azure.github.io/azure-sdk/policies_opensource.html", - "file-needs-copyright-header", - "Every source file should have a copyright header.", - ), - } - options = ( - ( - "ignore-file-needs-copyright-header", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow file without a copyright header.", - }, - ), - ) - - def __init__(self, linter=None): - super(FileHasCopyrightHeader, self).__init__(linter) - - def visit_module(self, node): - """Visits every file and checks that a copyright header is present. - - :param node: module node - :type node: ast.Module - :return: None - """ - try: - if not node.package: # don't throw an error on an __init__.py file - header = node.stream().read(200).lower() - if header.find(b'copyright') == -1: - self.add_message( - msg_id="file-needs-copyright-header", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if file is missing a copyright header.") - pass - - -class ClientUsesCorrectNamingConventions(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-naming-conventions" - priority = -1 - msgs = { - "C4727": ( - "Client is using an incorrect naming convention. See details:" - " https://azure.github.io/azure-sdk/python_introduction.html#naming-conventions", - "client-incorrect-naming-convention", - "Client method should use correct naming conventions.", - ) - } - options = ( - ( - "ignore-client-incorrect-naming-convention", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client to use incorrect naming conventions.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientUsesCorrectNamingConventions, self).__init__(linter) - - def visit_classdef(self, node): - """Visits every class in file and checks if it is a client. - Checks that correct naming convention is used for the client. - Also checks that any class constants use uppercase. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - # check for correct capitalization for "Client" and whatever the first letter of the prefix is - if "_" in node.name or node.name.endswith("client") or node.name[0] != node.name[0].upper(): - if not node.name.startswith("_") and node.name not in self.ignore_clients: - self.add_message( - msg_id="client-incorrect-naming-convention", node=node, confidence=None - ) - - # check for correct naming convention in any class constants - if node.name.endswith("Client"): - for idx in range(len(node.body)): - try: - const_name = node.body[idx].targets[0].name - if const_name != const_name.upper(): - self.add_message( - msg_id="client-incorrect-naming-convention", node=node.body[idx], confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses correct naming conventions.") - pass - - # check that methods in client class do not use camelcase - try: - for func in node.body: - if func.name != func.name.lower() and not func.name.startswith("_"): - self.add_message( - msg_id="client-incorrect-naming-convention", node=func, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses correct naming conventions.") - pass - - -class ClientMethodsHaveKwargsParameter(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-methods-have-kwargs" - priority = -1 - msgs = { - "C4728": ( - "Client method is missing a **kwargs parameter. See details:" - " https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods", - "client-method-missing-kwargs", - "All client methods should accept a kwargs parameter.", - ), - } - options = ( - ( - "ignore-client-method-missing-kwargs", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method without a kwargs parameter", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientMethodsHaveKwargsParameter, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that it has a kwargs parameter. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and node.parent.name not in self.ignore_clients: - # avoid false positive with @property - if node.decorators is not None: - if "builtins.property" in node.decoratornames(): - return - if not node.name.startswith("_") and \ - ("azure.core.tracing.decorator.distributed_trace" in node.decoratornames() or - "azure.core.tracing.decorator_async.distributed_trace_async" in node.decoratornames()): - if not node.args.kwarg: - self.add_message( - msg_id="client-method-missing-kwargs", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses kwargs parameter in method.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class ClientMethodNamesDoNotUseDoubleUnderscorePrefix(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-methods-no-double-underscore" - priority = -1 - msgs = { - "C4729": ( - "Client method name should not use a double underscore prefix. See details:" - " https://azure.github.io/azure-sdk/python_introduction.html#public-vs-private", - "client-method-name-no-double-underscore", - "Client method names should not use a leading double underscore prefix.", - ), - } - options = ( - ( - "ignore-client-method-name-no-double-underscore", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client method to have double underscore prefix.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - acceptable_names = ["__init__", "__enter__", "__exit__", "__aenter__", "__aexit__", "__repr__"] - - def __init__(self, linter=None): - super(ClientMethodNamesDoNotUseDoubleUnderscorePrefix, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that no name begins with a double underscore. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.is_method() and node.parent.name not in self.ignore_clients: - if node.name.startswith("__") and node.name not in self.acceptable_names: - self.add_message( - msg_id="client-method-name-no-double-underscore", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client method name does not use double underscore prefix.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class ClientDocstringUsesLiteralIncludeForCodeExample(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-docstring-literal-include" - priority = -1 - msgs = { - "C4730": ( - "Client docstring should use a literal include directive for the code example. See details:" - " https://azure.github.io/azure-sdk/python_documentation.html#code-snippets", - "client-docstring-use-literal-include", - "Client/methods should use literal include directives for code examples.", - ), - } - options = ( - ( - "ignore-client-docstring-use-literal-include", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client to use code block.", - }, - ), - ) - - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientDocstringUsesLiteralIncludeForCodeExample, self).__init__(linter) - - def visit_classdef(self, node): - """Visits every class in file and checks if it is a client. - Also checks that the class constructor uses literalinclude over a code-block for the code example. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - try: - if node.name.endswith("Client") and node.name not in self.ignore_clients: - if node.doc.find("code-block") != -1: - self.add_message( - msg_id="client-docstring-use-literal-include", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses literalinclude over code-block.") - pass - - def visit_functiondef(self, node): - """Visits every method in the client class and checks that it uses literalinclude - over a code-block for the code example. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.parent.name not in self.ignore_clients and node.is_method(): - if node.doc.find("code-block") != -1: - self.add_message( - msg_id="client-docstring-use-literal-include", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses literalinclude over code-block.") - pass - - visit_asyncfunctiondef = visit_functiondef - - -class AsyncClientCorrectNaming(BaseChecker): - __implements__ = IAstroidChecker - - name = "async-client-correct-naming" - priority = -1 - msgs = { - "C4731": ( - "Async client should not include `Async` in the client name. See details:" - " https://azure.github.io/azure-sdk/python_design.html#async-support", - "async-client-bad-name", - "Async clients should not have async in the name.", - ), - } - options = ( - ( - "ignore-async-client-bad-name", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow async client to include async in its name.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(AsyncClientCorrectNaming, self).__init__(linter) - - def visit_classdef(self, node): - """Visits every class in file and checks that an async client does not use - async in its name. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - try: - # avoid false positive when async name is used with a base class. - if node.name.endswith("Client") and "async" in node.name.lower() and "base" not in node.name.lower(): - if not node.name.startswith("_") and node.name not in self.ignore_clients: - self.add_message( - msg_id="async-client-bad-name", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if async client uses correct naming.") - pass - - -class SpecifyParameterNamesInCall(BaseChecker): - __implements__ = IAstroidChecker - - name = "specify-parameter-names" - priority = -1 - msgs = { - "C4732": ( - "Specify the parameter names when calling methods with more than 2 required positional parameters." - " See details: https://azure.github.io/azure-sdk/python_introduction.html#method-signatures", - "specify-parameter-names-in-call", - "You should specify the parameter names when the method has more than two positional arguments.", - ) - } - options = ( - ( - "ignore-specify-parameter-names-in-call", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Call the method without specifying parameter names.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(SpecifyParameterNamesInCall, self).__init__(linter) - - def visit_call(self, node): - """Visits every call in the client and checks that it specifies the parameter name in - the call if there are more than 2 require positional parameters. - - :param node: call node - :type node: ast.Call - :return: None - """ - try: - klass = node.parent.parent.parent - function = node.parent.parent - if klass.name.endswith("Client") and klass.name not in self.ignore_clients and function.is_method(): - # node.args represent positional arguments - if len(node.args) > 2 and node.func.attrname != "format": - self.add_message( - msg_id="specify-parameter-names-in-call", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client methods specify parameters name in call.") - pass - - -class ClientListMethodsUseCorePaging(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-list-methods-use-paging" - priority = -1 - msgs = { - "C4733": ( - "Operations that return collections should return a value that implements the Paging protocol. See details:" - " https://azure.github.io/azure-sdk/python_design.html#response-formats", - "client-list-methods-use-paging", - "Client methods that return collections should use the Paging protocol.", - ), - } - options = ( - ( - "ignore-client-list-methods-use-paging", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow collections method to not use paging protocol.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientListMethodsUseCorePaging, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that any list_ methods return - an ItemPaged or AsyncItemPaged value. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.parent.name not in self.ignore_clients and node.is_method(): - if node.name.startswith("list"): - try: - # infer_call_result gives the method return value as a string - returns = next(node.infer_call_result()).as_string() - if returns.find("ItemPaged") == -1 and returns.find("AsyncItemPaged") == -1: - self.add_message( - msg_id="client-list-methods-use-paging", node=node, confidence=None - ) - except (astroid.exceptions.InferenceError, AttributeError): # astroid can't always infer the return - logger.debug("Pylint custom checker failed to check if client list method uses core paging.") - pass - except AttributeError: - logger.debug("Pylint custom checker failed to check if client list method uses core paging.") - pass - - -class ClientLROMethodsUseCorePolling(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-lro-methods-use-polling" - priority = -1 - msgs = { - "C4734": ( - "Long running operations should return a value that implements the Poller protocol. See details:" - " https://azure.github.io/azure-sdk/python_design.html#response-formats", - "client-lro-methods-use-polling", - "Long running operations should use the polling protocol.", - ), - } - options = ( - ( - "ignore-client-lro-methods-use-polling", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow LRO method to not use polling protocol.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientLROMethodsUseCorePolling, self).__init__(linter) - - def visit_functiondef(self, node): - """Visits every method in the client and checks that any begin_ methods return - an LROPoller value. - - :param node: function node - :type node: ast.FunctionDef - :return: None - """ - try: - if node.parent.name.endswith("Client") and node.parent.name not in self.ignore_clients and node.is_method(): - if node.name.startswith("begin"): - try: - # infer_call_result gives the method return value as a string - returns = next(node.infer_call_result()).as_string() - if returns.find("LROPoller") == -1: - self.add_message( - msg_id="client-lro-methods-use-polling", node=node, confidence=None - ) - except (astroid.exceptions.InferenceError, AttributeError): # astroid can't always infer the return - logger.debug("Pylint custom checker failed to check if client begin method uses core polling.") - pass - except AttributeError: - logger.debug("Pylint custom checker failed to check if client begin method uses core polling.") - pass - - -class ClientLROMethodsUseCorrectNaming(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-lro-methods-use-correct-naming" - priority = -1 - msgs = { - "C4735": ( - "Methods that return an LROPoller should be prefixed with `begin_`. See details:" - " https://azure.github.io/azure-sdk/python_design.html#service-operations", - "lro-methods-use-correct-naming", - "Methods that return an LROPoller should be prefixed with `begin_`.", - ), - } - options = ( - ( - "ignore-client-lro-methods-use-correct-naming", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow LRO method to use a different name.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientLROMethodsUseCorrectNaming, self).__init__(linter) - self.is_client = [] - - def visit_classdef(self, node): - """Visits every class in file and checks if it is a client. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - if node.name.endswith("Client") and node.name not in self.ignore_clients: - self.is_client.append(True) - else: - self.is_client.append(False) - - def visit_return(self, node): - if self.is_client and self.is_client[-1]: - try: - # check for a return value of LROPoller in client class - if node.value.func.name == "LROPoller": - # get the method in which LROPoller is returned - method = node.value.func.scope() - if not method.name.startswith("begin") and not method.name.startswith("_"): - self.add_message( - msg_id="lro-methods-use-correct-naming", node=method, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client method with polling uses correct naming.") - pass - - -class ClientConstructorDoesNotHaveConnectionStringParam(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-conn-str-not-in-constructor" - priority = -1 - msgs = { - "C4736": ( - "The constructor must not take a connection string. See details: " - "https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods", - "connection-string-should-not-be-constructor-param", - "Client should have a method to create the client with a connection string.", - ), - } - options = ( - ( - "ignore-connection-string-should-not-be-constructor-param", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow client to use connection string param in constructor.", - }, - ), - ) - ignore_clients = ["PipelineClient", "AsyncPipelineClient", "ARMPipelineClient", "AsyncARMPipelineClient"] - - def __init__(self, linter=None): - super(ClientConstructorDoesNotHaveConnectionStringParam, self).__init__(linter) - - def visit_classdef(self, node): - """Visits every class in file and checks if it is a client. - If it is a client, it checks that a connection string parameter is not used in the constructor. - - :param node: class node - :type node: ast.ClassDef - :return: None - """ - try: - if node.name.endswith("Client") and node.name not in self.ignore_clients: - for func in node.body: - if func.name == "__init__": - for argument in func.args.args: - if argument.name == "connection_string" or argument.name == "conn_str": - self.add_message( - msg_id="connection-string-should-not-be-constructor-param", node=node, confidence=None - ) - except AttributeError: - logger.debug("Pylint custom checker failed to check if client uses connection string param in constructor.") - pass - - -class PackageNameDoesNotUseUnderscoreOrPeriod(BaseChecker): - __implements__ = IAstroidChecker - - name = "package-name-incorrect" - priority = -1 - msgs = { - "C4737": ( - "Package name should not use an underscore or period. Replace with dash (-). See details: " - "https://azure.github.io/azure-sdk/python_implementation.html#packaging", - "package-name-incorrect", - "Package name should use dashes instead of underscore or period.", - ), - } - options = ( - ( - "ignore-package-name-incorrect", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow package name to have a different naming convention.", - }, - ), - ) - - def __init__(self, linter=None): - super(PackageNameDoesNotUseUnderscoreOrPeriod, self).__init__(linter) - - def visit_module(self, node): - """Visits setup.py and checks that its package name follows correct naming convention. - - :param node: module node - :type node: ast.Module - :return: None - """ - try: - if node.file.endswith("setup.py"): - for nod in node.body: - if isinstance(nod, astroid.Assign): - if nod.targets[0].name == "PACKAGE_NAME": - package = nod.value - if package.value.find(".") != -1 or package.value.find("_") != -1: - self.add_message( - msg_id="package-name-incorrect", node=node, confidence=None - ) - except Exception: - logger.debug("Pylint custom checker failed to check if package name is correct.") - pass - - -class ServiceClientUsesNameWithClientSuffix(BaseChecker): - __implements__ = IAstroidChecker - - name = "client-name-incorrect" - priority = -1 - msgs = { - "C4738": ( - "Service client types should use a `Client` suffix. See details: " - "https://azure.github.io/azure-sdk/python_design.html#clients", - "client-suffix-needed", - "Client should use the correct suffix.", - ), - } - options = ( - ( - "ignore-client-suffix-needed", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow the client to have a different suffix.", - }, - ), - ) - - def __init__(self, linter=None): - super(ServiceClientUsesNameWithClientSuffix, self).__init__(linter) - - def visit_module(self, node): - """Visits a file that has "client" in the file name and checks that the service client - uses a `Client` suffix. - - :param node: module node - :type node: ast.Module - :return: None - """ - try: - # ignore base clients - if node.file.endswith("base_client.py") or node.file.endswith("base_client_async.py"): - return - if node.file.endswith("client.py") or node.file.endswith("client_async.py"): - has_client_suffix = False - for idx in range(len(node.body)): - if isinstance(node.body[idx], astroid.ClassDef): - if node.body[idx].name.endswith("Client"): - has_client_suffix = True - if has_client_suffix is False: - self.add_message( - msg_id="client-suffix-needed", node=node, confidence=None - ) - except Exception: - logger.debug("Pylint custom checker failed to check if service client has a client suffix.") - pass - - -class CheckDocstringParameters(BaseChecker): - __implements__ = IAstroidChecker - - name = "check-docstrings" - priority = -1 - msgs = { - "C4739": ( - 'Params missing in docstring: "%s". See details: ' - 'https://azure.github.io/azure-sdk/python_documentation.html#docstrings', - "docstring-missing-param", - "Docstring missing for param.", - ), - "C4740": ( - 'Param types missing in docstring: "%s". See details: ' - 'https://azure.github.io/azure-sdk/python_documentation.html#docstrings', - "docstring-missing-type", - "Docstring missing for param type.", - ), - "C4741": ( - "A return doc is missing in the docstring. See details: " - "https://azure.github.io/azure-sdk/python_documentation.html#docstrings", - "docstring-missing-return", - "Docstring missing for return doc.", - ), - "C4742": ( - "A return type is missing in the docstring. See details: " - "https://azure.github.io/azure-sdk/python_documentation.html#docstrings", - "docstring-missing-rtype", - "Docstring missing for return type.", - ), - "C4743": ( - '"%s" not found as a parameter. Use :keyword type myarg: if a keyword argument. See details: ' - 'https://azure.github.io/azure-sdk/python_documentation.html#docstrings', - "docstring-should-be-keyword", - "Docstring should use keywords.", - ), - } - options = ( - ( - "ignore-docstring-missing-param", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow a docstring param mismatch.", - }, - ), - ( - "ignore-docstring-missing-type", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow a docstring param type mismatch.", - }, - ), - ( - "ignore-docstring-missing-return", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow a docstring return doc mismatch", - }, - ), - ( - "ignore-docstring-missing-rtype", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow a docstring rtype mismatch", - }, - ), - ( - "ignore-docstring-should-be-keyword", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow a docstring to not use keyword for documentation.", - }, - ), - ) - - def __init__(self, linter=None): - super(CheckDocstringParameters, self).__init__(linter) - - def check_parameters(self, node): - """Parse the docstring for any params and types - and compares it to the function's parameters. - - Throws a pylint error if... - 1. Missing param in docstring. - 2. Missing a param type in the docstring. - 3. Missing a return doc in the docstring when a function returns something. - 4. Missing an rtype in the docstring when a function returns something. - 5. Extra params in docstring that aren't function parameters. Change to keywords. - - :param node: ast.ClassDef or ast.FunctionDef - :return: None - """ - arg_names = [] - # specific case for constructor where docstring found in class def - if isinstance(node, astroid.ClassDef): - for constructor in node.body: - if isinstance(constructor, astroid.FunctionDef) and constructor.name == "__init__": - arg_names = [arg.name for arg in constructor.args.args] - break - - if isinstance(node, astroid.FunctionDef): - arg_names = [arg.name for arg in node.args.args] - - try: - # not every method will have a docstring so don't crash here, just return - docstring = node.doc.split(":") - except AttributeError: - return - - docparams = {} - for idx, line in enumerate(docstring): - # this param has its type on a separate line - if line.startswith("param") and line.count(" ") == 1: - param = line.split("param ")[1] - docparams[param] = None - # this param has its type on the same line - if line.startswith("param") and line.count(" ") == 2: - _, param_type, param = line.split(" ") - docparams[param] = param_type - if line.startswith("type"): - param = line.split("type ")[1] - if param in docparams: - docparams[param] = docstring[idx+1] - - # check that all params are documented - missing_params = [] - for param in arg_names: - if param == "self" or param == "cls": - continue - if param not in docparams: - missing_params.append(param) - - if missing_params: - self.add_message( - msg_id="docstring-missing-param", args=(", ".join(missing_params)), node=node, confidence=None - ) - - # check if we have a type for each param and check if documented params that should be keywords - missing_types = [] - should_be_keywords = [] - for param in docparams: - if docparams[param] is None: - missing_types.append(param) - if param not in arg_names: - should_be_keywords.append(param) - - if missing_types: - self.add_message( - msg_id="docstring-missing-type", args=(", ".join(missing_types)), node=node, confidence=None - ) - - if should_be_keywords: - self.add_message( - msg_id="docstring-should-be-keyword", - args=(", ".join(should_be_keywords)), - node=node, - confidence=None - ) - - def check_return(self, node): - """Checks if function returns anything. - If return found, checks that the docstring contains a return doc and rtype. - - :param node: ast.FunctionDef - :return: None - """ - try: - returns = next(node.infer_call_result()).as_string() - if returns == "None": - return - except (astroid.exceptions.InferenceError, AttributeError): - # this function doesn't return anything, just return - return - - try: - # not every method will have a docstring so don't crash here, just return - docstring = node.doc.split(":") - except AttributeError: - return - - has_return, has_rtype = False, False - for line in docstring: - if line.startswith("return"): - has_return = True - if line.startswith("rtype"): - has_rtype = True - - if has_return is False: - self.add_message( - msg_id="docstring-missing-return", node=node, confidence=None - ) - if has_rtype is False: - self.add_message( - msg_id="docstring-missing-rtype", node=node, confidence=None - ) - - def visit_classdef(self, node): - """Visits every class in the file and finds the constructor. - Makes a call to compare class docstring with constructor params. - - :param node: ast.ClassDef - :return: None - """ - try: - for func in node.body: - if isinstance(func, astroid.FunctionDef) and func.name == "__init__": - self.check_parameters(node) - except Exception: - logger.debug("Pylint custom checker failed to check docstrings.") - pass - - def visit_functiondef(self, node): - """Visits every function in the file and makes calls - to check docstring parameters and return statements. - - :param node: ast.FunctionDef - :return: None - """ - try: - if node.name == "__init__": - return - self.check_parameters(node) - self.check_return(node) - except Exception: - logger.debug("Pylint custom checker failed to check docstrings.") - pass - - # this line makes it work for async functions - visit_asyncfunctiondef = visit_functiondef - - -class CheckForPolicyUse(BaseChecker): - __implements__ = IAstroidChecker - - name = "check-for-policies" - priority = -1 - msgs = { - "C4739": ( - "You should include a UserAgentPolicy in your HTTP pipeline. See details: " - "https://azure.github.io/azure-sdk/python_implementation.html#network-operations", - "missing-user-agent-policy", - "You should include a UserAgentPolicy in the HTTP Pipeline.", - ), - "C4740": ( - "You should include a LoggingPolicy in your HTTP pipeline. See details: " - "https://azure.github.io/azure-sdk/python_implementation.html#network-operations", - "missing-logging-policy", - "You should include a LoggingPolicy in the HTTP Pipeline.", - ), - "C4741": ( - "You should include a RetryPolicy in your HTTP pipeline. See details: " - "https://azure.github.io/azure-sdk/python_implementation.html#network-operations", - "missing-retry-policy", - "You should include a RetryPolicy in the HTTP Pipeline.", - ), - "C4742": ( - "You should include a DistributedTracingPolicy in your HTTP pipeline. See details: " - "https://azure.github.io/azure-sdk/python_implementation.html#network-operations", - "missing-distributed-tracing-policy", - "You should include a DistributedTracingPolicy in the HTTP Pipeline.", - ), - } - options = ( - ( - "ignore-missing-user-agent-policy", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow the client to not have a UserAgentPolicy", - }, - ), - ( - "ignore-missing-logging-policy", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow the client to not have a LoggingPolicy", - }, - ), - ( - "ignore-missing-retry-policy", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow the client to not have a RetryPolicy", - }, - ), - ( - "ignore-missing-distributed-tracing-policy", - { - "default": False, - "type": "yn", - "metavar": "", - "help": "Allow the client to not have a DistributedTracingPolicy", - }, - ), - ) - - def __init__(self, linter=None): - super(CheckForPolicyUse, self).__init__(linter) - self.node_to_use = None - self.has_policies = set() - self.ran_at_package_level = False - self.disable_logging_error = False - self.disable_user_agent_error = False - self.disable_tracing_error = False - self.disable_retry_error = False - - def visit_function(self, node, policy): - """Visits the function and searches line by line for the policy being used. - Also searches for if the policy came from the azure.core.configuration object. - - :param node: ast.FunctionDef - :param policy: The policy imported in the file. - :return: None - """ - for func in node.body: - if isinstance(func, astroid.FunctionDef): - for idx, item in enumerate(func.body): - try: - line = list(node.get_children())[idx].as_string() - if line.find(policy) != -1: - self.has_policies.add(policy) - if line.find("config.logging_policy") != -1: - self.has_policies.add("NetworkTraceLoggingPolicy") - if line.find("config.retry_policy") != -1: - self.has_policies.add("RetryPolicy") - if line.find("config.user_agent_policy") != -1: - self.has_policies.add("UserAgentPolicy") - except IndexError: - pass - - def visit_class(self, klass, policy): - """Visits any classes in the file and then makes a call - to search its methods for the policy being used. - - :param klass: A class within the file - :param policy: The policy imported in the file. - :return: None - """ - for idx, node in enumerate(klass): - if isinstance(node, astroid.ClassDef): - self.visit_function(node, policy) - - def visit_module(self, node): - """Visits every file in the package and searches for policies as base classes - or custom policies. If a core policy is imported in a file in calls helper - methods to check that the policy was used in the code. - - This pylint checker is different from the others as it collects information across - many files and then reports any errors. Due to this difference, disable commands - must be searched for manually. - - :param node: ast.Module - :return: None - """ - # only throw the error if pylint was run at package level since it needs to check all the files - # infer run location based on the location of the init file highest in dir hierarchy - if node.package: # the init file - count = node.file.split("azure-sdk-for-python")[1].count("-") - if node.file.split("azure-sdk-for-python")[1].count("\\") <= (5 + count) and \ - node.file.split("azure-sdk-for-python")[1].count("/") <= (5 + count): - self.ran_at_package_level = True - - # not really a good place to throw the pylint error, so we'll do it on the init file. - # By running this checker on all the files first and then reporting errors, pylint disables need to be - # done manually for some reason - if node.file.endswith("__init__.py") and self.node_to_use is None: - header = node.stream().read(200).lower() - if header.find(b'disable') != -1: - if header.find(b'missing-logging-policy') != -1: - self.disable_logging_error = True - if header.find(b'missing-user-agent-policy') != -1: - self.disable_user_agent_error = True - if header.find(b'missing-distributed-tracing-policy') != -1: - self.disable_tracing_error = True - if header.find(b'missing-retry-policy') != -1: - self.disable_retry_error = True - self.node_to_use = node - - for idx in range(len(node.body)): - # Check if the core policy is the base class for some custom policy, or a custom policy is being used - # and we try our best to find it based on common naming conventions. - if isinstance(node.body[idx], astroid.ClassDef): - if "NetworkTraceLoggingPolicy" in node.body[idx].basenames: - self.has_policies.add("NetworkTraceLoggingPolicy") - if node.body[idx].name.find("LoggingPolicy") != -1: - self.has_policies.add("NetworkTraceLoggingPolicy") - if "RetryPolicy" in node.body[idx].basenames or "AsyncRetryPolicy" in node.body[idx].basenames: - self.has_policies.add("RetryPolicy") - if node.body[idx].name.find("RetryPolicy") != -1: - self.has_policies.add("RetryPolicy") - if "UserAgentPolicy" in node.body[idx].basenames: - self.has_policies.add("UserAgentPolicy") - if node.body[idx].name.find("UserAgentPolicy") != -1: - self.has_policies.add("UserAgentPolicy") - if "DistributedTracingPolicy" in node.body[idx].basenames: - self.has_policies.add("DistributedTracingPolicy") - if node.body[idx].name.find("TracingPolicy") != -1: - self.has_policies.add("DistributedTracingPolicy") - - # policy is imported in this file, let's check that it gets used in the code - if isinstance(node.body[idx], astroid.ImportFrom): - for imp, pol in enumerate(node.body[idx].names): - if node.body[idx].names[imp][0].endswith("Policy") and \ - node.body[idx].names[imp][0] not in self.has_policies: - self.visit_class(node.body, node.body[idx].names[imp][0]) - - def close(self): - """This method is inherited from BaseChecker and called at the very end of linting a module. - It reports any errors and does a final check for any pylint disable statements. - - :return: None - """ - if self.ran_at_package_level: - if self.disable_logging_error is False: - if "NetworkTraceLoggingPolicy" not in self.has_policies: - self.add_message( - msg_id="missing-logging-policy", node=self.node_to_use, confidence=None - ) - if self.disable_retry_error is False: - if "RetryPolicy" not in self.has_policies: - self.add_message( - msg_id="missing-retry-policy", node=self.node_to_use, confidence=None - ) - if self.disable_user_agent_error is False: - if "UserAgentPolicy" not in self.has_policies: - self.add_message( - msg_id="missing-user-agent-policy", node=self.node_to_use, confidence=None - ) - if self.disable_tracing_error is False: - if "DistributedTracingPolicy" not in self.has_policies: - self.add_message( - msg_id="missing-distributed-tracing-policy", node=self.node_to_use, confidence=None - ) - - -# if a linter is registered in this function then it will be checked with pylint -def register(linter): - linter.register_checker(ClientsDoNotUseStaticMethods(linter)) - linter.register_checker(ClientConstructorTakesCorrectParameters(linter)) - linter.register_checker(ClientMethodsUseKwargsWithMultipleParameters(linter)) - linter.register_checker(ClientMethodsHaveTypeAnnotations(linter)) - linter.register_checker(ClientUsesCorrectNamingConventions(linter)) - linter.register_checker(ClientMethodsHaveKwargsParameter(linter)) - linter.register_checker(ClientHasKwargsInPoliciesForCreateConfigurationMethod(linter)) - linter.register_checker(AsyncClientCorrectNaming(linter)) - linter.register_checker(FileHasCopyrightHeader(linter)) - linter.register_checker(ClientMethodNamesDoNotUseDoubleUnderscorePrefix(linter)) - linter.register_checker(SpecifyParameterNamesInCall(linter)) - linter.register_checker(ClientConstructorDoesNotHaveConnectionStringParam(linter)) - linter.register_checker(PackageNameDoesNotUseUnderscoreOrPeriod(linter)) - linter.register_checker(ServiceClientUsesNameWithClientSuffix(linter)) - - # disabled by default, use pylint --enable=check-docstrings if you want to use it - linter.register_checker(CheckDocstringParameters(linter)) - - # Rules are disabled until false positive rate improved - # linter.register_checker(CheckForPolicyUse(linter)) - # linter.register_checker(ClientHasApprovedMethodNamePrefix(linter)) - # linter.register_checker(ClientMethodsHaveTracingDecorators(linter)) - # linter.register_checker(ClientDocstringUsesLiteralIncludeForCodeExample(linter)) - # linter.register_checker(ClientListMethodsUseCorePaging(linter)) - # linter.register_checker(ClientLROMethodsUseCorePolling(linter)) - # linter.register_checker(ClientLROMethodsUseCorrectNaming(linter)) - - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/setup.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/setup.py deleted file mode 100644 index b4b89126e95..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -from setuptools import setup - -setup( - name="pylint-guidelines-checker", - version="0.0.1", - url='http://github.com/Azure/azure-sdk-for-python', - license='MIT License', - description="A pylint plugin which enforces azure sdk guidelines.", - author='Microsoft Corporation', - author_email='azpysdkhelp@microsoft.com', - py_modules=['pylint_guidelines_checker'], -) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/__init__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/test_pylint_custom_plugins.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/test_pylint_custom_plugins.py deleted file mode 100644 index d866a1309c9..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/pylint_custom_plugin/tests/test_pylint_custom_plugins.py +++ /dev/null @@ -1,2343 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ - -import astroid -import pylint.testutils - -from azure.core import PipelineClient -from azure.core.configuration import Configuration -from pylint_custom_plugin import pylint_guidelines_checker as checker - - -class TestClientMethodsHaveTracingDecorators(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientMethodsHaveTracingDecorators - - def test_ignores_constructor(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_method(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_method_async(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - async def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node) - - def test_ignores_methods_with_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - from azure.core.tracing.decorator import distributed_trace - class SomeClient(): #@ - @distributed_trace - def create_configuration(self, **kwargs): #@ - pass - @distributed_trace - def get_thing(self, **kwargs): #@ - pass - @distributed_trace - def list_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_async_methods_with_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - from azure.core.tracing.decorator_async import distributed_trace_async - class SomeClient(): #@ - @distributed_trace_async - async def create_configuration(self, **kwargs): #@ - pass - @distributed_trace_async - async def get_thing(self, **kwargs): #@ - pass - @distributed_trace_async - async def list_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_sync_decorator_on_async_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - from azure.core.tracing.decorator import distributed_trace - class SomeClient(): #@ - @distributed_trace - async def create_configuration(self, **kwargs): #@ - pass - @distributed_trace - async def get_thing(self, **kwargs): #@ - pass - @distributed_trace - async def list_thing(self, **kwargs): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator-async", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator-async", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator-async", node=func_node_c - ), - ): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_async_decorator_on_sync_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - from azure.core.tracing.decorator_async import distributed_trace_async - class SomeClient(): #@ - @distributed_trace_async - def create_configuration(self, **kwargs): #@ - pass - @distributed_trace_async - def get_thing(self, **kwargs): #@ - pass - @distributed_trace_async - def list_thing(self, **kwargs): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-missing-tracing-decorator", node=func_node_c - ), - ): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_other_decorators(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - from azure.core.tracing.decorator import distributed_trace - class SomeClient(): #@ - @classmethod - @distributed_trace - def download_thing(self, some, **kwargs): #@ - pass - - @distributed_trace - @decorator - def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - - def test_ignores_other_decorators_async(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - from azure.core.tracing.decorator_async import distributed_trace_async - class SomeClient(): #@ - @classmethod - @distributed_trace_async - async def download_thing(self, some, **kwargs): #@ - pass - - @distributed_trace_async - @decorator - async def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - - def test_ignores_non_client_method(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - class SomethingElse(): #@ - def download_thing(self, some, **kwargs): #@ - pass - - @classmethod - async def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_implementation.html#distributed-tracing" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientsDoNotUseStaticMethods(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientsDoNotUseStaticMethods - - def test_ignores_constructor(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_method(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_method_async(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - async def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node) - - def test_ignores_methods_with_other_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace - def create_configuration(self): #@ - pass - @distributed_trace - def get_thing(self): #@ - pass - @distributed_trace - def list_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_async_methods_with_other_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace_async - async def create_configuration(self): #@ - pass - @distributed_trace_async - async def get_thing(self): #@ - pass - @distributed_trace_async - async def list_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_staticmethod_on_async_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - async def create_configuration(self): #@ - pass - @staticmethod - async def get_thing(self): #@ - pass - @staticmethod - async def list_thing(self): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_c - ), - ): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_staticmethod_on_sync_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - def create_configuration(self): #@ - pass - @staticmethod - def get_thing(self): #@ - pass - @staticmethod - def list_thing(self): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-should-not-use-static-method", node=func_node_c - ), - ): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_other_multiple_decorators(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - class SomeClient(): #@ - @classmethod - @distributed_trace - def download_thing(self, some, **kwargs): #@ - pass - - @distributed_trace - @decorator - def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - - def test_ignores_other_multiple_decorators_async(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - class SomeClient(): #@ - @classmethod - @distributed_trace_async - async def download_thing(self, some, **kwargs): #@ - pass - - @distributed_trace_async - @decorator - async def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - - def test_ignores_non_client_method(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - class SomethingElse(): #@ - @staticmethod - def download_thing(self, some, **kwargs): #@ - pass - - @staticmethod - async def do_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#method-signatures" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientHasApprovedMethodNamePrefix(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientHasApprovedMethodNamePrefix - - def test_ignores_constructor(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_private_method(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_if_exists_suffix(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def check_if_exists(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_from_prefix(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def from_connection_string(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_approved_prefix_names(self): - class_node, func_node_a, func_node_b, func_node_c, func_node_d, func_node_e, func_node_f, func_node_g, \ - func_node_h, func_node_i, func_node_j, func_node_k, func_node_l = astroid.extract_node(""" - class SomeClient(): #@ - def create_configuration(self): #@ - pass - def get_thing(self): #@ - pass - def list_thing(self): #@ - pass - def upsert_thing(self): #@ - pass - def set_thing(self): #@ - pass - def update_thing(self): #@ - pass - def replace_thing(self): #@ - pass - def append_thing(self): #@ - pass - def add_thing(self): #@ - pass - def delete_thing(self): #@ - pass - def remove_thing(self): #@ - pass - def begin_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_non_client_with_unapproved_prefix_names(self): - class_node, function_node = astroid.extract_node( - """ - class SomethingElse(): #@ - def download_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_nested_function_with_unapproved_prefix_names(self): - class_node, function_node = astroid.extract_node( - """ - class SomeClient(): #@ - def create_configuration(self, **kwargs): #@ - def nested(hello, world): - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_finds_unapproved_prefix_names(self): - class_node, func_node_a, func_node_b, func_node_c, func_node_d, func_node_e, func_node_f, func_node_g, \ - func_node_h, func_node_i, func_node_j, func_node_k, func_node_l, func_node_m, func_node_n, func_node_o, \ - func_node_p = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace - def build_configuration(self): #@ - pass - def generate_thing(self): #@ - pass - def make_thing(self): #@ - pass - def insert_thing(self): #@ - pass - def put_thing(self): #@ - pass - def creates_configuration(self): #@ - pass - def gets_thing(self): #@ - pass - def lists_thing(self): #@ - pass - def upserts_thing(self): #@ - pass - def sets_thing(self): #@ - pass - def updates_thing(self): #@ - pass - def replaces_thing(self): #@ - pass - def appends_thing(self): #@ - pass - def adds_thing(self): #@ - pass - def deletes_thing(self): #@ - pass - def removes_thing(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_a - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_b - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_c - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_d - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_e - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_f - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_g - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_h - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_i - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_j - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_k - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_l - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_m - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_n - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_o - ), - pylint.testutils.Message( - msg_id="unapproved-client-method-name-prefix", node=func_node_p - ) - ): - self.checker.visit_classdef(class_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#service-operations" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientConstructorTakesCorrectParameters(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientConstructorTakesCorrectParameters - - def test_finds_correct_params(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, thing_url, credential, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_non_constructor_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def create_configuration(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_non_client_constructor_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def __init__(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_finds_constructor_without_kwargs(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, thing_url, credential=None): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="missing-client-constructor-parameter-kwargs", node=function_node - ) - ): - self.checker.visit_functiondef(function_node) - - def test_finds_constructor_without_credentials(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, thing_url, **kwargs): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="missing-client-constructor-parameter-credential", node=function_node - ) - ): - self.checker.visit_functiondef(function_node) - - def test_finds_constructor_with_no_params(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="missing-client-constructor-parameter-credential", node=function_node - ), - pylint.testutils.Message( - msg_id="missing-client-constructor-parameter-kwargs", node=function_node - ) - ): - self.checker.visit_functiondef(function_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientMethodsUseKwargsWithMultipleParameters(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientMethodsUseKwargsWithMultipleParameters - - def test_ignores_method_abiding_to_guidelines(self): - class_node, function_node, function_node_a, function_node_b, function_node_c, function_node_d, \ - function_node_e, function_node_f, function_node_g, function_node_h, function_node_i, function_node_j, \ - function_node_k, function_node_l, function_node_m = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace - def do_thing(): #@ - pass - def do_thing_a(self): #@ - pass - def do_thing_b(self, one): #@ - pass - def do_thing_c(self, one, two): #@ - pass - def do_thing_d(self, one, two, three): #@ - pass - def do_thing_e(self, one, two, three, four): #@ - pass - def do_thing_f(self, one, two, three, four, five): #@ - pass - def do_thing_g(self, one, two, three, four, five, six=6): #@ - pass - def do_thing_h(self, one, two, three, four, five, six=6, seven=7): #@ - pass - def do_thing_i(self, one, two, three, four, five, *, six=6, seven=7): #@ - pass - def do_thing_j(self, one, two, three, four, five, *, six=6, seven=7): #@ - pass - def do_thing_k(self, one, two, three, four, five, **kwargs): #@ - pass - def do_thing_l(self, one, two, three, four, five, *args, **kwargs): #@ - pass - def do_thing_m(self, one, two, three, four, five, *args, six, seven=7, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - self.checker.visit_functiondef(function_node_c) - self.checker.visit_functiondef(function_node_d) - self.checker.visit_functiondef(function_node_e) - self.checker.visit_functiondef(function_node_f) - self.checker.visit_functiondef(function_node_g) - self.checker.visit_functiondef(function_node_h) - self.checker.visit_functiondef(function_node_i) - self.checker.visit_functiondef(function_node_j) - self.checker.visit_functiondef(function_node_k) - self.checker.visit_functiondef(function_node_l) - self.checker.visit_functiondef(function_node_m) - - def test_ignores_method_abiding_to_guidelines_async(self): - class_node, function_node, function_node_a, function_node_b, function_node_c, function_node_d, \ - function_node_e, function_node_f, function_node_g, function_node_h, function_node_i, function_node_j, \ - function_node_k, function_node_l, function_node_m = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace_async - async def do_thing(): #@ - pass - async def do_thing_a(self): #@ - pass - async def do_thing_b(self, one): #@ - pass - async def do_thing_c(self, one, two): #@ - pass - async def do_thing_d(self, one, two, three): #@ - pass - async def do_thing_e(self, one, two, three, four): #@ - pass - async def do_thing_f(self, one, two, three, four, five): #@ - pass - async def do_thing_g(self, one, two, three, four, five, six=6): #@ - pass - async def do_thing_h(self, one, two, three, four, five, six=6, seven=7): #@ - pass - async def do_thing_i(self, one, two, three, four, five, *, six=6, seven=7): #@ - pass - async def do_thing_j(self, one, two, three, four, five, *, six=6, seven=7): #@ - pass - async def do_thing_k(self, one, two, three, four, five, **kwargs): #@ - pass - async def do_thing_l(self, one, two, three, four, five, *args, **kwargs): #@ - pass - async def do_thing_m(self, one, two, three, four, five, *args, six, seven=7, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node) - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - self.checker.visit_asyncfunctiondef(function_node_c) - self.checker.visit_asyncfunctiondef(function_node_d) - self.checker.visit_asyncfunctiondef(function_node_e) - self.checker.visit_asyncfunctiondef(function_node_f) - self.checker.visit_asyncfunctiondef(function_node_g) - self.checker.visit_asyncfunctiondef(function_node_h) - self.checker.visit_asyncfunctiondef(function_node_i) - self.checker.visit_asyncfunctiondef(function_node_j) - self.checker.visit_asyncfunctiondef(function_node_k) - self.checker.visit_asyncfunctiondef(function_node_l) - self.checker.visit_asyncfunctiondef(function_node_m) - - def test_finds_methods_with_too_many_positional_args(self): - class_node, function_node, function_node_a, function_node_b, function_node_c, function_node_d, \ - function_node_e, function_node_f = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace - def do_thing(self, one, two, three, four, five, six): #@ - pass - def do_thing_a(self, one, two, three, four, five, six, seven=7): #@ - pass - def do_thing_b(self, one, two, three, four, five, six, *, seven): #@ - pass - def do_thing_c(self, one, two, three, four, five, six, *, seven, eight, nine): #@ - pass - def do_thing_d(self, one, two, three, four, five, six, **kwargs): #@ - pass - def do_thing_e(self, one, two, three, four, five, six, *args, seven, eight, nine): #@ - pass - def do_thing_f(self, one, two, three, four, five, six, *args, seven=7, eight=8, nine=9): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_b - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_c - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_d - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_e - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_f - ) - ): - self.checker.visit_functiondef(function_node) - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - self.checker.visit_functiondef(function_node_c) - self.checker.visit_functiondef(function_node_d) - self.checker.visit_functiondef(function_node_e) - self.checker.visit_functiondef(function_node_f) - - def test_finds_methods_with_too_many_positional_args_async(self): - class_node, function_node, function_node_a, function_node_b, function_node_c, function_node_d, \ - function_node_e, function_node_f = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace_async - async def do_thing(self, one, two, three, four, five, six): #@ - pass - async def do_thing_a(self, one, two, three, four, five, six, seven=7): #@ - pass - async def do_thing_b(self, one, two, three, four, five, six, *, seven): #@ - pass - async def do_thing_c(self, one, two, three, four, five, six, *, seven, eight, nine): #@ - pass - async def do_thing_d(self, one, two, three, four, five, six, **kwargs): #@ - pass - async def do_thing_e(self, one, two, three, four, five, six, *args, seven, eight, nine): #@ - pass - async def do_thing_f(self, one, two, three, four, five, six, *args, seven=7, eight=8, nine=9): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_b - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_c - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_d - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_e - ), - pylint.testutils.Message( - msg_id="client-method-has-more-than-5-positional-arguments", node=function_node_f - ) - ): - self.checker.visit_asyncfunctiondef(function_node) - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - self.checker.visit_asyncfunctiondef(function_node_c) - self.checker.visit_asyncfunctiondef(function_node_d) - self.checker.visit_asyncfunctiondef(function_node_e) - self.checker.visit_asyncfunctiondef(function_node_f) - - def test_ignores_non_client_methods(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomethingElse(): #@ - def do_thing(self, one, two, three, four, five, six): #@ - pass - - @distributed_trace_async - async def do_thing(self, one, two, three, four, five, six): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#method-signatures" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientMethodsHaveTypeAnnotations(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientMethodsHaveTypeAnnotations - - def test_ignores_correct_type_annotations(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self, one: str, two: int, three: bool, four: Union[str, thing], five: dict) -> int: #@ - pass - async def do_thing(self, one: str, two: int, three: bool, four: Union[str, thing], five: dict) -> int: #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_ignores_correct_type_comments(self): - class_node, function_node_a, function_node_b, function_node_c = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing_a(self, one, two, three, four, five): #@ - # type: (str, str, str, str, str) -> None - pass - - def do_thing_b(self, one, two): # type: (str, str) -> int #@ - pass - - def do_thing_c(self, #@ - one, # type: str - two, # type: str - three, # type: str - four, # type: str - five # type: str - ): - # type: (...) -> int - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - self.checker.visit_functiondef(function_node_c) - - def test_ignores_correct_type_comments_async(self): - class_node, function_node_a, function_node_b, function_node_c = astroid.extract_node(""" - class SomeClient(): #@ - async def do_thing_a(self, one, two, three, four, five): #@ - # type: (str, str, str, str, str) -> None - pass - - async def do_thing_b(self, one, two): # type: (str, str) -> int #@ - pass - - async def do_thing_c(self, #@ - one, # type: str - two, # type: str - three, # type: str - four, # type: str - five # type: str - ): - # type: (...) -> int - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - self.checker.visit_asyncfunctiondef(function_node_c) - - def test_ignores_no_parameter_method_with_annotations(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing_a(self): #@ - # type: () -> None - pass - - def do_thing_b(self) -> None: #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_ignores_no_parameter_method_with_annotations_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - async def do_thing_a(self): #@ - # type: () -> None - pass - - async def do_thing_b(self) -> None: #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_finds_no_parameter_method_without_annotations(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self): #@ - pass - async def do_thing(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_method_missing_annotations(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self, one, two, three): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node - ) - ): - self.checker.visit_functiondef(function_node) - - def test_finds_method_missing_annotations_async(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - async def do_thing(self, one, two, three): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node - ) - ): - self.checker.visit_asyncfunctiondef(function_node) - - def test_finds_constructor_without_annotations(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, one, two, three, four, five): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node - ) - ): - self.checker.visit_functiondef(function_node) - - def test_finds_missing_return_annotation_but_has_type_hints(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing_a(self, one: str, two: int, three: bool, four: Union[str, thing], five: dict): #@ - pass - - def do_thing_b(self, one, two, three, four, five): #@ - # type: (str, str, str, str, str) - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_missing_return_annotation_but_has_type_hints_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - async def do_thing_a(self, one: str, two: int, three: bool, four: Union[str, thing], five: dict): #@ - pass - - async def do_thing_b(self, one, two, three, four, five): #@ - # type: (str, str, str, str, str) - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_b - ), - ): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_finds_missing_annotations_but_has_return_hint(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing_a(self, one, two, three, four, five) -> None: #@ - pass - - def do_thing_b(self, one, two, three, four, five): #@ - # type: -> None - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_b - ) - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_missing_annotations_but_has_return_hint_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - async def do_thing_a(self, one, two, three, four, five) -> None: #@ - pass - - async def do_thing_b(self, one, two, three, four, five): #@ - # type: -> None - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-type-annotations", node=function_node_b - ) - ): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_ignores_non_client_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def do_thing(self, one, two, three, four, five, six): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def _do_thing(self, one, two, three, four, five, six): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#types-or-not" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientHasKwargsInPoliciesForCreateConfigurationMethod(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientHasKwargsInPoliciesForCreateConfigurationMethod - - def test_ignores_config_policies_with_kwargs(self): - function_node_a, function_node_b = astroid.extract_node(""" - def create_configuration(self, **kwargs): #@ - config = Configuration(**kwargs) - config.headers_policy = StorageHeadersPolicy(**kwargs) - config.user_agent_policy = StorageUserAgentPolicy(**kwargs) - config.retry_policy = kwargs.get('retry_policy') or ExponentialRetry(**kwargs) - config.redirect_policy = RedirectPolicy(**kwargs) - config.logging_policy = StorageLoggingPolicy(**kwargs) - config.proxy_policy = ProxyPolicy(**kwargs) - return config - - @staticmethod - def create_config(credential, api_version=None, **kwargs): #@ - # type: (TokenCredential, Optional[str], Mapping[str, Any]) -> Configuration - if api_version is None: - api_version = KeyVaultClient.DEFAULT_API_VERSION - config = KeyVaultClient.get_configuration_class(api_version, aio=False)(credential, **kwargs) - config.authentication_policy = ChallengeAuthPolicy(credential, **kwargs) - return config - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_config_policies_without_kwargs(self): - function_node_a, policy_a, policy_b, policy_c, function_node_b, policy_d = astroid.extract_node(""" - def create_configuration(self, **kwargs): #@ - config = Configuration(**kwargs) - config.headers_policy = StorageHeadersPolicy(**kwargs) - config.user_agent_policy = StorageUserAgentPolicy() #@ - config.retry_policy = kwargs.get('retry_policy') or ExponentialRetry(**kwargs) - config.redirect_policy = RedirectPolicy(**kwargs) - config.logging_policy = StorageLoggingPolicy() #@ - config.proxy_policy = ProxyPolicy() #@ - return config - - @staticmethod - def create_config(credential, api_version=None, **kwargs): #@ - # type: (TokenCredential, Optional[str], Mapping[str, Any]) -> Configuration - if api_version is None: - api_version = KeyVaultClient.DEFAULT_API_VERSION - config = KeyVaultClient.get_configuration_class(api_version, aio=False)(credential, **kwargs) - config.authentication_policy = ChallengeAuthPolicy(credential) #@ - return config - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="config-missing-kwargs-in-policy", node=policy_a - ), - pylint.testutils.Message( - msg_id="config-missing-kwargs-in-policy", node=policy_b - ), - pylint.testutils.Message( - msg_id="config-missing-kwargs-in-policy", node=policy_c - ), - pylint.testutils.Message( - msg_id="config-missing-kwargs-in-policy", node=policy_d - ) - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_ignores_policies_outside_create_config(self): - function_node_a, function_node_b = astroid.extract_node(""" - def _configuration(self, **kwargs): #@ - config = Configuration(**kwargs) - config.headers_policy = StorageHeadersPolicy(**kwargs) - config.user_agent_policy = StorageUserAgentPolicy(**kwargs) - config.retry_policy = kwargs.get('retry_policy') or ExponentialRetry() - config.redirect_policy = RedirectPolicy() - config.logging_policy = StorageLoggingPolicy() - config.proxy_policy = ProxyPolicy() - return config - - @staticmethod - def some_other_method(credential, api_version=None, **kwargs): #@ - # type: (TokenCredential, Optional[str], Mapping[str, Any]) -> Configuration - if api_version is None: - api_version = KeyVaultClient.DEFAULT_API_VERSION - config = KeyVaultClient.get_configuration_class(api_version, aio=False)(credential) - config.authentication_policy = ChallengeAuthPolicy(credential) - return config - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientUsesCorrectNamingConventions(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientUsesCorrectNamingConventions - - def test_ignores_constructor(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_internal_client(self): - class_node, function_node = astroid.extract_node(""" - class _BaseSomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_private_method(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def _private_method(self, **kwargs): #@ - pass - async def _another_private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_correct_client(self): - class_node = astroid.extract_node(""" - class SomeClient(): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_non_client(self): - class_node, function_node = astroid.extract_node( - """ - class SomethingElse(): #@ - def download_thing(self, some, **kwargs): #@ - pass - """ - ) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_correct_method_names(self): - class_node, function_node_a, function_node_b, function_node_c = astroid.extract_node(""" - class SomeClient(): #@ - def from_connection_string(self, **kwargs): #@ - pass - def get_thing(self, **kwargs): #@ - pass - def delete_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_correct_method_names_async(self): - class_node, function_node_a, function_node_b, function_node_c = astroid.extract_node(""" - class SomeClient(): #@ - def from_connection_string(self, **kwargs): #@ - pass - def get_thing(self, **kwargs): #@ - pass - def delete_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_correct_class_constant(self): - class_node = astroid.extract_node(""" - class SomeClient(): #@ - MAX_SIZE = 14 - MIN_SIZE = 2 - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_finds_incorrectly_named_client(self): - class_node_a, class_node_b, class_node_c = astroid.extract_node(""" - class some_client(): #@ - pass - class Some_Client(): #@ - pass - class someClient(): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=class_node_a - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=class_node_b - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=class_node_c - ), - ): - self.checker.visit_classdef(class_node_a) - self.checker.visit_classdef(class_node_b) - self.checker.visit_classdef(class_node_c) - - def test_finds_incorrectly_named_methods(self): - class_node, func_node_a, func_node_b, func_node_c, func_node_d, func_node_e, func_node_f \ - = astroid.extract_node(""" - class SomeClient(): #@ - def Create_Config(self): #@ - pass - def getThing(self): #@ - pass - def List_thing(self): #@ - pass - def UpsertThing(self): #@ - pass - def set_Thing(self): #@ - pass - def Updatething(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_c - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_d - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_e - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_f - ), - ): - self.checker.visit_classdef(class_node) - - def test_finds_incorrectly_named_methods_async(self): - class_node, func_node_a, func_node_b, func_node_c, func_node_d, func_node_e, func_node_f \ - = astroid.extract_node(""" - class SomeClient(): #@ - async def Create_Config(self): #@ - pass - async def getThing(self): #@ - pass - async def List_thing(self): #@ - pass - async def UpsertThing(self): #@ - pass - async def set_Thing(self): #@ - pass - async def Updatething(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_c - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_d - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_e - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=func_node_f - ), - ): - self.checker.visit_classdef(class_node) - - def test_finds_incorrectly_named_class_constant(self): - class_node, const_a, const_b = astroid.extract_node(""" - class SomeClient(): #@ - max_size = 14 #@ - min_size = 2 #@ - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=const_a - ), - pylint.testutils.Message( - msg_id="client-incorrect-naming-convention", node=const_b - ), - ): - self.checker.visit_classdef(class_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#naming-conventions" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientMethodsHaveKwargsParameter(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientMethodsHaveKwargsParameter - - def test_ignores_private_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def _create_configuration(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_properties(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @property - def key_id(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_properties_async(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @property - async def key_id(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node) - - def test_ignores_non_client_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def create_configuration(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_methods_with_kwargs(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def get_thing(self, **kwargs): #@ - pass - @distributed_trace - def remove_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_missing_kwargs(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.tracing.decorator import distributed_trace - - class SomeClient(): #@ - @distributed_trace - def get_thing(self): #@ - pass - @distributed_trace - def remove_thing(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-kwargs", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-kwargs", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_ignores_methods_with_kwargs_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - async def get_thing(self, **kwargs): #@ - pass - async def remove_thing(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_finds_missing_kwargs_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.tracing.decorator_async import distributed_trace_async - - class SomeClient(): #@ - @distributed_trace_async - async def get_thing(self): #@ - pass - @distributed_trace_async - async def remove_thing(self): #@ - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-missing-kwargs", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-method-missing-kwargs", node=function_node_b - ), - ): - self.checker.visit_asyncfunctiondef(function_node_a) - self.checker.visit_asyncfunctiondef(function_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestAsyncClientCorrectNaming(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.AsyncClientCorrectNaming - - def test_ignores_private_client(self): - class_node = astroid.extract_node(""" - class _AsyncBaseSomeClient(): #@ - def create_configuration(self): - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_correct_client(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def create_configuration(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_async_base_named_client(self): - class_node_a = astroid.extract_node(""" - class AsyncSomeClientBase(): #@ - def get_thing(self, **kwargs): - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node_a) - - def test_finds_incorrectly_named_client(self): - class_node_a = astroid.extract_node(""" - class AsyncSomeClient(): #@ - def get_thing(self, **kwargs): - pass - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="async-client-bad-name", node=class_node_a - ), - ): - self.checker.visit_classdef(class_node_a) - - def test_ignores_non_client(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def create_configuration(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#async-support" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestFileHasCopyrightHeader(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.FileHasCopyrightHeader - - # Unable to use the astroid for this testcase. - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/policies_opensource.html" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestSpecifyParameterNamesInCall(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.SpecifyParameterNamesInCall - - def test_ignores_call_with_only_two_unnamed_params(self): - class_node, call_node = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self): - self._client.thing(one, two) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_call(call_node) - - def test_ignores_call_with_two_unnamed_params_and_one_named(self): - class_node, call_node = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self): - self._client.thing(one, two, three=3) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_call(call_node) - - def test_ignores_call_from_non_client(self): - class_node, call_node = astroid.extract_node(""" - class SomethingElse(): #@ - def do_thing(self): - self._other.thing(one, two, three) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_call(call_node) - - def test_ignores_call_with_named_params(self): - class_node, call_node_a, call_node_b, call_node_c = astroid.extract_node(""" - class SomethingElse(): #@ - def do_thing_a(self): - self._other.thing(one=one, two=two, three=three) #@ - def do_thing_b(self): - self._other.thing(zero, number, one=one, two=two, three=three) #@ - def do_thing_c(self): - self._other.thing(zero, one=one, two=two, three=three) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_call(call_node_a) - self.checker.visit_call(call_node_b) - self.checker.visit_call(call_node_c) - - def test_ignores_non_client_function_call(self): - call_node = astroid.extract_node(""" - def do_thing(): - self._client.thing(one, two, three) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_call(call_node) - - def test_finds_call_with_more_than_two_unnamed_params(self): - class_node, call_node = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self): - self._client.thing(one, two, three) #@ - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="specify-parameter-names-in-call", node=call_node - ), - ): - self.checker.visit_call(call_node) - - def test_finds_call_with_more_than_two_unnamed_params_and_some_named(self): - class_node, call_node = astroid.extract_node(""" - class SomeClient(): #@ - def do_thing(self): - self._client.thing(one, two, three, four=4, five=5) #@ - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="specify-parameter-names-in-call", node=call_node - ), - ): - self.checker.visit_call(call_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#method-signatures" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientListMethodsUseCorePaging(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientListMethodsUseCorePaging - - def test_ignores_private_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def _list_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_non_client_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def list_things(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_methods_return_ItemPaged(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.paging import ItemPaged - - class SomeClient(): #@ - def list_thing(self): #@ - return ItemPaged() - @distributed_trace - def list_thing2(self): #@ - return ItemPaged( - command, prefix=name_starts_with, results_per_page=results_per_page, - page_iterator_class=BlobPropertiesPaged) - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_ignores_methods_return_AsyncItemPaged(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.async_paging import AsyncItemPaged - - class SomeClient(): #@ - async def list_thing(self): #@ - return AsyncItemPaged() - @distributed_trace - def list_thing2(self): #@ - return AsyncItemPaged( - command, prefix=name_starts_with, results_per_page=results_per_page, - page_iterator_class=BlobPropertiesPaged) - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_method_returning_something_else(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - def list_thing(self): #@ - return list() - def list_thing2(self): #@ - return LROPoller() - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-list-methods-use-paging", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-list-methods-use-paging", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_method_returning_something_else_async(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - async def list_thing(self, **kwargs): #@ - return list() - async def list_thing2(self, **kwargs): #@ - from azure.core.polling import LROPoller - return LROPoller() - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-list-methods-use-paging", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-list-methods-use-paging", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#response-formats" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientLROMethodsUseCorePolling(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientLROMethodsUseCorePolling - - def test_ignores_private_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def _begin_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_non_client_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def begin_things(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_methods_return_LROPoller(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - def begin_thing(self): #@ - return LROPoller() - @distributed_trace - def begin_thing2(self): #@ - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_finds_method_returning_something_else(self): - class_node, function_node_a, function_node_b = astroid.extract_node(""" - class SomeClient(): #@ - def begin_thing(self): #@ - return list() - def begin_thing2(self): #@ - return {} - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-lro-methods-use-polling", node=function_node_a - ), - pylint.testutils.Message( - msg_id="client-lro-methods-use-polling", node=function_node_b - ), - ): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#response-formats" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientLROMethodsUseCorrectNaming(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientLROMethodsUseCorrectNaming - - def test_ignores_private_methods(self): - class_node, return_node = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - def _do_thing(self): - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - self.checker.visit_return(return_node) - - def test_ignores_non_client_methods(self): - class_node, return_node = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomethingElse(): #@ - def begin_things(self): - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - self.checker.visit_return(return_node) - - def test_ignores_methods_return_LROPoller_and_correctly_named(self): - class_node, return_node_a, return_node_b = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - def begin_thing(self): - return LROPoller() #@ - @distributed_trace - def begin_thing2(self): - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) #@ - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - self.checker.visit_return(return_node_a) - self.checker.visit_return(return_node_b) - - def test_finds_incorrectly_named_method_returning_LROPoller(self): - class_node, function_node_a, return_node_a, function_node_b, return_node_b = astroid.extract_node(""" - from azure.core.polling import LROPoller - - class SomeClient(): #@ - def poller_thing(self): #@ - return LROPoller() #@ - @distributed_trace - def start_thing2(self): #@ - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) #@ - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="lro-methods-use-correct-naming", node=function_node_a - ), - pylint.testutils.Message( - msg_id="lro-methods-use-correct-naming", node=function_node_b - ), - ): - self.checker.visit_classdef(class_node) - self.checker.visit_return(return_node_a) - self.checker.visit_return(return_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#service-operations" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientConstructorDoesNotHaveConnectionStringParam(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientConstructorDoesNotHaveConnectionStringParam - - def test_ignores_client_with_no_conn_str_in_constructor(self): - class_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self): - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_ignores_non_client_methods(self): - class_node, function_node = astroid.extract_node(""" - class SomethingElse(): #@ - def __init__(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_classdef(class_node) - - def test_finds_client_method_using_conn_str_in_constructor_a(self): - class_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, connection_string): - return list() - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="connection-string-should-not-be-constructor-param", node=class_node - ), - ): - self.checker.visit_classdef(class_node) - - def test_finds_client_method_using_conn_str_in_constructor_b(self): - class_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, conn_str): - return list() - """) - - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="connection-string-should-not-be-constructor-param", node=class_node - ), - ): - self.checker.visit_classdef(class_node) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_design.html#constructors-and-factory-methods" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 - - -class TestClientMethodNamesDoNotUseDoubleUnderscorePrefix(pylint.testutils.CheckerTestCase): - CHECKER_CLASS = checker.ClientMethodNamesDoNotUseDoubleUnderscorePrefix - - def test_ignores_repr(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __repr__(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_constructor(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - def __init__(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_other_dunder(self): - class_node, function_node_a, function_node_b, function_node_c, function_node_d = astroid.extract_node(""" - class SomeClient(): #@ - def __enter__(self): #@ - pass - def __exit__(self): #@ - pass - def __aenter__(self): #@ - pass - def __aexit__(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node_a) - self.checker.visit_functiondef(function_node_b) - self.checker.visit_functiondef(function_node_c) - self.checker.visit_functiondef(function_node_d) - - def test_ignores_private_method(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(function_node) - - def test_ignores_private_method_async(self): - class_node, function_node = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - async def _private_method(self, **kwargs): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(function_node) - - def test_ignores_methods_with_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace - def create_configuration(self): #@ - pass - @distributed_trace - def get_thing(self): #@ - pass - @distributed_trace - def list_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_async_methods_with_decorators(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @distributed_trace_async - async def create_configuration(self): #@ - pass - @distributed_trace_async - async def get_thing(self): #@ - pass - @distributed_trace_async - async def list_thing(self): #@ - pass - """) - - with self.assertNoMessages(): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_double_underscore_on_async_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - async def __create_configuration(self): #@ - pass - @staticmethod - async def __get_thing(self): #@ - pass - @staticmethod - async def __list_thing(self): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_c - ), - ): - self.checker.visit_asyncfunctiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - self.checker.visit_asyncfunctiondef(func_node_c) - - def test_finds_double_underscore_on_sync_method(self): - class_node, func_node_a, func_node_b, func_node_c = astroid.extract_node(""" - class SomeClient(): #@ - @staticmethod - def __create_configuration(self): #@ - pass - @staticmethod - def __get_thing(self): #@ - pass - @staticmethod - def __list_thing(self): #@ - pass - """) - with self.assertAddsMessages( - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_a - ), - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_b - ), - pylint.testutils.Message( - msg_id="client-method-name-no-double-underscore", node=func_node_c - ), - ): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_functiondef(func_node_b) - self.checker.visit_functiondef(func_node_c) - - def test_ignores_non_client_method(self): - class_node, func_node_a, func_node_b = astroid.extract_node( - """ - class SomethingElse(): #@ - @staticmethod - def __download_thing(self, some, **kwargs): #@ - pass - - @staticmethod - async def __do_thing(self, some, **kwargs): #@ - pass - """ - ) - with self.assertNoMessages(): - self.checker.visit_functiondef(func_node_a) - self.checker.visit_asyncfunctiondef(func_node_b) - - def test_guidelines_link_active(self): - url = "https://azure.github.io/azure-sdk/python_introduction.html#public-vs-private" - config = Configuration() - client = PipelineClient(url, config=config) - request = client.get(url) - response = client._pipeline.run(request) - assert response.http_response.status_code == 200 \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_multiapi_client.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_multiapi_client.py deleted file mode 100644 index f0b546803e1..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_multiapi_client.py +++ /dev/null @@ -1,105 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- - -from msrest.service_client import SDKClient -from msrest import Serializer, Deserializer - -from azure.profiles import KnownProfiles, ProfileDefinition -from azure.profiles.multiapiclient import MultiApiClientMixin -from ._configuration import {{ client_name }}Configuration -{% if mixin_operations %}from ._operations_mixin import {{ client_name }}OperationsMixin{% endif %} - - -class {{ client_name }}({% if mixin_operations %}{{ client_name }}OperationsMixin, {% endif %}MultiApiClientMixin, SDKClient): - """{{ client_doc }} - - This ready contains multiple API versions, to help you deal with all Azure clouds - (Azure Stack, Azure Government, Azure China, etc.). - By default, uses latest API version available on public Azure. - For production, you should stick a particular api-version and/or profile. - The profile sets a mapping between the operation group and an API version. - The api-version parameter sets the default API version if the operation - group is not described in the profile. - - :ivar config: Configuration for client. - :vartype config: {{ client_name }}Configuration - - :param credentials: Credentials needed for the client to connect to Azure. - :type credentials: :mod:`A msrestazure Credentials - object` -{%- if has_subscription_id %} - :param subscription_id: Subscription credentials which uniquely identify - Microsoft Azure subscription. The subscription ID forms part of the URI - for every service call. - :type subscription_id: str -{%- endif %} - :param str api_version: API version to use if no profile is provided, or if - missing in profile. - :param str base_url: Service URL - :param profile: A profile definition, from KnownProfiles to dict. - :type profile: azure.profiles.KnownProfiles - """ - - DEFAULT_API_VERSION = '{{ last_api_version }}' - _PROFILE_TAG = "{{ module_name }}.{{ client_name }}" - LATEST_PROFILE = ProfileDefinition({ - _PROFILE_TAG: { - None: DEFAULT_API_VERSION, -{%- for rt_name, api_version in last_rt_list|dictsort %} - '{{ rt_name }}': '{{ mod_to_api_version[api_version] }}', -{%- endfor %} - }}, - _PROFILE_TAG + " latest" - ) - - def __init__(self, credentials{%- if has_subscription_id %}, subscription_id{% endif %}, api_version=None, base_url=None, profile=KnownProfiles.default): - self.config = {{ client_name }}Configuration(credentials{%- if has_subscription_id %}, subscription_id{% endif %}, base_url) - super({{ client_name }}, self).__init__( - credentials, - self.config, - api_version=api_version, - profile=profile - ) - - @classmethod - def _models_dict(cls, api_version): - return {k: v for k, v in cls.models(api_version).__dict__.items() if isinstance(v, type)} - - @classmethod - def models(cls, api_version=DEFAULT_API_VERSION): - """Module depends on the API version: -{% for mod_api_version, api_version in mod_to_api_version|dictsort %} - * {{ api_version }}: :mod:`{{ mod_api_version }}.models<{{ module_name }}.{{ mod_api_version }}.models>` -{%- endfor %} - """ -{%- for mod_api_version, api_version in mod_to_api_version|dictsort %} - {% if not loop.first %}el{% endif %}if api_version == '{{ api_version }}': - from .{{ mod_api_version }} import models - return models -{%- endfor %} - raise NotImplementedError("APIVersion {} is not available".format(api_version)) -{% for operation_name, available_apis in operations|dictsort %} - @property - def {{ operation_name }}(self): - """Instance depends on the API version: -{% for api in available_apis %} - * {{ mod_to_api_version[api[0]] }}: :class:`{{ api[1] }}<{{ module_name }}.{{ api[0] }}.operations.{{ api[1] }}>` -{%- endfor %} - """ - api_version = self._get_api_version('{{ operation_name }}') -{%- for api in available_apis %} - {% if not loop.first %}el{% endif %}if api_version == '{{ mod_to_api_version[api[0]] }}': - from .{{ api[0] }}.operations import {{ api[1] }} as OperationClass -{%- endfor %} - else: - raise NotImplementedError("APIVersion {} is not available".format(api_version)) - return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) -{% endfor %} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_operations_mixin.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_operations_mixin.py deleted file mode 100644 index 1c5e332c707..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/_operations_mixin.py +++ /dev/null @@ -1,34 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- -from msrest import Serializer, Deserializer - - -class {{ client_name }}OperationsMixin(object): - -{% for operation_name, metadata in mixin_operations|dictsort %} - def {{ operation_name }}{{ metadata['signature'] }}: - """{{ metadata['doc'] }} - """ - api_version = self._get_api_version('{{ operation_name }}') -{%- for api in metadata['available_apis'] %} - {% if not loop.first %}el{% endif %}if api_version == '{{ mod_to_api_version[api] }}': - from .{{ api }}.operations import {{ client_name }}OperationsMixin as OperationClass -{%- endfor %} - else: - raise NotImplementedError("APIVersion {} is not available".format(api_version)) - mixin_instance = OperationClass() - mixin_instance._client = self._client - mixin_instance.config = self.config - mixin_instance._serialize = Serializer(self._models_dict(api_version)) - mixin_instance._deserialize = Deserializer(self._models_dict(api_version)) - mixin_instance.api_version = api_version - return mixin_instance.{{ operation_name }}({{ metadata['call'] }}, **operation_config) -{% endfor %} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/models.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/models.py deleted file mode 100644 index 676f0147868..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/templates/models.py +++ /dev/null @@ -1,9 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -{%- for mod_api_version in default_models %} -from .{{ mod_api_version }}.models import * -{%- endfor %} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/trim_aio.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/trim_aio.py deleted file mode 100644 index 13779f8951c..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/scripts/trim_aio.py +++ /dev/null @@ -1,19 +0,0 @@ -import logging -from pathlib import Path -import shutil -import sys - - -_LOGGER = logging.getLogger(__name__) - - -def trim(base_folder): - base_folder = Path(base_folder) - for aio_folder in Path(base_folder).glob("**/aio"): - _LOGGER.info("Working on %s", aio_folder) - shutil.rmtree(aio_folder) # Let it throw at worst - - -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) - trim(sys.argv[1]) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/swagger_to_sdk_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/swagger_to_sdk_config.json deleted file mode 100644 index ae2cffc5223..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/swagger_to_sdk_config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://openapistorageprod.blob.core.windows.net/sdkautomation/prod/schemas/swagger_to_sdk_config.schema.json", - "meta": { - "autorest_options": { - "version": "V2", - "use": "@microsoft.azure/autorest.python@4.0.73", - "python": "", - "sdkrel:python-sdks-folder": "./sdk/.", - "multiapi": "", - "keep-version-file" :"", - "no-async": "" - }, - "advanced_options": { - "create_sdk_pull_requests": true, - "sdk_generation_pull_request_base": "integration_branch" - }, - "repotag": "azure-sdk-for-python", - "version": "0.2.0" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/dev_requirements.txt b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/dev_requirements.txt deleted file mode 100644 index 677164e0ab9..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/dev_requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e ../azure-devtools diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__init__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__init__.py deleted file mode 100644 index 4d06c976598..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__init__.py +++ /dev/null @@ -1,126 +0,0 @@ -from contextlib import suppress -import logging -import os -from pathlib import Path -from typing import Dict, Any, Optional, List - -from jinja2 import Template, PackageLoader, Environment -from .conf import read_conf, build_default_conf, CONF_NAME - -_LOGGER = logging.getLogger(__name__) - -_CWD = Path(__file__).resolve().parent -_TEMPLATE_PATH = _CWD / "template" - -def build_config(config : Dict[str, Any]) -> Dict[str, str]: - """Will build the actual config for Jinja2, based on SDK config. - """ - result = config.copy() - # Manage the classifier stable/beta - is_stable = result.pop("is_stable", False) - if is_stable: - result["classifier"] = "Development Status :: 5 - Production/Stable" - else: - result["classifier"] = "Development Status :: 4 - Beta" - # Manage the nspkg - package_name = result["package_name"] - result["package_nspkg"] = result.pop( - "package_nspkg", - package_name[:package_name.rindex('-')]+"-nspkg" - ) - # ARM? - result['is_arm'] = result.pop("is_arm", True) - - # Do I need msrestazure for this package? - result['need_msrestazure'] = result.pop("need_msrestazure", True) - - # Pre-compute some Jinja variable that are complicated to do inside the templates - package_parts = result["package_nspkg"][:-len('-nspkg')].split('-') - result['nspkg_names'] = [ - ".".join(package_parts[:i+1]) - for i in range(len(package_parts)) - ] - result['init_names'] = [ - "/".join(package_parts[:i+1])+"/__init__.py" - for i in range(len(package_parts)) - ] - - # Return result - return result - - -def build_packaging(output_folder: str, gh_token: Optional[str]=None, jenkins: bool = False, packages: List[str]=None, build_conf: bool = False) -> None: - package_names = set(packages) or set() - if jenkins: - sdk_id = os.environ["ghprbGhRepository"] - pr_number = int(os.environ["ghprbPullId"]) - - from github import Github - con = Github(gh_token) - repo = con.get_repo(sdk_id) - sdk_pr = repo.get_pull(pr_number) - # "get_files" of Github only download the first 300 files. Might not be enough. - package_names |= {f.filename.split('/')[0] for f in sdk_pr.get_files() if f.filename.startswith("azure")} - - if not package_names: - raise ValueError("Was unable to find out the package names.") - - for package_name in package_names: - build_packaging_by_package_name(package_name, output_folder, build_conf) - - -def build_packaging_by_package_name(package_name: str, output_folder: str, build_conf: bool = False) -> None: - _LOGGER.info("Building template %s", package_name) - package_folder = Path(output_folder) / Path(package_name) - - if build_conf: - build_default_conf(package_folder, package_name) - - conf = read_conf(package_folder) - if not conf: - raise ValueError("Create a {} file before calling this script".format(package_folder / CONF_NAME)) - - if not conf.get("auto_update", True): - _LOGGER.info(f"Package {package_name} has no auto-packaging update enabled") - return - - env = Environment( - loader=PackageLoader('packaging_tools', 'templates'), - keep_trailing_newline=True - ) - conf = build_config(conf) - - for template_name in env.list_templates(): - future_filepath = Path(output_folder) / package_name / template_name - - # Might decide to make it more generic one day - if template_name == "CHANGELOG.md" and future_filepath.exists(): - _LOGGER.info("Skipping CHANGELOG.md template, since a previous one was found") - # Never overwirte the ChangeLog - continue - - template = env.get_template(template_name) - result = template.render(**conf) - - # __init__.py is a weird one - if template_name == "__init__.py": - split_package_name = package_name.split("-")[:-1] - for i in range(len(split_package_name)): - init_path = Path(output_folder).joinpath( - package_name, - *split_package_name[:i+1], - template_name - ) - with open(init_path, "w") as fd: - fd.write(result) - - continue - - with open(future_filepath, "w") as fd: - fd.write(result) - # azure_bdist_wheel had been removed, but need to delete it manually - with suppress(FileNotFoundError): - (Path(output_folder) / package_name / "azure_bdist_wheel.py").unlink() - - - _LOGGER.info("Template done %s", package_name) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__main__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__main__.py deleted file mode 100644 index da4c398b19d..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/__main__.py +++ /dev/null @@ -1,54 +0,0 @@ -import argparse -import logging -import os -import sys - -from . import build_packaging - -_LOGGER = logging.getLogger(__name__) - -_epilog="""This script will automatically build the TOML configuration file with default value if it doesn't exist. -""" - -parser = argparse.ArgumentParser( - description='Packaging tools for Azure SDK for Python', - formatter_class=argparse.RawTextHelpFormatter, - epilog=_epilog -) -parser.add_argument('--output', '-o', - dest='output', default='.', - help='Output dir, should be SDK repo folder. [default: %(default)s]') -parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") -parser.add_argument("--build-conf", - dest="build_conf", action="store_true", - help="Build a default TOML file, with package name, fake pretty name, as beta package and no doc page. Do nothing if the file exists, remove manually the file if needed.") -parser.add_argument("--jenkins", - dest="jenkins", action="store_true", - help="In Jenkins mode, try to find what to generate from Jenkins env variables. Package names are then optional.") -parser.add_argument('package_names', nargs='*', help='The package name.') - -args = parser.parse_args() - -main_logger = logging.getLogger() -logging.basicConfig() -main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) - -if not args.package_names and not args.jenkins: - raise ValueError("At least one package name or Jenkins mode is required") - -try: - build_packaging( - args.output, - os.environ.get("GH_TOKEN", None), - args.jenkins, - args.package_names, - build_conf=args.build_conf - ) -except Exception as err: - if args.debug: - _LOGGER.exception(err) - else: - _LOGGER.critical(err) - sys.exit(1) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/change_log.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/change_log.py deleted file mode 100644 index d7c76d1e860..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/change_log.py +++ /dev/null @@ -1,201 +0,0 @@ -import json -import logging - -from json_delta import diff - -_LOGGER = logging.getLogger(__name__) - -class ChangeLog: - def __init__(self, old_report, new_report): - self.features = [] - self.breaking_changes = [] - self._old_report = old_report - self._new_report = new_report - - def build_md(self): - buffer = [] - if self.features: - buffer.append("**Features**") - buffer.append("") - for feature in self.features: - buffer.append(" - "+feature) - buffer.append("") - if self.breaking_changes: - buffer.append("**Breaking changes**") - buffer.append("") - for breaking_change in self.breaking_changes: - buffer.append(" - "+breaking_change) - return "\n".join(buffer).strip() - - @staticmethod - def _unpack_diff_entry(diff_entry): - return diff_entry[0], len(diff_entry) == 1 - - def operation(self, diff_entry): - path, is_deletion = self._unpack_diff_entry(diff_entry) - - # Is this a new operation group? - _, operation_name, *remaining_path = path - if not remaining_path: - if is_deletion: - self.breaking_changes.append(_REMOVE_OPERATION_GROUP.format(operation_name)) - else: - self.features.append(_ADD_OPERATION_GROUP.format(operation_name)) - return - - _, *remaining_path = remaining_path - if not remaining_path: - # Not common, but this means this has changed a lot. Compute the list manually - old_ops_name = list(self._old_report["operations"][operation_name]["functions"]) - new_ops_name = list(self._new_report["operations"][operation_name]["functions"]) - for removed_function in set(old_ops_name) - set(new_ops_name): - self.breaking_changes.append(_REMOVE_OPERATION.format(operation_name, removed_function)) - for added_function in set(new_ops_name) - set(old_ops_name): - self.features.append(_ADD_OPERATION.format(operation_name, added_function)) - return - - # Is this a new operation, inside a known operation group? - function_name, *remaining_path = remaining_path - if not remaining_path: - if is_deletion: - self.breaking_changes.append(_REMOVE_OPERATION.format(operation_name, function_name)) - else: - self.features.append(_ADD_OPERATION.format(operation_name, function_name)) - return - - if remaining_path[0] == "metadata": - # Ignore change in metadata for now, they have no impact - return - - # So method signaure changed. Be vague for now - self.breaking_changes.append(_SIGNATURE_CHANGE.format(operation_name, function_name)) - - - def models(self, diff_entry): - path, is_deletion = self._unpack_diff_entry(diff_entry) - - # Is this a new model? - _, mtype, *remaining_path = path - if not remaining_path: - # Seen once in Network, because exceptions were added. Bypass - return - model_name, *remaining_path = remaining_path - if not remaining_path: - # A new model or a model deletion is not very interesting by itself - # since it usually means that there is a new operation - # - # We might miss some discrimanator new sub-classes however - return - - # That's a model signature change - if mtype in ["enums", "exceptions"]: - # Don't change log anything for Enums for now - return - - _, *remaining_path = remaining_path - if not remaining_path: # This means massive signature changes, that we don't even try to list them - self.breaking_changes.append(_MODEL_SIGNATURE_CHANGE.format(model_name)) - return - - # This is a real model - parameter_name, *remaining_path = remaining_path - is_required = lambda report, model_name, param_name: report["models"]["models"][model_name]["parameters"][param_name]["properties"]["required"] - if not remaining_path: - if is_deletion: - self.breaking_changes.append(_MODEL_PARAM_DELETE.format(model_name, parameter_name)) - else: - # This one is tough, if the new parameter is "required", - # then it's breaking. If not, it's a feature - if is_required(self._new_report, model_name, parameter_name): - self.breaking_changes.append(_MODEL_PARAM_ADD_REQUIRED.format(model_name, parameter_name)) - else: - self.features.append(_MODEL_PARAM_ADD.format(model_name, parameter_name)) - return - - # The parameter already exists - new_is_required = is_required(self._new_report, model_name, parameter_name) - old_is_required = is_required(self._old_report, model_name, parameter_name) - - if new_is_required and not old_is_required: - # This shift from optional to required - self.breaking_changes.append(_MODEL_PARAM_CHANGE_REQUIRED.format(parameter_name, model_name)) - return - - -## Features -_ADD_OPERATION_GROUP = "Added operation group {}" -_ADD_OPERATION = "Added operation {}.{}" -_MODEL_PARAM_ADD = "Model {} has a new parameter {}" - -## Breaking Changes -_REMOVE_OPERATION_GROUP = "Removed operation group {}" -_REMOVE_OPERATION = "Removed operation {}.{}" -_SIGNATURE_CHANGE = "Operation {}.{} has a new signature" -_MODEL_SIGNATURE_CHANGE = "Model {} has a new signature" -_MODEL_PARAM_DELETE = "Model {} no longer has parameter {}" -_MODEL_PARAM_ADD_REQUIRED = "Model {} has a new required parameter {}" -_MODEL_PARAM_CHANGE_REQUIRED = "Parameter {} of model {} is now required" - -def build_change_log(old_report, new_report): - change_log = ChangeLog(old_report, new_report) - - result = diff(old_report, new_report) - - for diff_line in result: - # Operations - if diff_line[0][0] == "operations": - change_log.operation(diff_line) - else: - change_log.models(diff_line) - - return change_log - -def get_report_from_parameter(input_parameter): - if ":" in input_parameter: - package_name, version = input_parameter.split(":") - from .code_report import main - result = main( - package_name, - version=version if version not in ["pypi", "latest"] else None, - last_pypi=version == "pypi" - ) - if not result: - raise ValueError("Was not able to build a report") - if len(result) == 1: - with open(result[0], "r") as fd: - return json.load(fd) - - raise NotImplementedError("Multi-api changelog not yet implemented") - - with open(input_parameter, "r") as fd: - return json.load(fd) - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser( - description='ChangeLog computation', - ) - parser.add_argument('base', - help='Base. Could be a file path, or :. Version can be pypi, latest or a real version') - parser.add_argument('latest', - help='Latest. Could be a file path, or :. Version can be pypi, latest or a real version') - - parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") - - args = parser.parse_args() - - logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) - - old_report = get_report_from_parameter(args.base) - new_report = get_report_from_parameter(args.latest) - - # result = diff(old_report, new_report) - # with open("result.json", "w") as fd: - # json.dump(result, fd) - - change_log = build_change_log(old_report, new_report) - print(change_log.build_md()) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/code_report.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/code_report.py deleted file mode 100644 index 672a26aef77..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/code_report.py +++ /dev/null @@ -1,298 +0,0 @@ -import importlib -import inspect -import json -import logging -import glob -import os -import pkgutil -from pathlib import Path -import subprocess -import sys -import types -from typing import Dict, Any, Optional - -# Because I'm subprocessing myself, I need to do weird thing as import. -try: - # If I'm started as a module __main__ - from .venvtools import create_venv_with_package -except (ModuleNotFoundError, ImportError) as e: - # If I'm started by my main directly - from venvtools import create_venv_with_package - - -_LOGGER = logging.getLogger(__name__) - -def parse_input(input_parameter): - """From a syntax like package_name#submodule, build a package name - and complete module name. - """ - split_package_name = input_parameter.split('#') - package_name = split_package_name[0] - module_name = package_name.replace("-", ".") - if len(split_package_name) >= 2: - module_name = ".".join([module_name, split_package_name[1]]) - return package_name, module_name - -def create_empty_report(): - return { - "models": { - "enums": {}, - "exceptions": {}, - "models": {} - }, - "operations": {} - } - -def create_report(module_name: str) -> Dict[str, Any]: - module_to_generate = importlib.import_module(module_name) - - report = create_empty_report() - - # Look for models first - model_names = [model_name for model_name in dir(module_to_generate.models) if model_name[0].isupper()] - for model_name in model_names: - model_cls = getattr(module_to_generate.models, model_name) - if hasattr(model_cls, "_attribute_map"): - report["models"]["models"][model_name] = create_model_report(model_cls) - elif issubclass(model_cls, Exception): # If not, might be an exception - report["models"]["exceptions"][model_name] = create_model_report(model_cls) - else: - report["models"]["enums"][model_name] = create_model_report(model_cls) - # Look for operation groups - try: - operations_classes = [op_name for op_name in dir(module_to_generate.operations) if op_name[0].isupper()] - except AttributeError: - # This guy has no "operations", this is possible (Cognitive Services). Just skip it then. - operations_classes = [] - - for op_name in operations_classes: - op_content = {'name': op_name} - op_cls = getattr(module_to_generate.operations, op_name) - for op_attr_name in dir(op_cls): - op_attr = getattr(op_cls, op_attr_name) - if isinstance(op_attr, types.FunctionType) and not op_attr_name.startswith("_"): - # Keep it - func_content = create_report_from_func(op_attr) - op_content.setdefault("functions", {})[op_attr_name] = func_content - report['operations'][op_name] = op_content - - return report - -def create_model_report(model_cls): - result = { - 'name': model_cls.__name__, - } - # If _attribute_map, it's a model - if hasattr(model_cls, "_attribute_map"): - result['type'] = "Model" - for attribute, conf in model_cls._attribute_map.items(): - attribute_validation = getattr(model_cls, "_validation", {}).get(attribute, {}) - - result.setdefault('parameters', {})[attribute] = { - 'name': attribute, - 'properties': { - 'type': conf['type'], - 'required': attribute_validation.get('required', False), - 'readonly': attribute_validation.get('readonly', False) - } - } - elif issubclass(model_cls, Exception): # If not, might be an exception - result['type'] = "Exception" - else: # If not, it's an enum - result['type'] = "Enum" - result['values'] = list(model_cls.__members__) - - return result - -def create_report_from_func(function_attr): - func_content = { - 'name': function_attr.__name__, - 'metadata': getattr(function_attr, "metadata", {}), - 'parameters': [] - } - signature = inspect.signature(function_attr) - for parameter_name in signature.parameters: - if parameter_name == "self": - continue - if parameter_name =="custom_headers": - break # We reach Autorest generic - parameter = signature.parameters[parameter_name] - func_content["parameters"].append({ - 'name': parameter.name, - }) - return func_content - -# given an input of a name, we need to return the appropriate relative diff between the sdk_root and the actual package directory -def resolve_package_directory(package_name): - packages = [os.path.dirname(p) for p in (glob.glob('{}/setup.py'.format(package_name)) + glob.glob('sdk/*/{}/setup.py'.format(package_name)))] - - if len(packages) > 1: - print('There should only be a single package matched in either repository structure. The following were found: {}'.format(packages)) - sys.exit(1) - - return packages[0] - -def merge_report(report_paths): - """Merge report on the given paths list. - """ - if len(report_paths) == 1: - raise ValueError("Doesn't make sense to merge a report if there is only one report....") - - merged_report = create_empty_report() - for report in sorted(report_paths): - with report.open() as report_fd: - report_json = json.load(report_fd) - - merged_report["models"]["enums"].update(report_json["models"]["enums"]) - merged_report["models"]["exceptions"].update(report_json["models"]["exceptions"]) - merged_report["models"]["models"].update(report_json["models"]["models"]) - merged_report["operations"].update(report_json["operations"]) - return merged_report - -def main(input_parameter: str, version: Optional[str] = None, no_venv: bool = False, pypi: bool = False, last_pypi: bool = False, output: str = None): - package_name, module_name = parse_input(input_parameter) - path_to_package = resolve_package_directory(package_name) - - if (version or pypi or last_pypi) and not no_venv: - if version: - versions = [version] - else: - _LOGGER.info(f"Download versions of {package_name} on PyPI") - from pypi_tools.pypi import PyPIClient - client = PyPIClient() - versions = [str(v) for v in client.get_ordered_versions(package_name)] - _LOGGER.info(f"Got {versions}") - if last_pypi: - _LOGGER.info(f"Only keep last PyPI version") - versions = [versions[-1]] - - for version in versions: - _LOGGER.info(f"Installing version {version} of {package_name} in a venv") - with create_venv_with_package([f"{package_name}=={version}"]) as venv: - args = [ - venv.env_exe, - __file__, - "--no-venv", - "--version", - version, - input_parameter - ] - if output is not None: - args.append("--output=" + output) - try: - subprocess.check_call(args) - except subprocess.CalledProcessError: - # If it fail, just assume this version is too old to get an Autorest report - _LOGGER.warning(f"Version {version} seems to be too old to build a report (probably not Autorest based)") - # Files have been written by the subprocess - return - - modules = find_autorest_generated_folder(module_name) - result = [] - version = version or "latest" - output_folder = Path(path_to_package) / Path("code_reports") / Path(version) - output_folder.mkdir(parents=True, exist_ok=True) - - for module_name in modules: - _LOGGER.info(f"Working on {module_name}") - - report = create_report(module_name) - - module_for_path = get_sub_module_part(package_name, module_name) - if module_for_path: - output_filename = output_folder / Path(module_for_path+".json") - else: - if output is not None: - output_filename = output - else: - output_filename = output_folder / Path("report.json") - - with open(output_filename, "w") as fd: - json.dump(report, fd, indent=2) - _LOGGER.info(f"Report written to {output_filename}") - result.append(output_filename) - - if len(result) > 1: - merged_report = merge_report(result) - if output is not None: - output_filename = output - else: - output_filename = output_folder / Path("merged_report.json") - with open(output_filename, "w") as fd: - json.dump(merged_report, fd, indent=2) - _LOGGER.info(f"Merged report written to {output_filename}") - - return result - -def find_autorest_generated_folder(module_prefix="azure"): - """Find all Autorest generated code in that module prefix. - This actually looks for a "models" package only (not file). We could be smarter if necessary. - """ - _LOGGER.info(f"Looking for Autorest generated package in {module_prefix}") - - # Manually skip some namespaces for now - if module_prefix in ["azure.cli", "azure.storage", "azure.servicemanagement", "azure.servicebus"]: - _LOGGER.info(f"Skip {module_prefix}") - return [] - - result = [] - try: - _LOGGER.debug(f"Try {module_prefix}") - model_module = importlib.import_module(".models", module_prefix) - # If not exception, we MIGHT have found it, but cannot be a file. - # Keep continue to try to break it, file module have no __path__ - model_module.__path__ - _LOGGER.info(f"Found {module_prefix}") - result.append(module_prefix) - except (ModuleNotFoundError, AttributeError): - # No model, might dig deeper - prefix_module = importlib.import_module(module_prefix) - for _, sub_package, ispkg in pkgutil.iter_modules(prefix_module.__path__, module_prefix+"."): - if ispkg: - result += find_autorest_generated_folder(sub_package) - return result - - -def get_sub_module_part(package_name, module_name): - """Assuming package is azure-mgmt-compute and module name is azure.mgmt.compute.v2018-08-01 - will return v2018-08-01 - """ - sub_module_from_package = package_name.replace("-", ".") - if not module_name.startswith(sub_module_from_package): - _LOGGER.warning(f"Submodule {module_name} does not start with package name {package_name}") - return - return module_name[len(sub_module_from_package)+1:] - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser( - description='Code fingerprint building', - formatter_class=argparse.RawTextHelpFormatter, - ) - parser.add_argument('package_name', - help='Package name.') - parser.add_argument('--version', '-v', - dest='version', - help='The version of the package you want. By default, latest and current branch.') - parser.add_argument('--no-venv', - dest='no_venv', action="store_true", - help="If version is provided, this will assume the current accessible package is already this version. You should probably not use it.") - parser.add_argument('--pypi', - dest='pypi', action="store_true", - help="If provided, build report for all versions on pypi of this package.") - parser.add_argument('--last-pypi', - dest='last_pypi', action="store_true", - help="If provided, build report for last version on pypi of this package.") - parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") - parser.add_argument("--output", - dest="output", - help="Override output path.") - args = parser.parse_args() - - logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) - - main(args.package_name, args.version, args.no_venv, args.pypi, args.last_pypi, args.output) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/conf.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/conf.py deleted file mode 100644 index 2b821ac62c5..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/conf.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging -from pathlib import Path -from typing import Dict, Any - -import pytoml as toml - -_LOGGER = logging.getLogger(__name__) - -CONF_NAME = "sdk_packaging.toml" -_SECTION = "packaging" - -# Default conf -_CONFIG = { - "package_name": "packagename", - "package_nspkg": "packagenspkg", - "package_pprint_name": "MyService Management", - "package_doc_id": "", - "is_stable": False, - "is_arm": True, - "need_msrestazure": True -} - -def read_conf(folder: Path) -> Dict[str, Any]: - conf_path = folder / CONF_NAME - if not conf_path.exists(): - return {} - - with open(conf_path, "rb") as fd: - return toml.load(fd)[_SECTION] - -def build_default_conf(folder: Path, package_name: str) -> None: - conf_path = folder / CONF_NAME - if conf_path.exists(): - _LOGGER.info("Skipping default conf since the file exists") - return - - _LOGGER.info("Build default conf for %s", package_name) - conf = {_SECTION: _CONFIG.copy()} - conf[_SECTION]["package_name"] = package_name - conf[_SECTION]["package_nspkg"] = package_name[:package_name.rindex('-')]+"-nspkg" - - with open(conf_path, "w") as fd: - toml.dump(conf, fd) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/drop_tools.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/drop_tools.py deleted file mode 100644 index b5c1ab9cc55..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/drop_tools.py +++ /dev/null @@ -1,141 +0,0 @@ -"""This file is specific to Azure SDK for Python and should be split somewhere else.""" -import logging -from pathlib import Path -import re -import subprocess -import tempfile - -from github import Github - -from azure_devtools.ci_tools.github_tools import ( - manage_git_folder, - DashboardCommentableObject -) - -_LOGGER = logging.getLogger(__name__) -_SDK_FOLDER_RE = re.compile(r"^(sdk/[\w-]+)/(azure[\w-]+)/", re.ASCII) - -_STORAGE_ACCOUNT = "http://azuresdkinfrajobstore1.blob.core.windows.net/azure/azure-sdk-for-python/pullrequests/{prnumber}/dist/{file}" - -def execute_simple_command(cmd_line, cwd=None, shell=False, env=None): - try: - process = subprocess.Popen(cmd_line, - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - universal_newlines=True, - cwd=cwd, - shell=shell, - env=env) - output_buffer = [] - for line in process.stdout: - output_buffer.append(line.rstrip()) - _LOGGER.info(output_buffer[-1]) - process.wait() - output = "\n".join(output_buffer) - if process.returncode: - raise subprocess.CalledProcessError( - process.returncode, - cmd_line, - output - ) - return output - except Exception as err: - _LOGGER.error(err) - raise - else: - _LOGGER.info("Return code: %s", process.returncode) - -def get_package_names(sdk_pr): - files = [one_file.filename for one_file in sdk_pr.get_files() if one_file.status not in ['removed']] - # "get_files" of Github only download the first 300 files. Might not be enough. - package_names = {('.', f.split('/')[0]) for f in files if f.startswith("azure")} - # Handle the SDK folder as well - matches = {_SDK_FOLDER_RE.search(f) for f in files} - package_names.update({match.groups() for match in matches if match is not None}) - return package_names - -def build_package_from_pr_number(gh_token, sdk_id, pr_number, output_folder, *, with_comment=False): - """Will clone the given PR branch and vuild the package with the given name.""" - - con = Github(gh_token) - repo = con.get_repo(sdk_id) - sdk_pr = repo.get_pull(pr_number) - package_names = get_package_names(sdk_pr) - - absolute_output_folder = Path(output_folder).resolve() - - with tempfile.TemporaryDirectory() as temp_dir, \ - manage_git_folder(gh_token, Path(temp_dir) / Path("sdk"), sdk_id, pr_number=pr_number) as sdk_repo_root: - - for _, package_name in package_names: - _LOGGER.debug("Build {}".format(package_name)) - execute_simple_command( - ["python", "./build_package.py", "--dest", str(absolute_output_folder), package_name], - cwd=sdk_repo_root - ) - _LOGGER.debug("Build finished: {}".format(package_name)) - - if with_comment: - files = [f.name for f in absolute_output_folder.iterdir()] - comment_message = None - dashboard = DashboardCommentableObject(sdk_pr, "(message created by the CI based on PR content)") - try: - installation_message = build_installation_message(sdk_pr) - download_message = build_download_message(sdk_pr, files) - comment_message = installation_message + "\n\n" + download_message - dashboard.create_comment(comment_message) - except Exception: - _LOGGER.critical("Unable to do PR comment:\n%s", comment_message) - -def build_download_message(sdk_pr, files): - if not files: - return "" - message = "# Direct download\n\nYour files can be directly downloaded here:\n\n" - for filename in files: - message += "- [{}]({})\n".format( - filename, - _STORAGE_ACCOUNT.format(prnumber=sdk_pr.number, file=filename) - ) - return message - -def build_installation_message(sdk_pr): - package_names = get_package_names(sdk_pr) - - result = ["# Installation instruction"] - for _, package in package_names: - result.append("## Package {}".format(package)) - result.append(pr_message_for_package(sdk_pr, package)) - return "\n".join(result) - - -def pr_message_for_package(sdk_pr, package_name): - git_path = '"git+{}@{}#egg={}&subdirectory={}"'.format( - sdk_pr.head.repo.html_url, - sdk_pr.head.ref, - package_name, - package_name - ) - - pip_install = 'pip install {}' - pip_wheel = 'pip wheel --no-deps {}' - - pr_body = "You can install the package `{}` of this PR using the following command:\n\t`{}`".format( - package_name, - pip_install.format(git_path) - ) - - pr_body += "\n\n" - - pr_body += "You can build a wheel to distribute for test using the following command:\n\t`{}`".format( - pip_wheel.format(git_path) - ) - - pr_body += "\n\n" - pr_body += "If you have a local clone of this repository, you can also do:\n\n" - pr_body += "- `git checkout {}`\n".format(sdk_pr.head.ref) - pr_body += "- `pip install -e ./{}`\n".format(package_name) - pr_body += "\n\n" - pr_body += "Or build a wheel file to distribute for testing:\n\n" - pr_body += "- `git checkout {}`\n".format(sdk_pr.head.ref) - pr_body += "- `pip wheel --no-deps ./{}`\n".format(package_name) - return pr_body diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_package.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_package.py deleted file mode 100644 index 80a656112bf..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_package.py +++ /dev/null @@ -1,50 +0,0 @@ -import argparse -import logging -import os - -from packaging_tools.drop_tools import build_package_from_pr_number - -_LOGGER = logging.getLogger(__name__) - -def generate_main(): - """Main method""" - - parser = argparse.ArgumentParser( - description='Build package.', - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('--pr-number', '-p', - dest='pr_number', type=int, required=True, - help='PR number') - parser.add_argument('--repo', '-r', - dest='repo_id', default="Azure/azure-sdk-for-python", - help='Repo id. [default: %(default)s]') - parser.add_argument("--with-comment", - dest="with_comment", action="store_true", - help="Do a comment to the original PR with info.") - parser.add_argument("-v", "--verbose", - dest="verbose", action="store_true", - help="Verbosity in INFO mode") - parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") - - parser.add_argument('--output-folder', '-o', - dest='output_folder', default='.', - help='Output folder for package. [default: %(default)s]') - - args = parser.parse_args() - main_logger = logging.getLogger() - if args.verbose or args.debug: - logging.basicConfig() - main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) - - build_package_from_pr_number( - os.environ.get("GH_TOKEN", None), - args.repo_id, - args.pr_number, - args.output_folder, - with_comment=args.with_comment - ) - -if __name__ == "__main__": - generate_main() diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_sdk.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_sdk.py deleted file mode 100644 index 6a2cd44d3f6..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/generate_sdk.py +++ /dev/null @@ -1,133 +0,0 @@ -import argparse -import logging -from pathlib import Path -import tempfile - -from .swaggertosdk.SwaggerToSdkNewCLI import ( - build_project, -) -from .swaggertosdk.SwaggerToSdkCore import ( - CONFIG_FILE, - read_config, - solve_relative_path, - extract_conf_from_readmes, - get_input_paths, - get_repo_tag_meta, -) - -_LOGGER = logging.getLogger(__name__) - - -def generate(config_path, sdk_folder, project_pattern, readme, restapi_git_folder, autorest_bin=None, force_generation=False): - - sdk_folder = Path(sdk_folder).expanduser() - config = read_config(sdk_folder, config_path) - - global_conf = config["meta"] - repotag = get_repo_tag_meta(global_conf) - global_conf["autorest_options"] = solve_relative_path(global_conf.get("autorest_options", {}), sdk_folder) - global_conf["envs"] = solve_relative_path(global_conf.get("envs", {}), sdk_folder) - global_conf["advanced_options"] = solve_relative_path(global_conf.get("advanced_options", {}), sdk_folder) - if restapi_git_folder: - restapi_git_folder = Path(restapi_git_folder).expanduser() - - # Look for configuration in Readme - if readme: - swagger_files_in_pr = [readme] - else: - if not restapi_git_folder: - raise ValueError("RestAPI folder must be set if you don't provide a readme.") - swagger_files_in_pr = list(restapi_git_folder.glob('specification/**/readme.md')) - _LOGGER.info(f"Readme files: {swagger_files_in_pr}") - extract_conf_from_readmes(swagger_files_in_pr, restapi_git_folder, repotag, config, force_generation=force_generation) - - with tempfile.TemporaryDirectory() as temp_dir: - for project, local_conf in config.get("projects", {}).items(): - if readme: - if str(readme) not in project: - _LOGGER.info("Skip project %s (readme was %s)", project, readme) - continue - else: - if project_pattern and not any(p in project for p in project_pattern): - _LOGGER.info("Skip project %s", project) - continue - local_conf["autorest_options"] = solve_relative_path(local_conf.get("autorest_options", {}), sdk_folder) - - if readme and readme.startswith("http"): - # Simplify here, do not support anything else than Readme.md - absolute_markdown_path = readme - _LOGGER.info(f"HTTP Markdown input: {absolute_markdown_path}") - else: - markdown_relative_path, optional_relative_paths = get_input_paths(global_conf, local_conf) - - _LOGGER.info(f"Markdown input: {markdown_relative_path}") - _LOGGER.info(f"Optional inputs: {optional_relative_paths}") - - absolute_markdown_path = None - if markdown_relative_path: - absolute_markdown_path = Path(restapi_git_folder or "", markdown_relative_path).resolve() - if optional_relative_paths: - local_conf.setdefault('autorest_options', {})['input-file'] = [ - Path(restapi_git_folder or "", input_path).resolve() - for input_path - in optional_relative_paths - ] - - build_project( - temp_dir, - project, - absolute_markdown_path, - sdk_folder, - global_conf, - local_conf, - autorest_bin - ) - - -def generate_main(): - """Main method""" - - parser = argparse.ArgumentParser( - description='Build SDK using Autorest, offline version.', - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('--rest-folder', '-r', - dest='restapi_git_folder', default=None, - help='Rest API git folder. [default: %(default)s]') - parser.add_argument('--project', '-p', - dest='project', action='append', - help='Select a specific project. Do all by default. You can use a substring for several projects.') - parser.add_argument('--readme', '-m', - dest='readme', - help='Select a specific readme. Must be a path') - parser.add_argument('--config', '-c', - dest='config_path', default=CONFIG_FILE, - help='The JSON configuration format path [default: %(default)s]') - parser.add_argument('--autorest', - dest='autorest_bin', - help='Force the Autorest to be executed. Must be a executable command.') - parser.add_argument("-v", "--verbose", - dest="verbose", action="store_true", - help="Verbosity in INFO mode") - parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") - - parser.add_argument('--sdk-folder', '-s', - dest='sdk_folder', default='.', - help='A Python SDK folder. [default: %(default)s]') - - args = parser.parse_args() - main_logger = logging.getLogger() - if args.verbose or args.debug: - logging.basicConfig() - main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) - - generate(args.config_path, - args.sdk_folder, - args.project, - args.readme, - args.restapi_git_folder, - args.autorest_bin) - -if __name__ == "__main__": - generate_main() diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkCore.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkCore.py deleted file mode 100644 index 47914bdd453..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkCore.py +++ /dev/null @@ -1,289 +0,0 @@ -"""SwaggerToSdk core tools. -""" -from enum import Enum, unique -import json -import logging -import os -import re -import tempfile -from pathlib import Path - -import requests - -from github import Github, UnknownObjectException - -from .autorest_tools import ( - autorest_latest_version_finder, - autorest_bootstrap_version_finder, - autorest_swagger_to_sdk_conf, -) -from azure_devtools.ci_tools.github_tools import ( - get_files, - GithubLink -) - -_LOGGER = logging.getLogger(__name__) - -CONFIG_FILE = 'swagger_to_sdk_config.json' - -DEFAULT_COMMIT_MESSAGE = 'Generated from {hexsha}' - - -def build_file_content(): - autorest_version = autorest_latest_version_finder() - autorest_bootstrap_version = autorest_bootstrap_version_finder() - return { - 'autorest': autorest_version, - 'autorest_bootstrap': autorest_bootstrap_version, - } - - -def get_repo_tag_meta(meta_conf): - repotag = meta_conf.get("repotag") - if repotag: - return repotag - # Guess for now, "repotag" should be added everywhere - if "go" in meta_conf["autorest_options"]: - return "azure-sdk-for-go" - if "ruby" in meta_conf["autorest_options"]: - return "azure-sdk-for-ruby" - if "java" in meta_conf["autorest_options"]: - return "azure-sdk-for-java" - if "nodejs" in meta_conf["autorest_options"]: - return "azure-sdk-for-node" - if "typescript" in meta_conf["autorest_options"]: - return "azure-sdk-for-js" - raise ValueError("No repotag found or infered") - - -@unique -class Language(str, Enum): - GOLANG = "go" - RUBY = "ruby" - JAVA = "java" - NODEJS = "nodejs" - CSHARP = "csharp" - PYTHON = "python" - TYPESCRIPT = "typescript" - - -def get_language_from_conf(meta_conf): - """Detect the language based on the default Autorest options. - Assuming all language use --mylanguage in the config file. - If I don't find anything, well just say I don't know... - - This is based on autorest language flags. - :rtype: Language - """ - autorest_options_lang = set(meta_conf["autorest_options"].keys()) - languages = set() - for value in Language: - if value in autorest_options_lang: - languages.add(value) - - if not languages: - _LOGGER.warning("No detected language from this conf") - return None # I don't what this conf is about? - - language = languages.pop() - if languages: - _LOGGER.warning("This SwaggerToSdk conf seems to generate too much language in one call, assume we don't know") - return None - - return language - - -def get_context_tag_from_git_object(git_object): - files_list = [file.filename for file in get_files(git_object)] - return get_context_tag_from_file_list(files_list) - - -def get_context_tag_from_file_list(files_list): - context_tags = set() - for filename in files_list: - filepath = Path(filename) - filename = filepath.as_posix() - if "/examples/" in filename: - # Do not compute context for example that are not used in SDK - continue - # Match if RP name - match = re.match(r"specification/(.*)/Microsoft.\w*/(stable|preview)/", filename, re.I) - if match: - context_tags.add(match.groups()[0]) - continue - # Match if stable/preview but not RP like ARM (i.e. Cognitive Services) - match = re.match(r"specification/(.*)/(stable|preview)/", filename, re.I) - if match: - context_tags.add(match.groups()[0]) - continue - # Match Readme - # Do it last step, because if some weird Readme for ServiceFabric... - match = re.match(r"specification/(.*)/readme.\w*.?md", filename, re.I) - if match: - context_tags.add(match.groups()[0]) - continue - # No context-tags - return context_tags - - -def this_conf_will_generate_for_this_pr(git_object, config): - """Try to guess if this PR has a chance to generate something for this conf. - - Right now, just match the language in the conf with the presence - of ONLY "readme.language.md" files. - """ - lang = get_language_from_conf(config) - filenames = [file.filename.lower() for file in get_files(git_object)] - readme_lang = [name for name in filenames if re.match(r"(.*)readme.\w+.md", name)] - - if len(readme_lang) != len(filenames): - return True # This means there is files that are not language specific readme - - return bool([name for name in readme_lang if name.endswith("readme.{}.md".format(lang))]) - - -def get_readme_files_from_git_object(git_object, base_dir=Path('.')): - files_list = [file.filename for file in get_files(git_object)] - return get_readme_files_from_file_list(files_list, base_dir) - - -def get_readme_files_from_file_list(files_list, base_dir=Path('.')): - """Get readme files from this PR. - Algo is to look for context, and then search for Readme inside this context. - """ - readme_files = set() - context_tags = get_context_tag_from_file_list(files_list) - for context_tag in context_tags: - expected_folder = Path(base_dir) / Path("specification/{}".format(context_tag)) - if not expected_folder.is_dir(): - _LOGGER.warning("From context {} I didn't find folder {}".format( - context_tag, - expected_folder - )) - continue - for expected_readme in [l for l in expected_folder.iterdir() if l.is_file()]: - # Need to do a case-insensitive test. - match = re.match(r"readme.\w*.?md", expected_readme.name, re.I) - if match: - readme_files.add(expected_readme.relative_to(Path(base_dir))) - return readme_files - - -def read_config(sdk_git_folder, config_file): - """Read the configuration file and return JSON""" - config_path = os.path.join(sdk_git_folder, config_file) - with open(config_path, 'r') as config_fd: - return json.loads(config_fd.read()) - -def read_config_from_github(sdk_id, branch="master", gh_token=None): - raw_link = str(get_configuration_github_path(sdk_id, branch)) - _LOGGER.debug("Will try to download: %s", raw_link) - _LOGGER.debug("Token is defined: %s", gh_token is not None) - headers = {"Authorization": "token {}".format(gh_token)} if gh_token else {} - response = requests.get(raw_link, headers=headers) - if response.status_code != 200: - raise ValueError("Unable to download conf file for SDK {} branch {}: status code {}".format( - sdk_id, - branch, - response.status_code - )) - return json.loads(response.text) - -def extract_conf_from_readmes(swagger_files_in_pr, restapi_git_folder, sdk_git_id, config, force_generation=False): - readme_files_in_pr = {readme for readme in swagger_files_in_pr if getattr(readme, "name", readme).lower().endswith("readme.md")} - for readme_file in readme_files_in_pr: - build_swaggertosdk_conf_from_json_readme(readme_file, sdk_git_id, config, base_folder=restapi_git_folder, force_generation=force_generation) - -def get_readme_path(readme_file, base_folder='.'): - """Get a readable Readme path. - - If start with http, assume online, ignore base_folder and convert to raw link if necessary. - If base_folder is not None, assume relative to base_folder. - """ - if not isinstance(readme_file, Path) and readme_file.startswith("http"): - return GithubLink.from_string(readme_file).as_raw_link() - else: - if base_folder is None: - base_folder='.' - return str(Path(base_folder) / Path(readme_file)) - -def build_swaggertosdk_conf_from_json_readme(readme_file, sdk_git_id, config, base_folder='.', force_generation=False): - """Get the JSON conf of this README, and create SwaggerToSdk conf. - - Readme path can be any readme syntax accepted by autorest. - readme_file will be project key as-is. - - :param str readme_file: A path that Autorest accepts. Raw GH link or absolute path. - :param str sdk_dit_id: Repo ID. IF org/login is provided, will be stripped. - :param dict config: Config where to update the "projects" key. - :param bool force_generation: If no Swagger to SDK section is found, force once with the Readme as input - """ - readme_full_path = get_readme_path(readme_file, base_folder) - with tempfile.TemporaryDirectory() as temp_dir: - readme_as_conf = autorest_swagger_to_sdk_conf( - readme_full_path, - temp_dir - ) - generated_config = { - "markdown": readme_full_path, - } - sdk_git_short_id = sdk_git_id.split("/")[-1].lower() - _LOGGER.info("Looking for tag {} in readme {}".format(sdk_git_short_id, readme_file)) - for swagger_to_sdk_conf in readme_as_conf: - repo = swagger_to_sdk_conf.get("repo", "") - repo = repo.split("/")[-1].lower() # Be sure there is no org/login part - if repo == sdk_git_short_id: - _LOGGER.info("This Readme contains a swagger-to-sdk section for repo {}".format(repo)) - generated_config.update({ - "autorest_options": swagger_to_sdk_conf.get("autorest_options", {}), - "after_scripts": swagger_to_sdk_conf.get("after_scripts", []), - }) - config.setdefault("projects", {})[str(readme_file)] = generated_config - return generated_config - else: - _LOGGER.info("Skip mismatch {} from {}".format(repo, sdk_git_short_id)) - if not force_generation: - _LOGGER.info("Didn't find tag {} in readme {}. Did you forget to update the SwaggerToSdk section?".format(sdk_git_short_id, readme_file)) - else: - _LOGGER.info("Didn't find tag {} in readme {}. Forcing it.".format(sdk_git_short_id, readme_file)) - config.setdefault("projects", {})[str(readme_file)] = generated_config - -def get_input_paths(global_conf, local_conf): - """Returns a 2-tuple: - - Markdown Path or None - - Input-file Paths or empty list - """ - del global_conf # Unused - - relative_markdown_path = None # Markdown is optional - input_files = [] # Input file could be empty - if "markdown" in local_conf: - relative_markdown_path = Path(local_conf['markdown']) - input_files = local_conf.get('autorest_options', {}).get('input-file', []) - if input_files and not isinstance(input_files, list): - input_files = [input_files] - input_files = [Path(input_file) for input_file in input_files] - if not relative_markdown_path and not input_files: - raise ValueError("No input file found") - return (relative_markdown_path, input_files) - - -def solve_relative_path(autorest_options, sdk_root): - """Solve relative path in conf. - - If a key is prefixed by "sdkrel:", it's solved against SDK root. - """ - SDKRELKEY = "sdkrel:" - solved_autorest_options = {} - for key, value in autorest_options.items(): - if key.startswith(SDKRELKEY): - _LOGGER.debug("Found a sdkrel pair: %s/%s", key, value) - subkey = key[len(SDKRELKEY):] - solved_value = Path(sdk_root, value).resolve() - solved_autorest_options[subkey] = str(solved_value) - else: - solved_autorest_options[key] = value - return solved_autorest_options - -def get_configuration_github_path(sdk_id, branch="master"): - return GithubLink(sdk_id, "raw", branch, CONFIG_FILE) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkNewCLI.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkNewCLI.py deleted file mode 100644 index a2c21334293..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/SwaggerToSdkNewCLI.py +++ /dev/null @@ -1,311 +0,0 @@ -"""Swagger to SDK""" -import os -import shutil -import logging -import json -from pathlib import Path -import tempfile - -from git import Repo, GitCommandError - -from .SwaggerToSdkCore import ( - read_config_from_github, - DEFAULT_COMMIT_MESSAGE, - get_input_paths, - extract_conf_from_readmes, - get_readme_files_from_git_object, - build_file_content, - solve_relative_path, - this_conf_will_generate_for_this_pr -) -from .autorest_tools import ( - execute_simple_command, - generate_code, - merge_options, -) -from azure_devtools.ci_tools.git_tools import ( - checkout_and_create_branch, - do_commit, -) -from azure_devtools.ci_tools.github_tools import ( - configure_user, - manage_git_folder, -) - - -_LOGGER = logging.getLogger(__name__) - - -def move_wrapper_files_or_dirs(src_root, dst_root, global_conf, local_conf): - """Save wrapper files somewhere for replace them after generation. - """ - src_relative_path = local_conf.get('output_dir', '') - src_abs_path = Path(src_root, src_relative_path) - dst_abs_path = Path(dst_root, src_relative_path) - - wrapper_files_or_dirs = merge_options(global_conf, local_conf, "wrapper_filesOrDirs") or [] - - for wrapper_file_or_dir in wrapper_files_or_dirs: - for file_path in src_abs_path.glob(wrapper_file_or_dir): - relative_file_path = file_path.relative_to(src_abs_path) - file_path_dest = Path(dst_abs_path, relative_file_path) - if file_path.is_file(): - file_path_dest.parent.mkdir(parents=True, exist_ok=True) - _LOGGER.info("Moving %s to %s", str(file_path), str(file_path_dest)) - # This does not work in Windows if generatd and dest are not in the same drive - # file_path.replace(file_path_dest) - shutil.move(file_path, file_path_dest) - - -def delete_extra_files(sdk_root, global_conf, local_conf): - src_relative_path = local_conf.get('output_dir', '') - src_abs_path = Path(sdk_root, src_relative_path) - - delete_files_or_dirs = merge_options(global_conf, local_conf, "delete_filesOrDirs") or [] - - for delete_file_or_dir in delete_files_or_dirs: - for file_path in src_abs_path.glob(delete_file_or_dir): - if file_path.is_file(): - file_path.unlink() - else: - shutil.rmtree(str(file_path)) - - -def move_autorest_files(client_generated_path, sdk_root, global_conf, local_conf): - """Update data from generated to final folder. - - This is one only if output_dir is set, otherwise it's considered generated in place - and does not required moving - """ - dest = local_conf.get('output_dir', None) - if not dest: - return - destination_folder = get_local_path_dir(sdk_root, dest) - - generated_relative_base_directory = local_conf.get('generated_relative_base_directory') or \ - global_conf.get('generated_relative_base_directory') - - if generated_relative_base_directory: - client_possible_path = [elt for elt in client_generated_path.glob(generated_relative_base_directory) if elt.is_dir()] - try: - client_generated_path = client_possible_path.pop() - except IndexError: - err_msg = "Incorrect generated_relative_base_directory folder: {}\n".format(generated_relative_base_directory) - err_msg += "Base folders were: : {}\n".format([f.relative_to(client_generated_path) for f in client_generated_path.iterdir()]) - _LOGGER.critical(err_msg) - raise ValueError(err_msg) - if client_possible_path: - err_msg = "generated_relative_base_directory parameter is ambiguous: {} {}".format( - client_generated_path, - client_possible_path - ) - _LOGGER.critical(err_msg) - raise ValueError(err_msg) - - shutil.rmtree(str(destination_folder)) - # This does not work in Windows if generatd and dest are not in the same drive - # client_generated_path.replace(destination_folder) - shutil.move(client_generated_path, destination_folder) - - -def write_build_file(sdk_root, local_conf): - build_dir = local_conf.get('build_dir') - if build_dir: - build_folder = get_local_path_dir(sdk_root, build_dir) - build_file = Path(build_folder, "build.json") - with open(build_file, 'w') as build_fd: - json.dump(build_file_content(), build_fd, indent=2) - - -def execute_after_script(sdk_root, global_conf, local_conf): - after_scripts = merge_options(global_conf, local_conf, "after_scripts", keep_list_order=True) or [] - local_envs = dict(os.environ) - local_envs.update(global_conf.get("envs", {})) - - for script in after_scripts: - _LOGGER.info("Execute after script: %s", script) - execute_simple_command(script, cwd=sdk_root, shell=True, env=local_envs) - - -def get_local_path_dir(root, relative_path): - build_folder = Path(root, relative_path) - if not build_folder.is_dir(): - err_msg = "Folder does not exist or is not accessible: {}".format( - build_folder) - _LOGGER.critical(err_msg) - raise ValueError(err_msg) - return build_folder - - -def build_project(temp_dir, project, absolute_markdown_path, sdk_folder, global_conf, local_conf, autorest_bin=None): - absolute_generated_path = Path(temp_dir, project) - absolute_save_path = Path(temp_dir, "save") - move_wrapper_files_or_dirs(sdk_folder, absolute_save_path, global_conf, local_conf) - generate_code(absolute_markdown_path, - global_conf, - local_conf, - absolute_generated_path if "output_dir" in local_conf else None, - autorest_bin) - move_autorest_files(absolute_generated_path, sdk_folder, global_conf, local_conf) - move_wrapper_files_or_dirs(absolute_save_path, sdk_folder, global_conf, local_conf) - delete_extra_files(sdk_folder, global_conf, local_conf) - write_build_file(sdk_folder, local_conf) - execute_after_script(sdk_folder, global_conf, local_conf) - - -def build_libraries(config, skip_callback, restapi_git_folder, sdk_repo, temp_dir, autorest_bin=None): - """Main method of the the file""" - - global_conf = config["meta"] - global_conf["autorest_options"] = solve_relative_path(global_conf.get("autorest_options", {}), sdk_repo.working_tree_dir) - global_conf["envs"] = solve_relative_path(global_conf.get("envs", {}), sdk_repo.working_tree_dir) - global_conf["advanced_options"] = solve_relative_path(global_conf.get("advanced_options", {}), sdk_repo.working_tree_dir) - - for project, local_conf in config.get("projects", {}).items(): - if skip_callback(project, local_conf): - _LOGGER.info("Skip project %s", project) - continue - local_conf["autorest_options"] = solve_relative_path(local_conf.get("autorest_options", {}), sdk_repo.working_tree_dir) - - markdown_relative_path, optional_relative_paths = get_input_paths(global_conf, local_conf) - _LOGGER.info(f"Markdown input: {markdown_relative_path}") - _LOGGER.info(f"Optional inputs: {optional_relative_paths}") - - absolute_markdown_path = None - if markdown_relative_path: - absolute_markdown_path = Path(restapi_git_folder, markdown_relative_path).resolve() - if optional_relative_paths: - local_conf.setdefault('autorest_options', {})['input-file'] = [ - Path(restapi_git_folder, input_path).resolve() - for input_path - in optional_relative_paths - ] - - sdk_folder = sdk_repo.working_tree_dir - build_project( - temp_dir, - project, - absolute_markdown_path, - sdk_folder, - global_conf, - local_conf, - autorest_bin - ) - -def generate_sdk_from_git_object(git_object, branch_name, restapi_git_id, sdk_git_id, base_branch_names, *, fallback_base_branch_name="master", sdk_tag=None): - """Generate SDK from a commit or a PR object. - - git_object is the initial commit/PR from the RestAPI repo. If git_object is a PR, prefer to checkout Github PR "merge_commit_sha" - restapi_git_id explains where to clone the repo. - sdk_git_id explains where to push the commit. - sdk_tag explains what is the tag used in the Readme for the swagger-to-sdk section. If not provided, use sdk_git_id. - branch_name is the expected branch name in the SDK repo. - - If this branch exists, use it. - - If not, use the base branch to create that branch (base branch is where I intend to do my PR) - - If base_branch_names is not provided, use fallback_base_branch_name as base - - If this base branch is provided and does not exists, create this base branch first using fallback_base_branch_name (this one is required to exist) - - WARNING: - This method might push to "branch_name" and "base_branch_name". No push will be made to "fallback_base_branch_name" - """ - gh_token = os.environ["GH_TOKEN"] - message_template = DEFAULT_COMMIT_MESSAGE - autorest_bin = None - if sdk_tag is None: - sdk_tag = sdk_git_id - - try: # Checkout the sha if commit obj - branched_rest_api_id = restapi_git_id+'@'+git_object.sha - pr_number = None - except (AttributeError, TypeError): # This is a PR, don't clone the fork but "base" repo and PR magic commit - if git_object.merge_commit_sha: - branched_rest_api_id = git_object.base.repo.full_name+'@'+git_object.merge_commit_sha - else: - branched_rest_api_id = git_object.base.repo.full_name - pr_number = git_object.number - - # Always clone SDK from fallback branch that is required to exist - branched_sdk_git_id = sdk_git_id+'@'+fallback_base_branch_name - - # I don't know if the destination branch exists, try until it works - config = None - branch_list = base_branch_names + [branch_name] + [fallback_base_branch_name] - for branch in branch_list: - try: - config = read_config_from_github(sdk_git_id, branch, gh_token) - except Exception: - pass - else: - break - if config is None: - raise ValueError("Unable to locate configuration in {}".format(branch_list)) - global_conf = config["meta"] - - # If PR is only about a language that this conf can't handle, skip fast - if not this_conf_will_generate_for_this_pr(git_object, global_conf): - _LOGGER.info("Skipping this job based on conf not impacted by Git object") - return - - with tempfile.TemporaryDirectory() as temp_dir: - - clone_dir = Path(temp_dir) / Path(global_conf.get("advanced_options", {}).get("clone_dir", "sdk")) - _LOGGER.info("Clone dir will be: %s", clone_dir) - - with manage_git_folder(gh_token, Path(temp_dir) / Path("rest"), branched_rest_api_id, pr_number=pr_number) as restapi_git_folder, \ - manage_git_folder(gh_token, clone_dir, branched_sdk_git_id) as sdk_folder: - - readme_files_infered = get_readme_files_from_git_object(git_object, restapi_git_folder) - _LOGGER.info("Readmes files infered from PR: %s ", readme_files_infered) - if not readme_files_infered: - _LOGGER.info("No Readme in PR, quit") - return - - # SDK part - sdk_repo = Repo(str(sdk_folder)) - - for base_branch in base_branch_names: - _LOGGER.info('Checkout and create %s', base_branch) - checkout_and_create_branch(sdk_repo, base_branch) - - _LOGGER.info('Try to checkout destination branch %s', branch_name) - try: - sdk_repo.git.checkout(branch_name) - _LOGGER.info('The branch exists.') - except GitCommandError: - _LOGGER.info('Destination branch does not exists') - # Will be created by do_commit - - configure_user(gh_token, sdk_repo) - - # Look for configuration in Readme - _LOGGER.info('Extract conf from Readmes for target: %s', sdk_git_id) - extract_conf_from_readmes(readme_files_infered, restapi_git_folder, sdk_tag, config) - _LOGGER.info('End of extraction') - - def skip_callback(project, local_conf): - # We know "project" is based on Path in "readme_files_infered" - if Path(project) in readme_files_infered: - return False - # Might be a regular project - markdown_relative_path, optional_relative_paths = get_input_paths(global_conf, local_conf) - if not ( - markdown_relative_path in readme_files_infered or - any(input_file in readme_files_infered for input_file in optional_relative_paths)): - _LOGGER.info(f"In project {project} no files involved in this commit") - return True - return False - - build_libraries(config, skip_callback, restapi_git_folder, - sdk_repo, temp_dir, autorest_bin) - - try: - commit_for_sha = git_object.commit # Commit - except AttributeError: - commit_for_sha = list(git_object.get_commits())[-1].commit # PR - message = message_template + "\n\n" + commit_for_sha.message - commit_sha = do_commit(sdk_repo, message, branch_name, commit_for_sha.sha) - if commit_sha: - for base_branch in base_branch_names: - sdk_repo.git.push('origin', base_branch, set_upstream=True) - sdk_repo.git.push('origin', branch_name, set_upstream=True) - return "https://github.com/{}/commit/{}".format(sdk_git_id, commit_sha) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/autorest_tools.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/autorest_tools.py deleted file mode 100644 index c51325dde2e..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/swaggertosdk/autorest_tools.py +++ /dev/null @@ -1,150 +0,0 @@ -import json -import logging -import os.path -from pathlib import Path -import shutil -import subprocess - - -_LOGGER = logging.getLogger(__name__) - - -def autorest_latest_version_finder(): - autorest_bin = shutil.which("autorest") - cmd_line = "{} --version --json".format(autorest_bin) - return json.loads(subprocess.check_output(cmd_line.split()).decode().strip()) - - -def autorest_swagger_to_sdk_conf(readme, output_folder): - _LOGGER.info("Looking for swagger-to-sdk section in {}".format(readme)) - autorest_bin = shutil.which("autorest") - # --input-file=foo is to workaround a bug where the command is not executed at all if no input-file is found (even if we don't care about input-file here) - cmd_line = "{} {} --perform-load=false --swagger-to-sdk --output-artifact=configuration.json --input-file=foo --output-folder={}".format( - autorest_bin, - str(readme), - str(output_folder) - ) - execute_simple_command(cmd_line.split()) - conf_path = Path(output_folder, "configuration.json") - with conf_path.open() as fd: - conf_as_json = json.load(fd) - swagger_to_sdk_conf = [c for c in conf_as_json.get("swagger-to-sdk", []) if c] - return swagger_to_sdk_conf - - -def autorest_bootstrap_version_finder(): - try: - npm_bin = shutil.which('npm') - cmd_line = ("{} --json ls autorest -g".format(npm_bin)).split() - return json.loads(subprocess.check_output(cmd_line).decode().strip()) - except Exception: - return {} - - -def merge_options(global_conf, local_conf, key, *, keep_list_order=False): - """Merge the conf using override: local conf is prioritary over global. - - If keep_list_order is True, list are merged global+local. Might have duplicate. - If false, duplication are removed. - """ - global_keyed_conf = global_conf.get(key) # Could be None - local_keyed_conf = local_conf.get(key) # Could be None - - if global_keyed_conf is None or local_keyed_conf is None: - return global_keyed_conf or local_keyed_conf - - if isinstance(global_keyed_conf, list): - if keep_list_order: - options = list(global_keyed_conf) - options += local_keyed_conf - return options - options = set(global_keyed_conf) - else: - options = dict(global_keyed_conf) - - options.update(local_keyed_conf) - return options - - -def build_autorest_options(global_conf, local_conf): - """Build the string of the Autorest options""" - merged_options = merge_options(global_conf, local_conf, "autorest_options") or {} - def value(x): - escaped = x if " " not in x else "'"+x+"'" - return "={}".format(escaped) if escaped else "" - listify = lambda x: x if isinstance(x, list) else [x] - - sorted_keys = sorted(list(merged_options.keys())) # To be honest, just to help for tests... - return [ - "--{}{}".format(key.lower(), value(str(option))) - for key in sorted_keys - for option in listify(merged_options[key]) - ] - -def generate_code(input_file, global_conf, local_conf, output_dir=None, autorest_bin=None): - """Call the Autorest process with the given parameters. - - Input file can be a Path instance, a str (will be cast to Path), or a str starting with - http (will be passed to Autorest as is). - """ - if not autorest_bin: - autorest_bin = shutil.which("autorest") - if not autorest_bin: - raise ValueError("No autorest found in PATH and no autorest path option used") - - params = [str(input_file)] if input_file else [] - if output_dir: # For legacy. Define "output-folder" as "autorest_options" now - params.append("--output-folder={}".format(str(output_dir)+os.path.sep)) - params += build_autorest_options(global_conf, local_conf) - - input_files = local_conf.get("autorest_options", {}).get("input-file", []) - - if not input_file and not input_files: - raise ValueError("I don't have input files!") - - path_input_files = [pit for pit in input_files if isinstance(pit, Path)] - if input_file and isinstance(input_file, Path): - input_path = input_file.parent - elif path_input_files: - input_path = path_input_files[0].parent - else: - input_path = Path(".") - - cmd_line = autorest_bin.split() - cmd_line += params - _LOGGER.info("Autorest cmd line:\n%s", " ".join(cmd_line)) - - execute_simple_command(cmd_line, cwd=str(input_path)) - # Checks that Autorest did something if output_dir is under control - # Note that this can fail if "--output-folder" was overidden by the Readme. - if output_dir and (not output_dir.is_dir() or next(output_dir.iterdir(), None) is None): - raise ValueError("Autorest call ended with 0, but no files were generated") - - -def execute_simple_command(cmd_line, cwd=None, shell=False, env=None): - try: - process = subprocess.Popen(cmd_line, - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - universal_newlines=True, - cwd=cwd, - shell=shell, - env=env) - output_buffer = [] - for line in process.stdout: - output_buffer.append(line.rstrip()) - _LOGGER.info(output_buffer[-1]) - process.wait() - output = "\n".join(output_buffer) - if process.returncode: - raise subprocess.CalledProcessError( - process.returncode, - cmd_line, - output - ) - return output - except Exception as err: - _LOGGER.error(err) - raise - else: - _LOGGER.info("Return code: %s", process.returncode) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/MANIFEST.in b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/MANIFEST.in deleted file mode 100644 index 986ca26c2f5..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -recursive-include tests *.py *.yaml -include *.md -{%- for init_name in init_names %} -include {{ init_name }} -{%- endfor %} - diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/README.md b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/README.md deleted file mode 100644 index 293df1c0668..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Microsoft Azure SDK for Python - -This is the Microsoft Azure {{package_pprint_name}} Client Library. -This package has been tested with Python 2.7, 3.5, 3.6, 3.7 and 3.8. -For a more complete view of Azure libraries, see the [Github repo](https://github.com/Azure/azure-sdk-for-python/) - - -# Usage - -For code examples, see [{{package_pprint_name}}](https://docs.microsoft.com/python/api/overview/azure/{{package_doc_id}}) -on docs.microsoft.com. - - -# Provide Feedback - -If you encounter any bugs or have suggestions, please file an issue in the -[Issues](https://github.com/Azure/azure-sdk-for-python/issues) -section of the project. - - -![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-python%2F{{package_name}}%2FREADME.png) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/__init__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/__init__.py deleted file mode 100644 index 0260537a02b..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.cfg b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.cfg deleted file mode 100644 index 3c6e79cf31d..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.py deleted file mode 100644 index acd7d3c51b6..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/templates/setup.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python - -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -#-------------------------------------------------------------------------- - -import re -import os.path -from io import open -from setuptools import find_packages, setup - -# Change the PACKAGE_NAME only to change folder and different name -PACKAGE_NAME = "{{package_name}}" -PACKAGE_PPRINT_NAME = "{{package_pprint_name}}" - -# a-b-c => a/b/c -package_folder_path = PACKAGE_NAME.replace('-', '/') -# a-b-c => a.b.c -namespace_name = PACKAGE_NAME.replace('-', '.') - -# azure v0.x is not compatible with this package -# azure v0.x used to have a __version__ attribute (newer versions don't) -try: - import azure - try: - ver = azure.__version__ - raise Exception( - 'This package is incompatible with azure=={}. '.format(ver) + - 'Uninstall it with "pip uninstall azure".' - ) - except AttributeError: - pass -except ImportError: - pass - -# Version extraction inspired from 'requests' -with open(os.path.join(package_folder_path, 'version.py') - if os.path.exists(os.path.join(package_folder_path, 'version.py')) - else os.path.join(package_folder_path, '_version.py'), 'r') as fd: - version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', - fd.read(), re.MULTILINE).group(1) - -if not version: - raise RuntimeError('Cannot find version information') - -with open('README.md', encoding='utf-8') as f: - readme = f.read() -with open('CHANGELOG.md', encoding='utf-8') as f: - changelog = f.read() - -setup( - name=PACKAGE_NAME, - version=version, - description='Microsoft Azure {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), - long_description=readme + '\n\n' + changelog, - long_description_content_type='text/markdown', - license='MIT License', - author='Microsoft Corporation', - author_email='azpysdkhelp@microsoft.com', - url='https://github.com/Azure/azure-sdk-for-python', - classifiers=[ - '{{classifier}}', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'License :: OSI Approved :: MIT License', - ], - zip_safe=False, - packages=find_packages(exclude=[ - 'tests', - # Exclude packages that will be covered by PEP420 or nspkg - {%- for nspkg_name in nspkg_names %} - '{{ nspkg_name }}', - {%- endfor %} - ]), - install_requires=[ - 'msrest>=0.5.0', - {%- if need_msrestazure %} - 'msrestazure>=0.4.32,<2.0.0', - {%- endif %} - 'azure-common~=1.1', - {%- if need_azurecore %} - 'azure-mgmt-core>=1.0.0,<2.0.0', - {%- endif %} - ], - extras_require={ - ":python_version<'3.0'": ['{{package_nspkg}}'], - } -) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/update_pr.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/update_pr.py deleted file mode 100644 index fd471ae5a56..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/update_pr.py +++ /dev/null @@ -1,100 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -import re -import tempfile - -from azure_devtools.ci_tools.git_tools import ( - do_commit, -) -from azure_devtools.ci_tools.github_tools import ( - manage_git_folder, - configure_user -) - -from git import Repo -from github import Github - -from . import build_packaging_by_package_name - - -_LOGGER = logging.getLogger(__name__) -_SDK_FOLDER_RE = re.compile(r"^(sdk/[\w-]+)/(azure[\w-]+)/", re.ASCII) - - -def update_pr(gh_token, repo_id, pr_number): - from github import Github - con = Github(gh_token) - repo = con.get_repo(repo_id) - sdk_pr = repo.get_pull(pr_number) - files = [one_file.filename for one_file in sdk_pr.get_files() if one_file.status not in ['removed']] - # "get_files" of Github only download the first 300 files. Might not be enough. - package_names = {('.', f.split('/')[0]) for f in files if f.startswith("azure")} - # Handle the SDK folder as well - matches = {_SDK_FOLDER_RE.search(f) for f in files} - package_names.update({match.groups() for match in matches if match is not None}) - - # Get PR branch to push - head_repo = sdk_pr.head.repo.full_name - head_branch = sdk_pr.head.ref - branched_index = "{}@{}".format(head_repo, head_branch) - _LOGGER.info("Checkout %s", branched_index) - - with tempfile.TemporaryDirectory() as temp_dir, \ - manage_git_folder(gh_token, Path(temp_dir) / Path("sdk"), branched_index) as sdk_repo_root: - - sdk_repo = Repo(str(sdk_repo_root)) - configure_user(gh_token, sdk_repo) - - for base_folder, package_name in package_names: - if package_name.endswith("nspkg"): - _LOGGER.info("Skip nspkg packages for update PR") - continue - - # Rebuild packaging - _LOGGER.info("Try update package %s from folder %s", package_name, base_folder) - build_packaging_by_package_name(package_name, sdk_repo_root / Path(base_folder), build_conf=True) - # Commit that - do_commit( - sdk_repo, - "Packaging update of {}".format(package_name), - head_branch, - None # Unused - ) - # Push all commits at once - sdk_repo.git.push('origin', head_branch, set_upstream=True) - -def update_pr_main(): - """Main method""" - - parser = argparse.ArgumentParser( - description='Build package.', - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('--pr-number', '-p', - dest='pr_number', type=int, required=True, - help='PR number') - parser.add_argument('--repo', '-r', - dest='repo_id', default="Azure/azure-sdk-for-python", - help='Repo id. [default: %(default)s]') - parser.add_argument("-v", "--verbose", - dest="verbose", action="store_true", - help="Verbosity in INFO mode") - parser.add_argument("--debug", - dest="debug", action="store_true", - help="Verbosity in DEBUG mode") - - args = parser.parse_args() - main_logger = logging.getLogger() - if args.verbose or args.debug: - logging.basicConfig() - main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) - - update_pr( - os.environ.get("GH_TOKEN", None), - args.repo_id, - int(args.pr_number), - ) - -if __name__ == "__main__": - update_pr_main() diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/venvtools.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/venvtools.py deleted file mode 100644 index 714b7aa2932..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/packaging_tools/venvtools.py +++ /dev/null @@ -1,46 +0,0 @@ -from contextlib import contextmanager -import tempfile -import subprocess -import venv - -class ExtendedEnvBuilder(venv.EnvBuilder): - """An extended env builder which saves the context, to have access - easily to bin path and such. - """ - - def __init__(self, *args, **kwargs): - self.context = None - super(ExtendedEnvBuilder, self).__init__(*args, **kwargs) - - def ensure_directories(self, env_dir): - self.context = super(ExtendedEnvBuilder, self).ensure_directories(env_dir) - return self.context - - -def create(env_dir, system_site_packages=False, clear=False, - symlinks=False, with_pip=False, prompt=None): - """Create a virtual environment in a directory.""" - builder = ExtendedEnvBuilder(system_site_packages=system_site_packages, - clear=clear, symlinks=symlinks, with_pip=with_pip, - prompt=prompt) - builder.create(env_dir) - return builder.context - -@contextmanager -def create_venv_with_package(packages): - """Create a venv with these packages in a temp dir and yielf the env. - - packages should be an iterable of pip version instructio (e.g. package~=1.2.3) - """ - with tempfile.TemporaryDirectory() as tempdir: - myenv = create(tempdir, with_pip=True) - pip_call = [ - myenv.env_exe, - "-m", - "pip", - "install", - ] - subprocess.check_call(pip_call + ['-U', 'pip']) - if packages: - subprocess.check_call(pip_call + packages) - yield myenv \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/__init__.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/__init__.py deleted file mode 100644 index 0c36c2076ba..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/pypi.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/pypi.py deleted file mode 100644 index b9c6ff772dd..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/pypi_tools/pypi.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Optional - -from packaging.version import parse as Version, InvalidVersion - -import requests - -def get_pypi_xmlrpc_client(): - """This is actually deprecated client. - """ - import xmlrpc.client - return xmlrpc.client.ServerProxy("https://pypi.python.org/pypi", use_datetime=True) - -class PyPIClient: - def __init__(self, host="https://pypi.org"): - self._host = host - self._session = requests.Session() - - def project(self, package_name): - response = self._session.get( - "{host}/pypi/{project_name}/json".format( - host=self._host, - project_name=package_name - ) - ) - response.raise_for_status() - return response.json() - - def project_release(self, package_name, version): - response = self._session.get( - "{host}/pypi/{project_name}/{version}/json".format( - host=self._host, - project_name=package_name, - version=version - ) - ) - response.raise_for_status() - return response.json() - - def get_ordered_versions(self, package_name): - project = self.project(package_name) - versions = [ - Version(package_version) - for package_version - in project["releases"].keys() - ] - versions.sort() - return versions - - def get_relevant_versions(self, package_name): - """Return a tuple: (latest release, latest stable) - If there are different, it means the latest is not a stable - """ - versions = self.get_ordered_versions(package_name) - pre_releases = [version for version in versions if not version.is_prerelease] - return ( - versions[-1], - pre_releases[-1] - ) \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/sdk_packaging.toml b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/sdk_packaging.toml deleted file mode 100644 index e7687fdae93..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/sdk_packaging.toml +++ /dev/null @@ -1,2 +0,0 @@ -[packaging] -auto_update = false \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/setup.py b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/setup.py deleted file mode 100644 index ba9b5fe5312..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-py-test/tools/azure-sdk-tools/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -import os -from setuptools import setup, find_packages - -# This is a "fake" package, meaning it's not supposed to be released but used -# locally with "pip install -e" - -DEPENDENCIES = [ - # Packaging - 'packaging', - 'wheel', - 'Jinja2', - 'pytoml', - 'json-delta>=2.0', - # Tests - 'pytest-cov', - 'pytest>=3.5.1', - # 'azure-devtools>=0.4.1' override by packaging needs - 'readme_renderer', - # 'azure-storage-file<2.0', - 'azure-storage-common<1.4.1', - 'pyopenssl', - 'azure-mgmt-resource', - 'azure-mgmt-storage', - 'azure-mgmt-keyvault' -] - -setup( - name = "azure-sdk-tools", - version = "0.0.0", - author='Microsoft Corporation', - author_email='azpysdkhelp@microsoft.com', - url='https://github.com/Azure/azure-sdk-for-python', - packages=find_packages(), - long_description="Specific tools for Azure SDK for Python testing", - install_requires=DEPENDENCIES, - entry_points = { - 'console_scripts': [ - 'generate_package=packaging_tools.generate_package:generate_main', - 'generate_sdk=packaging_tools.generate_sdk:generate_main', - ], - }, - extras_require={ - ":python_version>='3.5'": ['pytest-asyncio>=0.9.0'] - } -) diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-tf-test/swagger_to_sdk_config.json b/tools/spec-gen-sdk/integrationTest/fixtures/sdk-tf-test/swagger_to_sdk_config.json deleted file mode 100644 index b0d1d6da812..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/sdk-tf-test/swagger_to_sdk_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://openapistorageprod.blob.core.windows.net/sdkautomation/prod/schemas/swagger_to_sdk_config.schema.json", - "meta": { - "after_scripts_in_repo_with_service": ["bash ./scripts/trenton_run.sh"], - "autorest_options_for_otherSDK": { - "use": "@microsoft.azure/autorest.go@2.1.134", - "go": "", - "sdkrel:go-sdk-folder": "./vendor", - "use-onever": "", - "preview-chk": "", - "version": "V2" - }, - "autorest_options": { - "trenton": "", - "use": "https://trenton.blob.core.windows.net/trenton/autorest-trenton-0.2.2.tgz", - "sdkrel:output-folder": "./azurerm/internal/services", - "clear-output-folder": "true" - }, - "advanced_options": { - "create_sdk_pull_requests": true, - "sdk_generation_pull_request_base": "integration_branch" - }, - "repotag": "azure-sdk-for-trenton", - "envs": { - "sdkrel:GOPATH": "../../../.." - }, - "version": "0.1.0" - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json deleted file mode 100644 index 8a74c219bcd..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "2020-01-01", - "title": "TestServiceClient", - "description": "Test Service Client for SDK Automation integration test." - }, - "host": "management.azure.com", - "schemes": [ - "https" - ], - "produces": [ - "application/json" - ], - "consumes": [ - "application/json" - ], - "security": [ - { - "azure_auth": [ - "user_impersonation" - ] - } - ], - "securityDefinitions": { - "azure_auth": { - "type": "oauth2", - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "flow": "implicit", - "description": "Azure Active Directory OAuth2 Flow", - "scopes": { - "user_impersonation": "impersonate your user account" - } - } - }, - "paths": { - "/providers/Microsoft.TestService/test": { - "get": { - "operationId": "Test_Get", - "description": "Get test.", - "x-ms-examples": { - "MsiOperationsList": { - "$ref": "./examples/TestGet.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/ApiVersionParameter" - } - ], - "responses": { - "200": { - "description": "The operation was successful.", - "schema": { - "$ref": "#/definitions/TestGetResult" - } - }, - "default": { - "description": "Error response describing why the operation failed.", - "schema": { - "$ref": "#/definitions/CloudError" - } - } - } - }, - "put": { - "operationId": "Test_Put", - "description": "Put test.", - "x-ms-examples": { - "MsiOperationsList": { - "$ref": "./examples/TestPut.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/ApiVersionParameter" - } - ], - "responses": { - "200": { - "description": "The operation was successful.", - "schema": { - "$ref": "#/definitions/TestPutResult" - } - }, - "default": { - "description": "Error response describing why the operation failed.", - "schema": { - "$ref": "#/definitions/CloudError" - } - } - } - } - } - }, - "definitions": { - "CloudError": { - "type": "object", - "x-ms-external": true, - "properties": { - "error": { - "description": "A list of additional details about the error.", - "$ref": "#/definitions/CloudErrorBody" - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "CloudErrorBody": { - "type": "object", - "x-ms-external": true, - "properties": { - "code": { - "type": "string", - "description": "An identifier for the error." - }, - "message": { - "type": "string", - "description": "A message describing the error, intended to be suitable for display in a user interface." - }, - "target": { - "type": "string", - "description": "The target of the particular error. For example, the name of the property in error." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/CloudErrorBody" - }, - "description": "A list of additional details about the error." - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "TestGetResult": { - "type": "object", - "title": "Test Get.", - "description": "Mocked result.", - "properties": { - "value": { - "type": "string", - "title": "Test result.", - "description": "Test result." - } - } - }, - "TestPutResult": { - "type": "object", - "title": "Test Put.", - "description": "Mocked result.", - "properties": { - "value": { - "type": "string", - "title": "Test result.", - "description": "Test result." - } - } - } - }, - "parameters": { - "ApiVersionParameter": { - "name": "api-version", - "in": "query", - "description": "Version of API to invoke.", - "required": true, - "type": "string" - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json deleted file mode 100644 index 1ddcda62b21..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parameters": { - "api-version": "2020-01-01" - }, - "responses": { - "200": { - "value": "Test" - } - } -} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json deleted file mode 100644 index 4aceae99438..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parameters": { - "api-version": "2020-01-01" - }, - "responses": { - "200": { - "value": "Test" - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.azureresourceschema.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.azureresourceschema.md deleted file mode 100644 index 4bc5737d20a..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.azureresourceschema.md +++ /dev/null @@ -1,19 +0,0 @@ -## AzureResourceSchema - -These settings apply only when `--azureresourceschema` is specified on the command line. - -### AzureResourceSchema multi-api - -``` yaml $(azureresourceschema) && $(multiapi) -batch: - - tag: package-2020-01 -``` - -### Tag: package-2020-01 and azureresourceschema - -These settings apply only when `--tag=package-2020-01 --azureresourceschema` is specified on the command line. -Please also specify `--azureresourceschema-folder=`. - -``` yaml $(tag) == 'package-2020-01' && $(azureresourceschema) -output-folder: $(azureresourceschema-folder)/schemas -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.md deleted file mode 100644 index 39529a7d0de..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.md +++ /dev/null @@ -1,75 +0,0 @@ -# Test Service - -``` yaml -openapi-type: arm -tag: package-2020-01 -license-header: MICROSOFT_MIT_NO_VERSION -``` - -``` yaml $(tag) == 'package-2020-01' -input-file: -- Microsoft.TestService/stable/2020-01-01/TestService.json -``` - -``` yaml $(multiapi) && !$(track2) -batch: - - tag: package-2020-01 -``` - -``` yaml $(swagger-to-sdk) -swagger-to-sdk: - - repo: azure-sdk-for-go - - repo: azure-sdk-for-js - - repo: azure-sdk-for-java - - repo: azure-sdk-for-python - - repo: azure-sdk-for-net - - repo: azure-sdk-for-trenton - - repo: azure-cli-extensions - - repo: azure-sdk-for-python-track2 - - repo: azure-resource-manager-schemas -``` - -``` yaml $(go) -go: - license-header: MICROSOFT_APACHE_NO_VERSION - namespace: testservice - clear-output-folder: true -``` - -``` yaml $(tag) == 'package-2020-01' && $(go) -output-folder: $(go-sdk-folder)/services/$(namespace)/mgmt/2020-01-01/$(namespace) -``` - -``` yaml $(typescript) -typescript: - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - package-name: "@azure/test-service" - output-folder: "$(typescript-sdks-folder)/sdk/testservice/arm-testservice" - clear-output-folder: true - generate-metadata: true -``` - - -``` yaml $(cli) -cli: - cli-name: TestService - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - namespace: azure.mgmt.TestService - package-name: azure-mgmt-TestService - clear-output-folder: false -``` - -``` yaml $(trenton) -trenton: - cli_name: TestService - azure_arm: true - license_header: MICROSOFT_MIT_NO_VERSION - payload_flattening_threshold: 2 - namespace: azure.mgmt.TestService - package_name: azure-mgmt-TestService - clear_output_folder: false -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.python.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.python.md deleted file mode 100644 index e725cf34177..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch0-add-service/specification/testservice/resource-manager/readme.python.md +++ /dev/null @@ -1,38 +0,0 @@ -# Python - -```yaml !$(track2) -python: - payload-flattening-threshold: 2 - namespace: azure.mgmt.testservice - package-name: azure-mgmt-testservice - package-version: 1.0.0 - clear-output-folder: true - no-namespace-folders: true - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/ -``` - -```yaml $(track2) -payload-flattening-threshold: 2 -namespace: azure.mgmt.testservice -package-name: azure-mgmt-testservice -package-version: 1.0.0 -clear-output-folder: true -no-namespace-folders: true -``` - -```yaml $(multiapi) && $(track2) -batch: - - tag: package-2020-01 - - multiapiscript: true -``` - -```yaml $(multiapiscript) -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/ -clear-output-folder: false -perform-load: false -``` - -``` yaml $(tag) == 'package-2020-01' && $(track2) -namespace: azure.mgmt.testservice.v2020_01 -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01 -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/TestService.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/TestService.json deleted file mode 100644 index 1a702a0cdda..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/TestService.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "2020-02-01", - "title": "TestServiceClient", - "description": "Test Service Client for SDK Automation integration test." - }, - "host": "management.azure.com", - "schemes": [ - "https" - ], - "produces": [ - "application/json" - ], - "consumes": [ - "application/json" - ], - "security": [ - { - "azure_auth": [ - "user_impersonation" - ] - } - ], - "securityDefinitions": { - "azure_auth": { - "type": "oauth2", - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "flow": "implicit", - "description": "Azure Active Directory OAuth2 Flow", - "scopes": { - "user_impersonation": "impersonate your user account" - } - } - }, - "paths": { - "/providers/Microsoft.TestService/test": { - "get": { - "operationId": "Test_Get", - "description": "Get test.", - "x-ms-examples": { - "MsiOperationsList": { - "$ref": "./examples/TestGet.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/ApiVersionParameter" - }, - { - "name": "test-param", - "in": "query", - "description": "New param to test in 2020-02-01", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "The operation was successful.", - "schema": { - "$ref": "#/definitions/TestGetResult" - } - }, - "default": { - "description": "Error response describing why the operation failed.", - "schema": { - "$ref": "#/definitions/CloudError" - } - } - } - } - } - }, - "definitions": { - "CloudError": { - "x-ms-external": true, - "properties": { - "error": { - "description": "A list of additional details about the error.", - "$ref": "#/definitions/CloudErrorBody" - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "CloudErrorBody": { - "x-ms-external": true, - "properties": { - "code": { - "type": "string", - "description": "An identifier for the error." - }, - "message": { - "type": "string", - "description": "A message describing the error, intended to be suitable for display in a user interface." - }, - "target": { - "type": "string", - "description": "The target of the particular error. For example, the name of the property in error." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/CloudErrorBody" - }, - "description": "A list of additional details about the error." - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "TestGetResult": { - "title": "Test Get.", - "description": "Mocked result.", - "properties": { - "value": { - "type": "string", - "title": "Test result.", - "description": "Test result." - } - } - } - }, - "parameters": { - "ApiVersionParameter": { - "name": "api-version", - "in": "query", - "description": "Version of API to invoke.", - "required": true, - "type": "string" - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/examples/TestGet.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/examples/TestGet.json deleted file mode 100644 index 1ddcda62b21..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/examples/TestGet.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parameters": { - "api-version": "2020-01-01" - }, - "responses": { - "200": { - "value": "Test" - } - } -} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/scenarios/shouldbeexcluded.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/scenarios/shouldbeexcluded.json deleted file mode 100644 index 9e26dfeeb6e..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/scenarios/shouldbeexcluded.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.md deleted file mode 100644 index e6d40f329a2..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.md +++ /dev/null @@ -1,82 +0,0 @@ -# Test Service - -``` yaml -openapi-type: arm -tag: package-2020-02 -``` - -``` yaml $(tag) == 'package-2020-01' -input-file: -- Microsoft.TestService/stable/2020-01-01/TestService.json -``` - -``` yaml $(tag) == 'package-2020-02' -input-file: -- Microsoft.TestService/stable/2020-02-01/TestService.json -``` - -``` yaml $(multiapi) && !$(track2) -batch: - - tag: package-2020-01 - - tag: package-2020-02 -``` - -``` yaml $(swagger-to-sdk) -swagger-to-sdk: - - repo: azure-sdk-for-go - - repo: azure-sdk-for-js - - repo: azure-sdk-for-java - - repo: azure-sdk-for-python - - repo: azure-sdk-for-net - - repo: azure-sdk-for-trenton - - repo: azure-cli-extensions - - repo: azure-sdk-for-python-track2 -``` - -``` yaml $(go) -go: - license-header: MICROSOFT_APACHE_NO_VERSION - namespace: testservice - clear-output-folder: true -``` - -``` yaml $(tag) == 'package-2020-01' && $(go) -output-folder: $(go-sdk-folder)/services/$(namespace)/mgmt/2020-01-01/$(namespace) -``` - -``` yaml $(tag) == 'package-2020-02' && $(go) -output-folder: $(go-sdk-folder)/services/$(namespace)/mgmt/2020-02-01/$(namespace) -``` - -``` yaml $(typescript) -typescript: - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - package-name: "@azure/test-service" - output-folder: "$(typescript-sdks-folder)/sdk/testservice/arm-testservice" - clear-output-folder: true - generate-metadata: true -``` - -``` yaml $(cli) -cli: - cli-name: TestService - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - namespace: azure.mgmt.TestService - package-name: azure-mgmt-TestService - clear-output-folder: false -``` - -``` yaml $(trenton) -trenton: - cli_name: TestService - azure_arm: true - license_header: MICROSOFT_MIT_NO_VERSION - payload_flattening_threshold: 2 - namespace: azure.mgmt.TestService - package_name: azure-mgmt-TestService - clear_output_folder: false -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.python.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.python.md deleted file mode 100644 index 2ea3e6a9180..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch1-add-02-01/specification/testservice/resource-manager/readme.python.md +++ /dev/null @@ -1,51 +0,0 @@ -# Python - -```yaml !$(track2) -python: - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice - payload-flattening-threshold: 2 - namespace: azure.mgmt.testservice - package-name: azure-mgmt-testservice - package-version: 1.0.1 - clear-output-folder: true - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/ -``` - -```yaml $(track2) -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice -payload-flattening-threshold: 2 -namespace: azure.mgmt.testservice -package-name: azure-mgmt-testservice -package-version: 1.0.1 -clear-output-folder: true -no-namespace-folders: true -``` - -```yaml $(multiapi) && $(track2) -batch: - - tag: package-2020-01 - - tag: package-2020-02 - - multiapiscript: true -``` - -```yaml $(multiapiscript) -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/ -clear-output-folder: false -perform-load: false -``` - -``` yaml $(tag) == 'package-2020-01' -namespace: azure.mgmt.testservice.v2020_01 -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01 -python: - namespace: azure.mgmt.testservice.v2020_01 - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01 -``` - -``` yaml $(tag) == 'package-2020-02' -namespace: azure.mgmt.testservice.v2020_02 -output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_02 -python: - namespace: azure.mgmt.testservice.v2020_02 - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_02 -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch2-empty-update/specification/testservice/resource-manager/readme.no-lang.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch2-empty-update/specification/testservice/resource-manager/readme.no-lang.md deleted file mode 100644 index 970238e6232..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch2-empty-update/specification/testservice/resource-manager/readme.no-lang.md +++ /dev/null @@ -1,3 +0,0 @@ -# No update on Spec - -Only update on empty markdown file. diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/AnotherService.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/AnotherService.json deleted file mode 100644 index 571a080c590..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/AnotherService.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "2020-01-01", - "title": "AnotherServiceClient", - "description": "Another Test Service Client for SDK Automation integration test." - }, - "host": "management.azure.com", - "schemes": [ - "https" - ], - "produces": [ - "application/json" - ], - "consumes": [ - "application/json" - ], - "security": [ - { - "azure_auth": [ - "user_impersonation" - ] - } - ], - "securityDefinitions": { - "azure_auth": { - "type": "oauth2", - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "flow": "implicit", - "description": "Azure Active Directory OAuth2 Flow", - "scopes": { - "user_impersonation": "impersonate your user account" - } - } - }, - "paths": { - "/providers/Microsoft.TestService/test": { - "get": { - "operationId": "Test_Get", - "description": "Get test.", - "x-ms-examples": { - "MsiOperationsList": { - "$ref": "./examples/TestGet.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/ApiVersionParameter" - } - ], - "responses": { - "200": { - "description": "The operation was successful.", - "schema": { - "$ref": "#/definitions/TestGetResult" - } - }, - "default": { - "description": "Error response describing why the operation failed.", - "schema": { - "$ref": "#/definitions/CloudError" - } - } - } - } - } - }, - "definitions": { - "CloudError": { - "x-ms-external": true, - "properties": { - "error": { - "description": "A list of additional details about the error.", - "$ref": "#/definitions/CloudErrorBody" - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "CloudErrorBody": { - "x-ms-external": true, - "properties": { - "code": { - "type": "string", - "description": "An identifier for the error." - }, - "message": { - "type": "string", - "description": "A message describing the error, intended to be suitable for display in a user interface." - }, - "target": { - "type": "string", - "description": "The target of the particular error. For example, the name of the property in error." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/CloudErrorBody" - }, - "description": "A list of additional details about the error." - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "TestGetResult": { - "title": "Test Get.", - "description": "Mocked result.", - "properties": { - "value": { - "type": "string", - "title": "Test result.", - "description": "Test result." - } - } - } - }, - "parameters": { - "ApiVersionParameter": { - "name": "api-version", - "in": "query", - "description": "Version of API to invoke.", - "required": true, - "type": "string" - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/examples/TestGet.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/examples/TestGet.json deleted file mode 100644 index 1ddcda62b21..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/examples/TestGet.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parameters": { - "api-version": "2020-01-01" - }, - "responses": { - "200": { - "value": "Test" - } - } -} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/readme.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/readme.md deleted file mode 100644 index 29e56348b7a..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/anotherservice/resource-manager/readme.md +++ /dev/null @@ -1,73 +0,0 @@ -# Test Service - -``` yaml -openapi-type: arm -tag: package-2020-01 -``` - -``` yaml $(tag) == 'package-2020-01' -input-file: -- Microsoft.AnotherService/stable/2020-01-01/AnotherService.json -``` - -``` yaml $(multiapi) -batch: - - tag: package-2020-01 -``` - -``` yaml $(swagger-to-sdk) -swagger-to-sdk: - - repo: azure-sdk-for-go - - repo: azure-sdk-for-js - - repo: azure-sdk-for-java - - repo: azure-sdk-for-python - - repo: azure-sdk-for-net - - repo: azure-sdk-for-trenton - - repo: azure-cli-extensions -``` - -``` yaml $(go) -go: - license-header: MICROSOFT_APACHE_NO_VERSION - namespace: anotherservice - clear-output-folder: true -``` - -``` yaml $(tag) == 'package-2020-01' && $(go) -output-folder: $(go-sdk-folder)/services/$(namespace)/mgmt/2020-01-01/$(namespace) -``` - -``` yaml $(typescript) -typescript: - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - package-name: "@azure/another-service" - output-folder: "$(typescript-sdks-folder)/sdk/anotherservice/arm-anotherservice" - clear-output-folder: true - generate-metadata: true -``` - -``` yaml $(python) -python: - basic-setup-py: true - output-folder: $(python-sdks-folder)/anotherservice/azure-mgmt-anotherservice - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - namespace: azure.mgmt.anotherservice - package-name: azure-mgmt-anotherservice - package-version: 1.0.0 - clear-output-folder: true -``` - -```yaml $(python) && $(multiapi) -batch: - - tag: package-2020-01 -``` - -``` yaml $(tag) == 'package-2020-01' && $(python) -python: - namespace: azure.mgmt.anotherservice.v2020_01 - output-folder: $(python-sdks-folder)/anotherservice/azure-mgmt-anotherservice/azure/mgmt/anotherservice/v2020_01 -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json deleted file mode 100644 index 251385102a4..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "2020-01-01", - "title": "TestServiceClient", - "description": "Test Service Client for SDK Automation integration test." - }, - "host": "management.azure.com", - "schemes": [ - "https" - ], - "produces": [ - "application/json" - ], - "consumes": [ - "application/json" - ], - "security": [ - { - "azure_auth": [ - "user_impersonation" - ] - } - ], - "securityDefinitions": { - "azure_auth": { - "type": "oauth2", - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "flow": "implicit", - "description": "Azure Active Directory OAuth2 Flow", - "scopes": { - "user_impersonation": "impersonate your user account" - } - } - }, - "paths": { - "/providers/Microsoft.TestService/test": { - "get": { - "operationId": "Test_Get", - "description": "Get test.", - "x-ms-examples": { - "MsiOperationsList": { - "$ref": "./examples/TestGet.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/ApiVersionParameter" - } - ], - "responses": { - "200": { - "description": "The operation was successful.", - "schema": { - "$ref": "#/definitions/TestGetResult" - } - }, - "default": { - "description": "Error response describing why the operation failed.", - "schema": { - "$ref": "#/definitions/CloudError" - } - } - } - } - } - }, - "definitions": { - "CloudError": { - "x-ms-external": true, - "properties": { - "error": { - "description": "A list of additional details about the error.", - "$ref": "#/definitions/CloudErrorBody" - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "CloudErrorBody": { - "x-ms-external": true, - "properties": { - "code": { - "type": "string", - "description": "An identifier for the error." - }, - "message": { - "type": "string", - "description": "A message describing the error, intended to be suitable for display in a user interface." - }, - "target": { - "type": "string", - "description": "The target of the particular error. For example, the name of the property in error." - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/CloudErrorBody" - }, - "description": "A list of additional details about the error." - } - }, - "description": "An error response from the ManagedServiceIdentity service." - }, - "TestGetResult": { - "title": "Test Get.", - "description": "Mocked result.", - "properties": { - "value": { - "type": "string", - "title": "Test result.", - "description": "Test result." - } - } - } - }, - "parameters": { - "ApiVersionParameter": { - "name": "api-version", - "in": "query", - "description": "Version of API to invoke.", - "required": true, - "type": "string" - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json deleted file mode 100644 index 1ddcda62b21..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parameters": { - "api-version": "2020-01-01" - }, - "responses": { - "200": { - "value": "Test" - } - } -} \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/readme.md b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/readme.md deleted file mode 100644 index 556112b24cd..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test-patch3-two-readme/specification/testservice/resource-manager/readme.md +++ /dev/null @@ -1,73 +0,0 @@ -# Test Service - -``` yaml -openapi-type: arm -tag: package-2020-01 -``` - -``` yaml $(tag) == 'package-2020-01' -input-file: -- Microsoft.TestService/stable/2020-01-01/TestService.json -``` - -``` yaml $(multiapi) -batch: - - tag: package-2020-01 -``` - -``` yaml $(swagger-to-sdk) -swagger-to-sdk: - - repo: azure-sdk-for-go - - repo: azure-sdk-for-js - - repo: azure-sdk-for-java - - repo: azure-sdk-for-python - - repo: azure-sdk-for-net - - repo: azure-sdk-for-trenton - - repo: azure-cli-extensions -``` - -``` yaml $(go) -go: - license-header: MICROSOFT_APACHE_NO_VERSION - namespace: testservice - clear-output-folder: true -``` - -``` yaml $(tag) == 'package-2020-01' && $(go) -output-folder: $(go-sdk-folder)/services/$(namespace)/mgmt/2020-01-01/$(namespace) -``` - -``` yaml $(typescript) -typescript: - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - package-name: "@azure/test-service" - output-folder: "$(typescript-sdks-folder)/sdk/testservice/arm-testservice" - clear-output-folder: true - generate-metadata: true -``` - -``` yaml $(python) -python: - basic-setup-py: true - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice - azure-arm: true - license-header: MICROSOFT_MIT_NO_VERSION - payload-flattening-threshold: 2 - namespace: azure.mgmt.testservice - package-name: azure-mgmt-testservice - package-version: 1.0.0 - clear-output-folder: true -``` - -```yaml $(python) && $(multiapi) -batch: - - tag: package-2020-01 -``` - -``` yaml $(tag) == 'package-2020-01' && $(python) -python: - namespace: azure.mgmt.testservice.v2020_01 - output-folder: $(python-sdks-folder)/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01 -``` diff --git a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test/specificationRepositoryConfiguration.json b/tools/spec-gen-sdk/integrationTest/fixtures/spec-test/specificationRepositoryConfiguration.json deleted file mode 100644 index 9fd165971f9..00000000000 --- a/tools/spec-gen-sdk/integrationTest/fixtures/spec-test/specificationRepositoryConfiguration.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "sdkRepositoryMappings": { - "azure-sdk-for-go": { - "mainRepository": "azure-sdk-for-go-test" - }, - "azure-sdk-for-js": { - "mainRepository": "azure-sdk-for-js-test" - }, - "azure-sdk-for-python": { - "mainRepository": "azure-sdk-for-python-test", - "mainBranch": "release/v3" - }, - "azure-sdk-for-python-track2": { - "mainRepository": "azure-sdk-for-python-track2-test", - "configFilePath": "swagger_to_sdk_custom_config.json" - }, - "azure-sdk-for-trenton": { - "mainRepository": "azure-sdk-for-trenton-test" - }, - "azure-resource-manager-schemas": { - "mainRepository": "azure-resource-manager-schemas-test" - } - }, - "overrides": { - "azure-rest-api-specs-pr": { - "sdkRepositoryMappings": { - "azure-sdk-for-js": { - "mainRepository": "azure-sdk-for-js-test-pr" - } - } - } - } -} diff --git a/tools/spec-gen-sdk/integrationTest/jest.setupAfterEnv.js b/tools/spec-gen-sdk/integrationTest/jest.setupAfterEnv.js deleted file mode 100644 index d590c057dad..00000000000 --- a/tools/spec-gen-sdk/integrationTest/jest.setupAfterEnv.js +++ /dev/null @@ -1,5 +0,0 @@ -jest.setTimeout(3600_000); - -// Avoid color output in snapshot -process.env.FORCE_COLOR = '0' // See chalk which is used by autorest -process.env.NO_COLOR = '1' \ No newline at end of file diff --git a/tools/spec-gen-sdk/integrationTest/test/L0-armschm-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L0-armschm-open.spec.ts deleted file mode 100644 index 8f09a469940..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L0-armschm-open.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareARMSchmSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it.skip('should create Azure resource manager schemas pr on spec pr opened', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchARMSchmLog - } = await prepareARMSchmSDKTest('opened-pr'); - - const specPRNumber = await createPRWithPatch( - specRepoName, fixtures.specTest.patch0_AddService, 'patch0' - ); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchARMSchmLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L0-js-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L0-js-open.spec.ts deleted file mode 100644 index f83711857b7..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L0-js-open.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it('should create JS sdk pr on spec pr opened', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog - } = await prepareJsSDKTest('opened-pr'); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L0-py-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L0-py-open.spec.ts deleted file mode 100644 index 0480629b073..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L0-py-open.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ - -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { preparePySDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it.skip('should create Python sdk pr on spec pr opened', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchPyLog - } = await preparePySDKTest('opened-pr'); - - const specPRNumber = await createPRWithPatch( - specRepoName, fixtures.specTest.patch0_AddService, 'patch0' - ); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchPyLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L0-py-t2-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L0-py-t2-open.spec.ts deleted file mode 100644 index 18b0308992b..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L0-py-t2-open.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ - -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { preparePyT2SDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it.skip('should create Python Track2 sdk pr on spec pr opened', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchPyT2Log - } = await preparePyT2SDKTest('opened-pr'); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchPyT2Log(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L0-tf-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L0-tf-open.spec.ts deleted file mode 100644 index 5daafce0dd7..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L0-tf-open.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ - -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareTfSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it.skip('should create terraform/trenton sdk pr on spec pr opened', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchTfLog - } = await prepareTfSDKTest('open-pr'); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchTfLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L1-js-merge.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L1-js-merge.spec.ts deleted file mode 100644 index 7c4b9bb2782..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L1-js-merge.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - getTestGithubClient, repoOwner, createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In merged PR, SDK Automation ', () => { - - it('should push integration branch and close gen pr if spec pr merged', async () => { - const github = await getTestGithubClient(); - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog - } = await prepareJsSDKTest('merged-pr'); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - await github.pulls.merge({ owner: repoOwner, repo: specRepoName, pull_number: specPRNumber }); - - // Launch SDK Automation for merged routine - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-empty.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-empty.spec.ts deleted file mode 100644 index 535d4578612..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-empty.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createPRWithPatch, getPRListInfo, getLoggerTextForAssert, getTestGithubClient, repoOwner } from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - it('should run in open pr (contains no spec update) after one merged pr', async () => { - const { specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog } = await prepareJsSDKTest( - 'multi-merge-empty' - ); - const github = await getTestGithubClient(); - - // Simulate spec PR merged and integration branch updated - let specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - await github.pulls.merge({ owner: repoOwner, repo: specRepoName, pull_number: specPRNumber }); - await createPRWithPatch(sdkRepoName, fixtures.sdkJs.patch0_AddServiceGen, 'sdkAutomation/@azure_test-service'); - - // New open PR - specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch2_Empty, 'patch2', { - fetchBase: true - }); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert(logger, specRepoName, specPRNumber, sdkRepoName))).toMatchSnapshot(); - }); -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-open.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-open.spec.ts deleted file mode 100644 index 94bdda282f5..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L1-js-multi-merge-open.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createPRWithPatch, getPRListInfo, getLoggerTextForAssert, getTestGithubClient, repoOwner } from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - it('should run in open pr after one merged pr', async () => { - const { specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog } = await prepareJsSDKTest( - 'multi-merge-open' - ); - const github = await getTestGithubClient(); - - // Simulate spec PR merged and integration branch updated - let specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - await github.pulls.merge({ owner: repoOwner, repo: specRepoName, pull_number: specPRNumber }); - await createPRWithPatch(sdkRepoName, fixtures.sdkJs.patch0_AddServiceGen, 'sdkAutomation/@azure_test-service'); - - // New open PR - specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch1_Add_02_01, 'patch1', { - fetchBase: true - }); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert(logger, specRepoName, specPRNumber, sdkRepoName))).toMatchSnapshot(); - }); -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L1-js-open-second-run.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L1-js-open-second-run.spec.ts deleted file mode 100644 index aab16d03e05..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L1-js-open-second-run.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { createPRWithPatch, getPRListInfo, getLoggerTextForAssert, getTestGithubClient, repoOwner } from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - it('should run on second time for open PR', async () => { - const { specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog } = await prepareJsSDKTest( - 'open-second-run' - ); - const github = await getTestGithubClient(); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch0_AddService, 'patch0'); - - // Simulate first SDK Automation run - const intBranchName = 'sdkAutomation/@azure_test-service'; - const genBranchName = `${intBranchName}@${specPRNumber}`; - await createPRWithPatch(sdkRepoName, fixtures.sdkJs.name, intBranchName); - await createPRWithPatch(sdkRepoName, fixtures.sdkJs.patch0_AddServiceGen, genBranchName); - await github.pulls.create({ - owner: repoOwner, - repo: sdkRepoName, - base: intBranchName, - head: genBranchName, - title: '[AutoPR] Simulate first SDK Automation' - }); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert(logger, specRepoName, specPRNumber, sdkRepoName))).toMatchSnapshot(); - }); -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/L1-js-open-two-readme.spec.ts b/tools/spec-gen-sdk/integrationTest/test/L1-js-open-two-readme.spec.ts deleted file mode 100644 index dd7a4eb9783..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/L1-js-open-two-readme.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - createPRWithPatch, getPRListInfo, getLoggerTextForAssert -} from '../utils'; -import { fixtures } from '../fixtures'; -import { prepareJsSDKTest } from './lang-common'; - -describe('In open PR, SDK Automation', () => { - - it('should handle two readme update', async () => { - const { - specRepoName, sdkRepoName, logger, launchSDKAutomation, patchJsLog - } = await prepareJsSDKTest('open-two-readme'); - - const specPRNumber = await createPRWithPatch(specRepoName, fixtures.specTest.patch3_TwoReadme, 'patch3'); - - // Launch SDK Automation - await launchSDKAutomation(specPRNumber); - - // Assert - expect(await getPRListInfo(sdkRepoName)).toMatchSnapshot(); - expect(patchJsLog(await getLoggerTextForAssert( - logger, specRepoName, specPRNumber, sdkRepoName - ))).toMatchSnapshot(); - }); - -}); diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-armschm-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-armschm-open.spec.ts.snap deleted file mode 100644 index 7e7b427217b..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-armschm-open.spec.ts.snap +++ /dev/null @@ -1,111 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should create Azure resource manager schemas pr on spec pr opened 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAuto/1/testservice", - "number": 1, - "state": "open", - "title": "[AutoPR testservice] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should create Azure resource manager schemas pr on spec pr opened 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -command npx n 12 -info Config: {} -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --use=@autorest/azureresourceschema@3.0.79 --azureresourceschema --multiapi --title=none --pass-thru:subset-reducer --azureresourceschema-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 1 changed files after SDK generate: -info A schemas/2020-01-01/Microsoft.TestService.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^common$/ -info 1 packages found after generation: -info schemas -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package testservice -info Package log to https://sdkautotest/dl//1/azure-resource-manager-schemas/testservice/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/testservice] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/testservice -git Checkout sdk folders from sdkGen and commit: schemas -git Push sdkAuto/1/testservice to / -info changelogScript is not configured -info Skip artifact search -info Upload 0 artifact: -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/testservice to master -github Create new PR -github PR created at https://github.com///pull/1 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-js-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-js-open.spec.ts.snap deleted file mode 100644 index 2534fdb39b6..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-js-open.spec.ts.snap +++ /dev/null @@ -1,137 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should create JS sdk pr on spec pr opened 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAuto/1/@azure_test-service", - "number": 1, - "state": "open", - "title": "[AutoPR @azure/test-service] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should create JS sdk pr on spec pr opened 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//1/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/1/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/1 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-open.spec.ts.snap deleted file mode 100644 index e20a7d05242..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-open.spec.ts.snap +++ /dev/null @@ -1,190 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should create Python sdk pr on spec pr opened 1`] = ` -Array [ - Object { - "base": "release/v3", - "head": "sdkAuto/1/azure-mgmt-testservice", - "number": 1, - "state": "open", - "title": "[AutoPR azure-mgmt-testservice] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should create Python sdk pr on spec pr opened 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: release/v3 -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: release/v3 -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/release/v3 -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info Legacy python init -command npx n 12 -info Config: {} -command python3 -m venv venv -info Config: {} -command pip install --upgrade setuptools wheel pip -info Config: {\\"logPrefix\\":\\"pip install\\"} -command pip install pathlib jinja2 msrestazure -info Config: {\\"logPrefix\\":\\"pip install\\"} -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --use=@microsoft.azure/autorest.python@4.0.73 --python --multiapi --keep-version-file --no-async --python-sdks-folder=//sdk ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 9 changed files after SDK generate: -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/_configuration.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/_test_service_client.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/models/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/models/_models.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/models/_models_py3.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/operations/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/operations/_test_operations.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/version.py -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^setup.py$|^azure$/ -info 1 packages found after generation: -info sdk/testservice/azure-mgmt-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package azure-mgmt-testservice -info Package log to https://sdkautotest/dl//1/azure-sdk-for-python/azure-mgmt-testservice/logs.txt -info baseBranch [release/v3] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/azure-mgmt-testservice] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/azure-mgmt-testservice -git Checkout sdk folders from sdkGen and commit: sdk/testservice/azure-mgmt-testservice -git Push sdkAuto/1/azure-mgmt-testservice to / -section Call legacy build for azure-sdk-for-python -command pip install -e ./tools/azure-sdk-tools/ -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildConfInit\\"} -command python -m packaging_tools --build-conf azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildConf\\"} -cmderr [buildConf] INFO:packaging_tools:Building template azure-mgmt-testservice -cmderr [buildConf] INFO:packaging_tools.conf:Build default conf for azure-mgmt-testservice -cmderr [buildConf] INFO:packaging_tools:Template done azure-mgmt-testservice -command python ./build_package.py --dest sdk/testservice/azure-mgmt-testservice sdk/testservice/azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildPackage\\"} -cmderr [buildPackage] warning: no files found matching '*.py' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.yaml' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.py' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.yaml' under directory 'tests' -command python ./scripts/dev_setup.py -p azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogSetup\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -command python -m packaging_tools.code_report azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogReport\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -command python -m packaging_tools.code_report azure-mgmt-testservice --last-pypi -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogReportLatest\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -warn Not exact 2 reports found: -warn Not generating changelog. -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.(whl|zip)$/ -info 2 artifact found: -info sdk/testservice/azure-mgmt-testservice/sdk/testservice/azure-mgmt-testservice/azure-mgmt-testservice-1.0.0.zip -info sdk/testservice/azure-mgmt-testservice/sdk/testservice/azure-mgmt-testservice/azure_mgmt_testservice-1.0.0-py2.py3-none-any.whl -info Upload 2 artifact: -info azure-mgmt-testservice-1.0.0.zip -info azure_mgmt_testservice-1.0.0-py2.py3-none-any.whl -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/azure-mgmt-testservice to release/v3 -github Create new PR -github PR created at https://github.com///pull/1 -section Report status -info Main status [warning] hasBreakingChange [false] -github Remove label on pull request: CI-BreakingChange-Python -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-t2-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-t2-open.spec.ts.snap deleted file mode 100644 index a8e55445779..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-py-t2-open.spec.ts.snap +++ /dev/null @@ -1,215 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should create Python Track2 sdk pr on spec pr opened 1`] = ` -Array [ - Object { - "base": "master", - "head": "enable-track2", - "number": 1, - "state": "closed", - "title": "enable-track2", - }, - Object { - "base": "master", - "head": "sdkAuto/1/track2_azure-mgmt-testservice", - "number": 2, - "state": "open", - "title": "[AutoPR track2_azure-mgmt-testservice] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should create Python Track2 sdk pr on spec pr opened 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_custom_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/enable-track2 -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info Legacy python init -command npx n 12 -info Config: {} -command python3 -m venv venv -info Config: {} -command pip install --upgrade setuptools wheel pip -info Config: {\\"logPrefix\\":\\"pip install\\"} -command pip install pathlib jinja2 msrestazure -info Config: {\\"logPrefix\\":\\"pip install\\"} -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --use=@autorest/python@5.3.0 --python --python-mode=update --multiapi --track2 --python-sdks-folder=//sdk ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -cmdout [Autorest] WARNING (PreCheck/CheckDuplicateSchemas): Checking for duplicate schemas, this could take a (long) while. Run with --verbose for more detail. -section Commit generate result -git Add * in SDK repo -info 25 changed files after SDK generate: -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/_configuration.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/_test_service_client.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/_version.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/aio/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/aio/_configuration.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/aio/_test_service_client.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/models.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/py.typed -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/_configuration.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/_metadata.json -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/_test_service_client.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/_version.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/aio/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/aio/_configuration.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/aio/_test_service_client.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/aio/operations/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/aio/operations/_test_operations.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/models/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/models/_models.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/models/_models_py3.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/operations/__init__.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/operations/_test_operations.py -info A sdk/testservice/azure-mgmt-testservice/azure/mgmt/testservice/v2020_01/py.typed -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^setup.py$|^azure$/ -info 1 packages found after generation: -info sdk/testservice/azure-mgmt-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package track2_azure-mgmt-testservice -info Package log to https://sdkautotest/dl//1/azure-sdk-for-python-track2/track2_azure-mgmt-testservice/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/track2_azure-mgmt-testservice] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/track2_azure-mgmt-testservice -git Checkout sdk folders from sdkGen and commit: sdk/testservice/azure-mgmt-testservice -git Push sdkAuto/1/track2_azure-mgmt-testservice to / -section Call legacy build for azure-sdk-for-python -command pip install -e ./tools/azure-sdk-tools/ -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildConfInit\\"} -command python -m packaging_tools --build-conf azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildConf\\"} -cmderr [buildConf] INFO:packaging_tools:Building template azure-mgmt-testservice -cmderr [buildConf] INFO:packaging_tools.conf:Build default conf for azure-mgmt-testservice -cmderr [buildConf] INFO:packaging_tools:Template done azure-mgmt-testservice -command python ./build_package.py --dest sdk/testservice/azure-mgmt-testservice sdk/testservice/azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"buildPackage\\"} -cmderr [buildPackage] warning: no files found matching '*.py' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.yaml' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.py' under directory 'tests' -cmderr [buildPackage] warning: no files found matching '*.yaml' under directory 'tests' -command python ./scripts/dev_setup.py -p azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogSetup\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -command python -m packaging_tools.code_report azure-mgmt-testservice -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogReport\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -command python -m packaging_tools.code_report azure-mgmt-testservice --last-pypi -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"warning\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"changelogReportLatest\\"} -warn Script return with result [warning] code [1] signal [null] cwd []: python -warn Not exact 2 reports found: -warn Not generating changelog. -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.(whl|zip)$/ -info 2 artifact found: -info sdk/testservice/azure-mgmt-testservice/sdk/testservice/azure-mgmt-testservice/azure-mgmt-testservice-0.1.0.zip -info sdk/testservice/azure-mgmt-testservice/sdk/testservice/azure-mgmt-testservice/azure_mgmt_testservice-0.1.0-py2.py3-none-any.whl -info Upload 2 artifact: -info azure-mgmt-testservice-0.1.0.zip -info azure_mgmt_testservice-0.1.0-py2.py3-none-any.whl -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/track2_azure-mgmt-testservice to master -github Create new PR -github PR created at https://github.com///pull/2 -section Report status -info Main status [warning] hasBreakingChange [false] -github Remove label on pull request: CI-BreakingChange-Python-Track2 -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-tf-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-tf-open.spec.ts.snap deleted file mode 100644 index a0bce073340..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L0-tf-open.spec.ts.snap +++ /dev/null @@ -1,132 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should create terraform/trenton sdk pr on spec pr opened 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAuto/1/testservice", - "number": 1, - "state": "open", - "title": "[AutoPR testservice] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should create terraform/trenton sdk pr on spec pr opened 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --use=@microsoft.azure/autorest.go@2.1.134 --go --use-onever --preview-chk --version=V2 --go-sdk-folder=//vendor ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -info Finish autorest_option_for_otherSDK -command autorest --trenton --use=https://trenton.blob.core.windows.net/trenton/autorest-trenton-0.2.2.tgz --clear-output-folder=true --output-folder=//azurerm/internal/services ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -cmdout [Autorest] WARNING (): 'cli.flatten.cli-flatten-set-enabled' is not set to true, skip flattenSetter -cmdout [Autorest] WARNING (): cli.auto-parameter-hidden is not true, skip visibility cleaner -section Commit generate result -git Add * in SDK repo -info 7 changed files after SDK generate: -info A azurerm/internal/services/testservice/client/client.go -info A azurerm/internal/services/testservice/registration.go -info A vendor/services/testservice/mgmt/2020-01-01/testservice/client.go -info A vendor/services/testservice/mgmt/2020-01-01/testservice/models.go -info A vendor/services/testservice/mgmt/2020-01-01/testservice/test.go -info A vendor/services/testservice/mgmt/2020-01-01/testservice/testserviceapi/interfaces.go -info A vendor/services/testservice/mgmt/2020-01-01/testservice/version.go -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^registration\\\\.go$/ -info 1 packages found after generation: -info azurerm/internal/services/testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package testservice -info Package log to https://sdkautotest/dl//1/azure-sdk-for-trenton/testservice/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/testservice] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/testservice -git Checkout sdk folders from sdkGen and commit: azurerm/internal/services/testservice -git Push sdkAuto/1/testservice to / -info changelogScript is not configured -info Skip artifact search -info Upload 0 artifact: -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/testservice to master -github Create new PR -github PR created at https://github.com///pull/1 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle:
    -
  • - Installation instruction for service testservice [Preview Changes]
    -
    -
  • -
- -info Rendered commentBody:
    -
  • -
    - ️✔️Succeeded Generate from - . Trenton Automation -
    -
    -warn	Skip initScript due to not configured
    -command	autorest --use=@microsoft.azure/autorest.go@2.1.134 --go --use-onever --preview-chk --version=V2 --go-sdk-folder=//vendor ..//specification/testservice/resource-manager/readme.md
    -command	autorest --trenton --use=https://trenton.blob.core.windows.net/trenton/autorest-trenton-0.2.2.tgz --clear-output-folder=true --output-folder=//azurerm/internal/services ..//specification/testservice/resource-manager/readme.md
    -cmdout	[Autorest] WARNING (): 'cli.flatten.cli-flatten-set-enabled' is not set to true, skip flattenSetter
    -cmdout	[Autorest] WARNING (): cli.auto-parameter-hidden is not true, skip visibility cleaner
    -
  • -
  • - -
  • -
- -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-merge.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-merge.spec.ts.snap deleted file mode 100644 index 93bd2a7b840..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-merge.spec.ts.snap +++ /dev/null @@ -1,139 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In merged PR, SDK Automation should push integration branch and close gen pr if spec pr merged 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAuto/@azure_test-service", - "number": 1, - "state": "closed", - "title": "[ReleasePR @azure/test-service] patch0", - }, -] -`; - -exports[`In merged PR, SDK Automation should push integration branch and close gen pr if spec pr merged 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch heads/master on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//1/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [main] -info targetBranch [sdkAuto/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get GenerationPR and close it if exist -github Get PR in / from :sdkAuto/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/1 -github Close IntegrationPR -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-empty.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-empty.spec.ts.snap deleted file mode 100644 index f71963b8012..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-empty.spec.ts.snap +++ /dev/null @@ -1,141 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should run in open pr (contains no spec update) after one merged pr 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAutomation/@azure_test-service", - "number": 1, - "state": "open", - "title": "sdkAutomation/@azure_test-service", - }, - Object { - "base": "master", - "head": "sdkAuto/2/@azure_test-service", - "number": 2, - "state": "open", - "title": "[AutoPR @azure/test-service] patch2", - }, -] -`; - -exports[`In open PR, SDK Automation should run in open pr (contains no spec update) after one merged pr 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Delete branch refs/heads/patch2 -git Fetch pull/2/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/sdkAutomation/@azure_test-service -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 1 changed files in spec PR: -info A specification/testservice/resource-manager/readme.no-lang.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//2/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/2/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/2/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/2/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/2/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/2 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-open.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-open.spec.ts.snap deleted file mode 100644 index c8b0ea0f674..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-multi-merge-open.spec.ts.snap +++ /dev/null @@ -1,145 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should run in open pr after one merged pr 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAutomation/@azure_test-service", - "number": 1, - "state": "open", - "title": "sdkAutomation/@azure_test-service", - }, - Object { - "base": "master", - "head": "sdkAuto/2/@azure_test-service", - "number": 2, - "state": "open", - "title": "[AutoPR @azure/test-service] patch1", - }, -] -`; - -exports[`In open PR, SDK Automation should run in open pr after one merged pr 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Delete branch refs/heads/patch1 -git Fetch pull/2/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/sdkAutomation/@azure_test-service -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 5 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-02-01/scenarios/shouldbeexcluded.json -info M specification/testservice/resource-manager/readme.md -info M specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//2/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/2/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/2/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/2/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/2/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/2 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-second-run.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-second-run.spec.ts.snap deleted file mode 100644 index 0ddb27886e2..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-second-run.spec.ts.snap +++ /dev/null @@ -1,160 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should run on second time for open PR 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAutomation/@azure_test-service", - "number": 1, - "state": "open", - "title": "sdkAutomation/@azure_test-service", - }, - Object { - "base": "master", - "head": "sdkAutomation/@azure_test-service@1", - "number": 2, - "state": "open", - "title": "sdkAutomation/@azure_test-service@1", - }, - Object { - "base": "sdkAutomation/@azure_test-service", - "head": "sdkAutomation/@azure_test-service@1", - "number": 3, - "state": "open", - "title": "[AutoPR] Simulate first SDK Automation", - }, - Object { - "base": "master", - "head": "sdkAuto/1/@azure_test-service", - "number": 4, - "state": "open", - "title": "[AutoPR @azure/test-service] patch0", - }, -] -`; - -exports[`In open PR, SDK Automation should run on second time for open PR 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch0 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/sdkAutomation/@azure_test-service -git Delete branch refs/heads/sdkAutomation/@azure_test-service@1 -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 6 changed files in spec PR: -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestPut.json -info A specification/testservice/resource-manager/readme.azureresourceschema.md -info A specification/testservice/resource-manager/readme.md -info A specification/testservice/resource-manager/readme.python.md -info Related readme.md list: -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//1/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/1/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/4 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-two-readme.spec.ts.snap b/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-two-readme.spec.ts.snap deleted file mode 100644 index 18d3085126c..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/__snapshots__/L1-js-open-two-readme.spec.ts.snap +++ /dev/null @@ -1,220 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`In open PR, SDK Automation should handle two readme update 1`] = ` -Array [ - Object { - "base": "master", - "head": "sdkAuto/1/@azure_another-service", - "number": 1, - "state": "open", - "title": "[AutoPR @azure/another-service] patch3", - }, - Object { - "base": "master", - "head": "sdkAuto/1/@azure_test-service", - "number": 2, - "state": "open", - "title": "[AutoPR @azure/test-service] patch3", - }, -] -`; - -exports[`In open PR, SDK Automation should handle two readme update 2`] = ` -"github Get specificationRepositoryConfiguration.json from / -info mainRepository: / -info mainBranch: master -info integrationRepository: / -info integrationBranchPrefix: sdkAutomation -info secondaryRepository: / -info secondaryBranch: master -github Get swagger_to_sdk_config.json from / -git Set remote main on / with auth -git Delete branch refs/heads/master -git Delete branch refs/heads/patch3 -git Fetch pull/1/merge on / -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -git Delete branch refs/heads/master -git Fetch / to main -git Checkout main -git Checkout secondary from main -warn Skip initScript due to not configured -info 6 changed files in spec PR: -info A specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/AnotherService.json -info A specification/anotherservice/resource-manager/Microsoft.AnotherService/stable/2020-01-01/examples/TestGet.json -info A specification/anotherservice/resource-manager/readme.md -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/TestService.json -info A specification/testservice/resource-manager/Microsoft.TestService/stable/2020-01-01/examples/TestGet.json -info A specification/testservice/resource-manager/readme.md -info Related readme.md list: -info specification/anotherservice/resource-manager/readme.md -info specification/testservice/resource-manager/readme.md -info Handle the following readme.md: -info specification/anotherservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/anotherservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/anotherservice/arm-anotherservice/LICENSE.txt -info A sdk/anotherservice/arm-anotherservice/README.md -info A sdk/anotherservice/arm-anotherservice/package.json -info A sdk/anotherservice/arm-anotherservice/rollup.config.js -info A sdk/anotherservice/arm-anotherservice/src/anotherServiceClient.ts -info A sdk/anotherservice/arm-anotherservice/src/anotherServiceClientContext.ts -info A sdk/anotherservice/arm-anotherservice/src/models/index.ts -info A sdk/anotherservice/arm-anotherservice/src/models/mappers.ts -info A sdk/anotherservice/arm-anotherservice/src/models/parameters.ts -info A sdk/anotherservice/arm-anotherservice/src/models/testMappers.ts -info A sdk/anotherservice/arm-anotherservice/src/operations/index.ts -info A sdk/anotherservice/arm-anotherservice/src/operations/test.ts -info A sdk/anotherservice/arm-anotherservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/anotherservice/arm-anotherservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/another-service -info Package log to https://sdkautotest/dl//1/azure-sdk-for-js/@azure_another-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/@azure_another-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/@azure_another-service -git Checkout sdk folders from sdkGen and commit: sdk/anotherservice/arm-anotherservice -git Push sdkAuto/1/@azure_another-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/anotherservice/arm-anotherservice/azure-another-service-1.0.0.tgz -info Upload 1 artifact: -info azure-another-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/@azure_another-service to master -github Create new PR -github PR created at https://github.com///pull/1 -info Handle the following readme.md: -info specification/testservice/resource-manager/readme.md -git Checkout branch sdkGen -section Call legacy generate -command autorest --version=V2 --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.4.4 --typescript-sdks-folder=/ ..//specification/testservice/resource-manager/readme.md -info Config: {\\"stdout\\":{\\"showInComment\\":{}},\\"stderr\\":{\\"showInComment\\":true,\\"scriptWarning\\":{}},\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"}} -section Commit generate result -git Add * in SDK repo -info 13 changed files after SDK generate: -info A sdk/testservice/arm-testservice/LICENSE.txt -info A sdk/testservice/arm-testservice/README.md -info A sdk/testservice/arm-testservice/package.json -info A sdk/testservice/arm-testservice/rollup.config.js -info A sdk/testservice/arm-testservice/src/models/index.ts -info A sdk/testservice/arm-testservice/src/models/mappers.ts -info A sdk/testservice/arm-testservice/src/models/parameters.ts -info A sdk/testservice/arm-testservice/src/models/testMappers.ts -info A sdk/testservice/arm-testservice/src/operations/index.ts -info A sdk/testservice/arm-testservice/src/operations/test.ts -info A sdk/testservice/arm-testservice/src/testServiceClient.ts -info A sdk/testservice/arm-testservice/src/testServiceClientContext.ts -info A sdk/testservice/arm-testservice/tsconfig.json -git Commit all the changes -section Detect changed packages -info Package from changed file search: /^package\\\\.json$/ -info 1 packages found after generation: -info sdk/testservice/arm-testservice -git Set remote main on / with auth -git Set remote secondary on / with auth -git Set remote integration on / with auth -section Handle package @azure/test-service -info Package log to https://sdkautotest/dl//1/azure-sdk-for-js/@azure_test-service/logs.txt -info baseBranch [master] baseRepo [/] baseRemote [integration] -info targetBranch [sdkAuto/1/@azure_test-service] targetRepo [/] baseRemote [integration] -info Skip sync baseBranch due to same remote same branch -git Create targetBranch sdkAuto/1/@azure_test-service -git Checkout sdk folders from sdkGen and commit: sdk/testservice/arm-testservice -git Push sdkAuto/1/@azure_test-service to / -section Call legacy build for azure-sdk-for-js -command npm pack --silent -info Config: {\\"exitCode\\":{\\"showInComment\\":true,\\"result\\":\\"error\\"},\\"stderr\\":{\\"showInComment\\":true},\\"logPrefix\\":\\"npmPack\\"} -info changelogScript is not configured -info Use legacy artifact search option -info Search artifact with: /\\\\.tgz$/ -info 1 artifact found: -info sdk/testservice/arm-testservice/azure-test-service-1.0.0.tgz -info Upload 1 artifact: -info azure-test-service-1.0.0.tgz -info Legacy InstallInstruction -github Get PR in / from :sdkAuto/1/@azure_test-service to master -github Create new PR -github PR created at https://github.com///pull/2 -section Report status -info Main status [succeeded] hasBreakingChange [false] -info Rendered commentSubTitle: -info Rendered commentBody: - -info Writing unified pipeline message to pipe.log" -`; diff --git a/tools/spec-gen-sdk/integrationTest/test/lang-common.ts b/tools/spec-gen-sdk/integrationTest/test/lang-common.ts deleted file mode 100644 index f47e54d476b..00000000000 --- a/tools/spec-gen-sdk/integrationTest/test/lang-common.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { - getRunIdPrefix, - initializeGithubRepoFromLocalFixture, - launchTestSDKAutomation, - repoOwner, - createPRWithPatch, - getTestGithubClient -} from '../utils'; -import { fixtures } from '../fixtures'; -import { getSdkAutoContext } from '../../src/automation/entrypoint'; -import { sdkAutomationCliConfig } from '../../src/cli/config'; -import { workflowInit, workflowMain } from '../../src/automation/workflow'; -import { sdkAutoReportStatus } from '../../src/automation/reportStatus'; -import { CommentCaptureTransport, sdkAutoLogLevels } from '../../src/automation/logging'; - -export const prepareSDKTestCommon = async ( - langAlias: string, - langFull: string, - sdkFixtureName: string, - repoNameParam: string, - sdkBaseBranch?: string, - isPrivate?: boolean -) => { - const namePrefix = `${getRunIdPrefix()}-${langAlias}-${repoNameParam}`; - let specOriginName = 'azure-rest-api-specs'; - let sdkOriginName = `${langFull}-test`; - let specRepoName = `${namePrefix}-spec`; - let sdkRepoName = `${namePrefix}-sdk`; - if (isPrivate) { - specOriginName += '-pr'; - sdkOriginName += '-pr'; - specRepoName += '-pr'; - sdkRepoName += '-pr'; - } - - await Promise.all([ - initializeGithubRepoFromLocalFixture(fixtures.specTest.name, specRepoName, { - 'specificationRepositoryConfiguration.json': [ - { - search: `"${sdkOriginName}"`, - replace: `"${sdkRepoName}"` - }, - { - search: `"${specOriginName}"`, - replace: `"${specRepoName}"` - } - ] - }), - initializeGithubRepoFromLocalFixture( - sdkFixtureName, - sdkRepoName, - { - 'swagger_to_sdk_config.json': [ - { - search: `"${langFull}-test"`, - replace: `"${sdkRepoName}"` - } - ] - }, - sdkBaseBranch - ) - ]); - - const logger = { - allLogs: [] as string[] - }; - - const launchSDKAutomation = (specPRNumber: number) => { - const config = sdkAutomationCliConfig; - return launchTestSDKAutomation( - (async () => { - const cwd = process.cwd(); - process.chdir(config.workingFolder); - try { - const sdkAutoContext = await getSdkAutoContext({ - specRepo: { owner: repoOwner, name: specRepoName }, - pullNumber: specPRNumber, - sdkName: langFull, - filterSwaggerToSdk: false, - github: { - token: config.githubToken, - id: config.githubApp.id, - privateKey: config.githubApp.privateKey - }, - storage: { - name: 'sdkautotest', - prefix: 'sdkautocontainer', - downloadCommand: 'DOWNLOAD {URL} TO {FILENAME}', - isPublic: !isPrivate - }, - runEnv: 'test', - branchPrefix: 'sdkAuto' - }); - - const captureTransport = new CommentCaptureTransport({ - extraLevelFilter: Object.keys(sdkAutoLogLevels.levels) as any[], - output: logger.allLogs - }); - sdkAutoContext.logger.add(captureTransport); - // sdkAutoContext.logger.add(new winston.transports.Console()); - - const context = await workflowInit(sdkAutoContext); - await workflowMain(context); - await sdkAutoReportStatus(context); - } finally { - process.chdir(cwd); - } - })(), - `${langAlias}-${repoNameParam}` - ); - }; - - return { namePrefix, specRepoName, sdkRepoName, logger, launchSDKAutomation }; -}; - -export const prepareJsSDKTest = async (repoNameParam: string, isPrivate?: boolean) => { - const context = await prepareSDKTestCommon( - 'js', - 'azure-sdk-for-js', - fixtures.sdkJs.name, - repoNameParam, - undefined, - isPrivate - ); - - const patchJsLog = (text: string) => { - const regexToMatchLine = /^cmderr\t\[npmPack\]/g; - text = text - .split('\n') - .filter((line) => line.match(regexToMatchLine) === null) - .join('\n'); - return text; - }; - - return { ...context, patchJsLog }; -}; - -export const preparePySDKTest = async (repoNameParam: string) => { - const context = await prepareSDKTestCommon( - 'py', - 'azure-sdk-for-python', - fixtures.sdkPy.name, - repoNameParam, - 'release/v3' - ); - - const patchPyLog = (text: string) => { - const regexToMatchLine = /\[changelog/g; - text = text - .split('\n') - .filter((line) => line.match(regexToMatchLine) === null) - .join('\n'); - return text; - }; - - return { ...context, patchPyLog }; -}; - -export const preparePyT2SDKTest = async (repoNameParam: string) => { - const context = await prepareSDKTestCommon('pyt2', 'azure-sdk-for-python-track2', fixtures.sdkPy.name, repoNameParam); - const githubClient = await getTestGithubClient(); - - const prNumber = await createPRWithPatch(context.sdkRepoName, fixtures.sdkPy.patch0_Track2, 'enable-track2', { - toReplace: { - 'swagger_to_sdk_custom_config.json': [ - { - search: 'azure-sdk-for-python-track2-test', - replace: context.sdkRepoName - } - ] - } - }); - await githubClient.pulls.merge({ - owner: repoOwner, - repo: context.sdkRepoName, - pull_number: prNumber - }); - - const patchPyT2Log = (text: string) => { - const regexToMatchLine = /\[changelog/g; - text = text - .split('\n') - .filter((line) => line.match(regexToMatchLine) === null) - .join('\n'); - return text; - }; - - return { ...context, patchPyT2Log }; -}; - -export const prepareTfSDKTest = async (repoNameParam: string) => { - const context = await prepareSDKTestCommon('tf', 'azure-sdk-for-trenton', fixtures.sdkTf.name, repoNameParam); - - const patchTfLog = (text: string) => text; - - return { ...context, patchTfLog }; -}; - -export const prepareARMSchmSDKTest = async (repoNameParam: string) => { - const context = await prepareSDKTestCommon( - 'armschm', - 'azure-resource-manager-schemas', - fixtures.schmARM.name, - repoNameParam - ); - - const patchARMSchmLog = (text: string) => text; - - return { ...context, patchARMSchmLog }; -}; diff --git a/tools/spec-gen-sdk/integrationTest/utils.ts b/tools/spec-gen-sdk/integrationTest/utils.ts deleted file mode 100644 index 6404bd240da..00000000000 --- a/tools/spec-gen-sdk/integrationTest/utils.ts +++ /dev/null @@ -1,256 +0,0 @@ -import * as fs from 'fs-extra'; -import _rimraf from 'rimraf'; -import { Octokit } from '@octokit/rest'; -import { sdkAutomationCliConfig } from '../src/cli/config'; -import { getAuthenticatedOctokit } from '../src/utils/githubUtils'; -import { deleteFolder } from '@ts-common/azure-js-dev-tools'; -import * as winston from 'winston'; -import path from 'path'; -import simpleGit, { ResetMode, SimpleGit, SimpleGitOptions } from 'simple-git'; -import { getCurrentBranch, gitAddAll, gitGetCommitter, gitGetDiffFileList, gitSetRemoteWithAuth } from '../src/utils/gitUtils'; -import { sdkAutoLogLevels } from '../src/automation/logging'; -import { simpleGitOptions } from '../src/automation/workflow'; - -const fixturePrefix = 'integrationTest/fixtures'; -export const workPrefix = sdkAutomationCliConfig.workingFolder; -export const repoOwner = sdkAutomationCliConfig.specRepo.split('/')[0]; - -let runId = sdkAutomationCliConfig.testRunId; -if (!runId) { - runId = Math.random().toString(36).substring(2, 8); -} -export const getRunIdPrefix = () => `test-${runId}`; -const logger = winston.createLogger({ - levels: sdkAutoLogLevels.levels, - transports: [new winston.transports.Console({ level: 'error' })] -}); -const [githubClient, getGithubAccessToken] = getAuthenticatedOctokit( - { - token: sdkAutomationCliConfig.githubToken, - id: sdkAutomationCliConfig.githubApp.id, - privateKey: sdkAutomationCliConfig.githubApp.privateKey - }, - logger -); - -export const getTestGithubClient = async (): Promise => { - return githubClient; -}; - -export const getTestGitClient = async (repoName: string) => { - const repoFolder = path.join(workPrefix, repoName); - fs.mkdirpSync(repoFolder); - - const repo = simpleGit({ ...simpleGitOptions, baseDir: repoFolder }); - await repo.init(false); - return repo; -}; - -export const cleanTestRepos = async (repos: string[]) => { - const github = await getTestGithubClient(); - - for (const repoName of repos) { - console.log(`Cleaning up ${repoOwner}/${repoName}`); - await deleteFolder(`${workPrefix}/${repoName}`); - try { - await github.repos.delete({ owner: repoOwner, repo: repoName }); - } catch (e) { - console.log(`Failed to delete ${repoOwner}/${repoName}: ${e.message} ${e.stack}`); - } - } -}; - -type ReplaceFileRecord = { - [filePath: string]: { - search: string; - replace: string; - }[]; -}; -export const applyReplaceFileRecord = (workPath: string, toReplace?: ReplaceFileRecord) => { - if (toReplace !== undefined) { - for (const [filePath, replaceArr] of Object.entries(toReplace)) { - let content = fs.readFileSync(`${workPath}/${filePath}`).toString(); - for (const { search, replace } of replaceArr) { - content = content.replace(search, replace); - } - fs.writeFileSync(`${workPath}/${filePath}`, content); - } - } -}; - -export const initializeGithubRepoFromLocalFixture = async ( - fixtureName: string, - repoName: string, - toReplace?: ReplaceFileRecord, - baseBranch: string = 'master' -) => { - console.log(`Initializing https://github.com/${repoOwner}/${repoName}`); - const fixturePath = path.join(fixturePrefix, fixtureName); - const workPath = path.join(workPrefix, repoName); - const github = await getTestGithubClient(); - - // Copy file - await fs.remove(workPath); - await fs.mkdirp(workPath); - await fs.copy(fixturePath, workPath); - applyReplaceFileRecord(workPath, toReplace); - const repo: SimpleGit = await getTestGitClient(repoName); - - // Create repo if not exist - try { - await github.repos.delete({ owner: repoOwner, repo: repoName }); - } catch (e) { - // Repo not found. Pass - } - await github.repos.createInOrg({ name: repoName, org: repoOwner }); - try { - await github.repos.get({ owner: repoOwner, repo: repoName }); - } catch (e) {} - - // Checkout branch - await gitGetCommitter(repo); - await repo.add([]).commit(`Init repo`) - const commit = await repo.revparse('HEAD'); - const currentBranch = await getCurrentBranch(repo); - if (baseBranch !== currentBranch) { - await repo.raw(['branch', '--copy', commit, baseBranch, '--force']); - await repo.checkoutLocalBranch(baseBranch); - } - - // Add and commit - await gitAddAll(repo); - const diff = await repo.diff(['--name-status', 'HEAD']); - let fileList = await gitGetDiffFileList(diff); - await repo.add(fileList).commit(`Init repo with fixture ${fixtureName}`) - - // Push - await gitSetRemoteWithAuth({ logger, getGithubAccessToken }, repo, 'origin', { owner: repoOwner, name: repoName }); - await repo.push([ - 'origin', - `+refs/heads/${baseBranch}:refs/heads/${baseBranch}` - ]); - console.log(`Initialized https://github.com/${repoOwner}/${repoName}`); -}; - -export const createPRWithPatch = async ( - repoName: string, - patchName: string, - branchName: string, - options: { - toReplace?: ReplaceFileRecord; - baseBranch?: string; - fetchBase?: boolean; - } = {} -) => { - const baseBranch = options.baseBranch ?? 'master'; - - console.log(`Creating PR in '${repoOwner}/${repoName}' with patch '${patchName}' on branch '${branchName}'`); - const workPath = `${workPrefix}/${repoName}`; - const patchPath = `${fixturePrefix}/${patchName}`; - const github = await getTestGithubClient(); - const repo = await getTestGitClient(repoName); - - await gitAddAll(repo); - const header = await repo.revparse('HEAD') - await repo.reset(ResetMode.HARD, [header]); - await repo.checkout(header, ['--force']); - - if (options.fetchBase) { - await repo.fetch([ - 'origin', - '--update-head-ok', - '--force', - `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}` - ]); - await repo.mergeFromTo(`origin/${baseBranch}`, baseBranch); - } - - await repo.checkout(branchName, ['--force']); - const baseCommit = await repo.revparse('HEAD'); - await repo.raw(['branch', '--copy', baseCommit, baseBranch, '--force']); - await repo.checkout(branchName, ['--force']); - - await fs.copy(patchPath, workPath); - applyReplaceFileRecord(workPath, options.toReplace); - - await gitAddAll(repo); - const diff = await repo.diff(['--name-status', 'HEAD']); - let fileList = await gitGetDiffFileList(diff); - await gitGetCommitter(repo); - await repo.add(fileList).commit(`Apply patch ${patchName}`) - - // Push - await gitSetRemoteWithAuth({ logger, getGithubAccessToken }, repo, 'origin', { owner: repoOwner, name: repoName }); - await repo.push([ - 'origin', - `+refs/heads/${branchName}:refs/heads/${branchName}` - ]); - - let pr = await github.pulls.create({ - owner: repoOwner, - repo: repoName, - head: branchName, - base: baseBranch, - title: branchName - }); - console.log(pr.data.html_url); - - // Wait for mergable data - while (pr.data.mergeable === null) { - pr = await github.pulls.get({ owner: repoOwner, repo: repoName, pull_number: pr.data.number }); - } - - return pr.data.number; -}; - -export const getPRListInfo = async (repoName: string) => { - const github = await getTestGithubClient(); - // Wait for 5 seconds to make sure we could get the latest pull request list - await new Promise((resolve) => setTimeout(resolve, 5000)); - const { data: sdkPRs } = await github.pulls.list({ - owner: repoOwner, - repo: repoName, - state: 'all' - }); - const result = sdkPRs.map((pr) => ({ - number: pr.number, - state: pr.state, - title: pr.title, - base: pr.base.ref, - head: pr.head.ref - })); - result.sort((a, b) => a.number - b.number); - return result; -}; - -export const getLoggerTextForAssert = async ( - _logger: { allLogs: string[] }, - specRepoName: string, - specPRNumber: number, - sdkRepoName: string -) => { - let text = _logger.allLogs.join('\n'); - text = text.replace(new RegExp(fs.realpathSync('.'), 'g'), '.'); - text = text.replace(new RegExp(repoOwner, 'g'), ''); - text = text.replace(new RegExp(specRepoName, 'g'), ''); - text = text.replace(new RegExp(sdkRepoName, 'g'), ''); - - text = text.replace(/ [a-z0-9]{40}/g, ` `); - - const version = require('pkginfo').read(module).package.version; - text = text.replace(new RegExp(version.replace('.', '\\.'), 'g'), ''); - - text = text.replace(new RegExp(path.resolve(workPrefix), 'g'), ''); - - return text; -}; - -export const launchTestSDKAutomation = async (automationPromise: Promise, info: string) => { - console.log(`Launching SDK Automation for ${info}`); - try { - await automationPromise; - } catch (e) { - console.log(e); - // Need log for diagnostic so do not fail on exception - } -}; diff --git a/tools/spec-gen-sdk/jest.config.integration.js b/tools/spec-gen-sdk/jest.config.integration.js deleted file mode 100644 index d3477635cab..00000000000 --- a/tools/spec-gen-sdk/jest.config.integration.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - preset: 'ts-jest', - globals: { - 'ts-jest': { - packageJson: 'package.json', - diagnostics: false, - tsConfig: "tsconfig.integration.json" - }, - }, - testMatch: [ - "/integrationTest/**/*.spec.ts", - ], - testPathIgnorePatterns: [ - "/node_modules", "/w", "/test" - ], - modulePathIgnorePatterns: [ - "/node_modules", "/w", "/test" - ], - unmockedModulePathPatterns: [ - "@microsoft.azure" - ], - transform: { - "^.+\\.(ts|tsx)$": "ts-jest" - }, - transformIgnorePatterns: [ - "/test", "/w" - ], - setupFilesAfterEnv: [ - '/integrationTest/jest.setupAfterEnv.js' - ], - moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"] -} diff --git a/tools/spec-gen-sdk/package-lock.json b/tools/spec-gen-sdk/package-lock.json new file mode 100644 index 00000000000..cd1bc0fe200 --- /dev/null +++ b/tools/spec-gen-sdk/package-lock.json @@ -0,0 +1,7440 @@ +{ + "name": "@azure-tools/spec-gen-sdk", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@azure-tools/spec-gen-sdk", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.2.0", + "@azure/storage-blob": "~12.17.0", + "@octokit/auth-app": "^2.4.5", + "@octokit/rest": "18.0.3", + "ajv": "^6.12.6", + "commonmark": "0.31.2", + "convict": "^6.2.4", + "difflib": "^0.2.4", + "dotenv": "^8.2.0", + "filehound": "^1.17.5", + "fs-extra": "^9.0.0", + "handlebars": "~4.7.7", + "js-yaml": "^3.14.0", + "jsonc-parser": "^2.3.1", + "lodash": "^4.17.20", + "pkginfo": "^0.4.1", + "prettier": "2.1.2", + "rimraf": "^5.0.10", + "simple-git": "^3.16.0", + "source-map": "0.7.3", + "tslib": "1.14.1", + "winston": "^3.3.3", + "winston-transport": "^4.4.0", + "yargs": "~16.2.0" + }, + "bin": { + "spec-gen-sdk": "bin/spec-gen-sdk" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@types/convict": "^5.2.0", + "@types/difflib": "^0.2.0", + "@types/fs-extra": "^9.0.1", + "@types/jest": "^29.5.11", + "@types/js-yaml": "^3.12.5", + "@types/lodash": "^4.14.161", + "@types/node": "^18.19.64", + "@types/prettier": "^2.1.5", + "@types/rimraf": "^3.0.0", + "@typescript-eslint/eslint-plugin": "^8.12.2", + "@typescript-eslint/parser": "^8.12.2", + "eslint": "^9.14.0", + "fs-extra": "^9.0.0", + "globals": "^15.12.0", + "jest": "~29.7.0", + "source-map-support": "^0.5.19", + "ts-jest": "~29.1.1", + "ts-node": "9.0.0", + "tslint": "^5.20.1", + "typescript": "~5.3.3", + "typescript-eslint": "^8.14.0" + }, + "engines": { + "node": ">=20.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/abort-controller/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-auth": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", + "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-http": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.4.tgz", + "integrity": "sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==", + "deprecated": "This package is no longer supported. Please migrate to use @azure/core-rest-pipeline", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/core-util": "^1.1.1", + "@azure/logger": "^1.0.0", + "@types/node-fetch": "^2.5.0", + "@types/tunnel": "^0.0.3", + "form-data": "^4.0.0", + "node-fetch": "^2.6.7", + "process": "^0.11.10", + "tslib": "^2.2.0", + "tunnel": "^0.0.6", + "uuid": "^8.3.0", + "xml2js": "^0.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/core-http/node_modules/@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-http/node_modules/@azure/core-tracing": { + "version": "1.0.0-preview.13", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", + "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-http/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-paging": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.0.tgz", + "integrity": "sha512-QSoGUp4Eq/gohEFNJaUOwTN7BCc2nHTjjbm75JT0aD7W65PWM1H/tItz0GsABn22uaKyGxiMhWQLt2r+FGU89Q==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-tracing": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", + "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-tracing/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/core-util": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", + "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/identity": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.5.0.tgz", + "integrity": "sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.26.1", + "@azure/msal-node": "^2.15.0", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/logger": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", + "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/logger/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@azure/msal-browser": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.27.0.tgz", + "integrity": "sha512-+b4ZKSD8+vslCtVRVetkegEhOFMLP3rxDWJY212ct+2r6jVg6OSQKc1Qz3kCoXo0FgwaXkb+76TMZfpHp8QtgA==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "14.16.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.16.0.tgz", + "integrity": "sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.1.tgz", + "integrity": "sha512-1NEFpTmMMT2A7RnZuvRl/hUmJU+GLPjh+ShyIqPktG2PvSd2yvPnzGd/BxIBAAvJG5nr9lH4oYcQXepDbaE7fg==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "14.16.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@azure/storage-blob": { + "version": "12.17.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz", + "integrity": "sha512-sM4vpsCpcCApagRW5UIjQNlNylo02my2opgp0Emi8x888hZUvJ3dN69Oq20cEGXkMUWnoCrBaB0zyS3yeB87sQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^3.0.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/storage-blob/node_modules/@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/storage-blob/node_modules/@azure/core-tracing": { + "version": "1.0.0-preview.13", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", + "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/storage-blob/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-app": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-2.11.0.tgz", + "integrity": "sha512-tC0BjqyTEjReIBHogOjLjF3rc2n4xwjZcpOaUUhybDnqkrp7Gxj5n91aGUcIFgJ3MDYf+f3XZehQd2B4ijG+4w==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^5.4.11", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^6.0.3", + "@types/lru-cache": "^5.1.0", + "deprecation": "^2.3.1", + "lru-cache": "^6.0.0", + "universal-github-app-jwt": "^1.0.1", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.40.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.2.tgz", + "integrity": "sha512-PTI7wpbGEZ2IR87TVh+TNWaLcgX/RsZQalFbQCq8XxYUrQ36RHyERrHSNXFy5gkWpspUAOYRSV707JJv6BhqJA==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^5.1.1", + "deprecation": "^2.3.1" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", + "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", + "license": "MIT", + "dependencies": { + "@types/node": ">= 8" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.3.tgz", + "integrity": "sha512-GubgemnLvUJlkhouTM2BtX+g/voYT/Mqh0SASGwTnLvSkW1irjt14N911/ABb6m1Hru0TwScOgFgMFggp3igfQ==", + "license": "MIT", + "dependencies": { + "@octokit/core": "^3.0.0", + "@octokit/plugin-paginate-rest": "^2.2.0", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "4.1.2" + } + }, + "node_modules/@octokit/types": { + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^12.11.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/convict": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/convict/-/convict-5.2.2.tgz", + "integrity": "sha512-yz26pc2bwg8YyYz/X5s/MJsUy40n54vxDdQCRENtqGfKdrmpPqXdOV8LDuHqTA0acoFxybLsJ5hc9ZYK6amDCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/difflib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@types/difflib/-/difflib-0.2.7.tgz", + "integrity": "sha512-NCG38r/Wxkx7ZnGntRAVl3dPReR6nrauZq51viGgCQ8iM0QldrF7mN65SFnU3cJPaXo6Ry5+zhL0EVkfOgJsHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/js-yaml": { + "version": "3.12.10", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.10.tgz", + "integrity": "sha512-/Mtaq/wf+HxXpvhzFYzrzCqNRcA958sW++7JOFC8nPrZcvfi/TrzOaaGbvt27ltJB2NQbHVAg5a1wUCsyMH7NA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", + "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz", + "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "license": "MIT" + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.19.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/tunnel": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", + "integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", + "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/type-utils": "8.15.0", + "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", + "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", + "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", + "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/utils": "8.15.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", + "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", + "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", + "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", + "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.15.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "license": "Apache-2.0" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/commonmark": { + "version": "0.31.2", + "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.31.2.tgz", + "integrity": "sha512-2fRLTyb9r/2835k5cwcAwOj0DEc44FARnMp5veGsJ+mEAZdi52sNopLu07ZyElQUz058H43whzlERDIaaSw4rg==", + "license": "BSD-2-Clause", + "dependencies": { + "entities": "~3.0.1", + "mdurl": "~1.0.1", + "minimist": "~1.2.8" + }, + "bin": { + "commonmark": "bin/commonmark" + }, + "engines": { + "node": "*" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "license": "ISC" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.63", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", + "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==", + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.5", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/file-js/-/file-js-0.3.0.tgz", + "integrity": "sha512-nZlX1pxpV6Mt8BghM3Z150bpsCT1zqil97UryusstZLSs9caYAe0Wph2UKPC3awfM2Dq4ri1Sv99KuK4EIImlA==", + "license": "MIT", + "dependencies": { + "bluebird": "^3.4.7", + "minimatch": "^3.0.3", + "proper-lockfile": "^1.2.0" + } + }, + "node_modules/file-js/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/file-js/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/filehound": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/filehound/-/filehound-1.17.6.tgz", + "integrity": "sha512-5q4zjFkI8W2zLmvbvyvI//K882IpEj6sMNXPUQlk5H6W4Wh3OSSylEAIEmMLELP9G7ileYjTKPXOn0YzzS55Lg==", + "license": "MIT", + "dependencies": { + "bluebird": "^3.7.2", + "file-js": "0.3.0", + "lodash": "^4.17.21", + "minimatch": "^5.0.0", + "moment": "^2.29.1", + "unit-compare": "^1.0.1" + } + }, + "node_modules/filehound/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", + "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", + "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proper-lockfile": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-1.2.0.tgz", + "integrity": "sha512-YNjxtCoY3A+lohlLXWCYrHDhUdfU3MMnuC+ADhloDvJo586LKW23dPrjxGvRGuus05Amcf0cQy6vrjjtbJhWpw==", + "license": "MIT", + "dependencies": { + "err-code": "^1.0.0", + "extend": "^3.0.0", + "graceful-fs": "^4.1.2", + "retry": "^0.10.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-git": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", + "integrity": "sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.5.tgz", + "integrity": "sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" + } + }, + "node_modules/tslint/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/tslint/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/tslint/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslint/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tslint/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz", + "integrity": "sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.15.0", + "@typescript-eslint/parser": "8.15.0", + "@typescript-eslint/utils": "8.15.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/unit-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unit-compare/-/unit-compare-1.0.1.tgz", + "integrity": "sha512-AeLMQr8gcen2WOTwV0Gvi1nKKbY4Mms79MoltZ6hrZV/VANgE/YQly3jtWZJA/fa9m4ajhynq3XMqh5rOyZclA==", + "license": "ISC", + "dependencies": { + "moment": "^2.14.1" + } + }, + "node_modules/universal-github-app-jwt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.2.0.tgz", + "integrity": "sha512-dncpMpnsKBk0eetwfN8D8OUHGfiDhhJ+mtsbMl+7PfW7mYjiH8LIcqRmYMtzYLgSh47HjfdBtrBwIQ/gizKR3g==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9.0.0", + "jsonwebtoken": "^9.0.2" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tools/spec-gen-sdk/package.json b/tools/spec-gen-sdk/package.json new file mode 100644 index 00000000000..070da26a372 --- /dev/null +++ b/tools/spec-gen-sdk/package.json @@ -0,0 +1,112 @@ +{ + "name": "@azure-tools/spec-gen-sdk", + "author": { + "name": "Microsoft Corporation", + "email": "azsdkteam@microsoft.com", + "url": "https://github.com/Azure/azure-sdk-tools" + }, + "version": "0.1.0", + "description": "A TypeScript implementation of the API specification to SDK tool", + "tags": [ + "spec-gen-sdk" + ], + "keywords": [ + "spec-gen-sdk" + ], + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "files": [ + "lib/**/*.js", + "lib/**/*.json", + "lib/**/*.js.map", + "lib/**/*.d.ts", + "lib/**/*.d.ts.map", + "lib/**/*.handlebars", + "images/**/*", + "src/**/*.ts", + "README.md" + ], + "license": "MIT", + "engines": { + "node": ">=20.10.0" + }, + "dependencies": { + "@azure/identity": "^4.2.0", + "@azure/storage-blob": "~12.17.0", + "@octokit/auth-app": "^2.4.5", + "@octokit/rest": "18.0.3", + "ajv": "^6.12.6", + "commonmark": "0.31.2", + "convict": "^6.2.4", + "difflib": "^0.2.4", + "dotenv": "^8.2.0", + "filehound": "^1.17.5", + "fs-extra": "^9.0.0", + "handlebars": "~4.7.7", + "js-yaml": "^3.14.0", + "jsonc-parser": "^2.3.1", + "lodash": "^4.17.20", + "pkginfo": "^0.4.1", + "prettier": "2.1.2", + "rimraf": "^5.0.10", + "simple-git": "^3.16.0", + "source-map": "0.7.3", + "tslib": "1.14.1", + "winston": "^3.3.3", + "winston-transport": "^4.4.0", + "yargs": "~16.2.0" + }, + "overrides": { + "@octokit/rest": "18.0.3", + "rimraf": "^5.0.10" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@types/convict": "^5.2.0", + "@types/difflib": "^0.2.0", + "@types/fs-extra": "^9.0.1", + "@types/jest": "^29.5.11", + "@types/js-yaml": "^3.12.5", + "@types/lodash": "^4.14.161", + "@types/node": "^18.19.64", + "@types/prettier": "^2.1.5", + "@types/rimraf": "^3.0.0", + "@typescript-eslint/eslint-plugin": "^8.12.2", + "@typescript-eslint/parser": "^8.12.2", + "eslint": "^9.14.0", + "fs-extra": "^9.0.0", + "globals": "^15.12.0", + "jest": "~29.7.0", + "source-map-support": "^0.5.19", + "ts-jest": "~29.1.1", + "ts-node": "9.0.0", + "tslint": "^5.20.1", + "typescript": "~5.3.3", + "typescript-eslint": "^8.14.0" + }, + "homepage": "https://github.com/Azure/azure-sdk-tools", + "repository": { + "type": "git", + "url": "git@github.com:Azure/azure-sdk-tools.git" + }, + "bugs": { + "url": "https://github.com/Azure/azure-sdk-tools/issues" + }, + "scripts": { + "build": "npm run clean && npm run lint && tsc && npm run copy", + "clean": "rimraf -rf lib", + "purge": "rimraf -rf node_modules package-lock.json", + "copy": "cd src && find . \\( -name '*.handlebars' -o -name '*.json' \\) -exec cp --parents {} ../lib \\; && cd ..", + "watch": "tsc --watch", + "test": "jest -c jest.config.js --verbose", + "start": "node lib/cli/cli.js", + "build-test": "npm run build && npm test", + "lint": "eslint src/**/*.ts", + "lint-fix": "eslint src/**/*.ts --fix", + "test-reportFormat": "jest -c jest.config.js --verbose ./test/reportFormat.test.ts", + "test-utils": "jest -c jest.config.js --verbose ./test/utils.test.ts" + }, + "bin": { + "spec-gen-sdk": "bin/spec-gen-sdk" + } +} diff --git a/tools/spec-gen-sdk/src/automation/entrypoint.ts b/tools/spec-gen-sdk/src/automation/entrypoint.ts index 74bdd661f87..93dd6c69df1 100644 --- a/tools/spec-gen-sdk/src/automation/entrypoint.ts +++ b/tools/spec-gen-sdk/src/automation/entrypoint.ts @@ -15,16 +15,6 @@ import { workflowMain } from './workflow'; import { TriggerType } from '../types/TriggerType'; -import { azureresourceschema } from '../langSpecs/langs/azureresourceschema'; -import { cli } from '../langSpecs/langs/cli'; -import { dotnet } from '../langSpecs/langs/dotnet'; -import { go } from '../langSpecs/langs/go'; -import { java } from '../langSpecs/langs/java'; -import { javascript } from '../langSpecs/langs/javascript'; -import { python } from '../langSpecs/langs/python'; -import { pythonTrack2 } from '../langSpecs/langs/pythonTrack2'; -import { trenton } from '../langSpecs/langs/trenton'; -import { LanguageConfiguration } from '../langSpecs/languageConfiguration'; import { getBlobName, loggerConsoleTransport, @@ -35,7 +25,7 @@ import { sdkAutoLogLevels } from './logging'; import { sdkAutoReportStatus } from './reportStatus'; -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from './sdkAutomationState'; import { DefaultAzureCredential } from '@azure/identity'; import * as pkginfo from 'pkginfo'; @@ -81,37 +71,12 @@ export type SdkAutoContext = { specPrTitle: string; specPrHtmlUrl: string; workingFolder: string; - legacyLangConfig?: LanguageConfiguration; blobContainerClient: ContainerClient; logsBlobUrl?: string; version: string; autorestConfig?: string; }; -const getLegacyLanguageConfig = (sdkName: string) => { - switch (sdkName) { - case 'azure-resource-manager-schemas': - return azureresourceschema; - case 'azure-cli-extensions': - return cli; - case 'azure-sdk-for-net': - return dotnet; - case 'azure-sdk-for-go': - return go; - case 'azure-sdk-for-java': - return java; - case 'azure-sdk-for-js': - return javascript; - case 'azure-sdk-for-python': - return python; - case 'azure-sdk-for-python-track2': - return pythonTrack2; - case 'azure-sdk-for-trenton': - return trenton; - } - return undefined; -}; - const getAutorestConfigFromPRComment = async ( octokit: Octokit, owner: string, @@ -207,8 +172,6 @@ export const getSdkAutoContext = async (options: SdkAutoOptions): Promise { console.log(`##vso[task.setVariable variable=SkippedJobs]azure-sdk-for-go`); console.log(`##vso[task.complete result=Failed;]`); } - } finally { - if (workflowContext) { - await sdkAutoReportStatus(workflowContext); - } - await loggerWaitToFinish(sdkContext.logger); - if (runSdkFilter) { - return workflowFilterSdkMainStatus; - } else { - return workflowContext?.status; - } + } + if (workflowContext) { + await sdkAutoReportStatus(workflowContext); + } + await loggerWaitToFinish(sdkContext.logger); + if (runSdkFilter) { + return workflowFilterSdkMainStatus; + } else { + return workflowContext?.status; } }; diff --git a/tools/spec-gen-sdk/src/automation/legacy.ts b/tools/spec-gen-sdk/src/automation/legacy.ts deleted file mode 100644 index 4358f97b18b..00000000000 --- a/tools/spec-gen-sdk/src/automation/legacy.ts +++ /dev/null @@ -1,435 +0,0 @@ -import { AutoRestOptions, AutoRestOptionValue } from '@ts-common/azure-js-dev-tools'; -import path from 'path'; -import * as glob from 'glob'; -import { InstallationInstructions } from '../langSpecs/installationInstructions'; -import { SDKRepositoryPackage } from '../langSpecs/sdkRepositoryPackage'; -import { getResolvedAutoRestOptions } from '../sdkRepository'; -import { SwaggerToSDKConfiguration as LegacySwaggerToSDKConfig } from '../swaggerToSDKConfiguration'; -import { InstallInstructionScriptOutput } from '../types/InstallInstructionScriptOutput'; -import { PackageData } from '../types/PackageData'; -import { repoKeyToString } from '../utils/githubUtils'; -import { runSdkAutoCustomScript, setSdkAutoStatus } from '../utils/runScript'; -import { WorkflowContext } from './workflow'; -import { SyncConfig } from './workflowPackage'; -import { CommentCaptureTransport } from './logging'; -import { SDKAutomationState } from '../sdkAutomationState'; - -const switchToNode12 = async (context: WorkflowContext) => { - context.scriptEnvs.N_PREFIX = path.resolve(context.tmpFolder); - await runSdkAutoCustomScript( - context, - { path: `npx n 12` }, - { - cwd: context.workingFolder, - statusContext: context - } - ); - context.scriptEnvs.PATH = `${path.join(context.scriptEnvs.N_PREFIX, 'bin')}:${context.scriptEnvs.PATH}`; -}; - -export const legacyInit = async (context: WorkflowContext) => { - if (context.skipLegacy) { - return; - } - switch (context.config.sdkName) { - case 'azure-resource-manager-schemas': - await switchToNode12(context); - break; - - case 'azure-sdk-for-net': - await runSdkAutoCustomScript( - context, - { path: `sudo apt-get install -y dotnet-sdk-6.0`, logPrefix: 'apt-get' }, - { cwd: context.tmpFolder, statusContext: context } - ); - break; - - case 'azure-sdk-for-python': - case 'azure-sdk-for-python-track2': - case 'azure-cli-extensions': - context.logger.info('Legacy python init'); - const options = { cwd: context.workingFolder, statusContext: context }; - - await switchToNode12(context); - - await runSdkAutoCustomScript( - context, - { path: `python3 -m venv venv` }, - { - cwd: context.tmpFolder, - statusContext: context - } - ); - const venvPath = path.join(context.tmpFolder, 'venv'); - context.scriptEnvs.VIRTUAL_ENV = path.resolve(venvPath); - context.scriptEnvs.PATH = `${path.join(path.resolve(venvPath), 'bin')}:${context.scriptEnvs.PATH}`; - - await runSdkAutoCustomScript( - context, - { path: `pip install --index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/ --upgrade setuptools wheel pip`, logPrefix: 'pip install' }, - options - ); - await runSdkAutoCustomScript( - context, - { path: `pip install pathlib jinja2 msrestazure --index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/`, logPrefix: 'pip install' }, - options - ); - - break; - } -}; - -export const legacyGenerate = async ( - context: WorkflowContext, - readmeMd: string[], - statusContext: { status: SDKAutomationState } -) => { - if (context.skipLegacy) { - return; - } - context.logger.log('section', `Call legacy generate`); - - const config = context.swaggerToSdkConfig as LegacySwaggerToSDKConfig; - - for (const readmeMdPath of readmeMd) { - const runGen = async (options: AutoRestOptions) => { - if (typeof options.use !== 'string' || !options.use) { - options.use = context.legacyLangConfig?.generatorPackageName; - } - - const args: string[] = []; - if (options) { - for (const optionName of Object.keys(options)) { - let argument = optionName; - if (!argument.startsWith('--')) { - argument = `--${argument}`; - } - - const optionValue: AutoRestOptionValue = options[optionName]; - if (Array.isArray(optionValue)) { - argument += `=${optionValue.join(',')}`; - } else if (optionValue !== undefined && optionValue !== '') { - argument += `=${optionValue}`; - } - - args.push(argument); - } - } - - args.push(path.relative(context.sdkFolder, path.join(context.specFolder, readmeMdPath))); - - await runSdkAutoCustomScript( - context, - { - path: 'autorest', - stdout: { - showInComment: /(warning|error)/i - }, - stderr: { - showInComment: true, - scriptWarning: /(warning|error)/i - }, - exitCode: { - showInComment: true, - result: 'error' - } - }, - { - cwd: context.sdkFolder, - fallbackName: 'Autorest', - argList: args, - statusContext - } - ); - }; - - const autorestOptions = await getResolvedAutoRestOptions( - path.resolve(context.sdkFolder), - config, - readmeMdPath, - 'autorest_options' - ); - - const autorestOptionsForOtherSDK = await getResolvedAutoRestOptions( - path.resolve(context.sdkFolder), - config, - readmeMdPath, - 'autorest_options_for_otherSDK' - ); - - if (Object.keys(autorestOptionsForOtherSDK).length > 0 && !(autorestOptionsForOtherSDK instanceof Array)) { - await runGen(autorestOptionsForOtherSDK); - context.logger.info('Finish autorest_option_for_otherSDK'); - } - - if (!(autorestOptions instanceof Array)) { - await runGen(autorestOptions); - } else { - for (const autorestOption of autorestOptions) { - await runGen(autorestOption); - } - } - } - - context.logger.log('endsection', `Call legacy generate`); -}; - -export const legacyBuildPackage = async (context: WorkflowContext, pkg: PackageData) => { - if (context.skipLegacy) { - return; - } - const legacyAfterScripts = (context.swaggerToSdkConfig as LegacySwaggerToSDKConfig).meta?.after_scripts ?? []; - context.legacyAfterScripts.push(...legacyAfterScripts); - - const commonRunOptions = { - exitCode: { - showInComment: true, - result: 'error' - }, - stderr: { - showInComment: true - } - } as const; - const commonOptions = { - cwd: context.sdkFolder, - statusContext: pkg - } as const; - - if (context.legacyAfterScripts.length > 0) { - context.logger.log('section', 'Call legacy after_scripts'); - - for (const scriptCmd of context.legacyAfterScripts) { - await runSdkAutoCustomScript(context, { path: scriptCmd, ...commonRunOptions }, commonOptions); - } - - context.logger.log('endsection', 'Call legacy after_scripts'); - } - - switch (context.config.sdkName) { - case 'azure-sdk-for-net': - context.logger.log('section', `Call legacy build for azure-sdk-for-net`); - - const scope = path.basename(path.dirname(pkg.relativeFolderPath)); - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'dotnet', logPrefix: 'msbuild', stdout: { scriptWarning: /\: error / } }, - { - ...commonOptions, - cwd: context.sdkFolder, - argList: ['msbuild', 'eng/mgmt.proj', '/t:CreateNugetPackage', `/p:Scope=${scope}`, '/v:n', '/p:SkipTests=true'] - } - ); - - context.logger.log('endsection', `Call legacy build for azure-sdk-for-net`); - break; - - case 'azure-sdk-for-js': - context.logger.log('section', `Call legacy build for azure-sdk-for-js`); - - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'npm pack --silent', logPrefix: 'npmPack' }, - { ...commonOptions, cwd: path.join(context.sdkFolder, pkg.relativeFolderPath) } - ); - - context.logger.log('endsection', `Call legacy build for azure-sdk-for-js`); - break; - - case 'azure-cli-extensions': - context.logger.log('section', `Call legacy build for azure-cli-extensions`); - - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'python', logPrefix: 'pkgBuild' }, - { - ...commonOptions, - cwd: context.sdkFolder, - argList: ['./scripts/automation/build_package.py', '--dest', pkg.relativeFolderPath, pkg.relativeFolderPath] - } - ); - - context.logger.log('endsection', `Call legacy build for azure-cli-extensions`); - break; - - case 'azure-sdk-for-python': - case 'azure-sdk-for-python-track2': - context.logger.log('section', `Call legacy build for azure-sdk-for-python`); - - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'pip', logPrefix: 'buildConfInit' }, - { ...commonOptions, argList: ['install', '-e', './tools/azure-sdk-tools/'] } - ); - let pkgName = pkg.name; - const prefix = context.legacyLangConfig?.packageNameAltPrefix; - if (prefix !== undefined) { - pkgName = pkgName.substr(prefix.length); - } - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'python', logPrefix: 'buildConf' }, - { - ...commonOptions, - cwd: path.join(context.sdkFolder, path.dirname(pkg.relativeFolderPath)), - argList: ['-m', 'packaging_tools', '--build-conf', pkgName] - } - ); - await runSdkAutoCustomScript( - context, - { ...commonRunOptions, path: 'python', logPrefix: 'buildPackage' }, - { ...commonOptions, argList: ['./build_package.py', '--dest', pkg.relativeFolderPath, pkg.relativeFolderPath] } - ); - await runSdkAutoCustomScript( - context, - { - ...commonRunOptions, - path: 'python', - logPrefix: 'changelogSetup', - exitCode: { showInComment: true, result: 'warning' } - }, - { ...commonOptions, argList: ['./scripts/dev_setup.py', '-p', pkgName] } - ); - await runSdkAutoCustomScript( - context, - { - ...commonRunOptions, - path: 'python', - logPrefix: 'changelogReport', - exitCode: { showInComment: true, result: 'warning' } - }, - { ...commonOptions, argList: ['-m', 'packaging_tools.code_report', pkgName] } - ); - await runSdkAutoCustomScript( - context, - { - ...commonRunOptions, - exitCode: { showInComment: true, result: 'warning' }, - path: 'python', - logPrefix: 'changelogReportLatest' - }, - { ...commonOptions, argList: ['-m', 'packaging_tools.code_report', pkgName, '--last-pypi'] } - ); - - let reportPattern = `code_reports/**/merged_report.json`; - let reportFiles = glob.sync(reportPattern, { cwd: path.join(context.sdkFolder, pkg.relativeFolderPath) }); - if (reportFiles.length !== 2) { - reportPattern = `code_reports/**/*.json`; - reportFiles = glob.sync(reportPattern, { cwd: path.join(context.sdkFolder, pkg.relativeFolderPath) }); - if (reportFiles.length !== 2) { - context.logger.warn('Not exact 2 reports found:'); - for (const filePath of reportFiles) { - context.logger.warn(`\t${filePath}`); - } - context.logger.warn('Not generating changelog.'); - setSdkAutoStatus(context, 'warning'); - break; - } - } - - if (reportFiles[0].startsWith('code_reports/latest')) { - const tmp = reportFiles[0]; - reportFiles[0] = reportFiles[1]; - reportFiles[1] = tmp; - } - - const changelogs: string[] = []; - const captureTransport = new CommentCaptureTransport({ - output: changelogs, - extraLevelFilter: ['cmderr', 'cmdout'] - }); - context.logger.add(captureTransport); - await runSdkAutoCustomScript( - context, - { - ...commonRunOptions, - exitCode: { showInComment: true, result: 'warning' }, - stdout: { showInComment: true }, - stderr: { showInComment: true }, - path: 'python', - logPrefix: 'Changelog' - }, - { - ...commonOptions, - cwd: path.join(context.sdkFolder, pkg.relativeFolderPath), - argList: ['-m', 'packaging_tools.change_log', reportFiles[0], reportFiles[1]] - } - ); - context.logger.remove(captureTransport); - - for (const changelog of changelogs) { - if (changelog.indexOf('Breaking changes') !== -1) { - context.logger.warn(`Breaking change found in changelog`); - pkg.hasBreakingChange = true; - break; - } - } - - context.logger.log('endsection', `Call legacy build for azure-sdk-for-python`); - break; - } -}; - -export const legacyInstallInstruction = async (context: WorkflowContext, pkg: PackageData, syncConfig: SyncConfig) => { - if (context.skipLegacy) { - return; - } - const getInstallInstruction = async (option?: InstallationInstructions): Promise => { - if (!option) { - return undefined; - } - let result = option; - if (typeof option === 'function') { - result = await option({ - packageName: pkg.name, - artifactDownloadCommand: (url, fileName) => - context.config.storage.downloadCommand.replace('{URL}', url).replace('{FILENAME}', fileName), - artifactUrls: pkg.artifactBlobUrls!, - generationRepositoryUrl: `https://github.com/${repoKeyToString(context.sdkRepoConfig.integrationRepository)}`, - package: { - context: { - isPublic: !context.legacyLangConfig?.isPrivatePackage && context.config.storage.isPublic - } - } as SDKRepositoryPackage, - sdkRepositoryGenerationPullRequestHeadBranch: syncConfig.targetBranch - }); - } - if (typeof result === 'string') { - return result; - } - if (Array.isArray(result)) { - return result.join('\n'); - } - return undefined; - }; - - const output: InstallInstructionScriptOutput = { - full: (await getInstallInstruction(context.legacyLangConfig?.installationInstructions)) ?? '', - lite: await getInstallInstruction(context.legacyLangConfig?.liteInstallationInstruction) - }; - return output; -}; - -export const legacyArtifactSearchOption = (context: WorkflowContext, pkg: PackageData) => { - if (context.skipLegacy) { - return; - } - switch (context.config.sdkName) { - case 'azure-sdk-for-net': - if (pkg.status === 'failed') { - return false; - } - return { - searchRegex: new RegExp(`${path.basename(pkg.relativeFolderPath).replace(/\./g, '\\.')}.*nupkg$`), - searchFolder: 'artifacts/packages' - }; - - case 'azure-sdk-for-js': - return { searchRegex: /\.tgz$/ }; - - case 'azure-cli-extensions': - case 'azure-sdk-for-python': - case 'azure-sdk-for-python-track2': - return { searchRegex: /\.(whl|zip)$/ }; - } - return false; -}; diff --git a/tools/spec-gen-sdk/src/automation/logging.ts b/tools/spec-gen-sdk/src/automation/logging.ts index d10000343ea..07a59b47587 100644 --- a/tools/spec-gen-sdk/src/automation/logging.ts +++ b/tools/spec-gen-sdk/src/automation/logging.ts @@ -3,7 +3,7 @@ import { default as Transport } from 'winston-transport'; import { AppendBlobClient } from '@azure/storage-blob'; import { SdkAutoContext } from './entrypoint'; import { PackageData } from '../types/PackageData'; -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from './sdkAutomationState'; export const sdkAutoLogLevels = { levels: { diff --git a/tools/spec-gen-sdk/src/automation/reportStatus.ts b/tools/spec-gen-sdk/src/automation/reportStatus.ts index 69a06b403ed..910d21309d7 100644 --- a/tools/spec-gen-sdk/src/automation/reportStatus.ts +++ b/tools/spec-gen-sdk/src/automation/reportStatus.ts @@ -1,10 +1,10 @@ -import { MessageRecord, sendSuccess, sendFailure } from '@azure/swagger-validation-common'; +import { MessageRecord, sendSuccess, sendFailure } from '../types/Message'; import * as fs from 'fs'; import * as path from 'path'; import * as prettier from 'prettier'; import * as Handlebars from 'handlebars'; -import { getSDKAutomationStateString, SDKAutomationState } from '../sdkAutomationState'; +import { getSDKAutomationStateString, SDKAutomationState } from './sdkAutomationState'; import { setSdkAutoStatus } from '../utils/runScript'; import { FailureType, setFailureType, WorkflowContext } from './workflow'; import { updateBreakingChangesLabel } from './updateBreakingChangesLabels'; @@ -106,7 +106,7 @@ export const sdkAutoReportStatus = async (context: WorkflowContext) => { }; export const prettyFormatHtml = (s: string) => { - return prettier.format(s, { parser: 'html' }).replace(/\/gi, '
\n'); + return prettier.format(s, { parser: 'html' }).replace(/
/gi, '
\n'); }; const commentDetailTemplate = fs.readFileSync(`${__dirname}/../templates/commentDetailNew.handlebars`).toString(); @@ -207,7 +207,7 @@ const renderHandlebarTemplate = ( .replace(/(<\/?[a-z]+>)\s+(<\/?[a-z]+>)/gi, (_, p1, p2) => `${p1}${p2}`) .replace(/(<\/?[a-z]+>)\s+(<\/?[a-z]+>)/gi, (_, p1, p2) => `${p1}${p2}`); - commentBody = commentBody.replace(/\/g, '\n'); + commentBody = commentBody.replace(/
/g, '\n'); return commentBody; }; diff --git a/tools/spec-gen-sdk/src/sdkAutomationState.ts b/tools/spec-gen-sdk/src/automation/sdkAutomationState.ts similarity index 55% rename from tools/spec-gen-sdk/src/sdkAutomationState.ts rename to tools/spec-gen-sdk/src/automation/sdkAutomationState.ts index 9613d053051..22f70f8e497 100644 --- a/tools/spec-gen-sdk/src/sdkAutomationState.ts +++ b/tools/spec-gen-sdk/src/automation/sdkAutomationState.ts @@ -1,5 +1,3 @@ -import { BlobStorageBlockBlob, BlobStoragePrefix, map } from '@ts-common/azure-js-dev-tools'; - /** * The generation status strings for an SDK repository. */ @@ -70,37 +68,6 @@ export function getSDKAutomationStateImageName(state: SDKAutomationState): strin return SDKAutomationStateImageNames[state]; } -/** - * Get the image prefix relative to the SDK Automation application's working prefix. - * @param automationWorkingPrefix The working prefix for the SDK Automation application. - */ -export function getSDKAutomationStateImagePrefix(automationWorkingPrefix: BlobStoragePrefix): BlobStoragePrefix { - return automationWorkingPrefix.getPrefix('images/'); -} - -/** - * Get the image blobs relative to the working prefix for the SDK Automation application. - * @param automationWorkingPrefix The working prefix for the SDK Automation application. - */ -export function getSDKAutomationStateImageBlobs(automationWorkingPrefix: BlobStoragePrefix): BlobStorageBlockBlob[] { - const imagePrefix: BlobStoragePrefix = getSDKAutomationStateImagePrefix(automationWorkingPrefix); - return map(Object.values(SDKAutomationStateImageNames), (imageName: string) => imagePrefix.getBlockBlob(imageName)); -} - -/** - * Get the image blob associated with the provided state. - * @param automationWorkingPrefix The working prefix for the SDK Automation application. - * @param state The state to get the blob for. - */ -export function getSDKAutomationStateImageBlob( - automationWorkingPrefix: BlobStoragePrefix, - state: SDKAutomationState -): BlobStorageBlockBlob { - const imagePrefix: BlobStoragePrefix = getSDKAutomationStateImagePrefix(automationWorkingPrefix); - const imageName: string = getSDKAutomationStateImageName(state); - return imagePrefix.getBlockBlob(imageName); -} - /** * The generation status for an SDK repository. */ diff --git a/tools/spec-gen-sdk/src/automation/updateBreakingChangesLabels.ts b/tools/spec-gen-sdk/src/automation/updateBreakingChangesLabels.ts index 542cfa00b1b..ba5b1366e55 100644 --- a/tools/spec-gen-sdk/src/automation/updateBreakingChangesLabels.ts +++ b/tools/spec-gen-sdk/src/automation/updateBreakingChangesLabels.ts @@ -1,5 +1,5 @@ import { addPullRequestLabelOctokit, getPullRequestLabelsOctokit, removePullRequestLabelOctokit } from '../utils/githubUtils'; -import { sdkLabels } from '@azure/swagger-validation-common'; +import { sdkLabels } from '../types/sdks'; import { WorkflowContext } from './workflow'; /** @@ -39,8 +39,7 @@ export async function updateBreakingChangesLabel( // Using Github config setting. To control which language's breaking change label should be processed. const sdkBreakingChangesLabel = - context.swaggerToSdkConfig.packageOptions.breakingChangesLabel ?? - context.legacyLangConfig?.breakingChangesLabel?.name; + context.swaggerToSdkConfig.packageOptions.breakingChangesLabel; // Support language: azure-sdk-for-go azure-sdk-for-js azure-sdk-for-python const sdkNameList = ['azure-sdk-for-go', 'azure-sdk-for-js', 'azure-sdk-for-python']; diff --git a/tools/spec-gen-sdk/src/automation/workflow.ts b/tools/spec-gen-sdk/src/automation/workflow.ts index 03a6afd0f31..1a26b7cd456 100644 --- a/tools/spec-gen-sdk/src/automation/workflow.ts +++ b/tools/spec-gen-sdk/src/automation/workflow.ts @@ -27,18 +27,16 @@ import { writeTmpJsonFile } from '../utils/fsUtils'; import { GenerateInput } from '../types/GenerateInput'; -import { legacyGenerate, legacyInit } from './legacy'; import { GenerateOutput, getGenerateOutput } from '../types/GenerateOutput'; import { getPackageData, PackageData } from '../types/PackageData'; import { workflowPkgMain } from './workflowPackage'; -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from './sdkAutomationState'; import { CommentCaptureTransport, getBlobName } from './logging'; -import { findSwaggerToSDKConfiguration } from '@ts-common/azure-js-dev-tools'; -import { SwaggerToSDKConfiguration as LegacySwaggerToSdkConfig } from '../swaggerToSDKConfiguration'; -import { ReadmeMdFileProcessMod } from '../langSpecs/languageConfiguration'; +import { findSwaggerToSDKConfiguration } from '../utils/readme'; import { getInitOutput } from '../types/InitOutput'; -import { MessageRecord, sdkSuppressionsFileName, SdkSuppressionsYml, SdkPackageSuppressionsEntry, parseYamlContent, validateSdkSuppressionsFile } from '@azure/swagger-validation-common'; -import { removeDuplicatesFromRelatedFiles } from '../utils/utils'; +import { MessageRecord } from '../types/Message'; +import { sdkSuppressionsFileName, SdkSuppressionsYml, SdkPackageSuppressionsEntry, validateSdkSuppressionsFile } from '../types/sdkSuppressions'; +import { parseYamlContent, removeDuplicatesFromRelatedFiles } from '../utils/utils'; import { SDKSuppressionContentList } from '../utils/handleSuppressionLines'; export const remoteIntegration = 'integration'; @@ -147,9 +145,8 @@ export const workflowMain = async (context: WorkflowContext) => { const callMode = context.swaggerToSdkConfig.advancedOptions.generationCallMode ?? - context.legacyLangConfig?.readmeMdFileProcessMod ?? 'one-for-all-configs'; - if (callMode === 'one-for-all-configs' || callMode === ReadmeMdFileProcessMod.Batch) { + if (callMode === 'one-for-all-configs') { await workflowHandleReadmeMdOrTypeSpecProject(context, changedSpecs); } else { for (const changedSpec of changedSpecs) { @@ -506,8 +503,7 @@ const workflowInitSdkRepo = async ( swaggerToSdkConfig: SwaggerToSdkConfig ) => { const cloneDir = - swaggerToSdkConfig.advancedOptions.cloneDir ?? - (swaggerToSdkConfig as LegacySwaggerToSdkConfig).meta?.advanced_options?.clone_dir; + swaggerToSdkConfig.advancedOptions.cloneDir; const sdkFolderName = cloneDir ? path.join(sdkRepoConfig.mainRepository.name, cloneDir) : sdkRepoConfig.mainRepository.name; @@ -564,9 +560,9 @@ const fileInitOutput = 'initOutput.json'; const workflowCallInitScript = async (context: WorkflowContext) => { const initScriptConfig = context.swaggerToSdkConfig.initOptions?.initScript; if (initScriptConfig === undefined) { - context.logger.log('warn', `Skip initScript due to not configured`); - await legacyInit(context); - return; + context.logger.error('ConfigError: initScript is not configured in the swagger-to-sdk config. Please refer to the schema.'); + setFailureType(context, FailureType.PipelineFrameworkFailed); + throw new Error('The initScript is not configured in the swagger-to-sdk config. Please refer to the schema.'); } writeTmpJsonFile(context, fileInitInput, {}); @@ -724,15 +720,9 @@ const workflowCallGenerateScript = async ( }; if (context.swaggerToSdkConfig.generateOptions.generateScript === undefined) { - // Fallback to legacy autorest - try { - await legacyGenerate(context, relatedReadmeMdFiles, statusContext); - } catch (e) { - setFailureType(context, FailureType.CodegenFailed); - throw e; - } - setSdkAutoStatus(context, statusContext.status); - return { ...statusContext, generateInput, generateOutput }; + context.logger.error('ConfigError: generateScript is not configured in the swagger-to-sdk config. Please refer to the schema.'); + setFailureType(context, FailureType.PipelineFrameworkFailed); + throw new Error('The generateScript is not configured in the swagger-to-sdk config. Please refer to the schema.'); } context.logger.log('section', 'Call generateScript'); @@ -805,46 +795,13 @@ const workflowSaveGenerateResult = async (context: WorkflowContext) => { const workflowDetectChangedPackages = async (context: WorkflowContext, fileList: string[], readmeMdList: string[]) => { context.logger.log('section', 'Detect changed packages'); if (context.pendingPackages.length === 0) { - let searchConfig = context.swaggerToSdkConfig.packageOptions.packageFolderFromFileSearch; - if (searchConfig === false) { - context.logger.warn(`Warning: Skip detecting changed packages based on the config in readme.md. Please refer to the schema https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/sdkautomation/SwaggerToSdkConfigSchema.json for 'packageOptions' configuration.`); + const searchConfig = context.swaggerToSdkConfig.packageOptions.packageFolderFromFileSearch; + if (!searchConfig) { + context.logger.warn(`Warning: Skip detecting changed packages based on the config in swagger_to_sdk.config. Please refer to the schema https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/sdkautomation/SwaggerToSdkConfigSchema.json for 'packageOptions' configuration.`); return; } - if (searchConfig === undefined) { - const legacyFilenameConfig = context.legacyLangConfig?.packageRootFileName; - if (!legacyFilenameConfig) { - throw new Error('N/A (this code has been deprecated)'); - } - searchConfig = { - packageNamePrefix: context.legacyLangConfig?.packageNameAltPrefix, - searchRegex: - typeof legacyFilenameConfig === 'string' - ? new RegExp(`^${legacyFilenameConfig.replace('.', '\\.')}$`) - : legacyFilenameConfig - }; - } - context.logger.info(`Package from changed file search: ${searchConfig.searchRegex}`); - const packageFolderList = await searchRelatedParentFolders(fileList, { - rootFolder: context.sdkFolder, - searchFileRegex: searchConfig.searchRegex - }); - for (const packageFolderPath of Object.keys(packageFolderList)) { - let packageName = await context.legacyLangConfig?.packageNameCreator?.( - context.sdkFolder, - packageFolderPath, - readmeMdList[0] - ); - if (packageName && context.legacyLangConfig?.packageNameAltPrefix) { - packageName = context.legacyLangConfig.packageNameAltPrefix + packageName; - } - context.pendingPackages.push( - getPackageData(context, { - packageName, - path: [packageFolderPath], - result: 'succeeded' - }) - ); - } + //TODO can we delete this? + context.logger.info(`TODO ${fileList.length * readmeMdList.length}`); } context.logger.info(`${context.pendingPackages.length} packages found after generation:`); diff --git a/tools/spec-gen-sdk/src/automation/workflowPackage.ts b/tools/spec-gen-sdk/src/automation/workflowPackage.ts index 27e71146ce1..2b8a22a902e 100644 --- a/tools/spec-gen-sdk/src/automation/workflowPackage.ts +++ b/tools/spec-gen-sdk/src/automation/workflowPackage.ts @@ -8,7 +8,6 @@ import { deleteTmpJsonFile, readTmpJsonFile, writeTmpJsonFile } from '../utils/f import { RepoKey, repoKeyToString } from '../utils/githubUtils'; import { gitCheckoutBranch, gitGetCommitter } from '../utils/gitUtils'; import { isLineMatch, runSdkAutoCustomScript, setSdkAutoStatus } from '../utils/runScript'; -import { legacyArtifactSearchOption, legacyBuildPackage, legacyInstallInstruction } from './legacy'; import { CommentCaptureTransport, getBlobName, loggerStorageAccountTransport } from './logging'; import { branchMain, @@ -50,7 +49,7 @@ export const workflowPkgMain = async (context: WorkflowContext, pkg: PackageData await workflowPkgDetectArtifacts(context, pkg); await workflowPkgSaveSDKArtifact(context, pkg); await workflowPkgSaveApiViewArtifact(context, pkg); - await workflowPkgCallInstallInstructionScript(context, pkg, syncConfig); + await workflowPkgCallInstallInstructionScript(context, pkg); await pushBranchPromise; await workflowPkgUpdatePR(context, pkg, syncConfig); @@ -64,7 +63,7 @@ export const workflowPkgMain = async (context: WorkflowContext, pkg: PackageData const workflowPkgCallBuildScript = async (context: WorkflowContext, pkg: PackageData) => { const runOptions = context.swaggerToSdkConfig.packageOptions.buildScript; if (!runOptions) { - await legacyBuildPackage(context, pkg); + context.logger.info('buildScript of packageOptions is not configured in swagger_to_sdk_config.json.'); return; } @@ -119,14 +118,7 @@ const workflowPkgCallChangelogScript = async (context: WorkflowContext, pkg: Pac }; const workflowPkgDetectArtifacts = async (context: WorkflowContext, pkg: PackageData) => { - let searchOption = context.swaggerToSdkConfig.artifactOptions.artifactPathFromFileSearch; - if (searchOption === undefined) { - searchOption = legacyArtifactSearchOption(context, pkg); - if (searchOption) { - context.logger.info(`Use legacy artifact search option`); - } - } - + const searchOption = context.swaggerToSdkConfig.artifactOptions.artifactPathFromFileSearch; if (!searchOption) { context.logger.info(`Skip artifact search`); return; @@ -224,19 +216,11 @@ const fileInstallInstructionInput = 'installInstructionInput.json'; const fileInstallInstructionOutput = 'installInstructionOutput.json'; const workflowPkgCallInstallInstructionScript = async ( context: WorkflowContext, - pkg: PackageData, - syncConfig: SyncConfig + pkg: PackageData ) => { const runOptions = context.swaggerToSdkConfig.artifactOptions.installInstructionScript; if (!runOptions) { - const legacyResult = await legacyInstallInstruction(context, pkg, syncConfig); - if (legacyResult === undefined) { - context.logger.info('Skip installInstructionScript'); - } else { - context.logger.info(`Legacy InstallInstruction`); - pkg.installationInstructions = legacyResult.full; - pkg.liteInstallationInstruction = legacyResult.lite; - } + context.logger.info('Skip installInstructionScript'); return; } diff --git a/tools/spec-gen-sdk/src/blobProxy.ts b/tools/spec-gen-sdk/src/blobProxy.ts deleted file mode 100644 index 244cab331c8..00000000000 --- a/tools/spec-gen-sdk/src/blobProxy.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BlobStorageBlob, BlobStoragePrefix } from '@ts-common/azure-js-dev-tools'; - -/** - * An interface that can create blob proxy URLs from blob URLs and that can resolve blob proxy URLs - * back to their original blob URLs. - */ -export interface BlobProxy { - /** - * Get the blob proxy URL for the provided blob. - * @param blob The blob to get a proxy URL for. - * @returns The blob proxy URL for the provided blob. - */ - getProxyURL(workingPrefix: BlobStoragePrefix, blob: BlobStorageBlob): string; - /** - * Get the blob URL for the provided blob proxy URL. - * @param blobProxyURL The proxy URL to get the blob URL for. - * @param The blob URL for the provided blob proxy URL. - */ - resolveProxyURL(workingPrefix: BlobStoragePrefix, blobProxyURL: string): Promise; -} diff --git a/tools/spec-gen-sdk/src/cli/cli.ts b/tools/spec-gen-sdk/src/cli/cli.ts index e9d84fe6528..c50bfa25569 100644 --- a/tools/spec-gen-sdk/src/cli/cli.ts +++ b/tools/spec-gen-sdk/src/cli/cli.ts @@ -1,14 +1,7 @@ -import { getRepository } from '@ts-common/azure-js-dev-tools'; +import { getRepository } from '../utils/githubUtils'; import { sdkAutoMain } from '../automation/entrypoint'; -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from '../automation/sdkAutomationState'; import { sdkAutomationCliConfig } from './config'; -// import { cliMain } from './main'; - -// tslint:disable-next-line: no-floating-promises -// cliMain(sdkAutomationCliConfig).catch(e => { -// console.error(e); -// process.exit(-1); -// }); // tslint:disable-next-line: no-floating-promises (async () => { diff --git a/tools/spec-gen-sdk/src/cli/main.ts b/tools/spec-gen-sdk/src/cli/main.ts deleted file mode 100644 index 1085b701e63..00000000000 --- a/tools/spec-gen-sdk/src/cli/main.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { SDKAutomation } from '../sdkAutomation'; -import { - getRepository, - AzureBlobStorage, - RealGitHub, - ExecutableGit, - StringMap, - getGitHubRepositoryFromUrl -} from '@ts-common/azure-js-dev-tools'; -import { getAzureDevOpsLogger, Logger, timestamps } from '@azure/logger-js'; -import { Octokit } from '@octokit/rest'; -import { createAppAuth } from '@octokit/auth-app'; -import { App as GithubApp } from '@octokit/app'; -import { SDKAutomationCliConfig } from './config/schema'; -import { RealBlobProxy } from '../realBlobProxy'; - -interface Clients { - github: RealGitHub; - git: ExecutableGit; -} - -export const getClientsWithAccessToken = (config: SDKAutomationCliConfig, logger: Logger): Clients => { - const { githubToken, githubApp: appConfig } = config; - - if (githubToken) { - return { - github: RealGitHub.fromToken(githubToken), - git: new ExecutableGit({ - authentication: githubToken - }) - }; - } - - const githubApp = new GithubApp(appConfig); - - const installationIdCache: StringMap = {}; - const getInstallationId = async (scope: string) => { - let installationId = installationIdCache[scope]; - if (installationId === undefined) { - const jwtToken = githubApp.getSignedJsonWebToken(); - const octokit = new Octokit({ - auth: `Bearer ${jwtToken}`, - previews: ['machine-man'] - }); - try { - const { - data: { id } - } = await octokit.apps.getOrgInstallation({ org: scope }); - installationId = id; - installationIdCache[scope] = id; - } catch (e) { - try { - const { - data: { id } - } = await octokit.apps.getUserInstallation({ username: scope }); - installationId = id; - installationIdCache[scope] = id; - await logger.logError(JSON.stringify(e)); - } catch (e) { - await logger.logError(`GithubApp ${appConfig.id} doesn't have installation for: ${scope}`); - await logger.logError(JSON.stringify(e)); - return undefined; - } - } - } - - return installationId; - }; - const getAccessToken = async (scope: string) => { - const installationId = await getInstallationId(scope); - return installationId === undefined ? undefined : githubApp.getInstallationAccessToken({ installationId }); - }; - - return { - github: RealGitHub.fromOctokit( - async (scope: string): Promise => { - const installationId = await getInstallationId(scope); - return new Octokit({ - authStrategy: createAppAuth, - auth: { - appId: appConfig.id, - privateKey: appConfig.privateKey, - installationId - } - }) as Octokit; - } - ), - git: new ExecutableGit({ - authentication: async (url: string) => { - const repo = getGitHubRepositoryFromUrl(url); - const token = await getAccessToken(repo!.owner); - return token ? `x-access-token:${token}` : undefined; - } - }) - }; -}; - -export const cliMain = async (config: SDKAutomationCliConfig) => { - const workingFolder = 'work'; - - const { - executionMode, - isTriggeredByUP, - prNumber, - sdkRepoName, - specRepo, - blobStorage: blobConfig, - githubCommentAuthorName - } = config; - - const logger = timestamps(getAzureDevOpsLogger()); - - const blobStorage = new AzureBlobStorage(blobConfig.name); - const blobStoragePrefix = blobStorage.getPrefix(blobConfig.prefix); - const clients = getClientsWithAccessToken(config, logger); - - const repo = getRepository(specRepo); - // Refresh PR ahead of time to refresh merge commit to avoid unadvertised object error - await logger.logInfo(`Refreshing merge commit for PR ${prNumber}`); - await clients.github.getPullRequest(repo, prNumber); - let launchAutomation: () => Promise; - - const sdkAutomation = new SDKAutomation(workingFolder, { - buildID: config.azureCliArgs.buildId, - logger, - githubCommentAuthorName, - deleteClonedRepositories: false, - createGenerationPullRequests: true, - blobProxy: new RealBlobProxy(config.blobStorage.name), - downloadCommandTemplate: config.blobStorage.downloadCommand, - isPublic: config.blobStorage.isPublic, - ...clients - }); - - switch (executionMode) { - case 'SDK_FILTER': { - launchAutomation = () => - sdkAutomation.filterSDKReposToTrigger(repo, prNumber, blobStoragePrefix, isTriggeredByUP); - break; - } - default: { - launchAutomation = () => - sdkAutomation.pipelineTrigger(repo, prNumber, blobStoragePrefix, sdkRepoName, isTriggeredByUP); - break; - } - } - - try { - await launchAutomation(); - } catch (e) { - if (e.message && e.message.indexOf('Server does not allow request for unadvertised object') > -1) { - await logger.logWarning('Failed to retrieve merge commit. Retrying...'); - await launchAutomation(); - } else { - throw e; - } - } -}; diff --git a/tools/spec-gen-sdk/src/fakeBlobProxy.ts b/tools/spec-gen-sdk/src/fakeBlobProxy.ts deleted file mode 100644 index a5611eda91c..00000000000 --- a/tools/spec-gen-sdk/src/fakeBlobProxy.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BlobStorageBlob, BlobStoragePrefix } from '@ts-common/azure-js-dev-tools'; -import { BlobProxy } from './blobProxy'; - -/** - * A BlobProxy implementation that doesn't proxy blob URLs. - */ -export class FakeBlobProxy implements BlobProxy { - public getProxyURL(_workingPrefix: BlobStoragePrefix, blob: BlobStorageBlob): string { - return blob.getURL(); - } - - public resolveProxyURL(_workingPrefix: BlobStoragePrefix, blobProxyURL: string): Promise { - return Promise.resolve(blobProxyURL); - } -} diff --git a/tools/spec-gen-sdk/src/index.ts b/tools/spec-gen-sdk/src/index.ts deleted file mode 100644 index a840b789054..00000000000 --- a/tools/spec-gen-sdk/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { dotnet as csharp } from './langSpecs/langs/dotnet'; -export { go } from './langSpecs/langs/go'; -export { java } from './langSpecs/langs/java'; -export { javascript } from './langSpecs/langs/javascript'; -export * from './langSpecs/languageConfiguration'; -export { python } from './langSpecs/langs/python'; -export * from './sdkAutomation'; -export * from './specificationPREvent'; -export { ruby } from './langSpecs/langs/ruby'; -export { cli } from './langSpecs/langs/cli'; -export { trenton } from './langSpecs/langs/trenton'; -export { azureresourceschema } from './langSpecs/langs/azureresourceschema'; diff --git a/tools/spec-gen-sdk/src/langSpecs/generateBreakingChnageReport.ts b/tools/spec-gen-sdk/src/langSpecs/generateBreakingChnageReport.ts deleted file mode 100644 index f1c85239bd9..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/generateBreakingChnageReport.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { RunOptions } from '@ts-common/azure-js-dev-tools'; -import { SDKRepositoryPackage } from './sdkRepositoryPackage'; - -export type BreakingChangeReportOptions = RunOptions & { - changedPackage: SDKRepositoryPackage; - captureOutput: (logLine: string) => void, - captureError: (logLine: string) => void, - captureChangeLog: (logLine: string, containsBreakingChange?: boolean) => void, -}; - -export type GenerateBreakingChangeReportOptions = (option: BreakingChangeReportOptions) => Promise; diff --git a/tools/spec-gen-sdk/src/langSpecs/installationInstructions.ts b/tools/spec-gen-sdk/src/langSpecs/installationInstructions.ts deleted file mode 100644 index 6816c9c7dab..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/installationInstructions.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { SDKRepositoryPackage } from './sdkRepositoryPackage'; - -/** - * The options that will be provided when generating installation instructions. - */ -export interface InstallationInstructionsOptions { - /** - * The name of the package. - */ - packageName: string; - /** - * The URLs that the package artifacts can be downloaded from. - */ - artifactUrls: string[]; - /** - * The URL to the generation repository. - */ - generationRepositoryUrl: string; - /** - * The name of the head branch for the SDK repository's generation pull request. - */ - sdkRepositoryGenerationPullRequestHeadBranch: string; - - artifactDownloadCommand: (url: string, fileName: string) => string; - - package: SDKRepositoryPackage; -} - -/** - * The types that can be used to generate installation instructions. - */ -export type InstallationInstructions = - | string - | string[] - | Promise - | ((options: InstallationInstructionsOptions) => string | string[] | Promise); diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/azureresourceschema.ts b/tools/spec-gen-sdk/src/langSpecs/langs/azureresourceschema.ts deleted file mode 100644 index 22a9a413e74..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/azureresourceschema.ts +++ /dev/null @@ -1,56 +0,0 @@ -import path from 'path'; -import { ReadmeMdFileProcessMod, LanguageConfiguration } from '../languageConfiguration'; -import { toArray } from '@ts-common/azure-js-dev-tools'; -import { Logger } from '@azure/logger-js'; - -/** - * A language configuration for AzureResourceSchema. - */ -export const azureresourceschema: LanguageConfiguration = { - name: 'AzureResourceSchema', - generatorPackageName: '@microsoft.azure/autorest.azureresourceschema', - aliases: ['azure-resource-manager-schemas'], - packageRootFileName: 'common', - readmeMdFileProcessMod: ReadmeMdFileProcessMod.Sequencial, - keepReleasePROpen: true, - packageNameCreator: getPackageName, - RunnerReportLoggerCreator: getRunnerReportLogger -}; - -/** - * Get the name of the package from the package.json file found in the package folder. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -export function getPackageName(rootedRepositoryFolderPath: string, - relativePackageFolderPath: string, readmeMdFileUrl: string): string { - return path.basename(path.dirname(path.dirname(readmeMdFileUrl))); -} - -export function getRunnerReportLogger(output: string[]): Logger { - const logFn = (text: string | string[]) => { - if (text instanceof Array && (!text.join('.').includes('node') - || text.join('.').includes('PostProcessor'))) { - output.push(...toArray(text)); - } - return Promise.resolve(); - }; - - const logRes = (text: string | string[]) => { - if (text instanceof Array && (text.join('.').includes('PostProcessor') - || text.join('.').includes('passing') || text.join('.').includes('failing'))) { - output.push(...toArray(text)); - } - return Promise.resolve(); - }; - - const dummyFn = () => Promise.resolve(); - - return { - logError: logFn, - logWarning: logFn, - logInfo: logRes, - logSection: dummyFn, - logVerbose: dummyFn - }; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/cli.ts b/tools/spec-gen-sdk/src/langSpecs/langs/cli.ts deleted file mode 100644 index 828f99206cb..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/cli.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { getChildFilePaths, getPathName, run, getName } from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; - -/** - * A language configuration for Python. - */ -export const cli: LanguageConfiguration = { - name: 'Cli', - generatorPackageName: 'autorest.cli', - packageRootFileName: /^setup.cfg$/, - packageNameCreator: getPackageName, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions, - liteInstallationInstruction: genLiteInstruction -}; - -/** - * Get the name of the package from the relative package folder path. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -export function getPackageName(_rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - return getPathName(relativePackageFolderPath); -} - -export function genLiteInstruction(options: InstallationInstructionsOptions): string[] { - let wheelFile: string = ''; - for (const artifactUrl of options.artifactUrls) { - if (artifactUrl.endsWith('whl')) { - wheelFile = artifactUrl; - } - } - const result: string[] = options.package.context.isPublic - ? [`az extension add --source=${wheelFile}`] - : [ - options.artifactDownloadCommand(wheelFile, getName(wheelFile)), - `az extension add --source=${getName(wheelFile)}` - ]; - result.push(``); - return result; -} - -export async function createPackage(options: PackageCommandOptions): Promise { - await run( - 'python', - [ - './scripts/automation/build_package.py', - '--dest', - options.rootedPackageFolderPath, - options.relativePackageFolderPath - ], - { - ...options, - executionFolderPath: options.repositoryFolderPath, - capturePrefix: 'build_package' - } - ); - return (await getChildFilePaths(options.rootedPackageFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.whl') || filePath.endsWith('.zip'), - recursive: false - }))!; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - let wheelFile: string = ''; - for (const artifactUrl of options.artifactUrls) { - if (artifactUrl.endsWith('whl')) { - wheelFile = artifactUrl; - } - } - const result: string[] = [ - `(message created by the CI based on PR content)`, - `# Installation instruction`, - `## Package ${options.packageName}`, - `You can install the package \`${options.packageName}\` of this PR using the following command:`, - `Please install the latest Azure CLI and try this`, - `
`
-  ]
-    .concat(
-      options.package.context.isPublic
-        ? [``, `az extension add --source=${wheelFile}`]
-        : [
-            ``,
-            options.artifactDownloadCommand(wheelFile, getName(wheelFile)),
-            `az extension add --source=${getName(wheelFile)}`
-          ]
-    )
-    .concat([`
`, `# Direct download`, ``, `Your files can be directly downloaded here:`, ``]); - for (const artifactUrl of options.artifactUrls) { - result.push(`- [${getPathName(artifactUrl)}](${artifactUrl})`); - } - result.push(``); - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/dotnet.ts b/tools/spec-gen-sdk/src/langSpecs/langs/dotnet.ts deleted file mode 100644 index 54432a4d408..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/dotnet.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - getChildFilePaths, - getParentFolderPath, - getPathName, - run, - RunOptions, - RunResult -} from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; - -/** - * A language configuration for C#. - */ -export const dotnet: LanguageConfiguration = { - name: '.NET', - generatorPackageName: '@microsoft.azure/autorest.csharp', - aliases: ['C#', 'CSharp', 'C-Sharp', 'CS', 'NET', 'DotNET', 'Dot-NET'], - packageRootFileName: /.*\.sln|^src$/, - packageNameCreator: getPackageName, - afterGenerationCommands: createNugetPackage, - packageCommands: findPackage, - installationInstructions: getInstallationInstructions -}; - -/** - * Get the name of the package from the relative package folder path. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -export function getPackageName(_rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - return getPathName(relativePackageFolderPath); -} - -export async function createNugetPackage(options: PackageCommandOptions): Promise { - const runOptions: RunOptions = { - ...options, - capturePrefix: 'MSBuild', - executionFolderPath: options.repositoryFolderPath - }; - const scope: string = getPathName(getParentFolderPath(options.relativePackageFolderPath)); - const dotnetResult: RunResult = await run( - 'dotnet', - ['msbuild', 'build.proj', '/t:CreateNugetPackage', `/p:Scope=${scope}`, '/v:n', '/p:SkipTests=true'], - runOptions - ); - if (dotnetResult.error) { - await options.logger.logError(dotnetResult.error.toString()); - } -} - -export async function findPackage(options: PackageCommandOptions): Promise { - const packagePrefix: string = getPathName(options.relativePackageFolderPath); - const packageSuffix = 'nupkg'; - await options.logger.logInfo( - `Looking for files that match "${packagePrefix}*${packageSuffix}" in "${options.repositoryFolderPath}...` - ); - return ( - (await getChildFilePaths(options.repositoryFolderPath, { - recursive: true, - fileCondition: (filePath: string) => { - const fileName: string = getPathName(filePath); - return fileName.startsWith(packagePrefix) && fileName.endsWith(packageSuffix); - } - })) || [] - ); -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - const localFeedsUrl = `https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds`; - return [ - `## Installation Instructions`, - `In order to use the [generated nuget package](${options.artifactUrls[0]}) in your app, \ - you will have to use it from a private feed.`, - `To create a private feed, see the following link:`, - `[${localFeedsUrl}](${localFeedsUrl})`, - `This will allow you to create a new local feed and add the location of the new feed as one of the sources.`, - `## Direct Download`, - `The generated package can be directly downloaded from here:`, - `- [${options.packageName}](${options.artifactUrls[0]})` - ]; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/dotnetTrack2.ts b/tools/spec-gen-sdk/src/langSpecs/langs/dotnetTrack2.ts deleted file mode 100644 index f7f1de79bd3..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/dotnetTrack2.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageConfiguration } from '../languageConfiguration'; -import { getPackageName, createNugetPackage, findPackage, getInstallationInstructions } from './dotnet'; - -/** - * A language configuration for C#. - */ -export const dotnetTrack2: LanguageConfiguration = { - name: '.NET Track2', - generatorPackageName: '@autorest/csharp-v3', - aliases: ['NET-Track2'], - packageRootFileName: /.*\.sln|^src$/, - packageNameCreator: getPackageName, - afterGenerationCommands: createNugetPackage, - packageCommands: findPackage, - packageNameAltPrefix: 'track2_', - installationInstructions: getInstallationInstructions -}; diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/go.ts b/tools/spec-gen-sdk/src/langSpecs/langs/go.ts deleted file mode 100644 index 4e84e96b447..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/go.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - copyFolder, - createFolder, - deleteFolder, - joinPath, - replaceAll, - where, - pathRelativeTo, - copyFile -} from '@ts-common/azure-js-dev-tools'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; -import { InstallationInstructionsOptions } from '../installationInstructions'; - -/** - * A language configuration for Go. - */ -export const go: LanguageConfiguration = { - name: 'Go', - generatorPackageName: '@microsoft.azure/autorest.go', - packageRootFileName: 'client.go', - packageNameCreator: getPackageName, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions -}; - -/** - * Get the name of the package from the relative package folder path. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -function getPackageName(_rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - const firstSlashIndex: number = relativePackageFolderPath.indexOf('/'); - const lastSlashIndex: number = relativePackageFolderPath.lastIndexOf('/'); - return relativePackageFolderPath.substring(firstSlashIndex + 1, lastSlashIndex); -} - -async function createPackage(options: PackageCommandOptions): Promise { - let zipFilePath: string; - const zipFolderPath: string = await createGoZipFolder(options); - try { - await copyGoProfilesToZipFolder(options, zipFolderPath); - await copyGoPackageToZipFolder(options, zipFolderPath); - zipFilePath = await createGoPackageZipFile(options, zipFolderPath); - } finally { - await options.logger.logSection(`Deleting ${zipFolderPath}...`); - await deleteFolder(zipFolderPath); - } - return zipFilePath; -} - -/** - * Create the zip folder that the Go package zip file will be created from. - * @param options The package command options. - */ -async function createGoZipFolder(options: PackageCommandOptions): Promise { - const zipFolderPath: string = joinPath(options.repositoryFolderPath, 'zip'); - await options.logger.logSection(`Creating folder ${zipFolderPath}...`); - await createFolder(zipFolderPath); - return zipFolderPath; -} - -/** - * Copy the Go package source code folder to the zip folder. - * @param options The package command options. - * @param zipFolderPath The path to the zip folder. - */ -async function copyGoPackageToZipFolder(options: PackageCommandOptions, zipFolderPath: string): Promise { - const zipPackageFolderPath: string = joinPath(zipFolderPath, options.relativePackageFolderPath); - await options.logger.logSection(`Copying ${options.rootedPackageFolderPath} to ${zipPackageFolderPath}...`); - await copyFolder(options.rootedPackageFolderPath, zipPackageFolderPath); -} - -/** - * Copy the Go profiles folder to the zip folder. - * @param options The package command options. - * @param zipFolderPath The path to the zip folder. - */ -async function copyGoProfilesToZipFolder(options: PackageCommandOptions, zipFolderPath: string): Promise { - const profilesFolderPath: string = joinPath(options.repositoryFolderPath, 'profiles'); - const zipProfilesFolderPath: string = joinPath(zipFolderPath, 'profiles'); - const changedProfilesFilePaths: string[] = where(options.changedFilePaths, (changedFilePath: string) => - changedFilePath.startsWith(profilesFolderPath) - ); - if (changedProfilesFilePaths.length === 0) { - await options.logger.logSection( - `Not copying anything from the profiles folder since no profile files were changed.` - ); - } else { - await options.logger.logSection( - `Copying ${changedProfilesFilePaths.length} changed files ` + - `from ${profilesFolderPath} to ${zipProfilesFolderPath}...` - ); - let copyNumber = 0; - for (const changedProfilesFilePath of changedProfilesFilePaths) { - const changedProfilesRelativeFilePath: string = pathRelativeTo(changedProfilesFilePath, profilesFolderPath); - const targetFilePath: string = joinPath(zipProfilesFolderPath, changedProfilesRelativeFilePath); - await options.logger.logInfo(`${++copyNumber}. Copying ${changedProfilesFilePath} to ${targetFilePath}...`); - await copyFile(changedProfilesFilePath, targetFilePath, true); - } - } -} - -/** - * Create the package zip file from the zip folder. - * @param options The package command options. - * @param zipFolderPath The path to the zip folder. - */ -async function createGoPackageZipFile(options: PackageCommandOptions, zipFolderPath: string): Promise { - const packageName: string = getPackageName(options.repositoryFolderPath, options.relativePackageFolderPath); - const packageZipFilePath: string = joinPath( - options.rootedPackageFolderPath, - `${replaceAll(packageName, '/', '.')}.zip` - ); - await options.logger.logSection(`Compressing ${zipFolderPath} to ${packageZipFilePath}...`); - await options.compressor.zipFolder(zipFolderPath, packageZipFilePath); - return packageZipFilePath; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - return [ - `## Installation Instructions`, - `You can install the package \`${options.packageName}\` of this PR ` + - `by downloading the [package](${options.artifactUrls}) and extracting it ` + - `to the root of your azure-sdk-for-go directory.`, - `## Direct Download`, - `The generated package can be directly downloaded from here:`, - `- [${options.packageName}](${options.artifactUrls})` - ]; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/java.ts b/tools/spec-gen-sdk/src/langSpecs/langs/java.ts deleted file mode 100644 index abcd96a7acf..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/java.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { getChildFilePaths, joinPath, mvnExecutable, run, RunResult, getPathName } from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; - -/** - * A language configuration for Java. - */ -export const java: LanguageConfiguration = { - name: 'Java', - generatorPackageName: '@microsoft.azure/autorest.java', - packageRootFileName: 'pom.xml', - packageCommands: createPackage, - installationInstructions: getInstallationInstructions -}; - -/** - * Create the package file for a package folder. - * @param options The options for creating the package. - */ -export async function createPackage(options: PackageCommandOptions): Promise { - const result: string[] = []; - const mvnResult: RunResult = await run( - mvnExecutable(), - [ - 'source:jar', - 'javadoc:jar', - 'package', - '-f', - options.rootedPackageFolderPath, - '-DskipTests', - '--batch-mode', - '-q' - ], - { - ...options, - captureOutput: options.captureError, // As we use -q to output error only, all the output should be error. - capturePrefix: 'mvn', - throwOnError: false - } - ); - if (mvnResult.exitCode !== 0 || options.packageData.status === 'failed') { - // Suppress error message as java sdk generation has a lot of problem - options.packageData.status = 'warning'; - } else { - result.push(joinPath(options.rootedPackageFolderPath, 'pom.xml')); - - const targetFolderPath: string = joinPath(options.rootedPackageFolderPath, 'target'); - const jarFilePaths: string[] | undefined = await getChildFilePaths(targetFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.jar') - }); - if (jarFilePaths) { - result.push(...jarFilePaths); - } - } - return result; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - const result: string[] = [ - `## Installation Instructions`, - `You can install the package \`${options.packageName}\` of this PR by downloading the artifact jar files. ` + - `Then ensure that the jar files are on your project's classpath.`, - `## Direct Download`, - `The generated package artifacts can be directly downloaded from here:` - ]; - for (const artifactUrl of options.artifactUrls) { - result.push(`- [${getPathName(artifactUrl)}](${artifactUrl})`); - } - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/javascript.ts b/tools/spec-gen-sdk/src/langSpecs/langs/javascript.ts deleted file mode 100644 index 677b8d1d437..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/javascript.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - getChildFilePaths, - getPathName, - joinPath, - PackageJson, - readPackageJsonFileSync, - npm -} from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; - -/** - * A language configuration for JavaScript-based languages. - */ -export const javascript: LanguageConfiguration = { - name: 'JavaScript', - generatorPackageName: '@microsoft.azure/autorest.typescript', - aliases: ['TypeScript', 'TS', 'JS', 'Node', 'Nodejs', 'Node.js'], - packageRootFileName: 'package.json', - packageNameCreator: getPackageName, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions -}; - -/** - * Get the name of the package from the package.json file found in the package folder. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -export function getPackageName(rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - let packageName: string; - const packageJsonFilePath: string = joinPath(rootedRepositoryFolderPath, relativePackageFolderPath, 'package.json'); - try { - const packageJson: PackageJson = readPackageJsonFileSync(packageJsonFilePath); - packageName = packageJson.name || relativePackageFolderPath; - } catch (error) { - packageName = relativePackageFolderPath; - } - return packageName; -} - -/** - * Create the package file for a package folder. - * @param options The options for creating the package. - */ -export async function createPackage(options: PackageCommandOptions): Promise { - await npm(['pack'], { - ...options, - executionFolderPath: options.rootedPackageFolderPath, - capturePrefix: 'npmPack' - }); - return (await getChildFilePaths(options.rootedPackageFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.tgz') - }))!; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - const result: string[] = [ - `## Installation Instructions`, - `You can install the package \`${options.packageName}\` of this PR using the following command:`, - `\`\`\`bash` - ] - .concat( - options.artifactUrls.length === 0 - ? [] - : options.package.context.isPublic - ? [`npm install ${options.artifactUrls[0]}`] - : [ - options.artifactDownloadCommand(options.artifactUrls[0], getPathName(options.artifactUrls[0])), - `npm install ${getPathName(options.artifactUrls[0])}` - ] - ) - .concat([`\`\`\``, `## Direct Download`, `The generated package can be directly downloaded from here:`]); - for (const artifactUrl of options.artifactUrls) { - result.push(`- [${getPathName(artifactUrl)}](${artifactUrl})`); - } - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/python.ts b/tools/spec-gen-sdk/src/langSpecs/langs/python.ts deleted file mode 100644 index 5832678d8cc..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/python.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { getChildFilePaths, getPathName, run } from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; -import * as glob from 'glob'; -import { BreakingChangeReportOptions } from '../generateBreakingChnageReport'; -import { SDKRepository } from '../../sdkRepository'; -import { SDKRepositoryPackage } from '../sdkRepositoryPackage'; -import { createPackageCommandOptions } from '../packageCommand'; -import { sdkLabels } from '@azure/swagger-validation-common'; -/** - * A language configuration for Python. - */ -export const python: LanguageConfiguration = { - name: 'Python', - generatorPackageName: '@microsoft.azure/autorest.python', - packageRootFileName: /^setup.py$|^azure$/, - packageNameCreator: getPackageName, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions, - generateBreakingChangeReport: generateBreakingChangeReport, - runLangAfterScripts : initSetupPy, - breakingChangeLabel: { name: sdkLabels['azure-sdk-for-python'].deprecatedBreakingChange as string, color: 'dc1432' }, - breakingChangesLabel: { name: sdkLabels['azure-sdk-for-python'].breakingChange as string, color: 'dc1432' } -}; - -export async function initSetupPy(sdkRepo: SDKRepository, changedPackage: SDKRepositoryPackage): Promise { - const packageName = changedPackage.data.name; - const commandOptions = createPackageCommandOptions(sdkRepo, changedPackage); - try { - await run('pip', ['install', '-e' , './tools/azure-sdk-tools/'], { - ...commandOptions, - executionFolderPath: changedPackage.repositoryFolderPath, - capturePrefix: 'build_conf_init', - throwOnError: true - }); - - await run('python', ['-m', 'packaging_tools' , '--build-conf', packageName], { - ...commandOptions, - executionFolderPath: changedPackage.getRootedPackageFolderPath() + '/../', - capturePrefix: 'build_conf', - throwOnError: true - }); - - return true; - } catch (e) { - return false; - } -} - -export async function generateBreakingChangeReport(option: BreakingChangeReportOptions): Promise { - const { changedPackage } = option; - const packagePath = changedPackage.getRootedPackageFolderPath(); - const packageName = getPathName(packagePath); - option.executionFolderPath = changedPackage.repositoryFolderPath; - - // Setup tools - await run('python', ['./scripts/dev_setup.py', '-p', packageName], { - ...option, - capturePrefix: 'breaking_change_setup' - }); - - // Get latest report - await run('python', ['-m', 'packaging_tools.code_report', packageName], { - ...option, - captureError: option.captureOutput, - capturePrefix: 'breaking_change_report_latest' - }); - - // Get current pypi package report - await run('python', ['-m', 'packaging_tools.code_report', packageName, '--last-pypi'], { - ...option, - captureError: option.captureOutput, - capturePrefix: 'breaking_change_report_pypi' - }); - - // Get breaking change report - let reportPattern = `code_reports/**/merged_report.json`; - let reportFiles = glob.sync(reportPattern, { cwd: packagePath }); - if (reportFiles.length !== 2) { - reportPattern = `code_reports/**/*.json`; - reportFiles = glob.sync(reportPattern, { cwd: packagePath }); - if (reportFiles.length !== 2) { - option.captureChangeLog('Not exact 2 reports found:'); - reportFiles.forEach(filePath => option.captureChangeLog(filePath)); - option.captureChangeLog('Not generating changelog.'); - return false; - } - } - - if (reportFiles[0].startsWith('code_reports/latest')) { - const tmp = reportFiles[0]; - reportFiles[0] = reportFiles[1]; - reportFiles[1] = tmp; - } - - await run('python', ['-m', 'packaging_tools.change_log', reportFiles[0], reportFiles[1]], { - ...option, - captureOutput: (outputLine) => { - if (outputLine.trim() === '') { - return; - } - option.captureChangeLog(outputLine, outputLine.indexOf('Breaking changes') !== -1); - }, - captureError: option.captureChangeLog, - executionFolderPath: packagePath, - capturePrefix: 'ChangeLog' - }); - - return true; -} - -/** - * Get the name of the package from the relative package folder path. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -export function getPackageName(_rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - return getPathName(relativePackageFolderPath); -} - -export async function createPackage(options: PackageCommandOptions): Promise { - await run( - 'python', - ['./build_package.py', '--dest', options.rootedPackageFolderPath, options.relativePackageFolderPath], - { - ...options, - executionFolderPath: options.repositoryFolderPath, - capturePrefix: 'build_package' - } - ); - return (await getChildFilePaths(options.rootedPackageFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.whl') || filePath.endsWith('.zip'), - recursive: false - }))!; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - const result: string[] = [ - `(message created by the CI based on PR content)`, - `# Installation instruction`, - `## Package ${options.packageName}`, - `You can install the package \`${options.packageName}\` of this PR using the following command:`, - `\t\`pip install ` + - `"git+${options.generationRepositoryUrl}@${options.sdkRepositoryGenerationPullRequestHeadBranch}` + - `#egg=${options.packageName}&subdirectory=${options.packageName}"\``, - ``, - `You can build a wheel to distribute for test using the following command:`, - `\t\`pip wheel --no-deps ` + - `"git+${options.generationRepositoryUrl}@${options.sdkRepositoryGenerationPullRequestHeadBranch}` + - `#egg=${options.packageName}&subdirectory=${options.packageName}"\``, - ``, - `If you have a local clone of this repository, you can also do:`, - ``, - `- \`git checkout ${options.sdkRepositoryGenerationPullRequestHeadBranch}\``, - `- \`pip install -e ./${options.packageName}\``, - ``, - ``, - `Or build a wheel file to distribute for testing:`, - ``, - `- \`git checkout ${options.sdkRepositoryGenerationPullRequestHeadBranch}\``, - `- \`pip wheel --no-deps ./${options.packageName}\``, - ``, - ``, - `# Direct download`, - ``, - `Your files can be directly downloaded here:`, - `` - ]; - for (const artifactUrl of options.artifactUrls) { - result.push(`- [${getPathName(artifactUrl)}](${artifactUrl})`); - } - result.push(``); - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/pythonTrack2.ts b/tools/spec-gen-sdk/src/langSpecs/langs/pythonTrack2.ts deleted file mode 100644 index 48deec23035..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/pythonTrack2.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { LanguageConfiguration } from '../languageConfiguration'; -import { initSetupPy, createPackage, getPackageName, getInstallationInstructions, generateBreakingChangeReport } from './python'; -import { sdkLabels } from '@azure/swagger-validation-common'; - -/** - * A language configuration for Python. - */ -export const pythonTrack2: LanguageConfiguration = { - name: 'Python-Track2', - generatorPackageName: '@autorest/python', - packageRootFileName: /^setup.py$|^azure$/, - packageNameCreator: getPackageName, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions, - packageNameAltPrefix: 'track2_', - generateBreakingChangeReport: generateBreakingChangeReport, - runLangAfterScripts : initSetupPy, - breakingChangeLabel: { name: sdkLabels['azure-sdk-for-python-track2'].deprecatedBreakingChange as string, color: 'dc1432' }, - breakingChangesLabel: { name: sdkLabels['azure-sdk-for-python-track2'].deprecatedBreakingChange as string, color: 'dc1432' } -}; diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/ruby.ts b/tools/spec-gen-sdk/src/langSpecs/langs/ruby.ts deleted file mode 100644 index 8d036c4e4c3..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/ruby.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { any, getChildFilePaths, run, RunResult, getName } from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; -import { RepositoryCommandOptions } from '../repositoryCommandOptions'; - -/** - * A language configuration for Ruby. - */ -export const ruby: LanguageConfiguration = { - name: 'Ruby', - generatorPackageName: '@microsoft.azure/autorest.ruby', - generationCommands: ['bundle install', rakeArmRegen], - packageRootFileName: /.*\.gemspec/, - packageCommands: createPackage, - installationInstructions: getInstallationInstructions -}; - -/** - * Run "rake arm:regen['package-name']" on each of the packages to regenerate. - */ -async function rakeArmRegen(options: RepositoryCommandOptions): Promise { - if (!options.specificationPullRequestHeadCommitId) { - await options.logger.logError( - `Can't generate ruby packages because no specification pull request head commit id was provided.` - ); - options.repositoryData.status = 'failed'; - } else { - const packageNamesToGenerate: string[] = await getPackageNamesToGenerate(); - for (const packageNameToGenerate of packageNamesToGenerate) { - const result: RunResult = await run( - `rake`, - [`arm:regen['${packageNameToGenerate}','${options.specificationPullRequestHeadCommitId}','resource-manager']`], - options - ); - if (result.exitCode !== 0) { - options.repositoryData.status = 'failed'; - break; - } - } - } -} - -export async function getPackageNamesToGenerate(): Promise { - const result: string[] = []; - // for (const readmeMdFileUrlToGenerate of options.repositoryData.readmeMdFileUrlsToGenerate) { - // const readmeRubyMdFileUrlToGenerate: string = readmeMdFileUrlToGenerate.replace('readme.md', 'readme.ruby.md'); - // const readmeRubyMdFileResponse: HttpResponse = await options.httpClient.sendRequest({ - // method: 'GET', - // url: readmeRubyMdFileUrlToGenerate - // }); - // if (readmeRubyMdFileResponse.statusCode === 200 && readmeRubyMdFileResponse.body) { - // const packageNameToGenerate: string | undefined = getPackageNameToGenerate(readmeRubyMdFileResponse.body); - // if (packageNameToGenerate) { - // result.push(packageNameToGenerate); - // } - // } - // } - return result; -} - -export function getPackageNameToGenerate(readmeMdFileContents: string): string | undefined { - let result: string | undefined; - const packageNameRegExp: RegExp = /package-name:(.*)/i; - const packageNameMatch: RegExpMatchArray | null = readmeMdFileContents.match(packageNameRegExp); - if (packageNameMatch) { - result = packageNameMatch[1].trim(); - const managementPrefix = 'azure_mgmt_'; - if (!result.startsWith(managementPrefix)) { - result = undefined; - } else { - result = result.substring(managementPrefix.length); - } - } - - return result; -} - -async function createPackage(options: PackageCommandOptions): Promise { - const result: string[] = []; - - const packageFolderPath: string = options.rootedPackageFolderPath; - await options.logger.logInfo(`Looking for gemspec files in "${packageFolderPath}"...`); - const gemspecFilePaths: string[] | undefined = await getChildFilePaths(packageFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.gemspec') - }); - if (!any(gemspecFilePaths)) { - await options.logger.logError(`Didn't find any gemspec files in "${packageFolderPath}".`); - } else { - for (const gemspecFilePath of gemspecFilePaths) { - const gemBuildResult: RunResult = await run('gem', ['build', gemspecFilePath], options); - if (gemBuildResult.error) { - await options.logger.logError(gemBuildResult.error.toString()); - options.packageData.status = 'failed'; - } else if (gemBuildResult.exitCode !== 0) { - await options.logger.logError(`Failed to create gem for "${gemspecFilePath}".`); - options.packageData.status = 'failed'; - } else { - const gemFilePaths: string[] | undefined = await getChildFilePaths(packageFolderPath, { - fileCondition: (filePath: string) => filePath.endsWith('.gem') - }); - if (!any(gemFilePaths)) { - await options.logger.logError(`Didn't find any gem files in "${packageFolderPath}".`); - } else { - result.push(...gemFilePaths); - } - } - } - } - - return result; -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - const artifactUrl: string = options.artifactUrls[0]; - const artifactName: string = getName(artifactUrl); - const artifactNameDashIndex: number = artifactName.indexOf('-'); - const gemName: string = artifactName.substring(0, artifactNameDashIndex); - const gemVersion: string = artifactName.substring(artifactNameDashIndex + 1, artifactName.lastIndexOf('.')); - return [ - `## Installation Instructions`, - `The Gem file for \`${gemName}\` can be downloaded [here](${artifactUrl}).`, - `After downloading the gem file, you can add it to your Ruby project by running the following command:`, - `\`\`\`gem '${gemName}', '${gemVersion}', '/${artifactName}'\`\`\``, - `## Direct Download`, - `The generated gem can be directly downloaded from here:`, - `- [${artifactName}](${artifactUrl})` - ]; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/langs/trenton.ts b/tools/spec-gen-sdk/src/langSpecs/langs/trenton.ts deleted file mode 100644 index b17b0d32085..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/langs/trenton.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { - commandToString, - Command, - parseCommands, - run, - findEntryInPath, - getParentFolderPath, - getName - } from '@ts-common/azure-js-dev-tools'; -import path from 'path'; -import { LanguageConfiguration } from '../languageConfiguration'; -import { PackageCommandOptions } from '../packageCommandOptions'; -import { InstallationInstructionsOptions } from '../installationInstructions'; -import { - SDKRepository, - resolveEnvironmentVariables, - replaceCommandVariables - } from '../../sdkRepository'; -import { getConfigMeta } from '../../swaggerToSDKConfiguration'; -import { createRepositoryCommandOptions } from '../repositoryCommand'; -import { SDKRepositoryPackage } from '../sdkRepositoryPackage'; -import { existsSync } from 'fs'; -import { Logger } from '@azure/logger-js'; - -/** - * A language configuration for Trenton. - */ -export const trenton: LanguageConfiguration = { - name: 'Trenton', - generatorPackageName: '@microsoft.azure/autorest.trenton', - packageRootFileName: 'registration.go', - isPrivatePackage: true, - runLangAfterScripts : runAfterScriptsInRepoWithService, - getExtraRelativeFolderPaths, - packageNameCreator: getPackageName, - packageCommands: createPackage, - liteInstallationInstruction: genLiteInstruction - // installationInstructions: getInstallationInstructions -}; - -/** - * Get the name of the package from the relative package folder path. - * @param rootedRepositoryFolderPath The rooted path to the repository folder. - * @param relativePackageFolderPath The path to the package folder relative to the repository folder. - */ -function getPackageName(_rootedRepositoryFolderPath: string, relativePackageFolderPath: string): string { - return getName(relativePackageFolderPath); -} - -/** - * Function that run specific script for Lang scope. - * For Terraform, it mainly focuses on compile terraform code and modify files. - * @param sdkRepo The context in which the scripts should run. - * @param changedPackageName Used to determine the service name. - */ -async function runAfterScriptsInRepoWithService( - sdkRepo: SDKRepository, changedPackage: SDKRepositoryPackage -): Promise { - const changedPackageName = changedPackage.data.name; - const service = changedPackageName.split('/').slice(-1)[0]; - const scripts = getConfigMeta(sdkRepo.swaggerToSDKConfiguration, 'after_scripts_in_repo_with_service') || []; - if (scripts.length === 0) { - return true; - } - - const commandOptions = createRepositoryCommandOptions(sdkRepo, sdkRepo.repoPath); - const envConfig = getConfigMeta(sdkRepo.swaggerToSDKConfiguration, 'envs') || {}; - const envs = resolveEnvironmentVariables(envConfig, sdkRepo.repoPath); - - const commands: Command[] = []; - scripts.forEach(script => commands.push(...parseCommands(script))); - for (const command of commands) { - command.args?.push(service); - replaceCommandVariables(command, commandOptions, changedPackage.logger); - try { - await run(command, undefined, { - ...commandOptions, - runner: sdkRepo.context.runner, - executionFolderPath: sdkRepo.repoPath, - showCommand: true, - showResult: true, - log: sdkRepo.logger.logInfo, - environmentVariables: envs, - capturePrefix: `after_scripts_in_repo|${command.executable}`, - throwOnError: true - }); - - } catch (e) { - await sdkRepo.logger.logError(`Fail to run sdk specified script: ${commandToString(command)}`); - sdkRepo.data.status = 'warning'; - return false; - } - } - await sdkRepo.logger.logInfo(`Run sdk specified script successfully for ${changedPackageName}`); - - return true; -} - -async function getExtraRelativeFolderPaths( - relativeFolderPath: string, fileChanged: string[], logger: Logger -): Promise { - const result: string[] = []; - - for (const filePath of fileChanged) { - const packageRootFolderFile = - await findEntryInPath('client.go', filePath, (p) => existsSync(p)); - if (packageRootFolderFile === undefined) { - continue; - } - const packageRootFolder = getParentFolderPath(packageRootFolderFile); - if (packageRootFolder !== relativeFolderPath - && !result.includes(packageRootFolder) - ) { - await logger.logInfo(`Add ${packageRootFolder} to package extra folders`); - result.push(packageRootFolder); - } - } - - return result; -} - -export async function createPackage(options: PackageCommandOptions): Promise { - const repoDir = options.repositoryFolderPath; - const packageFolder = path.join(repoDir, 'tmp_gopath', 'bin'); - const packageName = 'terraform-provider-azurerm'; - const version = `0.${options.buildID}.${options.packageIndex}`; - const result = await run( - 'sh', - [ - './scripts/package.sh', - packageFolder, - packageName, - version, - options.rootedPackageFolderPath - ], - { - ...options, - executionFolderPath: options.repositoryFolderPath, - capturePrefix: 'build_package' - } - ); - if (result.error?.message === undefined) { - return `${packageName}:${version}`; - } - return undefined!; -} - -export function genLiteInstruction(options: InstallationInstructionsOptions): string[] { - const result: string[] = [ `` ]; - for (const artifactUrl of options.artifactUrls) { - const packageinfos = artifactUrl.split(':'); - const packageName = packageinfos[0]; - const version = packageinfos[1]; - const ins = `az artifacts universal download \ - --organization "https://dev.azure.com/azure-sdk/" \ - --project "internal" \ - --scope project \ - --feed "sdk-automation-test" \ - --name ${packageName} \ - --version ${version} \ - --path .`; - result.push(ins); - } - result.push(``); - return result; - -} - -/** - * Get installation instructions for a package using the provided options. - * @param options The options that can be used when generating installation instructions. - */ -export function getInstallationInstructions(options: InstallationInstructionsOptions): string[] { - return [ - `## Installation Instructions`, - `You can install the package \`${options.packageName}\` of this PR ` + - `by downloading the [package](${options.artifactUrls}) and extracting it ` + - `to the root of your azure-sdk-for-go directory.`, - `## Direct Download`, - `The generated package can be directly downloaded from here:`, - `- [${options.packageName}](${options.artifactUrls})` - ]; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/languageConfiguration.ts b/tools/spec-gen-sdk/src/langSpecs/languageConfiguration.ts deleted file mode 100644 index 32a2f39e455..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/languageConfiguration.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { PackageCommand } from './packageCommand'; -import { InstallationInstructions } from './installationInstructions'; -import { RepositoryCommand } from './repositoryCommand'; -import { GenerateBreakingChangeReportOptions } from './generateBreakingChnageReport'; -import { SDKRepository } from '../sdkRepository'; -import { GithubLabel } from '../utils/githubUtils'; -import { SDKRepositoryPackage } from './sdkRepositoryPackage'; -import { Logger } from '@azure/logger-js'; - -/** - * Process mod's generate method for each readmeMdFileUrl. - * Batch for invoking runGeneration method for all readmeMdFileUrl first. - * Sequencial for processing each readmeMdFileUrl wholly one by one. - */ -export enum ReadmeMdFileProcessMod { - Batch, - Sequencial -} - -/** - * A configuration for how to interact with repositories in a specific programming language. - */ -export interface LanguageConfiguration { - /** - * The name of the programming language. - */ - name: string; - /** - * The package name of the generator that will be used to generate this language's packages. - */ - generatorPackageName: string; - /** - * Process mod's generate method for each readmeMdFileUrl. - */ - readmeMdFileProcessMod?: ReadmeMdFileProcessMod; - /** - * Aliases that the programming language may also be known by. - */ - aliases?: string[]; - /** - * Commands that will be run to generate source code that will later be combined into packages. If - * this is not specified, then it will default to just running AutoRest. - */ - generationCommands?: RepositoryCommand | RepositoryCommand[]; - /** - * A function that returns the name of a package. - */ - packageNameCreator?: ( - rootedRepositoryFolderPath: string, - relativePackageFolderPath: string, - readmeMdFileUrl: string - ) => string | Promise; - - packageNameAltPrefix?: string; - - /** - * A function that customize the message show on github. - */ - RunnerReportLoggerCreator?: ( - output: string[] - ) => Logger; - /** - * A function that implements the logics after code-gen. Initialized for Terraform. - */ - runLangAfterScripts?: ( - sdkRepo: SDKRepository, - sdkPackage: SDKRepositoryPackage - ) => Promise; - /** - * The name of a file that is found at the root of a generated package for this language. - */ - packageRootFileName?: string | RegExp; - /** - * Commands that should be run in the context of a package that was changed as a result of running - * AutoRest. These will be run before files are added and committed to the generation branch. - */ - afterGenerationCommands?: PackageCommand | PackageCommand[]; - /** - * The command that should be run to create a package for this language. - */ - packageCommands?: PackageCommand | PackageCommand[]; - /** - * The text of the comment that explains how to install/reference an SDK build drop from a - * customer's code. - */ - installationInstructions?: InstallationInstructions; - /** - * Lite installation instruction for this Lang. - */ - liteInstallationInstruction?: InstallationInstructions; - /** - * Flag used to indicate whether the package should be published as public release. - */ - isPrivatePackage?: boolean; - /** - * This variable will be deleted when new SDK breaking change review flow is being used. - * We will use 'breakingChangesLabel' instead. - */ - breakingChangeLabel?: GithubLabel; - /** - * Keep release PR open after being created. - */ - keepReleasePROpen?: boolean; - - /** - * Breaking change for this Lang. - */ - breakingChangesLabel?: GithubLabel; - - generateBreakingChangeReport?: GenerateBreakingChangeReportOptions; - - getExtraRelativeFolderPaths?: (relativePath: string, fileChanged: string[], logger: Logger) => Promise; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/packageCommand.ts b/tools/spec-gen-sdk/src/langSpecs/packageCommand.ts deleted file mode 100644 index 5e77a40c64b..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/packageCommand.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { BlobStorageBlockBlob, Command, getPathName, parseCommands, run } from '@ts-common/azure-js-dev-tools'; -import { PackageCommandOptions } from './packageCommandOptions'; -import { createRepositoryCommandOptions } from './repositoryCommand'; -import { RepositoryCommandOptions } from './repositoryCommandOptions'; -import { trimNewLine, errorToLog } from '../sdkAutomation'; -import { replaceCommandVariables, SDKRepository } from '../sdkRepository'; -import { SDKRepositoryPackage } from './sdkRepositoryPackage'; - -export type PackageCommand = - | ((options: PackageCommandOptions) => void | string | string[] | Promise) - | string; - -export function createPackageCommandOptions( - repository: SDKRepository, - changedPackage: SDKRepositoryPackage -): PackageCommandOptions { - const rootedPackageFolderPath: string = changedPackage.getRootedPackageFolderPath(); - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - repository, - changedPackage.repositoryFolderPath - ); - const buildID = repository.buildID; - const packageIndex = changedPackage.packageIndex; - return { - ...repositoryCommandOptions, - relativePackageFolderPath: changedPackage.data.relativeFolderPath, - rootedPackageFolderPath, - logger: changedPackage.logger, - changedFilePaths: changedPackage.data.changedFilePaths, - executionFolderPath: rootedPackageFolderPath, - captureOutput: (text: string) => changedPackage.logger.logInfo(trimNewLine(text)), - captureError: (text: string) => changedPackage.logger.logError(trimNewLine(text)), - capturePrefix: 'PkgCmd', - throwOnError: true, - log: (text: string) => changedPackage.logger.logInfo(trimNewLine(text)), - packageData: changedPackage.data, - buildID, - packageIndex - }; -} - -export async function runPackageCommands( - changedPackage: SDKRepositoryPackage, - packageCommands: PackageCommand | PackageCommand[], - packageCommandOptions: PackageCommandOptions, - isPrivatePackage?: boolean -): Promise { - let result = true; - const packageCommandsArray: PackageCommand[] = Array.isArray(packageCommands) ? packageCommands : [packageCommands]; - try { - for (const packageCommand of packageCommandsArray) { - if (typeof packageCommand === 'string') { - const parsedPackageCommands: Command[] = parseCommands(packageCommand); - for (const parsedPackageCommand of parsedPackageCommands) { - replaceCommandVariables(parsedPackageCommand, packageCommandOptions, changedPackage.logger); - await run(parsedPackageCommand, undefined, { - ...packageCommandOptions, - capturePrefix: getPathName(parsedPackageCommand.executable) - }); - } - } else { - const packageCommandResult: void | string | string[] = await Promise.resolve( - packageCommand(packageCommandOptions) - ); - if (packageCommandResult) { - changedPackage.artifactFilePaths.push( - ...(Array.isArray(packageCommandResult) ? packageCommandResult : [packageCommandResult]) - ); - } - } - } - } catch (error) { - await changedPackage.logger.logError(`Failed to create the package ${changedPackage.data.name}.`); - await changedPackage.logger.logError(errorToLog(error, false)); - changedPackage.data.status = 'failed'; - result = false; - } - - if (!changedPackage.data.artifactBlobUrls) { - changedPackage.data.artifactBlobUrls = []; - } - if (changedPackage.artifactFilePaths.length > 0) { - const artifactBlobUrls: string[] = changedPackage.data.artifactBlobUrls; - - for (const artifactFilePath of changedPackage.artifactFilePaths) { - if (isPrivatePackage) { - changedPackage.data.isPrivatePackage = true; - artifactBlobUrls.push(artifactFilePath); - } else { - const artifactFileName: string = getPathName(artifactFilePath); - - const artifactFileBlob: BlobStorageBlockBlob = changedPackage.packagePrefix.getBlockBlob( - artifactFileName - ); - const artifactFileBlobUrl: string = changedPackage.context.getBlobProxyUrl(artifactFileBlob); - await changedPackage.logger.logSection(`Uploading ${artifactFilePath} to ${artifactFileBlobUrl}...`); - await artifactFileBlob.setContentsFromFile(artifactFilePath); - await changedPackage.logger.logInfo(`Done uploading ${artifactFilePath} to ${artifactFileBlobUrl}.`); - artifactBlobUrls.push(artifactFileBlobUrl); - changedPackage.data.isPrivatePackage = false; - } - } - - await changedPackage.context.writeGenerationData(); - } - - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/packageCommandOptions.ts b/tools/spec-gen-sdk/src/langSpecs/packageCommandOptions.ts deleted file mode 100644 index abba4d9ab24..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/packageCommandOptions.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { RepositoryCommandOptions } from './repositoryCommandOptions'; -import { SDKRepositoryPackageData } from './sdkRepositoryPackage'; - -/** - * Options that can be used within a package command. - */ -export interface PackageCommandOptions extends RepositoryCommandOptions { - /** - * The path to the package folder relative to the repository folder. - */ - readonly relativePackageFolderPath: string; - /** - * The rooted path to the package folder. - */ - readonly rootedPackageFolderPath: string; - /** - * The rooted file paths to the files in the SDK repository that were changed after AutoRest was - * run. - */ - readonly changedFilePaths: string[]; - /** - * The data associated with the package. - */ - readonly packageData: SDKRepositoryPackageData; - - /** - * Enable pipeline Build.BuildID - */ - readonly buildID: string; - /** - * Package index, starts from 0 - */ - readonly packageIndex: number; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/repositoryCommand.ts b/tools/spec-gen-sdk/src/langSpecs/repositoryCommand.ts deleted file mode 100644 index 20e8b5dc53b..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/repositoryCommand.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Command, parseCommands, run, getPathName } from '@ts-common/azure-js-dev-tools'; -import { RepositoryCommandOptions } from './repositoryCommandOptions'; -import { trimNewLine, errorToLog } from '../sdkAutomation'; -import { replaceCommandVariables, SDKRepository } from '../sdkRepository'; - -export type RepositoryCommand = ((options: RepositoryCommandOptions) => void | Promise) | string; - -export function createRepositoryCommandOptions( - repository: SDKRepository, - rootedRepositoryFolderPath: string -): RepositoryCommandOptions { - return { - specificationPullRequestHeadCommitId: - repository.context.specificationPullRequest && repository.context.specificationPullRequest.headCommit, - repositoryFolderPath: rootedRepositoryFolderPath, - compressor: repository.context.createCompressor(), - logger: repository.logger, - executionFolderPath: rootedRepositoryFolderPath, - runner: repository.context.runner, - showCommand: true, - showResult: true, - captureOutput: (text: string) => repository.logger.logInfo(trimNewLine(text)), - captureError: (text: string) => repository.logger.logError(trimNewLine(text)), - capturePrefix: 'GenCmd', - throwOnError: true, - log: (text: string) => repository.logger.logInfo(trimNewLine(text)), - repositoryData: repository.data - }; -} - -export async function runRepositoryCommands( - repository: SDKRepository, - repositoryCommands: RepositoryCommand | RepositoryCommand[], - repositoryCommandOptions: RepositoryCommandOptions -): Promise { - let result = true; - - const repositoryCommandsArray: RepositoryCommand[] = Array.isArray(repositoryCommands) - ? repositoryCommands - : [repositoryCommands]; - try { - for (const repositoryCommand of repositoryCommandsArray) { - if (typeof repositoryCommand === 'string') { - const parsedRepositoryCommands: Command[] = parseCommands(repositoryCommand); - for (const parsedRepositoryCommand of parsedRepositoryCommands) { - replaceCommandVariables(parsedRepositoryCommand, repositoryCommandOptions, repository.logger); - await run(parsedRepositoryCommand, undefined, { - ...repositoryCommandOptions, - capturePrefix: getPathName(parsedRepositoryCommand.executable) - }); - } - } else { - await Promise.resolve(repositoryCommand(repositoryCommandOptions)); - } - } - } catch (error) { - await repository.logger.logError(`Failed to run repository command`); - await repository.logger.logError(errorToLog(error, false)); - repository.data.status = 'failed'; - result = false; - } - - return result; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/repositoryCommandOptions.ts b/tools/spec-gen-sdk/src/langSpecs/repositoryCommandOptions.ts deleted file mode 100644 index 1be6b5a225b..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/repositoryCommandOptions.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { Compressor, RunOptions } from '@ts-common/azure-js-dev-tools'; -import { SDKRepositoryData } from '../sdkRepository'; - -/** - * Options that can be used within a repository command. - */ -export interface RepositoryCommandOptions extends RunOptions { - /** - * The head commit id of the specification pull request. - */ - readonly specificationPullRequestHeadCommitId?: string; - /** - * The path to the repository folder. - */ - readonly repositoryFolderPath: string; - /** - * The Compressor that can be used to create archives. - */ - readonly compressor: Compressor; - /** - * The logger that can be used to write logs. - */ - readonly logger: Logger; - /** - * The data associated with the repository. - */ - readonly repositoryData: SDKRepositoryData; -} diff --git a/tools/spec-gen-sdk/src/langSpecs/sdkRepositoryPackage.ts b/tools/spec-gen-sdk/src/langSpecs/sdkRepositoryPackage.ts deleted file mode 100644 index 7b2c838a3b6..00000000000 --- a/tools/spec-gen-sdk/src/langSpecs/sdkRepositoryPackage.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { - BlobStorageBlob, - BlobStorageBlockBlob, - BlobStoragePrefix, - joinPath -} from '@ts-common/azure-js-dev-tools'; -import { InstallationInstructions, InstallationInstructionsOptions } from './installationInstructions'; -import { LanguageConfiguration } from './languageConfiguration'; -import { SDKAutomationState } from '../sdkAutomationState'; -import { SDKRepositoryContext } from '../sdkRepository'; - -/** - * The data that describes an SDK repository package. - */ -export interface SDKRepositoryPackageData { - /** - * The name of the package. - */ - readonly name: string; - /** - * The relative path to the root of the package folder from the root of the SDK repository. - */ - readonly relativeFolderPath: string; - /** - * The relative path to the root of the extra package folders from the root of the SDK repository. - */ - extraRelativeFolderPaths: string[]; - /** - * The current status of creating and uploading this package. - */ - status: SDKAutomationState; - /** - * Message to be shown for this package. - */ - messages: string[]; - /** - * Does this package has breaking change. - */ - hasBreakingChange?: boolean; - /** - * The URL of the blob where this SDK repository package's logs will be written to. - */ - logsBlobUrl: string; - /** - * The URLs of the blobs where this SDK repository package's artifacts will be written to. - */ - artifactBlobUrls?: string[]; - /** - * The URLs of the generated apiView. - */ - apiViewUrl?: string; - /** - * Used to indicate whether the package should be released as public - */ - isPrivatePackage: boolean; - /** - * The installation instructions for this package. - */ - installationInstructions?: string; - /** - * Lite installation instruction for this package. - */ - liteInstallationInstruction?: string | undefined; - /** - * The URL of the blob where this SDK repository package's installation instructions will be - * written to. - */ - installationInstructionsBlobUrl?: string; - /** - * The URL to the created generation pull request for this SDK repository package. - */ - generationPullRequestUrl?: string; - /** - * The URL to the diff page of the created generation pull request for this SDK repository package. - */ - generationPullRequestDiffUrl?: string; - /** - * The URL to the integration pull request for this SDK repository package. - */ - integrationPullRequestUrl?: string; - /** - * The files in this package that have changed. - */ - readonly changedFilePaths: string[]; - /** - * The name of the generation branch for this package. - */ - readonly generationBranch: string; - /** - * The repository where the SDK's generation pull request and branch will be created. This is the - * first repository where the automatically generated SDK will appear. - */ - readonly generationRepository: string; - /** - * The URL to this package's generation repository. - */ - readonly generationRepositoryUrl: string; - /** - * The name of the integration branch for this package. - */ - readonly integrationBranch: string; - /** - * The repository where the SDK's integration/staging pull request and branch will be created. The - * SDK's integration branch and pull request are where merged SDK generation pull requests will be - * staged before they are merged and published in the main repository. - */ - readonly integrationRepository: string; - /** - * Whether or not this SDK repository package's generation branch should be based off of the - * integration branch or the main branch. - */ - readonly useIntegrationBranch: boolean; - /** - * The main repository for the SDK. This is where the SDK packages are published from. - */ - readonly mainRepository: string; -} - -/** - * An SDK repository package. - */ -export class SDKRepositoryPackage { - /** - * The file paths to the artifacts that were created as a result of running package commands. - */ - public readonly artifactFilePaths: string[] = []; - - /** - * Create a new SDKRepositoryPackage object. - * @param repositoryFolderPath The rooted path to this package folder. - * @param language The language that this package is written in. - * @param logsBlob The blob that this package's logs will be written to. - * @param specPRIterationPrefix The iteration-specific prefix where this SDK repository's packages - * will be uploaded to. - * @param packagePrefix The specification pull-request-specific prefix where this SDK repository's - * packages will be uploaded to. - * @param logger The logger that will write logs about this SDKRepositoryPackage. - * @param context The context that this SDKRepositoryPackage will run its operations under. - * @param data The data related to the SDK repository package. - */ - constructor( - public readonly repositoryFolderPath: string, - private readonly language: LanguageConfiguration, - public readonly logsBlob: BlobStorageBlob, - public readonly packagePrefix: BlobStoragePrefix, - public readonly logger: Logger, - public readonly context: SDKRepositoryContext, - public readonly data: SDKRepositoryPackageData, - public readonly packageIndex: number - ) {} - - /** - * Get the rooted folder path of this SDK repository package. - */ - public getRootedPackageFolderPath(): string { - return joinPath(this.repositoryFolderPath, this.data.relativeFolderPath); - } - - /** - * Create and upload the installation instructions related to this package. - */ - public async createAndUploadInstallationInstructions(): Promise { - let instructions: InstallationInstructions | undefined = this.language.installationInstructions; - let liteInstructions: InstallationInstructions | undefined = this.language.liteInstallationInstruction; - const options: InstallationInstructionsOptions = { - packageName: this.data.name, - artifactUrls: this.data.artifactBlobUrls!, - generationRepositoryUrl: this.data.generationRepositoryUrl, - sdkRepositoryGenerationPullRequestHeadBranch: this.data.generationBranch, - artifactDownloadCommand: this.context.artifactDownloadCommand, - package: this - }; - let blobInstructionContent: string = ''; - if (this.language.isPrivatePackage === undefined || this.language.isPrivatePackage === false) { - if (instructions) { - await this.logger.logSection(`Creating package installation instructions...`); - if (typeof instructions === 'function') { - instructions = await Promise.resolve(instructions(options)); - } else if (typeof instructions !== 'string') { - instructions = await instructions; - } - if (Array.isArray(instructions)) { - instructions = instructions.join('\n'); - } - - if (instructions) { - blobInstructionContent = instructions; - this.data.installationInstructions = instructions; - const installationInstructionsBlob: BlobStorageBlockBlob = this.packagePrefix.getBlockBlob('instructions.md'); - this.data.installationInstructionsBlobUrl = this.context.getBlobProxyUrl(installationInstructionsBlob); - await this.logger.logSection( - `Uploading package installation instructions to ${this.data.installationInstructionsBlobUrl}...` - ); - await installationInstructionsBlob.setContentsFromString(instructions, { contentType: 'text/plain' }); - } - } - } - if (liteInstructions) { - await this.logger.logSection(`Creating package LITE installation instructions...`); - if (typeof liteInstructions === 'function') { - liteInstructions = await Promise.resolve(liteInstructions(options)); - } else if (typeof liteInstructions !== 'string') { - liteInstructions = await liteInstructions; - } - if (Array.isArray(liteInstructions)) { - liteInstructions = liteInstructions.join('\n'); - } - - if (liteInstructions) { - this.data.liteInstallationInstruction = liteInstructions; - const installationInstructionsBlob: BlobStorageBlockBlob = this.packagePrefix.getBlockBlob( - 'lite_instructions.md' - ); - this.data.installationInstructionsBlobUrl = this.context.getBlobProxyUrl(installationInstructionsBlob); - await this.logger.logSection( - `Uploading package installation instructions to ${this.data.installationInstructionsBlobUrl}...` - ); - blobInstructionContent = blobInstructionContent + '\n' + liteInstructions; - await installationInstructionsBlob.setContentsFromString(blobInstructionContent, { contentType: 'text/plain' }); - } - } - } - - /** - * Log an error message and set this SDK repository package's status to "failed". - * @param errorMessage The error message to log. - */ - public logError(errorMessage: string): Promise { - this.data.status = 'failed'; - return Promise.all([this.logger.logError(errorMessage), this.context.writeGenerationData()]); - } -} diff --git a/tools/spec-gen-sdk/src/realBlobProxy.ts b/tools/spec-gen-sdk/src/realBlobProxy.ts deleted file mode 100644 index bbd2ce2136a..00000000000 --- a/tools/spec-gen-sdk/src/realBlobProxy.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { BlobProxy } from './blobProxy'; -import { BlobStoragePrefix, BlobStorageBlob, Duration, URLBuilder } from '@ts-common/azure-js-dev-tools'; - -export class RealBlobProxy implements BlobProxy { - private readonly blobProxyUrlBuilderPrefix: URLBuilder; - - constructor(private readonly blobProxyUrlPrefix: string) { - this.blobProxyUrlBuilderPrefix = URLBuilder.parse(blobProxyUrlPrefix); - } - - public getProxyURL(workingPrefix: BlobStoragePrefix, blob: BlobStorageBlob): string { - const workingPrefixBlobName: string = workingPrefix.path.blobName; - const blobPathRelativeToWorkingPrefix: string = workingPrefixBlobName - ? blob.path.blobName.substring(workingPrefixBlobName.length) - : blob.path.blobName; - return `${this.blobProxyUrlPrefix}${blobPathRelativeToWorkingPrefix}`; - } - - public resolveProxyURL(workingPrefix: BlobStoragePrefix, blobProxyURL: string): Promise { - let result: string | undefined; - if (blobProxyURL && blobProxyURL.startsWith(this.blobProxyUrlPrefix)) { - const proxyBlobUrlBuilder: URLBuilder = URLBuilder.parse(blobProxyURL); - const proxyBlobUrlPath: string | undefined = proxyBlobUrlBuilder.getPath(); - if (proxyBlobUrlPath) { - const prefixPath: string | undefined = this.blobProxyUrlBuilderPrefix.getPath(); - const proxyBlobUrlRelativePath: string = prefixPath - ? proxyBlobUrlPath.substring(prefixPath.length) - : proxyBlobUrlPath; - const blob: BlobStorageBlob = workingPrefix.getBlob(proxyBlobUrlRelativePath); - result = blob.getURL({ - sasToken: { - startTime: Duration.minutes(-5).fromNow(), - endTime: Duration.minutes(30).fromNow() - } - }); - } - } - return Promise.resolve(result); - } -} diff --git a/tools/spec-gen-sdk/src/runnerReportLogger.ts b/tools/spec-gen-sdk/src/runnerReportLogger.ts deleted file mode 100644 index 4a3f218b198..00000000000 --- a/tools/spec-gen-sdk/src/runnerReportLogger.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { toArray } from '@ts-common/azure-js-dev-tools'; - -export const getRunnerReportLogger = (output: string[]): Logger => { - const logFn = (text: string | string[]) => { - output.push(...toArray(text)); - return Promise.resolve(); - }; - - const logWarning = (text: string | string[]) => { - if (text instanceof Array && text.join('.').includes('WARNING')) { - output.push(...toArray(text)); - } - return Promise.resolve(); - }; - - const dummyFn = () => Promise.resolve(); - - return { - logError: logFn, - logWarning: logFn, - logInfo: logWarning, - logSection: dummyFn, - logVerbose: dummyFn - }; -}; diff --git a/tools/spec-gen-sdk/src/sdkAutomation.ts b/tools/spec-gen-sdk/src/sdkAutomation.ts deleted file mode 100644 index 25b3bc236d4..00000000000 --- a/tools/spec-gen-sdk/src/sdkAutomation.ts +++ /dev/null @@ -1,752 +0,0 @@ -import { - getCompositeLogger, - Logger, - LoggerOptions, - splitLines, - timestamps, - wrapLogger, - getDefaultLogger -} from '@azure/logger-js'; -import { - ArchiverCompressor, - BlobStorageAppendBlob, - BlobStorageBlockBlob, - BlobStorageContainer, - BlobStoragePrefix, - Compressor, - createTemporaryFolder, - ExecutableGit, - FakeGitHub, - findFileInPath, - findFolderInPath, - getChildFilePaths, - getRootPath, - GitHub, - HttpClient, - isRooted, - joinPath, - map, - NodeHttpClient, - normalizePath, - PackageJson, - pathRelativeTo, - readPackageJsonFileSync, - Repository, - Runner, - toArray -} from '@ts-common/azure-js-dev-tools'; -import { BlobProxy } from './blobProxy'; -import { FakeBlobProxy } from './fakeBlobProxy'; -import { pythonTrack2 } from './langSpecs/langs/pythonTrack2'; -import { dotnetTrack2 } from './langSpecs/langs/dotnetTrack2'; -import { dotnet } from './langSpecs/langs/dotnet'; -import { go } from './langSpecs/langs/go'; -import { java } from './langSpecs/langs/java'; -import { javascript } from './langSpecs/langs/javascript'; -import { LanguageConfiguration } from './langSpecs/languageConfiguration'; -import { python } from './langSpecs/langs/python'; -import { ruby } from './langSpecs/langs/ruby'; -import { cli } from './langSpecs/langs/cli'; -import { trenton } from './langSpecs/langs/trenton'; -import { azureresourceschema } from './langSpecs/langs/azureresourceschema'; - -import { - getSDKAutomationStateImageBlob, - getSDKAutomationStateImageName, - getSDKAutomationStates -} from './sdkAutomationState'; -import { getSpecificationPullRequest } from './specificationPullRequest'; -import { resolve } from 'path'; - -/** - * The optional properties that can be provided when creating a new SDKAutomation object. - */ -export interface SDKAutomationOptions { - /** - * The main logger that will be used to log the automation's state. Typically this will be a - * central telemetry database. This logger will be composed together with additional loggers as an - * automation event is processed. - */ - readonly logger?: Logger; - /** - * The client that will be used to interact with GitHub. - */ - readonly github?: GitHub; - /** - * The client that will be used to interact with Git. - */ - readonly git?: ExecutableGit; - /** - * The language configurations that will be supported. - */ - readonly supportedLanguageConfigurations?: - | LanguageConfiguration - | LanguageConfiguration[] - | ((defaultLanguages: LanguageConfiguration[]) => void | LanguageConfiguration | LanguageConfiguration[]); - /** - * A factory function that creates Compressor objects. - */ - readonly compressorCreator?: () => Compressor; - /** - * The runner object that will be used to execute external-process commands. - */ - readonly runner?: Runner; - /** - * The client that will be used to send HTTP requests. - */ - readonly httpClient?: HttpClient; - /** - * Whether or not to delete the locally cloned repositories used for generation. Defaults to true. - */ - readonly deleteClonedRepositories?: boolean; - /** - * An object that can be used to create and resolve blob proxy URLs. - */ - readonly blobProxy?: BlobProxy; - /** - * Whether or not to generate each language in parallel. Defaults to false. - */ - readonly generateLanguagesInParallel?: boolean; - /** - * Whether or not to add timestamps to the blob loggers. - */ - readonly logTimestamps?: boolean; - /** - * Whether or not to create generation pull requests for SDK repositories. - */ - readonly createGenerationPullRequests?: boolean; - /** - * Author name of the generated comment displayed on github. Add "[bot]" to - * end of the name if we are github app. - */ - readonly githubCommentAuthorName?: string; - - /** - * Enable Build.BuildID in pipeline - */ - readonly buildID?: string; - - readonly downloadCommandTemplate?: string; - - readonly isPublic?: boolean; -} - -export interface SDKAutomationContext { - /** - * The main logger that will be used to log the automation's state. Typically this will be a - * central telemetry database. This logger will be composed together with additional loggers as an - * automation event is processed. - */ - logger: Logger; - /** - * The client that will be used to interact with GitHub. - */ - github: GitHub; - /** - * The client that will be used to interact with Git. - */ - git: ExecutableGit; - /** - * The language configurations that will be supported. - */ - readonly supportedLanguageConfigurations: LanguageConfiguration[]; - /** - * A factory function that creates Compressor objects. - */ - readonly createCompressor: () => Compressor; - /** - * The runner object that will be used to execute external-process commands. - */ - readonly runner?: Runner; - /** - * The folder where SDKAutomation can create folders and clone repositories to. - */ - readonly automationWorkingFolderPath: string; - /** - * Whether or not to delete the locally cloned repositories used for generation. - */ - readonly deleteClonedRepositories: boolean; - /** - * An object that can be used to create and resolve blob proxy URLs. - */ - readonly blobProxy: BlobProxy; - /** - * Whether or not to generate each language in parallel. - */ - readonly generateLanguagesInParallel: boolean; - /** - * Whether or not to add timestamps to the blob loggers. - */ - readonly logTimestamps: boolean; - /** - * Whether or not to create generation pull requests for SDK repositories. - */ - readonly createGenerationPullRequests: boolean; - /** - * Author name of the generated comment displayed on github. Add "[bot]" to - * end of the name if we are github app. - */ - readonly githubCommentAuthorName: string; - - readonly getBlobLogger: (appendBlob: BlobStorageAppendBlob, options?: BlobLoggerOptions) => Logger; - - readonly artifactDownloadCommand: (url: string, filename: string) => string; - - readonly logContext: (logger?: Logger) => Promise; - - readonly isPublic: boolean; - - sdkAutomationVersion?: string; - - isPipelineTriggered: boolean; - - buildID: string; -} - -/** - * The main class for the SDK Automation application. - */ -export class SDKAutomation { - public context: SDKAutomationContext; - - /** - * Create a new SDKAutomation object that will use the provided context to handle events. - * @param automationWorkingFolderPath The folder where SDKAutomation will do its work. All folders and files - * created will be done inside of this folder. - * @param context The context that the SDKAutomation object will use to handle events. - */ - constructor(automationWorkingFolderPath: string, options: SDKAutomationOptions = {}) { - this.context = { - logger: (options.logger && splitLines(options.logger)) || getDefaultLogger(), - github: getGitHub(options.github, options.logger), - git: getGit(options.git, options.logger), - supportedLanguageConfigurations: getSupportedLanguages(options.supportedLanguageConfigurations, options.logger), - createCompressor: getCompressorCreator(options.compressorCreator), - getBlobLogger: this.getBlobLogger, - runner: options.runner, - automationWorkingFolderPath: resolve(automationWorkingFolderPath), - deleteClonedRepositories: - options.deleteClonedRepositories === undefined ? true : options.deleteClonedRepositories, - blobProxy: getBlobProxy(options.blobProxy, options.logger), - generateLanguagesInParallel: !!options.generateLanguagesInParallel, - logTimestamps: !!options.logTimestamps, - createGenerationPullRequests: !!options.createGenerationPullRequests, - githubCommentAuthorName: options.githubCommentAuthorName || 'openapi-bot[bot]', - buildID: options.buildID || '01', - isPipelineTriggered: false, - logContext: this.logContext, - artifactDownloadCommand: options.downloadCommandTemplate - ? (url, filename) => options.downloadCommandTemplate!.replace('{URL}', url).replace('{FILENAME}', filename) - : (url) => `curl ${url}`, - isPublic: !!options.isPublic - }; - } - - /** - * Log the context that a SpecificationPREvent will be handled with. - */ - public logContext = async (logger?: Logger): Promise => { - if (!logger) { - logger = this.context.logger; - } - - if (logger) { - this.context.sdkAutomationVersion = await getOpenAPISDKAutomationVersion(logger); - - if (this.context.github instanceof FakeGitHub) { - await logger.logWarning(`Using FakeGitHub client.`); - } else { - await logger.logInfo(`Using non-FakeGitHub client.`); - } - } - } - - public async pipelineTrigger( - repo: Repository, - pullRequestNumber: number, - workingPrefix: BlobStoragePrefix, - sdkRepoName: string, - isTriggeredByUP: boolean - ): Promise { - this.context.isPipelineTriggered = true; - await executeAndLog(this.context.logger, 'Failed to run SDK Automation: ', async () => { - await ensurePrefixContainerExists(workingPrefix, this.context.logger); - const pullRequest = await this.context.github.getPullRequest(repo, pullRequestNumber); - if (pullRequest.state === 'closed' && !pullRequest.merged) { - throw new Error(`TriggerError: PR is closed: ${pullRequest.html_url}. Please re-open the PR if you want to trigger the SDK generation.`); - } - const specPR = await getSpecificationPullRequest( - this.context, - workingPrefix, - pullRequest, - true, - isTriggeredByUP, - sdkRepoName - ); - await specPR.generateModifiedServices(); - }); - } - - public async filterSDKReposToTrigger( - repo: Repository, - pullRequestNumber: number, - workingPrefix: BlobStoragePrefix, - isTriggeredByUP: boolean - ): Promise { - this.context.isPipelineTriggered = true; - await executeAndLog(this.context.logger, 'Failed to run SDK Automation: ', async () => { - await ensurePrefixContainerExists(workingPrefix, this.context.logger); - const pullRequest = await this.context.github.getPullRequest(repo, pullRequestNumber); - if (pullRequest.state === 'closed' && !pullRequest.merged) { - throw new Error(`TriggerError: PR is closed: ${pullRequest.html_url}. Please re-open the PR if you want to trigger the SDK generation.`); - } - - const specPR = await getSpecificationPullRequest(this.context, workingPrefix, pullRequest, true, isTriggeredByUP); - const readmeMdRepositories = await specPR.getSDKReposToTrigger(); - const enabledJobs = ''.concat('|', readmeMdRepositories.join('|'), '|'); - - console.log(`##vso[task.setVariable variable=EnabledJobs;isOutput=true]${enabledJobs}`); - }); - } - - /** - * Create a Logger that writes its logs to the provided blob. - * @param appendBlob The blob to log to. - * @param options Options for the new logger. - */ - public getBlobLogger = (appendBlob: BlobStorageAppendBlob, options?: BlobLoggerOptions): Logger => { - return getBlobLogger(appendBlob, { - ...options, - logTimestamps: (options && options.logTimestamps) || this.context.logTimestamps - }); - } -} - -/** - * Get the version of the openapi-sdk-automation package that the application is using. - */ -export async function getOpenAPISDKAutomationVersion(logger?: Logger): Promise { - if (!logger) { - logger = getDefaultLogger(); - } - let result: string | undefined; - const expectedPackageName = 'openapi-sdk-automation'; - const packageJsonFilePath: string | undefined = await findFileInPath('package.json', __dirname); - if (!packageJsonFilePath) { - await logger.logWarning(`No package.json file found for ${expectedPackageName}.`); - } else { - const packageJson: PackageJson | undefined = readPackageJsonFileSync(packageJsonFilePath); - if (!packageJson) { - await logger.logWarning(`Failed to parse package.json file at ${packageJsonFilePath}.`); - } else { - if (packageJson.name !== expectedPackageName) { - await logger.logWarning( - `Closest package.json file (${packageJsonFilePath}) was not for ${expectedPackageName}.` - ); - } else { - await logger.logInfo(`Using ${expectedPackageName} version ${packageJson.version}.`); - result = packageJson.version; - } - } - } - return result; -} - -// tslint:disable-next-line: no-any -export function errorToLog(error: any, withStack: boolean = false): string { - return `${error.toString()}, ${JSON.stringify(error, undefined, 2)} ${(withStack && error.stack) || ''}`; -} - -/** - * Run the provided action and log any error that is thrown. - * @param logger The logger to use to log the error. - * @param errorMessagePrefix The prefix to prepend to the logged error message. - * @param action The action to run. - */ -export async function executeAndLog( - logger: Logger | undefined, - errorMessagePrefix: string | undefined, - action: () => T | Promise -): Promise { - let result: T; - try { - result = await Promise.resolve(action()); - } catch (error) { - if (logger) { - await logger.logError(`${errorMessagePrefix || ''}${errorToLog(error)}`); - } - throw error; - } - return result; -} - -async function ensurePrefixContainerExists(prefix: BlobStoragePrefix, logger?: Logger): Promise { - if (!logger) { - logger = getDefaultLogger(); - } - const prefixContainer: BlobStorageContainer = prefix.getContainer(); - await logger.logInfo(`Ensuring that the container at ${prefixContainer.getURL()} exists...`); - await prefixContainer.create(); -} - -const imagesFolderName = 'images'; -/** - * Ensure that the state images exist in the provided prefix. If they don't exist, then upload them. - * @param prefix The BlobStoragePrefix to ensure that the state images exist in. - */ -export async function ensureStateImagesExist(prefix: BlobStoragePrefix, logger?: Logger): Promise { - if (!logger) { - logger = getDefaultLogger(); - } - const imagesFolderPath: string | undefined = await findFolderInPath(imagesFolderName, __dirname); - if (!imagesFolderPath) { - await logger.logWarning(`Could not find the "${imagesFolderName}" folder.`); - } else { - await logger.logInfo(`Found the "${imagesFolderName}" folder at "${imagesFolderPath}".`); - - await ensurePrefixContainerExists(prefix, logger); - - for (const state of getSDKAutomationStates()) { - const imageBlob: BlobStorageBlockBlob = getSDKAutomationStateImageBlob(prefix, state); - const imageName: string = getSDKAutomationStateImageName(state); - const imageFilePath: string = joinPath(imagesFolderPath, imageName); - await logger.logInfo(`Uploading ${imageFilePath} to ${imageBlob.getURL()}...`); - await imageBlob.setContentsFromFile(imageFilePath, { contentType: `image/gif` }); - } - } -} - -const schemasFolderName = 'schemas'; -/** - * Ensure that the JSON schemas for the SDK Automation configuration files exist in the provided - * prefix. If they don't exist, then upload them. - * @param prefix The BlobStoragePrefix to ensure that the JSON schemas exist in. - */ -export async function ensureJSONSchemasExist(prefix: BlobStoragePrefix, logger?: Logger): Promise { - if (!logger) { - logger = getDefaultLogger(); - } - const schemasFolderPath: string | undefined = await findFolderInPath(schemasFolderName, __dirname); - if (!schemasFolderPath) { - await logger.logWarning(`Could not find the "${schemasFolderName}" folder.`); - } else { - await logger.logInfo(`Found the "${schemasFolderName}" folder at "${schemasFolderPath}".`); - - await ensurePrefixContainerExists(prefix, logger); - - const schemaFilePaths: string[] | undefined = await getChildFilePaths(schemasFolderPath, { recursive: true }); - if (!schemaFilePaths) { - await logger.logWarning(`No "${schemasFolderName}" folder found.`); - } else { - if (logger) { - await logger.logInfo(`Found ${schemaFilePaths.length} schema files:`); - for (const schemaFilePath of schemaFilePaths) { - await logger.logInfo(schemaFilePath); - } - } - - const schemaPrefix: BlobStoragePrefix = prefix.getPrefix(`${schemasFolderName}/`); - for (const schemaFilePath of schemaFilePaths) { - const schemaRelativeFilePath: string = pathRelativeTo(schemaFilePath, schemasFolderPath); - const schemaBlob: BlobStorageBlockBlob = schemaPrefix.getBlockBlob(schemaRelativeFilePath); - await logger.logInfo(`Uploading ${schemaFilePath} to ${schemaBlob.getURL()}...`); - await schemaBlob.setContentsFromFile(schemaFilePath, { contentType: `application/json` }); - } - } - } -} - -/** - * All of the languages that are supported by SwaggerToSDK. - */ -export function getAllLanguages(): LanguageConfiguration[] { - return [dotnetTrack2, pythonTrack2, dotnet, go, java, javascript, python, ruby, cli, trenton, azureresourceschema]; -} - -/** - * Get the client that will be used by an SDKAutomation object to interact with GitHub. - * @param github The GitHub client provided to the SDKAutomation constructor. - */ -export function getGitHub(github?: GitHub, logger?: Logger): GitHub { - if (logger) { - if (github) { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`Using provided GitHub.`); - } else { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`No provided GitHub. Using FakeGitHub instance.`); - } - } - return github || new FakeGitHub(); -} - -/** - * Get the client that will be used by an SDKAutomation object to interact with Git. - * @param git The Git client provided to the SDKAutomation constructor. - */ -export function getGit(git?: ExecutableGit, logger?: Logger): ExecutableGit { - if (logger) { - if (git) { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`Using provided Git.`); - } else { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`No provided Git. Using ExecutableGit instance.`); - } - } - return git || new ExecutableGit(); -} - -/** - * Get the languages that are supported by an SDKAutomation object. - * @param languages The languages that are supported by an SDKAutomation object. - */ -export function getSupportedLanguages( - languages?: - | LanguageConfiguration - | LanguageConfiguration[] - | ((defaultLanguages: LanguageConfiguration[]) => void | LanguageConfiguration | LanguageConfiguration[]), - logger?: Logger -): LanguageConfiguration[] { - let result: LanguageConfiguration[]; - if (Array.isArray(languages)) { - result = languages; - } else if (languages && typeof languages !== 'function') { - result = [languages]; - } else { - result = getAllLanguages(); - if (languages) { - const functionResult: void | LanguageConfiguration | LanguageConfiguration[] = languages(result); - if (functionResult) { - result = Array.isArray(functionResult) ? functionResult : [functionResult]; - } - } - } - - if (logger) { - // tslint:disable-next-line: no-floating-promises - logger.logInfo( - `Using supported languages: ${JSON.stringify(map(result, (language: LanguageConfiguration) => language.name))}` - ); - } - - return result; -} - -/** - * Get the compressor creator that an SDKAutomation object will use to handle events. - * @param compressorCreator The compressorCreator provided to the SDKAutomation constructor. - */ -export function getCompressorCreator(compressorCreator?: () => Compressor): () => Compressor { - return compressorCreator || (() => new ArchiverCompressor()); -} - -/** - * Get the HttpClient that an SDKAutomation object will use to handle events. - * @param httpClient The HttpClient provided to the SDKAutomation constructor. - */ -export function getHttpClient(httpClient?: HttpClient, logger?: Logger): HttpClient { - if (logger) { - if (httpClient) { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`Using provided HttpClient.`); - } else { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`No HttpClient provided. Using NodeHttpClient.`); - } - } - return httpClient || new NodeHttpClient(); -} - -/** - * Get the path to the current working directory's root. - */ -export function getRootFolderPath(): string { - return normalizePath(getRootPath(process.cwd())!); -} - -/** - * Get the working folder path that SDK Automation should work under. - * @param automationWorkingFolderPath The suggested folder path that SDK Automation should work - * under. If this isn't specified, then the current working directory will be used. - */ -export function getAutomationWorkingFolderPath(automationWorkingFolderPath?: string): string { - if (!automationWorkingFolderPath) { - automationWorkingFolderPath = process.cwd(); - } else if (!isRooted(automationWorkingFolderPath)) { - automationWorkingFolderPath = joinPath(process.cwd(), automationWorkingFolderPath); - } - return automationWorkingFolderPath; -} - -/** - * Create a temporary working folder in the provided base working folder path. If a temporary folder - * cannot be created in the provided base working folder path, then this function will attempt to - * create a temporary working folder in the current working directory. - * @param automationWorkingFolderPath The ideal folder that working folders will be created in. - */ -export async function getGenerationWorkingFolderPath(automationWorkingFolderPath?: string): Promise { - const customAutomationWorkingFolderPath: boolean = !!automationWorkingFolderPath; - automationWorkingFolderPath = getAutomationWorkingFolderPath(automationWorkingFolderPath); - - let generationWorkingFolderPath: string; - try { - generationWorkingFolderPath = await createTemporaryFolder(automationWorkingFolderPath); - } catch (error) { - if (!customAutomationWorkingFolderPath) { - throw error; - } else { - // Error when trying to create the working folder path. Fall back to creating a temporary - // folder in the current working directory. - generationWorkingFolderPath = await createTemporaryFolder(process.cwd()); - } - } - - return generationWorkingFolderPath; -} - -/** - * Get a blob that can be used to write logs to. - * @param prefix The prefix that the logs will be written under. - * @param blobName The name of the logs blob. Defaults to "logs.txt". - */ -export function getLogsBlob(prefix: BlobStoragePrefix, blobName: string = 'logs.txt'): BlobStorageAppendBlob { - return prefix.getAppendBlob(blobName); -} - -/** - * The content type of log blobs. - */ -export const logsBlobContentType = 'text/plain'; - -/** - * Create a blob that can be used to write logs to. - * @param prefix The prefix that the logs will be written under. - * @param blobName The name of the logs blob. Defaults to "logs.txt". - */ -export async function createLogsBlob( - prefix: BlobStoragePrefix, - blobName: string = 'logs.txt' -): Promise { - const logsBlob: BlobStorageAppendBlob = getLogsBlob(prefix, blobName); - await logsBlob.delete(); - await logsBlob.create({ contentType: logsBlobContentType }); - return logsBlob; -} - -/** - * Get a BlobStorageBlockBlob that can be used to write data under the provided prefix. - * @param prefix The prefix that the data blob will be written under. - */ -export function getDataBlob(prefix: BlobStoragePrefix): BlobStorageBlockBlob { - return prefix.getBlockBlob('data.json'); -} - -export interface BlobLoggerOptions extends LoggerOptions { - /** - * Whether or not to add timestamps to blob loggers. - */ - readonly logTimestamps?: boolean; - - /** - * Whether not to return instantly and defer the log action in background. - */ - readonly blockingAsync?: boolean; -} - -/** - * Create a Logger that writes its logs to the provided blob. - * @param appendBlob The blob to log to. - * @param options Options for the new logger. - */ -export function getBlobLogger(appendBlob: BlobStorageAppendBlob, options?: BlobLoggerOptions): Logger { - let contentBuffer = ''; - let flushingInProgress = false; - - const addToContents = async (contentsToAdd: string): Promise => { - try { - return await appendBlob.addToContents(contentsToAdd); - } catch (e) { - await appendBlob.create({ contentType: 'text/plain' }); - return appendBlob.addToContents(contentsToAdd); - } - }; - - const log = (text: string | string[]): Promise => { - let contentsToAdd = ''; - for (const textLine of toArray(text)) { - contentsToAdd += `${textLine}\n`; - } - - if (options && options.blockingAsync) { - return addToContents(contentsToAdd); - } - - // Deferred logging - contentBuffer += contentsToAdd; - if (flushingInProgress) { - // Someone else is writing to log. Let's return in advance. - return Promise.resolve(true); - } - - // Flushing logs. - flushingInProgress = true; - // tslint:disable-next-line: no-floating-promises - (async () => { - while (contentBuffer !== '') { - const contentToFlush = contentBuffer; - contentBuffer = ''; - await addToContents(contentToFlush); - } - flushingInProgress = false; - })(); - - return Promise.resolve(true); - }; - - let result: Logger = { - logInfo: log, - logError: log, - logWarning: log, - logSection: log, - logVerbose: log - }; - if (options) { - result = wrapLogger(result, options); - if (options.logTimestamps) { - result = timestamps(result); - } - } - return result; -} - -export function getBlobProxy(blobProxy?: BlobProxy, logger?: Logger): BlobProxy { - if (logger) { - if (blobProxy) { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`Using the provided BlobProxy.`); - } else { - // tslint:disable-next-line: no-floating-promises - logger.logInfo(`No BlobProxy provided. Using a FakeBlobProxy.`); - } - } - return blobProxy || new FakeBlobProxy(); -} - -/** - * Trim a single newline sequence from the end of the provided value, if the newline sequence - * exists on the value. - * @param value The value to trim. - */ -export function trimNewLine(value: string): string { - const trimEndLength: number = value.endsWith('\r\n') ? 2 : value.endsWith('\n') ? 1 : 0; - return trimEndLength === 0 ? value : value.substring(0, value.length - trimEndLength); -} - -/** - * Get a composite logger that will split the provided text logs into individual lines before - * passing them onto the composed loggers. - */ -export function getSplitLineCompositeLogger(...loggers: (Logger | undefined)[]): Logger { - return splitLines(getCompositeLogger(...loggers)); -} diff --git a/tools/spec-gen-sdk/src/sdkRepository.ts b/tools/spec-gen-sdk/src/sdkRepository.ts deleted file mode 100644 index a5c0185af13..00000000000 --- a/tools/spec-gen-sdk/src/sdkRepository.ts +++ /dev/null @@ -1,1442 +0,0 @@ -import { Logger, prefix, wrapLogger } from '@azure/logger-js'; -import { sync as rimrafSync } from 'rimraf'; -import { - any, - autorest, - AutoRestOptions, - AutoRestOptionValue, - BlobStorageAppendBlob, - BlobStoragePrefix, - Command, - contains, - createFolder, - ExecutableGit, - first, - folderExists, - getParentFolderPath, - getRepository, - Git, - GitHub, - GitHubGetPullRequestsOptions, - GitHubPullRequest, - joinPath, - map, - parseCommands, - pathRelativeTo, - replaceAll, - Repository, - run, - StringMap, - where, - commandToString, - findEntryInPath -} from '@ts-common/azure-js-dev-tools'; -import { ReadmeMdFileProcessMod, LanguageConfiguration } from './langSpecs/languageConfiguration'; -import { createPackageCommandOptions, runPackageCommands } from './langSpecs/packageCommand'; -import { createRepositoryCommandOptions, runRepositoryCommands } from './langSpecs/repositoryCommand'; -import { - createLogsBlob, - getSplitLineCompositeLogger, - trimNewLine, - errorToLog -} from './sdkAutomation'; -import { SDKAutomationState } from './sdkAutomationState'; -import { SDKRepositoryPackage, SDKRepositoryPackageData } from './langSpecs/sdkRepositoryPackage'; -import { - getCreateSdkPullRequests, - getSDKGenerationPullRequestBase, - SwaggerToSDKConfiguration, - getConfigMeta, - getConfigAdvancedOption -} from './swaggerToSDKConfiguration'; -import { updatePullRequestLabels } from './utils/githubUtils'; -import { getPullRequestRepository, SpecificationPullRequestData } from './specificationPullRequest'; -import { PackageCommandOptions } from './langSpecs/packageCommandOptions'; -import { RepositoryCommandOptions } from './langSpecs/repositoryCommandOptions'; -import { getRunnerReportLogger } from './runnerReportLogger'; -import { resolveChangedTags } from './utils/resolveChangedTags'; -import { existsSync } from 'fs'; -import { SpecificationPullRequestGenerationContext } from './specificationPullRequestGeneration'; - -const REMOTE_NAME_GEN = 'generation'; -const REMOTE_NAME_INT = 'integration'; -const REMOTE_NAME_MAIN = 'main'; -const REMOTE_NAME_SECONDARY = 'secondary'; -const BRANCH_GENERATION = 'sdkAutomation/generated'; - -export interface SDKRepositoryContext extends SpecificationPullRequestGenerationContext { - - /** - * Details about the specification pull request. - */ - specificationPullRequest?: SpecificationPullRequestData; - - isPipelineTriggered: boolean; - - useMergedRoutine: boolean; - - /** - * Update the generation data blobs with the current state of the generation. - */ - writeGenerationData(): Promise; -} - -/** - * The data that describes an SDK repository. - */ -export interface SDKRepositoryData { - /** - * The repository where the SDK's generation pull request and branch will be created. This is the - * first repository where the automatically generated SDK will appear. - */ - generationRepository: string; - /** - * The URL of the SDK's generation repository. - */ - generationRepositoryUrl: string; - /** - * The repository where the SDK's integration/staging pull request and branch will be created. The - * SDK's integration branch and pull request are where merged SDK generation pull requests will be - * staged before they are merged and published in the main repository. - */ - integrationRepository: string; - /** - * The URL of the SDK's integration repository. - */ - integrationRepositoryUrl: string; - /** - * Used for updating integration branch since some tooling scripts should be excluded. - */ - readonly secondaryRepository: string; - readonly secondaryRepositoryUrl: string; - readonly secondaryBranch: string; - /** - * The main repository for the SDK. This is where the SDK packages are published from. - */ - readonly mainRepository: string; - /** - * The URL of the SDK's main repository. - */ - readonly mainRepositoryUrl: string; - /** - * The prefix that will be applied to integration branches. - */ - readonly integrationBranchPrefix: string; - /** - * The name of the branch in the main repository that integration branches will be based on - * (integration pull requests will merge into). Defaults to "master"." - */ - readonly mainBranch: string; - /** - * The name of the programming language that was assigned to this SDK repository. - */ - readonly languageName: string; - /** - * The OpenAPI readme.md AutoRest configuration file URLs to generate within the context of this - * SDK repository. - */ - readonly readmeMdFileUrlsToGenerate: string[]; - /** - * The generation status for this SDK repository. - */ - status: SDKAutomationState; - /** - * Generation message to be shown. - */ - messages: string[]; - /** - * If sdk breaking change is detected. - */ - hasBreakingChange?: boolean; - /** - * The URL of the blob where this SDK repository's generation logs will be written to. - */ - logsBlobUrl?: string; - /** - * The URL of the blob where this SDK repository's diff will be written to. - */ - diffBlobUrl?: string; - /** - * The changed packages in this SDK repository. - */ - changedPackages?: SDKRepositoryPackageData[]; - - artifactsZipUrl?: string; -} - -/** - * An SDK repository that will have AutoRest run in it. - */ -export class SDKRepository { - /** - * The packages in this SDK repository that were changed after AutoRest was run. - */ - public readonly changedPackages: SDKRepositoryPackage[]; - - public readonly repoPath: string; - - public readonly git: ExecutableGit; - - /** - * Enable pipeline's Build.BuildID - */ - public readonly buildID: string; - public currentReadmeIndex: number; - - /** - * A mapping between a readme.md file's URL to the scripts that should be run after AutoRest is - * run on the readme.md file's URL. - */ - private readonly readmeMdAfterScripts: StringMap; - - private readonly remoteMainBranchName: string; - - private readonly localMainBranchName: string; - - private readonly enableCreatePullRequests: boolean; - - /** - * Used for integration branch since some tooling scripts should be excluded. - */ - private readonly remoteSecondaryRepositoryUrl: string; - private readonly remoteSecondaryBranchName: string; - - /** - * Create a new SDKRepository object. - * @param logsBlob The blob that this SDK repository's logs will be written to. - * @param logger The logger that will write logs related to this SDK repository. - * @param language The LanguageConfiguration that will be used for this SDKRepository. - * @param swaggerToSDKConfiguration The swagger_to_sdk_config.json file for this repository. - * @param specPRIterationPrefix The BlobStoragePrefix where this SDK repository's blobs will be written to. - * @param sdkRepositoryPrefix The BlobStoragePrefix where this SDK repository's blobs will be written to. - * @param context The context object that will be used to invoke operations outside of this - * object's scope. - * @param data The data that describes the SDKRepository. - * @param buildID The automation pipeline's BuildID. - */ - constructor( - public readonly logsBlob: BlobStorageAppendBlob, - public readonly logger: Logger, - public readonly language: LanguageConfiguration, - public readonly swaggerToSDKConfiguration: SwaggerToSDKConfiguration, - private readonly sdkRepositoryPrefix: BlobStoragePrefix, - public readonly context: SDKRepositoryContext, - public readonly data: SDKRepositoryData, - buildID: string - ) { - this.readmeMdAfterScripts = {}; - this.changedPackages = []; - this.enableCreatePullRequests = - getCreateSdkPullRequests(this.swaggerToSDKConfiguration) && this.context.createGenerationPullRequests; - this.remoteMainBranchName = this.data.mainBranch; - this.localMainBranchName = this.remoteMainBranchName; - this.remoteSecondaryBranchName = this.data.secondaryBranch; - this.remoteSecondaryRepositoryUrl = this.data.secondaryRepositoryUrl; - this.repoPath = getRepositoryFolderPath( - this.context.generationWorkingFolderPath, - this.swaggerToSDKConfiguration, - this.data.mainRepository - ); - this.git = this.context.git.scope({ - executionFolderPath: this.repoPath, - runner: this.context.runner, - throwOnError: true, - log: (text: string) => this.logger.logInfo(trimNewLine(text)), - showCommand: true - }); - this.buildID = buildID; - } - - public addReadmdMdAfterScripts(readmeMdFileUrl: string, afterScripts: string[]): void { - this.readmeMdAfterScripts[readmeMdFileUrl] = afterScripts; - } - - /** - * Generate the modified SDKs in this repository, upload any generated artifacts, and create any - * necessary pull requests in the SDK repository. - */ - public async generate(): Promise { - await this.logsBlob.create({ contentType: 'text/plain' }); - this.data.logsBlobUrl = this.context.getBlobProxyUrl(this.logsBlob); - this.data.status = 'inProgress'; - await this.context.writeGenerationData(); - if (this.context.useMergedRoutine) { - await this.closeGenerationPullRequests(true); - } - - try { - await createFolder(this.repoPath); - await this.rewriteRepositoryToFallback(); - await this.cloneSDKRepository(); - - const languageReadmeMdFileProcessModMod = this.language.readmeMdFileProcessMod ?? ReadmeMdFileProcessMod.Batch; - - for (this.currentReadmeIndex = 0; this.currentReadmeIndex - < this.data.readmeMdFileUrlsToGenerate.length; this.currentReadmeIndex ++ ) { - if (this.currentReadmeIndex > 0 - && languageReadmeMdFileProcessModMod.valueOf() !== ReadmeMdFileProcessMod.Batch) { - await this.resetSDKRepository(); - this.changedPackages.splice(0); - } - const readmeMdFileUrl = this.data.readmeMdFileUrlsToGenerate[this.currentReadmeIndex]; - await this.runGeneration(readmeMdFileUrl); - if (languageReadmeMdFileProcessModMod.valueOf() === ReadmeMdFileProcessMod.Batch - && this.currentReadmeIndex < this.data.readmeMdFileUrlsToGenerate.length - 1) { - continue; - } - await this.runAfterScriptsInRepo(); - - const changedPackages = await this.findChangedPackages(); - this.addChangedPackages(changedPackages); - - await this.forEachChangedPackage( - (changedPackage) => runLangAfterScript(this.language, this, changedPackage), - changedPackages); - - await this.context.writeGenerationData(); - - if (languageReadmeMdFileProcessModMod.valueOf() === ReadmeMdFileProcessMod.Batch) { - await this.logger.logInfo('readmeMdFileProcessMod: In Batch Mode.'); - for (const readmeMdFileUrlRunScript of this.data.readmeMdFileUrlsToGenerate) { - await this.forEachChangedPackage( - (changedPackage) => this.runAfterScripts(changedPackage, readmeMdFileUrlRunScript), - changedPackages - ); - } - } else { - await this.logger.logInfo('readmeMdFileProcessMod: In Sequencial Mode.'); - await this.forEachChangedPackage( - (changedPackage) => this.runAfterScripts(changedPackage, readmeMdFileUrl), - changedPackages - ); - } - - await this.git.addAll(); - await this.git.run(['commit', '--allow-empty', '-m', 'SDK Automation Generation']); - - await this.forEachChangedPackage( - (changedPackage) => this.createPackageAndInstallationInstruction(changedPackage), - changedPackages - ); - - // Token may expire after autorest generation so we refresh token here - await this.git.refreshRemoteAuthentication(); - - await this.forEachChangedPackage( - (changedPackage) => this.updateBranchForPullRequest(changedPackage), - changedPackages - ); - - await this.forEachChangedPackage(async (changedPackage) => { - const packageContentChanged = await this.updateTargetBranch(changedPackage); - if (packageContentChanged) { - await this.updateTargetPR(changedPackage); - await this.generateBreakingChangeLog(changedPackage); - } else { - await changedPackage.logger.logWarning('No file is changed.'); - } - if (changedPackage.data.status === 'inProgress') { - changedPackage.data.status = packageContentChanged ? 'succeeded' : 'warning'; - } - }, changedPackages); - - // await this.createArtifactsZip(); - await this.context.writeGenerationData(); - } - } catch (error) { - await this.logError(`SDK Repository Error: ${JSON.stringify(error, undefined, 2)}`); - await this.logError(error.stack); - - throw error; - } finally { - await this.deleteClonedSDKRepository(); - await this.updateStatusAfterGeneration(); - } - } - - /** - * Close the generation pull requests that are associated with the specification pull request. - * @param parallel Whether or not to close the generation pull requests in parallel. - */ - public async closeGenerationPullRequests(parallel: boolean): Promise { - const disableGenerationPRAutomation = getConfigAdvancedOption( - this.swaggerToSDKConfiguration, - 'disable_generation_pr_automation' - ); - const github: GitHub = this.context.github; - const generationRepository: string = this.data.generationRepository; - - return this.forEachGenerationPullRequest(parallel, async (generationPullRequest: GitHubPullRequest) => { - const generationPullRequestRepository: Repository = getPullRequestRepository(generationPullRequest); - - if (disableGenerationPRAutomation) { - await this.logger.logInfo( - `Skip to close generation pull request at ${generationPullRequest.html_url} as it's disabled in config.` - ); - } else { - try { - await this.logger.logInfo(`Closing pull request ${generationPullRequest.html_url}...`); - await github.closePullRequest(generationPullRequestRepository, generationPullRequest.number); - await this.logger.logInfo( - `Deleting branch "${generationPullRequest.head.ref}" in ${generationRepository}...` - ); - await github.deleteBranch(generationRepository, generationPullRequest.head.ref); - } catch (error) { - await this.logger.logError( - `Failed to close the generation pull request at ` + - `${generationPullRequest.html_url}: ${error}, ${JSON.stringify(error)}` - ); - } - } - - if (!this.context.isPipelineTriggered) { - await updatePullRequestLabels( - github, - generationPullRequestRepository, - generationPullRequest, - ['GenerationPR', 'SpecPRClosed'], - this.logger - ); - } - }); - } - - private async updateStatusAfterGeneration(): Promise { - if (this.data.status === 'inProgress') { - if (!any(this.data.changedPackages)) { - this.data.status = 'warning'; - } else { - const packageStates: SDKAutomationState[] = map( - this.data.changedPackages, - (changedPackage: SDKRepositoryPackageData) => changedPackage.status - ); - this.data.status = - first(packageStates, (packageState: SDKAutomationState) => packageState === 'failed') || - first(packageStates, (packageState: SDKAutomationState) => packageState === 'warning') || - 'succeeded'; - } - } - await this.context.writeGenerationData(); - if (this.data.status === 'failed') { - throw new Error('ResultFailure: The result is marked as failure due to at least one required step fails. Please refer to the detail log in pipeline run or local console for more information.'); - } - } - - /** - * Log an error message and set this SDK repository's status to "failed". - * @param errorMessage The error message to log. - */ - private logError(errorMessage: string): Promise { - this.data.status = 'failed'; - return Promise.all([this.logger.logError(errorMessage), this.context.writeGenerationData()]); - } - - private async checkRepositoryBranchesStatus(repositoryUrl: string): Promise { - const regexp: RegExp = /https:\/\/github.com\//; - repositoryUrl = repositoryUrl.replace(regexp, ''); - const branches = await this.context.github.getAllBranches(repositoryUrl); - let response: boolean; - if (branches && Array.isArray(branches) && branches.length > 0) { - response = true; - } else { - response = false; - } - return response; - } - - private async rewriteRepositoryToFallback(): Promise { - const [ - generationRepositoryExist, - integrationRepositoryExist, - mainRepositoryExist, - secondaryRepositoryExist - ] = await Promise.all([ - this.checkRepositoryBranchesStatus(this.data.generationRepositoryUrl), - this.checkRepositoryBranchesStatus(this.data.integrationRepositoryUrl), - this.checkRepositoryBranchesStatus(this.data.mainRepositoryUrl), - this.checkRepositoryBranchesStatus(this.data.secondaryRepositoryUrl) - ]); - - if (!mainRepositoryExist) { - throw new Error(`ConfigError: Main repository ${this.data.mainRepositoryUrl} doesn't exist. Please refer to the https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/sdkautomation/SpecConfigSchema.json schema to fix the 'mainRepository' in 'specificationRepositoryConfiguration.json' under the root folder of the 'azure-rest-api-specs(-pr) repository.`); - } - - if (!secondaryRepositoryExist) { - throw new Error(`ConfigError: Secondary repository ${this.data.secondaryRepositoryUrl} doesn't exist. Please refer to the https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/sdkautomation/SpecConfigSchema.json schema to fix the 'secondaryRepository' in 'specificationRepositoryConfiguration.json' under the root folder of the 'azure-rest-api-specs(-pr) repository.`); - } - - if (!integrationRepositoryExist) { - await this.logError( - `Integration repository ${this.data.integrationRepositoryUrl} doesn't exist. ` + - `Using fallback ${this.data.mainRepositoryUrl}` - ); - this.data.integrationRepository = this.data.mainRepository; - this.data.integrationRepositoryUrl = this.data.mainRepositoryUrl; - } - - if (!generationRepositoryExist) { - await this.logError( - `Generation repository ${this.data.generationRepositoryUrl} doesn't exist. ` + - `Using fallback ${this.data.integrationRepositoryUrl}` - ); - this.data.generationRepository = this.data.integrationRepository; - this.data.generationRepositoryUrl = this.data.integrationRepositoryUrl; - } - } - - private async deleteClonedSDKRepository(): Promise { - const repositoryFolderPath = this.repoPath; - - if (!this.context.deleteClonedRepositories) { - await this.logger.logInfo( - `Not deleting clone of ${this.data.generationRepository} at folder ${repositoryFolderPath}.` - ); - return; - } - - await this.logger.logSection( - `Deleting clone of ${this.data.generationRepository} at folder ${repositoryFolderPath}...` - ); - if (!(await folderExists(repositoryFolderPath))) { - await this.logger.logWarning(`repository folder (${repositoryFolderPath}) doesn't exist.`); - return; - } - - try { - rimrafSync(repositoryFolderPath); - } catch { - await this.logger.logWarning(`Failed to delete repository folder (${repositoryFolderPath}).`); - return; - } - - await this.logger.logInfo( - `Finished deleting clone of ${this.data.generationRepository} at folder ${repositoryFolderPath}.` - ); - } - - /** - * Clone this SDK repository to the provided folder path. - */ - private async cloneSDKRepository(): Promise { - await this.logger.logSection(`Cloning SDK repo...`); - - await this.git.resetRepoFolder(); - - await this.git.addRemote(REMOTE_NAME_GEN, this.data.generationRepositoryUrl); - await this.git.addRemote(REMOTE_NAME_INT, this.data.integrationRepositoryUrl); - await this.git.addRemote(REMOTE_NAME_MAIN, this.data.mainRepositoryUrl); - await this.git.addRemote(REMOTE_NAME_SECONDARY, this.data.secondaryRepositoryUrl); - await this.git.fetch({ remoteName: REMOTE_NAME_MAIN }); - await this.git.fetch({ remoteName: REMOTE_NAME_SECONDARY, refSpec: this.data.secondaryBranch }); - - await this.git.checkout(`${REMOTE_NAME_MAIN}/${this.data.mainBranch}`, { - localBranchName: this.localMainBranchName - }); - await this.git.checkout(this.localMainBranchName, { - localBranchName: BRANCH_GENERATION - }); - - return true; - } - - private async resetSDKRepository(): Promise { - await this.git.checkout(BRANCH_GENERATION); - await this.git.resetAll({ - hard: true, - target: this.localMainBranchName - }); - await this.git.run(['clean', '-xdf']); - } - - /** - * Get the generation pull requests in this SDK repository that were created as a result of the - * provided specification pull request. - * @param specificationPullRequestNumber The specification pull request's number. - */ - private async getGenerationPullRequests( - specificationPullRequestNumber: number, - options?: GitHubGetPullRequestsOptions - ): Promise { - const allPullRequests: GitHubPullRequest[] = []; - allPullRequests.push(...(await this.context.github.getPullRequests(this.data.integrationRepository, options))); - if (this.data.integrationRepository !== this.data.mainRepository) { - allPullRequests.push(...(await this.context.github.getPullRequests(this.data.mainRepository, options))); - } - const suffix = `@${specificationPullRequestNumber}`; - return where(allPullRequests, (pr: GitHubPullRequest) => pr.head.label.endsWith(suffix)); - } - - private async forEachChangedPackage( - action: (changedPackage: SDKRepositoryPackage) => unknown, - packages: SDKRepositoryPackage[], - predicate: (changedPackage: SDKRepositoryPackage) => boolean = (_) => true - ): Promise { - const filteredPackage = where(packages, predicate); - for (const changedPackage of filteredPackage) { - try { - await Promise.resolve(action(changedPackage)); - } catch (error) { - await changedPackage.logError(`SDK Repository Package Error: ${error}, ${JSON.stringify(error)}`); - } - } - } - - private async updateBranchForPullRequest(changedPackage: SDKRepositoryPackage): Promise { - const { - logger, - data: { useIntegrationBranch, integrationBranch } - } = changedPackage; - - if (!useIntegrationBranch) { - return; - } - - const checkOutIntegrationBranchFromSecondary = async () => - this.git.checkout(`${REMOTE_NAME_SECONDARY}/${this.remoteSecondaryBranchName}`, { - localBranchName: integrationBranch - }); - await checkOutIntegrationBranchFromSecondary(); - - if (!this.context.useMergedRoutine) { - await logger.logInfo( - `Update main branch ` + - `with secondary branch: ${this.remoteSecondaryRepositoryUrl}/${this.remoteSecondaryBranchName}` - ); - const secondaryRepositoryUrl = await this.git.getRemoteUrl(REMOTE_NAME_SECONDARY); - const integrationRepositoryUrl = await this.git.getRemoteUrl(REMOTE_NAME_INT); - if (secondaryRepositoryUrl !== integrationRepositoryUrl) { - try { - await this.git.push({ setUpstream: REMOTE_NAME_INT, branchName: this.localMainBranchName }); - } catch { - await logger.logError( - `Fail to push branch ${integrationBranch} to ${REMOTE_NAME_INT}/${this.localMainBranchName}` - ); - } - } - } - return; - } - - private async updateTargetBranch(changedPackage: SDKRepositoryPackage): Promise { - const { - logger, - data: { integrationBranch } - } = changedPackage; - const { targetName, targetRepo, targetBranch, baseBranch } = this.getGenBranchInfo(changedPackage); - - if (targetBranch !== integrationBranch) { - await this.git.checkout(baseBranch); - // Create Branch - await logger.logSection(`Creating SDK branch "${targetBranch}" in ${targetRepo} ...`); - // We generate output starting from main branch so checkout main branch here - await this.git.createLocalBranch(targetBranch); - } else { - await this.git.checkout(integrationBranch); - } - - await this.updatePackageFolderToIndexFromBranch(changedPackage, BRANCH_GENERATION); - // List files to add inside the package - const packageDiff: ExecutableGit.DiffResult = await this.git.diff({ - commit1: baseBranch, - usePager: false, - ignoreSpace: 'all', - staged: true, - nameOnly: true - }); - await logger.logInfo(`${packageDiff.filesChanged.length} files staged for commit:`); - for (const filePath of packageDiff.filesChanged) { - await logger.logInfo(pathRelativeTo(filePath, this.repoPath)); - } - - if (!any(packageDiff.filesChanged)) { - await logger.logInfo( - `No differences were detected between ` + - `the generation branch and its parent branch after the after_scripts were run.` - ); - changedPackage.data.status = 'warning'; - } else { - // Get commit message and commit - const specPullRequest = this.context.specificationPullRequest!; - const sdkCommitMessages: string[] = [`Generated from ${specPullRequest.headCommit}`]; - - if (this.context.useMergedRoutine) { - try { - const commitResponse = await this.context.github - .getCommit(specPullRequest.headRepository, specPullRequest.headCommit); - if (commitResponse !== undefined) { - sdkCommitMessages.push(commitResponse!.commit.message); - } - } catch (error) { - await logger.logWarning( - `Unable to get details about the head commit. ` + - `This is probably because the head commit is in a fork that we don't have permission to read from. ` + - `${error} ${JSON.stringify(error)}` - ); - } - } - - await this.git.commit(sdkCommitMessages); - } - - await logger.logInfo(`Pushing branch "${targetBranch}" to "${targetRepo}"...`); - await this.git.push({ setUpstream: targetName, branchName: targetBranch, force: true }); - - return any(packageDiff.filesChanged); - } - - private async updatePackageFolderToIndexFromBranch( - changedPackage: SDKRepositoryPackage, - refSpec: string - ): Promise { - const checkoutFolder = async (folderPath: string) => { - try { - rimrafSync(joinPath(changedPackage.repositoryFolderPath, folderPath)); - } catch { - await this.logger.logError( - `Fail to delete folder: ${joinPath(changedPackage.repositoryFolderPath, folderPath)}` - ); - } - const result = await this.git.run(['checkout', refSpec, '--', folderPath], { - throwOnError: false - }); - if (result.exitCode) { - changedPackage.data.status = 'warning'; - await changedPackage.logger.logWarning( - `Failed to checkout ${folderPath} from ${refSpec} . Please check ${refSpec} for detail.` - ); - } else { - await this.git.add(folderPath); - } - }; - - await checkoutFolder(changedPackage.data.relativeFolderPath); - - for (const folderPath of changedPackage.data.extraRelativeFolderPaths) { - await checkoutFolder(folderPath); - } - } - - private async createPackageAndInstallationInstruction(changedPackage: SDKRepositoryPackage): Promise { - if (!this.language.packageCommands || this.language.packageCommands.length === 0) { - await changedPackage.logger.logWarning(`${this.language.name} has no registered package commands.`); - } else { - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions(this, changedPackage); - if ( - await runPackageCommands( - changedPackage, - this.language.packageCommands, - packageCommandOptions, - this.language.isPrivatePackage - ) - ) { - await changedPackage.createAndUploadInstallationInstructions(); - } - } - } - - private async generateBreakingChangeLog(changedPackage: SDKRepositoryPackage): Promise { - if (typeof this.language.generateBreakingChangeReport !== 'function') { - return; - } - - let genSuccess = false; - try { - genSuccess = await this.language.generateBreakingChangeReport({ - changedPackage, - showCommand: true, - captureOutput: (text: string) => changedPackage.logger.logInfo(trimNewLine(text)), - captureError: (text: string) => changedPackage.logger.logError(trimNewLine(text)), - captureChangeLog: (text: string, containsBreakingChange?: boolean) => { - if (containsBreakingChange) { - this.data.hasBreakingChange = true; - changedPackage.data.hasBreakingChange = true; - changedPackage.data.status = 'warning'; - } - changedPackage.data.messages.push(`${text}`); - return changedPackage.logger.logInfo(trimNewLine(text)); - }, - log: (text: string) => changedPackage.logger.logInfo(trimNewLine(text)) - }); - } catch (e) { - await changedPackage.logError(`${e.stack} ${e.message}`); - } - - if (!genSuccess) { - await changedPackage.logError(`[ChangeLog] WARNING: Failed to generate ChangeLog.`); - changedPackage.data.status = 'warning'; - } - } - - private getGenBranchInfo( - changedPackage: SDKRepositoryPackage - ): { - baseName: string; - baseRepo: string; - baseBranch: string; - targetName: string; - targetRepo: string; - targetBranch: string; - } { - const useMergedRoutine = this.context.useMergedRoutine; - - let baseName: string = REMOTE_NAME_MAIN; - let baseRepo: string = changedPackage.data.mainRepository; - let baseBranch: string = this.remoteMainBranchName; - let targetName: string = REMOTE_NAME_GEN; - let targetRepo: string = changedPackage.data.generationRepository; - let targetBranch: string = changedPackage.data.generationBranch; - - if (changedPackage.data.useIntegrationBranch) { - if (useMergedRoutine) { - targetName = REMOTE_NAME_INT; - targetRepo = changedPackage.data.integrationRepository; - targetBranch = changedPackage.data.integrationBranch; - } else { - baseName = REMOTE_NAME_INT; - baseRepo = changedPackage.data.integrationRepository; - baseBranch = this.localMainBranchName; - } - } - - return { baseName, baseRepo, baseBranch, targetName, targetRepo, targetBranch }; - } - - private async updateTargetPR(changedPackage: SDKRepositoryPackage): Promise { - const { logger } = changedPackage; - - if (!this.enableCreatePullRequests) { - await logger.logWarning(`Creating pull request is disabled.`); - return; - } - - const useMergedRoutine = this.context.useMergedRoutine; - const { baseRepo, baseBranch, targetBranch, targetRepo } = this.getGenBranchInfo(changedPackage); - const headLabel = `${getRepository(targetRepo).owner}:${targetBranch}`; - - await logger.logInfo(`Checking if pull request exists...`); - const github = this.context.github; - const openPullRequests = - await github.getPullRequests(baseRepo, { - head: headLabel, - base: baseBranch, - state: 'open', - sort: 'updated' - // tslint:disable-next-line: no-any - } as any); - let pullRequest: GitHubPullRequest | undefined = first( - openPullRequests, - (openPullRequest: GitHubPullRequest) => openPullRequest.state === 'open' - ); - - const specPR = this.context.specificationPullRequest!; - let body = useMergedRoutine - ? `Created to release ${changedPackage.data.name}.\ -Reopen this PR to release the SDK. -If you can't reopen it, click \ -here\ - to create a new one.` - : `Created to sync ${specPR.htmlUrl}.`; - if (changedPackage.data.installationInstructions) { - body += `\n${changedPackage.data.installationInstructions}`; - } - const title = - `[${useMergedRoutine ? 'ReleasePR' : 'AutoPR'} ${this.language.packageNameAltPrefix || ''}${ - changedPackage.data.name - }]` + ` ${specPR.title}`; - - if (pullRequest) { - await logger.logInfo(`Pull request already exists at "${pullRequest.html_url}" Updating it.`); - await github.updatePullRequest(baseRepo, pullRequest.number, { title, body }); - } else { - await logger.logSection( - `Creating SDK pull request in "${baseRepo}" from "${targetBranch}" to "${baseBranch}"...` - ); - const maintainerCanModify: boolean = baseRepo === targetRepo; - pullRequest = await github.createPullRequest(baseRepo, baseBranch, headLabel, { - title, - body, - maintainerCanModify - }); - await logger.logInfo(`Created pull request at ${pullRequest.html_url}.`); - } - - if (useMergedRoutine && !this.language.keepReleasePROpen) { - await logger.logInfo(`Closing ReleasePR after created`); - await github.closePullRequest(baseRepo, pullRequest.number); - } - - if (!this.context.isPipelineTriggered) { - await updatePullRequestLabels(github, baseRepo, pullRequest, ['GenerationPR', 'SpecPRInProgress'], logger); - } - - changedPackage.data.generationPullRequestUrl = pullRequest.html_url; - changedPackage.data.generationPullRequestDiffUrl = pullRequest.html_url + '/files'; - } - - private addChangedPackages(changedPackages: SDKRepositoryPackage[]): void { - for (const changedPackage of changedPackages) { - if ( - !contains( - this.changedPackages, - (sdkPackage: SDKRepositoryPackage) => sdkPackage.data.name === changedPackage.data.name - ) - ) { - this.changedPackages.push(changedPackage); - - if (!this.data.changedPackages) { - this.data.changedPackages = []; - } - this.data.changedPackages.push(changedPackage.data); - } - } - } - - private async findChangedPackages(): Promise { - const diffResult = await this.getDiffResult(); - if (diffResult === undefined) { - await this.logger.logError('Failed to find any diff after autorest so no changed packages was found.'); - return []; - } - - const changedPackages: SDKRepositoryPackage[] = []; - const changedPackageFolderPaths: string[] = await this.getChangedPackageFolderPaths(diffResult); - let packageIndex: number = 1; - for (const changedPackageFolderPath of changedPackageFolderPaths) { - const relativePackageFolderPath: string = pathRelativeTo(changedPackageFolderPath, this.repoPath); - const packageName: string = await getPackageName(this.language, this.repoPath, relativePackageFolderPath, - this.data.readmeMdFileUrlsToGenerate[this.currentReadmeIndex]); - const altPackageName: string = this.language.packageNameAltPrefix - ? `${this.language.packageNameAltPrefix}${packageName}` - : packageName; - const packageDataMessages = []; - - const packagePrefix: BlobStoragePrefix = getPackagePrefix(this.sdkRepositoryPrefix, altPackageName); - const packageLogsBlob: BlobStorageAppendBlob = await createLogsBlob(packagePrefix); - // Add warning/error message to messages to show on github. - const logger = getSplitLineCompositeLogger( - prefix( - wrapLogger(this.logger, { - logError: this.logger.logInfo, - logWarning: this.logger.logInfo - }), - `[${altPackageName}]` - ), - this.context.getBlobLogger(packageLogsBlob), - this.language.RunnerReportLoggerCreator ? - this.language.RunnerReportLoggerCreator(packageDataMessages) : - getRunnerReportLogger(packageDataMessages) - ); - await logger.logInfo(`Package name for "${changedPackageFolderPath}" is "${altPackageName}".`); - - const extraRelativeFolderPaths = this.language.getExtraRelativeFolderPaths - ? await this.language.getExtraRelativeFolderPaths(relativePackageFolderPath, diffResult.filesChanged, logger) - : []; - const useIntegrationBranch = - getSDKGenerationPullRequestBase(this.swaggerToSDKConfiguration) === 'integration_branch'; - const integrationBranch = `${this.data.integrationBranchPrefix}/${altPackageName.replace(/\//g, '_')}`; - const generationBranch = - `${integrationBranch}@` + - `${this.context.specificationPullRequest ? this.context.specificationPullRequest.number : 'specPrNumber'}`; - - const packageData: SDKRepositoryPackageData = { - name: packageName, - messages: packageDataMessages, - relativeFolderPath: relativePackageFolderPath, - extraRelativeFolderPaths: extraRelativeFolderPaths, - status: 'inProgress', - logsBlobUrl: this.context.getBlobProxyUrl(packageLogsBlob), - changedFilePaths: where(diffResult.filesChanged, (changedFilePath: string) => - changedFilePath.startsWith(changedPackageFolderPath) - ), - integrationBranch, - integrationRepository: this.data.integrationRepository, - useIntegrationBranch, - generationBranch, - generationRepository: this.data.generationRepository, - generationRepositoryUrl: this.data.generationRepositoryUrl, - mainRepository: this.data.mainRepository, - isPrivatePackage: this.language.isPrivatePackage === undefined ? false : this.language.isPrivatePackage - }; - - changedPackages.push( - new SDKRepositoryPackage( - this.repoPath, - this.language, - packageLogsBlob, - packagePrefix, - logger, - this.context, - packageData, - this.currentReadmeIndex * 100 + packageIndex - ) - ); - packageIndex++; - } - if (changedPackages.length === 0) { - await this.logger.logWarning('Failed to find any changed packages. Please check the changed file list.'); - await this.logger.logWarning(diffResult.filesChanged.join('\n')); - } - return changedPackages; - } - - private async getChangedPackageFolderPaths(diffResult: Git.DiffResult): Promise { - const result: string[] = []; - if (!this.language.packageRootFileName) { - await this.logger.logInfo( - `No packageRootFileName property has been specified in the language configuration for ${this.language.name}.` - ); - } else { - for (const modifiedFile of diffResult.filesChanged) { - const packageRootFilePath: string | undefined = await findEntryInPath( - this.language.packageRootFileName, - modifiedFile, - (path) => existsSync(path) - ); - if (!packageRootFilePath) { - await this.logger.logVerbose(`No package root file found for modified file ${modifiedFile}.`); - } else { - const packageFolderPath: string = getParentFolderPath(packageRootFilePath); - if (packageFolderPath !== this.repoPath && !contains(result, packageFolderPath)) { - result.push(packageFolderPath); - } - } - } - - await this.logger.logInfo(`Found ${result.length} package folder${result.length === 1 ? '' : 's'} that changed:`); - for (const changedPackageFolder of result) { - await this.logger.logInfo(` ${changedPackageFolder}`); - } - } - - return result; - } - - private async getDiffResult(): Promise { - await this.logger.logSection('Getting diff after AutoRest ran...'); - const diffBlob: BlobStorageAppendBlob = getDiffBlob(this.sdkRepositoryPrefix); - await diffBlob.create({ contentType: 'text/plain' }); - const diffBlobLogger: Logger = await this.context.getBlobLogger(diffBlob); - - // We stage all files before diffing so that we can detect new/untracked files. If we didn't, - // then new/untracked files wouldn't show up in the diff. - await this.git.addAll(); - let firstLineLogged = false; - const gitDiffResult: Git.DiffResult = await this.git.diff({ - usePager: false, - commit1: `${REMOTE_NAME_MAIN}/${this.data.mainBranch}`, - ignoreSpace: 'all', - staged: true, - showResult: true, - log: async (text: string) => { - if (!firstLineLogged) { - await this.logger.logInfo(trimNewLine(text)); - firstLineLogged = true; - } - await diffBlobLogger.logInfo(trimNewLine(text)); - } - }); - await this.git.resetAll(); - this.data.diffBlobUrl = this.context.getBlobProxyUrl(diffBlob); - - let result: Git.DiffResult | undefined; - if (!any(gitDiffResult.filesChanged)) { - await this.logger.logInfo(`No changes were detected after AutoRest ran.`); - } else { - result = gitDiffResult; - await this.logger.logInfo(`The following files were changed:`); - for (const file of gitDiffResult.filesChanged) { - await this.logger.logInfo(` ${file}`); - } - } - - return result; - } - - private async runGeneration(readmeMdFileUrl: string): Promise { - const runGen = async (options: AutoRestOptions) => { - await addAutoRestAndGeneratorVersions(options, this.language, this.logger); - if (this.language.generationCommands) { - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions(this, this.repoPath); - return await runRepositoryCommands(this, this.language.generationCommands, repositoryCommandOptions); - } - - try { - await autorest(readmeMdFileUrl, options, { - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest'), - runner: this.context.runner, - executionFolderPath: this.repoPath, - showCommand: true, - log: (text: string) => this.logger.logInfo(trimNewLine(text)), - captureOutput: (text: string) => this.logger.logInfo(trimNewLine(text)), - captureError: (text: string) => this.logger.logError(trimNewLine(text)), - capturePrefix: 'AutoRest', - throwOnError: true - }); - return true; - } catch (error) { - await this.logError(`Failed to run autorest.`); - await this.logError(errorToLog(error, false)); - return false; - } - }; - - const autorestOptions = await getResolvedAutoRestOptions( - this.repoPath, - this.swaggerToSDKConfiguration, - readmeMdFileUrl, - 'autorest_options' - ); - - const autorestOptionsForOtherSDK = await getResolvedAutoRestOptions( - this.repoPath, - this.swaggerToSDKConfiguration, - readmeMdFileUrl, - 'autorest_options_for_otherSDK' - ); - - if (Object.keys(autorestOptionsForOtherSDK).length > 0 && !(autorestOptionsForOtherSDK instanceof Array)) { - await runGen(autorestOptionsForOtherSDK); - await this.logger.logInfo('Finish autorest_option_for_otherSDK'); - } - - if (!(autorestOptions instanceof Array)) { - return runGen(autorestOptions); - } - - let result = true; - for (const autorestOption of autorestOptions) { - result = result && (await runGen(autorestOption)); - } - return result; - } - - private async runAfterScriptsInRepo(): Promise { - const scripts = getConfigMeta(this.swaggerToSDKConfiguration, 'after_scripts_in_repo') || []; - if (scripts.length === 0) { - await this.logger.logInfo('No after_scripts_in_repo to run'); - return; - } - - const commandOptions = createRepositoryCommandOptions(this, this.repoPath); - const envConfig = getConfigMeta(this.swaggerToSDKConfiguration, 'envs') || {}; - const envs = resolveEnvironmentVariables(envConfig, this.repoPath); - - const commands: Command[] = []; - scripts.forEach((script) => commands.push(...parseCommands(script))); - for (const command of commands) { - replaceCommandVariables(command, commandOptions, this.logger); - try { - await run(command, undefined, { - ...commandOptions, - runner: this.context.runner, - executionFolderPath: this.repoPath, - showCommand: true, - showResult: true, - log: this.logger.logInfo, - environmentVariables: envs, - capturePrefix: `after_scripts_in_repo|${command.executable}`, - throwOnError: true - }); - } catch (e) { - await this.logger.logError(`Failed to run after_scripts_in_repo: ${commandToString(command)}`); - this.data.status = 'failed'; - throw e; - } - } - } - - private async runAfterScripts(changedPackage: SDKRepositoryPackage, readmeMdFileUrl: string): Promise { - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions(this, changedPackage); - - if (this.language.afterGenerationCommands && this.language.afterGenerationCommands.length > 0) { - await runPackageCommands(changedPackage, this.language.afterGenerationCommands, packageCommandOptions); - } - - const afterScripts = getConfigMeta(this.swaggerToSDKConfiguration, 'after_scripts') || []; - const readmeMdAfterScripts: string[] | undefined = this.readmeMdAfterScripts[readmeMdFileUrl]; - if (readmeMdAfterScripts) { - afterScripts.push(...readmeMdAfterScripts); - } - - if (afterScripts.length === 0) { - await changedPackage.logger.logInfo(`No after_scripts to run.`); - return; - } - - const envConfig = getConfigMeta(this.swaggerToSDKConfiguration, 'envs'); - const envs = resolveEnvironmentVariables(envConfig, changedPackage.repositoryFolderPath); - await changedPackage.logger.logSection(`Running after_scripts...`); - - const afterScriptCommands: Command[] = []; - for (const afterScript of afterScripts) { - afterScriptCommands.push(...parseCommands(afterScript)); - } - - for (const afterScriptCommand of afterScriptCommands) { - replaceCommandVariables(afterScriptCommand, packageCommandOptions, changedPackage.logger); - try { - await run(afterScriptCommand, undefined, { - ...packageCommandOptions, - runner: changedPackage.context.runner, - executionFolderPath: changedPackage.repositoryFolderPath, - showCommand: true, - showResult: true, - log: (text: string) => changedPackage.logger.logInfo(trimNewLine(text)), - environmentVariables: envs, - capturePrefix: `after_scripts|${afterScriptCommand.executable}`, - throwOnError: true - }); - } catch (e) { - if (changedPackage.data.relativeFolderPath === 'schemas') { - changedPackage.data.status = 'warning'; - } else { - await changedPackage.logError(`Failed to run after_scripts: ${commandToString(afterScriptCommand)}`); - changedPackage.data.status = 'failed'; - } - return; - } - } - } - - private async forEachGenerationPullRequest( - parallel: boolean, - action: (generationPullRequest: GitHubPullRequest) => Promise - ): Promise { - const specificationPullRequest = this.context.specificationPullRequest!; - - await this.logger.logInfo( - `Getting generation pull requests for specification pull request ${specificationPullRequest.htmlUrl}...` - ); - const matchingGenerationPullRequests: GitHubPullRequest[] = await this.getGenerationPullRequests( - specificationPullRequest.number, - { open: true } - ); - if (!any(matchingGenerationPullRequests)) { - await this.logger.logInfo(`No generation pull requests found.`); - } else { - if (parallel) { - await Promise.all( - matchingGenerationPullRequests.map((matchingGenerationPullRequest: GitHubPullRequest) => { - return action(matchingGenerationPullRequest); - }) - ); - } else { - for (const matchingGenerationPullRequest of matchingGenerationPullRequests) { - await action(matchingGenerationPullRequest); - } - } - } - } -} - -/** - * Convert each value in the StringMap using the conversion function. - * @param map The map to convert. - * @param conversion The conversion function that converts values of type T to values of type U. - */ -export function resolveEnvironmentVariables( - envMap: StringMap | undefined, - repositoryFolderPath: string -): StringMap { - const envs: StringMap = {}; - for (const [entryName, entryValue] of Object.entries(process.env)) { - envs[entryName] = entryValue || ''; - } - - if (envMap) { - for (let [entryName, entryValue] of Object.entries(envMap)) { - if (entryName.toLowerCase().startsWith('sdkrel:')) { - entryName = entryName.substring('sdkrel:'.length); - entryValue = joinPath(repositoryFolderPath, entryValue as string); - } - envs[entryName] = entryValue.toString(); - } - } - - return envs; -} - -export async function getResolvedAutoRestOptions( - repositoryFolderPath: string, - swaggerToSDKConfiguration: SwaggerToSDKConfiguration, - readmeMdFileUrl: string, - optionName: 'autorest_options' | 'autorest_options_for_otherSDK' -): Promise { - const autorestOptions: AutoRestOptions = getConfigMeta(swaggerToSDKConfiguration, optionName) || {}; - let resolveChangedTagsOptionName: string | undefined = undefined; - - for (const autorestOptionName of Object.keys(autorestOptions)) { - const autorestOptionValue: AutoRestOptionValue = autorestOptions[autorestOptionName]; - if (autorestOptionName.startsWith('sdkrel:') && typeof autorestOptionValue === 'string') { - const resolvedAutorestOptionName: string = autorestOptionName.substring('sdkrel:'.length); - const resolvedAutorestOptionValue: string = joinPath(repositoryFolderPath, autorestOptionValue); - delete autorestOptions[autorestOptionName]; - autorestOptions[resolvedAutorestOptionName] = resolvedAutorestOptionValue; - } - - if (autorestOptionName.startsWith('tags-changed-in-batch:')) { - resolveChangedTagsOptionName = autorestOptionName.substring('tags-changed-in-batch:'.length); - autorestOptions[resolveChangedTagsOptionName] = autorestOptions[autorestOptionName]; - delete autorestOptions[autorestOptionName]; - } - } - - if (resolveChangedTagsOptionName === undefined) { - return autorestOptions; - } - - // Try to resolve the changed tags - const changedTags = await resolveChangedTags(); - delete autorestOptions[resolveChangedTagsOptionName]; - return changedTags.map((tagName) => ({ - ...autorestOptions, - tag: tagName - })); -} - -export async function addAutoRestAndGeneratorVersions( - autorestOptions: AutoRestOptions, - languageConfiguration: LanguageConfiguration, - logger: Logger -): Promise { - if (typeof autorestOptions.use !== 'string' || !autorestOptions.use) { - await logger.logInfo( - `No generator was specified to use for this ${languageConfiguration.name} SDK repository. ` + - `Defaulting to ${languageConfiguration.generatorPackageName}.` - ); - autorestOptions.use = languageConfiguration.generatorPackageName; - } -} - -/** - * Get the path that the repository should be cloned to. - * @param workingFolderPath The path to the current generation instance's working folder. - * @param swaggerToSDKConfig The SwaggerToSDK configuration from the repository. - * @param repositoryNumber The repository's number in the ordered of repositories in the - * generation's readme.md file. - */ -export function getRepositoryFolderPath( - workingFolderPath: string, - swaggerToSDKConfig: SwaggerToSDKConfiguration | undefined, - repository: string -): string { - const repositoryFolderRelativePath: string = - getConfigAdvancedOption(swaggerToSDKConfig, 'clone_dir') || getRepository(repository).name; - return joinPath(workingFolderPath, repositoryFolderRelativePath); -} - -export function getDiffBlob(storagePrefix: BlobStoragePrefix): BlobStorageAppendBlob { - return storagePrefix.getAppendBlob('diff.txt'); -} - -/** - * Get the name of the package at the provided package folder path. - * @param languageConfiguration The language configuration for the package. - * @param rootedRepositoryFolderPath The rooted folder path to the cloned repository. - * @param relativePackageFolderPath The relative folder path from the root of the repository to the - * package folder. - */ -export function getPackageName( - languageConfiguration: LanguageConfiguration, - rootedRepositoryFolderPath: string, - relativePackageFolderPath: string, - readmeMdFileUrl: string -): Promise { - return Promise.resolve( - languageConfiguration.packageNameCreator - ? languageConfiguration.packageNameCreator(rootedRepositoryFolderPath, relativePackageFolderPath, readmeMdFileUrl) - : relativePackageFolderPath - ); -} - -export async function runLangAfterScript( - languageConfiguration: LanguageConfiguration, - sdkRepo: SDKRepository, - changedPackage: SDKRepositoryPackage -): Promise { - if (languageConfiguration.runLangAfterScripts) { - await changedPackage.logger.logInfo('Running runLangAfterScript'); - return languageConfiguration.runLangAfterScripts(sdkRepo, changedPackage); - } else { - await changedPackage.logger.logInfo('No run LangAfterScript'); - } - return true; -} - -export function getPropertyNameMatch(propertyName: string): string { - return replaceAll(replaceAll(propertyName, '_', ''), '-', '')!.toLowerCase(); -} - -export function createCommandProperties(values: StringMap): StringMap { - const result: StringMap = {}; - for (const [propertyName, propertyValue] of Object.entries(values)) { - if (typeof propertyValue === 'string' || typeof propertyValue === 'number' || typeof propertyValue === 'boolean') { - const propertyNameMatch: string = getPropertyNameMatch(propertyName); - result[propertyNameMatch] = propertyValue.toString(); - } - } - return result; -} - -/** - * Replace any variable references in the provided command. - * @param command The command to replace variable references in. - * @param options The properties to use to replace variable references in the command. - */ -export function replaceCommandVariables(command: Command, options: unknown, logger: Logger): void { - const properties: StringMap = createCommandProperties(options as StringMap); - - command.executable = replaceStringVariables(command.executable, properties, logger); - - if (any(command.args)) { - for (let i = 0; i < command.args.length; ++i) { - command.args[i] = replaceStringVariables(command.args[i], properties, logger); - } - } -} - -export function replaceStringVariables(value: string, properties: StringMap, logger: Logger): string { - const propertyReferenceRegex: RegExp = /\$\((.*?)\)/; - - let result = ''; - let remaining: string = value; - // tslint:disable-next-line: no-constant-condition - while (true) { - const match: RegExpExecArray | null = propertyReferenceRegex.exec(remaining); - if (!match) { - result += remaining; - break; - } else { - result += remaining.substring(0, match.index); - - const propertyReference: string = match[0]; - remaining = remaining.substring(match.index + propertyReference.length); - - const propertyReferenceName: string = match[1]; - const propertyNameMatch: string = getPropertyNameMatch(propertyReferenceName); - let propertyValue: string | undefined = properties[propertyNameMatch]; - if (propertyValue === undefined) { - for (const [matchPropertyName, matchPropertyValue] of Object.entries(properties)) { - if (propertyNameMatch === getPropertyNameMatch(matchPropertyName)) { - propertyValue = matchPropertyValue; - break; - } - } - } - - if (propertyValue === undefined) { - result += propertyReference; - // tslint:disable-next-line: no-floating-promises - logger.logWarning(`Found no property replacement for "${propertyReferenceName}" in "${value}".`); - } else { - remaining = propertyValue + remaining; - } - } - } - - return result; -} - -function getPackagePrefix(storagePrefix: BlobStoragePrefix, packageName: string): BlobStoragePrefix { - return storagePrefix.getPrefix(`${packageName}/`); -} diff --git a/tools/spec-gen-sdk/src/sdkRepositoryMapping.ts b/tools/spec-gen-sdk/src/sdkRepositoryMapping.ts deleted file mode 100644 index adc6ecf4f34..00000000000 --- a/tools/spec-gen-sdk/src/sdkRepositoryMapping.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * The mapping that determines where different branches/pull requests will be created within the SDK - * Automation process. - */ -export interface SDKRepositoryMapping { - /** - * The repository where the SDK's generation pull request and branch will be created. This is the - * first repository where the automatically generated SDK will appear. If this is not specified, - * then the integrationRepository will be used instead. - */ - generationRepository: string; - /** - * The repository where the SDK's integration/staging pull request and branch will be created. The - * SDK's integration branch and pull request are where merged SDK generation pull requests will be - * staged before they are merged and published in the main repository. If this is not specified, - * then the mainRepository will be used instead. - */ - integrationRepository: string; - /** - * The main repository for the SDK. This is where the SDK packages are published from. - */ - mainRepository: string; - /** - * The secondary repository for the SDK since some SDK should exclude tooling scripts. - * If this is not specified, then the mainRepository will be used instead. - */ - secondaryRepository: string; - /** - * The prefix that will be applied to the beginning of integration branches. Defaults to - * "sdkAutomation". - */ - integrationBranchPrefix: string; - /** - * The name of the branch in the main repository that integration branches will be based on - * (integration pull requests will merge into). Defaults to "master"." - */ - mainBranch: string; - /** - * The name of the branch in the secondary repository that integration branches will be based on - * (integration pull requests will merge into). Defaults to "master". - */ - secondaryBranch: string; - - configFilePath: string; -} - -/** - * The default prefix that will be applied to integration branches. - */ -export const defaultIntegrationBranchPrefix = 'sdkAutomation'; -/** - * The default main branch in the main repository that integration branches will be based on. - */ -export const defaultMainBranch = 'master'; - -export const defaultConfigFilePath = 'swagger_to_sdk_config.json'; diff --git a/tools/spec-gen-sdk/src/specificationPREvent.ts b/tools/spec-gen-sdk/src/specificationPREvent.ts deleted file mode 100644 index 28914e497e2..00000000000 --- a/tools/spec-gen-sdk/src/specificationPREvent.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { BlobStoragePrefix, ExecutableGit, GitHub, GitHubPullRequestWebhookBody } from '@ts-common/azure-js-dev-tools'; - -/** - * A data type that contains the GitHub pull request webhook body that GitHub sent when an OpenAPI - * specification pull request is changed. - */ -export interface SpecificationPREvent { - /** - * The webhook body that was sent by GitHub when the OpenAPI specification pull request was - * changed. - */ - readonly webhookBody: GitHubPullRequestWebhookBody; - /** - * The blob storage prefix that should be used to store all data that is created as a result of - * the automation. - */ - readonly workingPrefix: BlobStoragePrefix; - /** - * The new Logger that SDK Automation should use to log. - */ - readonly logger?: Logger; - /** - * The new GitHub client that SDK Automation should use to interact with GitHub. - */ - readonly github?: GitHub; - /** - * The new Git client that SDK Automation should use to interact with Git. - */ - readonly git?: ExecutableGit; -} diff --git a/tools/spec-gen-sdk/src/specificationPullRequest.ts b/tools/spec-gen-sdk/src/specificationPullRequest.ts deleted file mode 100644 index 20f1d891c99..00000000000 --- a/tools/spec-gen-sdk/src/specificationPullRequest.ts +++ /dev/null @@ -1,1012 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { - a, - any, - b, - BlobStorageBlob, - BlobStorageBlockBlob, - BlobStoragePrefix, - body, - BuilderActions, - contains, - details, - getParentFolderPath, - getPathName, - getRepository, - getRepositoryBranch, - getRepositoryFullName, - GitHubComment, - GitHubPullRequest, - h3, - html, - img, - joinPath, - LIBuilder, - Repository, - RepositoryBranch, - RepositoryConfiguration, - StringMap, - URLBuilder, - where, - h4, - getGithubRepositoryUrl, - first, - RealGitHub, - getFilesChangedFromFullDiff -} from '@ts-common/azure-js-dev-tools'; -import { executeAndLog, getDataBlob, trimNewLine, SDKAutomationContext } from './sdkAutomation'; -import { getSDKAutomationStateImageBlob, getSDKAutomationStateString, SDKAutomationState } from './sdkAutomationState'; -import { SDKRepositoryData } from './sdkRepository'; -import { SDKRepositoryPackageData } from './langSpecs/sdkRepositoryPackage'; -import { - getSpecificationPullRequestGeneration, - SpecificationPullRequestGeneration, - SpecificationPullRequestGenerationData, - getLanguageConfigurationForRepository -} from './specificationPullRequestGeneration'; -import { SpecificationReadmeMdFile } from './specificationReadmeMdFile'; -import { - SpecificationRepositoryConfiguration, - getSpecificationRepositoryConfiguration -} from './specificationRepositoryConfiguration'; -import { addPullRequestLabel, removePullRequestLabel } from './utils/githubUtils'; -import { existsSync, readFileSync } from 'fs'; -import * as Handlebars from 'handlebars'; -import * as format from '@azure/swagger-validation-common'; -import * as fs from 'fs-extra'; - -/** - * The data that describes a OpenAPI specification pull request. - */ -export interface SpecificationPullRequestData { - /** - * The GitHub repository that should be used for getting files. - */ - readonly specPRRepository: Repository; - /** - * The SHA hash for that commit that should be used for getting files. - */ - readonly specPRCommit: string; - /** - * The GitHub repository that the pull request exists in. - */ - readonly baseRepository: Repository; - /** - * The pull request's number. - */ - readonly number: number; - /** - * The GitHub repository that the pull request is attempting to merge from. - */ - readonly headRepository: Repository; - /** - * The branch that the pull request is attempting to merge from. - */ - readonly headBranch: RepositoryBranch; - /** - * The SHA hash for the commit that is trying to merge. - */ - readonly headCommit: string; - /** - * The branch that the pull request is attempting to merge into. - */ - readonly baseBranch: RepositoryBranch; - /** - * The URL to the html version of the pull request. - */ - readonly htmlUrl: string; - /** - * The temporary SHA hash for the commit that will result if the pull request is merged. The - * initial event that GitHub sends when a pull request is created will not have a merge commit, so - * in those cases this will be undefined. - */ - readonly mergeCommit: string | undefined; - - readonly merged: boolean | undefined; - /** - * The title of the pull request. - */ - readonly title: string; - /** - * The id of the comment that SDK Automation will write its status to. - */ - commentId?: number; - /** - * The URL of the blob where this pull request's data will be written to. - */ - readonly dataBlobUrl: string; - /** - * Data pertaining to this specific generation. - */ - readonly generation: SpecificationPullRequestGenerationData; -} - -/** - * An object that can be used to interact with a OpenAPI specification pull request. - */ -export class SpecificationPullRequest { - private readonly specRepoFolder: string; - - /** - * Create a new SpecificationPullRequest object that can be used to interact with the existing - * GitHub OpenAPI specification pull request. - * @param context The SDKAutomation context that the SpecificationPullRequest should use. - * @param automationWorkingPrefix The working prefix for the SDK Automation application. - * @param dataBlob The blob storage blob that this pull request's generation data will be written - * to. - * @param generation The SpecificationPullRequestGeneration object that contains information about - * this specification generation. - * @param data The data that describes this OpenAPI specification pull request. - * @param isTriggeredByUP Whether the SDKAutomation is triggered by unified pipeline or not. - * @param sdkRepoName Selected SDK repo name to generate. Used in pipeline. - */ - constructor( - public readonly context: SDKAutomationContext, - private readonly automationWorkingPrefix: BlobStoragePrefix, - public readonly dataBlob: BlobStorageBlockBlob, - public readonly generation: SpecificationPullRequestGeneration, - public readonly data: SpecificationPullRequestData, - public readonly isTriggeredByUP: boolean, - private readonly sdkRepoName?: string - ) { - this.specRepoFolder = joinPath(context.automationWorkingFolderPath, this.data.specPRRepository.name); - } - - /** - * Generate SDKs and create pull requests for any services that were modified or added in this - * specification pull request. - */ - public async generateModifiedServices(): Promise { - await this.cloneSpecRepo(); - await this.populateSDKRepositoryReadmeMdFilesToGenerate(); - await this.generation.generateSDKRepositories(); - await this.manipulateBreakingChangeLabel(); - await this.prepareUnifiedPipelineMessage(); - this.throwErrorIfFailed(); - } - - public async getSDKReposToTrigger(): Promise { - await this.cloneSpecRepo(); - const readmeMdFilesToGenerate: SpecificationReadmeMdFile[] = await this.getReadmeMdFilesToGenerate(); - return this.getSDKReposFromReadmeMdFiles(readmeMdFilesToGenerate); - } - - public async getSDKReposFromReadmeMdFiles(readmeMdFilesToGenerate: SpecificationReadmeMdFile[]): Promise { - const logger: Logger = this.generation.logger; - const readmeMdRepositories: string[] = []; - for (const readmeMdFileToGenerate of readmeMdFilesToGenerate) { - await logger.logSection( - `Looking for repositories to generate in "${readmeMdFileToGenerate.relativeFilePath}"...` - ); - const readmeMdRepositoryConfigurations: - | RepositoryConfiguration[] - | undefined = await readmeMdFileToGenerate.getSwaggerToSDKRepositoryConfigurations(); - - if (readmeMdRepositoryConfigurations) { - for (const readmeMdRepositoryConfiguration of readmeMdRepositoryConfigurations) { - if (readmeMdRepositories.indexOf(readmeMdRepositoryConfiguration.repo) === -1) { - await this.context.logger.logInfo( - `Add new SDK repo task to trigger ${readmeMdRepositoryConfiguration.repo}` - ); - readmeMdRepositories.push(readmeMdRepositoryConfiguration.repo); - } - } - } - } - return readmeMdRepositories; - } - - public async prepareUnifiedPipelineMessage(): Promise { - if (!this.isTriggeredByUP) { - return; - } - let isShowLiteInstruction: boolean = false; - if (this.data.generation.sdkRepositories - .filter(repo => repo.changedPackages - ?.filter(pack => pack.liteInstallationInstruction !== undefined).length - ).length > 0) { - isShowLiteInstruction = true; - } - - const subtitle = getPullRequestCommentSubtitleForSDK( - this.automationWorkingPrefix, - this.sdkRepoName!, - this.data, - isShowLiteInstruction, - this.context.sdkAutomationVersion - ); - - const commentBody = getPullRequestCommentBodyForSDK( - this.automationWorkingPrefix, - this.sdkRepoName!, - this.data, - this.context.sdkAutomationVersion - ); - - const statusMap: Map = new Map([ - ['pending', 'Error'], - ['inprogress', 'Error'], - ['failed', 'Error'], - ['warning', 'Warning'], - ['succeeded', 'Info'] - ]); - - const type = statusMap.get(String(this.generation.sdkRepositories[0].data.status).toLowerCase()); - - const pipelineResultData: format.MessageRecord = { - type: 'Markdown', - mode: 'replace', - level: type as format.MessageLevel, - message: commentBody, - time: new Date() - }; - - const decode = (str: string): string => Buffer.from(str, 'base64').toString('binary'); - const encode = (str: string): string => Buffer.from(str, 'binary').toString('base64'); - console.log(`##vso[task.setVariable variable=SubTitle]${encode(subtitle)}`); - console.log(decode(encode(subtitle))); - - await this.context.logger.logInfo('Writing unified pipeline message to pipe.log'); - fs.writeFileSync('output/pipe.log', JSON.stringify(pipelineResultData) - .replace(/\\n/g, '') - .replace(/\\\"/g, '\'') + '\n'); - return; - } - - public throwErrorIfFailed(): void { - for (const sdkRepository of this.generation.sdkRepositories) { - if (sdkRepository.data.status === 'failed') { - if (this.isTriggeredByUP) { - console.log('##vso[task.setVariable variable=ValidationResult]failure'); - } - throw new Error('ResultFailure: The result is marked as failure due to at least one required step fails. Please refer to the detail log in pipeline run or local console for more information.'); - } - } - if (this.isTriggeredByUP) { - console.log('##vso[task.setVariable variable=ValidationResult]success'); - } - return; - } - - public async manipulateBreakingChangeLabel(): Promise { - const sdkRepositories = this.generation.sdkRepositories; - const specRepository: Repository = this.data.baseRepository; - const specPRNumber: number = this.data.number; - const specPullRequest = await this.context.github.getPullRequest(specRepository, specPRNumber); - if (sdkRepositories.length > 0) { - for (const sdkRepository of sdkRepositories) { - const breakingChangeLabel = sdkRepository.language.breakingChangeLabel; - if (breakingChangeLabel) { - if (sdkRepository.data.hasBreakingChange) { - await addPullRequestLabel( - this.context.github, - specRepository, - specPullRequest, - breakingChangeLabel, - this.context.logger - ); - } else { - await removePullRequestLabel( - this.context.github, - specRepository, - specPullRequest, - breakingChangeLabel, - this.context.logger - ); - } - } - } - } else { - if (this.sdkRepoName) { - const languageConfiguration = getLanguageConfigurationForRepository( - this.sdkRepoName, - this.context.supportedLanguageConfigurations - ); - if (languageConfiguration?.breakingChangeLabel) { - await removePullRequestLabel(this.context.github, - specRepository, - specPullRequest, - languageConfiguration.breakingChangeLabel, - this.context.logger - ); - } - } - } - } - - public async cloneSpecRepo(): Promise { - const git = this.context.git.scope({ - executionFolderPath: this.specRepoFolder, - log: (text: string) => this.context.logger.logInfo(trimNewLine(text)), - showCommand: true, - throwOnError: true, - runner: this.context.runner - }); - - await git.resetRepoFolder(); - - await git.addRemote('origin', getGithubRepositoryUrl(this.data.specPRRepository)); - if (this.data.merged) { - // Cannot fetch commit directly if PR is merged and is not the latest commit in master - await git.fetch({ remoteName: 'origin' }); - } else { - // Cannot checkout merge commit if we only fetch origin when PR is not merged - await git.fetch({ remoteName: 'origin', refSpec: this.data.specPRCommit }); - } - await git.checkout(this.data.specPRCommit, { localBranchName: 'sdkAutomation' }); - } - - /** - * Populate the readme.md file lists to generate in each of the SDK repositories. - */ - public async populateSDKRepositoryReadmeMdFilesToGenerate(): Promise { - let specificationRepositoryConfiguration = - await getSpecificationRepositoryConfiguration(this.context, this.data.specPRRepository); - if (specificationRepositoryConfiguration !== undefined) { - specificationRepositoryConfiguration.specRepoOwner = this.data.specPRRepository.owner; - const overrides = specificationRepositoryConfiguration.overrides; - if (overrides !== undefined) { - const repo = this.data.specPRRepository; - const overrideDetail = overrides[`${repo.owner}/${repo.name}`] || overrides[repo.name]; - if (overrideDetail !== undefined) { - specificationRepositoryConfiguration = { ...specificationRepositoryConfiguration, ...overrideDetail }; - } - } - } - const readmeMdFilesToGenerate: SpecificationReadmeMdFile[] = await this.getReadmeMdFilesToGenerate(); - await this.addReadmeMdFilesToGenerateToSDKRepositories( - readmeMdFilesToGenerate, - specificationRepositoryConfiguration - ); - } - - /** - * Update the generation data blobs with the current state of the generation. - */ - public async writeGenerationData(): Promise { - if (this.isTriggeredByUP) { - return; - } - const specificationRepository: Repository = this.data.baseRepository; - const specPRNumber: number = this.data.number; - - if (this.sdkRepoName === undefined) { - const generationData: string = JSON.stringify(this.data, undefined, ' '); - const generationHtml: string = getPullRequestCommentHTML(this.automationWorkingPrefix, this.data); - await this.dataBlob.setContentsFromString(generationData, { contentType: 'application/json' }); - const specPRComments: GitHubComment[] = await this.context.github.getPullRequestComments( - specificationRepository, - specPRNumber - ); - - if (contains(specPRComments, (comment: GitHubComment) => comment.id === this.data.commentId)) { - await this.context.github.updatePullRequestComment( - specificationRepository, - specPRNumber, - this.data.commentId!, - generationHtml - ); - } - - await this.generation.writeGenerationData(generationData, generationHtml); - } else { - // Triggered from pipeline - let isShowLiteInstruction: boolean = false; - if (this.data.generation.sdkRepositories - .filter(repo => repo.changedPackages - ?.filter(pack => pack.liteInstallationInstruction !== undefined).length - ).length > 0) { - isShowLiteInstruction = true; - } - const generationHTML = getPullRequestCommentHTMLForSDK( - this.sdkRepoName, - this.data, - isShowLiteInstruction, - this.context.sdkAutomationVersion - ); - - if (this.data.commentId === undefined) { - const specPRComments: GitHubComment[] = await this.context.github.getPullRequestComments( - specificationRepository, - specPRNumber - ); - const targetComment = first(specPRComments, (comment: GitHubComment) => { - if (comment.user.login !== this.context.githubCommentAuthorName) { - return false; - } - const firstLine = comment.body.split('\n')[0]; - // tslint:disable-next-line: no-use-before-declare - if (firstLine.indexOf(handleBarHelpers.renderSDKTitleMapping(this.sdkRepoName!)) === -1) { - return false; - } - return true; - }); - if (targetComment !== undefined) { - this.data.commentId = targetComment.id; - } - } - - if (this.data.commentId !== undefined) { - await this.context.github.updatePullRequestComment( - specificationRepository, - specPRNumber, - this.data.commentId, - generationHTML - ); - } else { - const githubComment = await this.context.github.createPullRequestComment( - specificationRepository, - specPRNumber, - generationHTML - ); - this.data.commentId = githubComment.id; - } - } - } - - /** - * Get the file paths relative to the root of the repository of the files that were modified in - * this pull request. - */ - public async getChangedFilesRelativePaths(): Promise { - const logger: Logger = this.generation.logger; - const githubClient = await (this.context.github as RealGitHub).getClient(this.data.specPRRepository); - - let changedFilesRelativePaths: string[] = []; - await logger.logSection(`Getting PR diff contents...`); - const diffResponse = await githubClient.pulls.get({ - pull_number: this.data.number, - repo: this.data.specPRRepository.name, - owner: this.data.specPRRepository.owner, - mediaType: { - format: 'diff' - } - }); - const diffContent = diffResponse.data as unknown as string; - changedFilesRelativePaths = getFilesChangedFromFullDiff(diffContent); - await logger.logInfo(`PR diff response body contains ${changedFilesRelativePaths.length} changed files:`); - for (const changedFileRelativePath of changedFilesRelativePaths) { - await logger.logInfo(` ${changedFileRelativePath}`); - } - return changedFilesRelativePaths; - } - - /** - * Get the file paths relative to the root of the repository of the readme.md files that are - * related to this pull request's specification changes. - */ - public async getReadmeMdFilesToGenerate(): Promise { - const logger: Logger = this.generation.logger; - - const result: SpecificationReadmeMdFile[] = []; - const changedFilesRelativePaths: string[] = await this.getChangedFilesRelativePaths(); - if (changedFilesRelativePaths.length > 0) { - const specificationChangedFileRelativePaths: string[] = where(changedFilesRelativePaths, (path: string) => - path.startsWith('specification/') && path.indexOf('/scenarios/') === -1 - ); - const readmeCache: StringMap = {}; - - for (const changedFileRelativePath of specificationChangedFileRelativePaths) { - let folderRelativePath: string = getParentFolderPath(changedFileRelativePath); - - while (folderRelativePath && folderRelativePath !== '.') { - const readmeMdRelativePath: string = joinPath(folderRelativePath, 'readme.md'); - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - this.specRepoFolder, - logger, - readmeMdRelativePath - ); - if (specificationReadmeMdFile.contentsPath in readmeCache) { - const cachedValue: SpecificationReadmeMdFile | undefined = - readmeCache[specificationReadmeMdFile.contentsPath]; - if (!cachedValue) { - folderRelativePath = getParentFolderPath(folderRelativePath); - } else { - break; - } - } else { - const foundReadmeMdFile: boolean = existsSync(specificationReadmeMdFile.contentsPath); - readmeCache[specificationReadmeMdFile.contentsPath] = foundReadmeMdFile - ? specificationReadmeMdFile - : undefined; - if (!foundReadmeMdFile) { - folderRelativePath = getParentFolderPath(folderRelativePath); - } else { - break; - } - } - } - } - for (const readmeMdFile of Object.values(readmeCache)) { - if (readmeMdFile) { - result.push(readmeMdFile); - } - } - - await logger.logInfo(`Found ${result.length} readme.md files to generate:`); - for (const readmeMdFileToGenerate of result) { - await logger.logInfo(` ${readmeMdFileToGenerate.relativeFilePath}`); - } - } - - return result; - } - - /** - * Get the proxy URL for the provided blob relative to this specification pull request's working - * prefix. - * @param blob The blob to get the proxy URL for. - * @returns The proxy URL for the provided blob relative to this specification pull request's - * working prefix. - */ - public getBlobProxyUrl = (blob: BlobStorageBlob): string => { - return this.context.blobProxy.getProxyURL(this.automationWorkingPrefix, blob); - } - - /** - * Add the provided readme.md relative file paths to the SDK repositories that they should be - * generated for. - * @param specificationRepositoryConfiguration The configuration for the specification repository. - * @param readmeMdFilesToGenerate The readme.md relative file paths. - */ - private async addReadmeMdFilesToGenerateToSDKRepositories( - readmeMdFilesToGenerate: SpecificationReadmeMdFile[], - specificationRepositoryConfiguration?: SpecificationRepositoryConfiguration - ): Promise { - const logger: Logger = this.generation.logger; - for (const readmeMdFileToGenerate of readmeMdFilesToGenerate) { - await logger.logSection( - `Looking for repositories to generate in "${readmeMdFileToGenerate.relativeFilePath}"...` - ); - const readmeMdRepositoryConfigurations: - | RepositoryConfiguration[] - | undefined = await readmeMdFileToGenerate.getSwaggerToSDKRepositoryConfigurations(); - - if (readmeMdRepositoryConfigurations) { - for (const readmeMdRepositoryConfiguration of readmeMdRepositoryConfigurations) { - if (this.sdkRepoName !== undefined && readmeMdRepositoryConfiguration.repo !== this.sdkRepoName) { - await this.context.logger.logInfo(`Skip unselected SDK repo ${readmeMdRepositoryConfiguration.repo}`); - continue; - } - await this.generation.addReadmeMdFileToGenerateForSDKRepository( - readmeMdRepositoryConfiguration, - readmeMdFileToGenerate, - this.context.supportedLanguageConfigurations, - specificationRepositoryConfiguration - ); - } - } - } - await this.writeGenerationData(); - } -} - -/** - * Get a new SpecificationPullRequest object for the provided details. - * @param sdkAutomation The SDKAutomation object that is the current context. - * @param automationWorkingPrefix The blob storage prefix that all of the pull request's data will be under. - * @param pullRequestUrl The URL to the specification pull request. - * @param newIteration Whether or not this request is for a new pull request iteration. - * @param sdkRepoName Selected sdk repo to generate. Used in pipeline only. - */ -export async function getSpecificationPullRequest( - context: SDKAutomationContext, - automationWorkingPrefix: BlobStoragePrefix, - pullRequest: GitHubPullRequest, - newIteration: boolean, - isTriggeredByUP: boolean, - sdkRepoName?: string -): Promise { - const isPipelineTriggered = sdkRepoName !== undefined; - const pullRequestRepository: Repository = getPullRequestRepository(pullRequest); - const headBranch: RepositoryBranch = getRepositoryBranch(pullRequest.head.label); - let headRepository: Repository; - if (!headBranch.owner || headBranch.owner === pullRequestRepository.owner) { - headRepository = pullRequestRepository; - } else { - headRepository = { - owner: headBranch.owner, - name: pullRequestRepository.name - }; - } - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - automationWorkingPrefix, - pullRequestRepository, - pullRequest.number, - sdkRepoName - ); - const pullRequestDataBlob: BlobStorageBlockBlob = getDataBlob(pullRequestPrefix); - - let pullRequestCommentId: number | undefined; - let pullRequestData: SpecificationPullRequestData | undefined; - - if (!isPipelineTriggered && (await pullRequestDataBlob.exists())) { - const pullRequestDataBlobContents: string | undefined = (await pullRequestDataBlob.getContentsAsString()).contents; - if (pullRequestDataBlobContents) { - pullRequestData = JSON.parse(pullRequestDataBlobContents) as SpecificationPullRequestData; - pullRequestCommentId = pullRequestData.commentId; - } - } - - await context.logger.logInfo(`Retrieving pull request from ${pullRequest.html_url} ...`); - - const getBlobProxyUrl = (blob: BlobStorageBlob) => context.blobProxy.getProxyURL(automationWorkingPrefix, blob); - - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - pullRequest.number, - pullRequestPrefix, - { - ...context, - generationWorkingFolderPath: context.automationWorkingFolderPath, - isPipelineTriggered, - getBlobProxyUrl - }, - context.buildID, - !newIteration && pullRequestData ? pullRequestData.generation.number : undefined - ); - - const logger: Logger = generation.logger; - await logger.logSection(`Received pull request change webhook request from GitHub for "${pullRequest.html_url}".`); - await context.logContext(logger); - - return executeAndLog(logger, undefined, async () => { - await logger.logSection( - `Getting generation state from ${getBlobProxyUrl(pullRequestDataBlob)}...` - ); - - let specPRRepository: Repository; - let specPRCommit: string; - if (pullRequest.merge_commit_sha) { - specPRRepository = pullRequestRepository; - specPRCommit = pullRequest.merge_commit_sha; - } else { - specPRRepository = headRepository; - specPRCommit = pullRequest.head.sha; - } - await logger.logInfo(`Using Commit: ${specPRCommit}`); - - if (pullRequestCommentId === undefined && !isPipelineTriggered) { - const commentText: string = getPullRequestCommentHTML(automationWorkingPrefix); - const comment: GitHubComment = await context.github.createPullRequestComment( - pullRequestRepository, - pullRequest.number, - commentText - ); - pullRequestCommentId = comment.id; - } - - if (!pullRequestData || newIteration) { - pullRequestData = { - specPRRepository, - specPRCommit, - baseRepository: pullRequestRepository, - headRepository, - number: pullRequest.number, - headBranch: getRepositoryBranch(pullRequest.head.label), - headCommit: pullRequest.head.sha, - baseBranch: getRepositoryBranch(pullRequest.base.label), - htmlUrl: pullRequest.html_url, - mergeCommit: pullRequest.merge_commit_sha, - merged: pullRequest.merged, - title: pullRequest.title, - commentId: pullRequestCommentId, - dataBlobUrl: getBlobProxyUrl(pullRequestDataBlob), - generation: generation.data - }; - } else { - generation.data = pullRequestData.generation; - } - - const result = new SpecificationPullRequest( - context, - automationWorkingPrefix, - pullRequestDataBlob, - generation, - pullRequestData, - isTriggeredByUP, - sdkRepoName - ); - await result.writeGenerationData(); - - generation.specificationPullRequest = result; - - return result; - }); -} - -const pullRequestUrlRepositoryNameRegex: RegExp = /https:\/\/api\.github\.com\/repos\/(.*)\/pulls\/.*/; -/** - * Get the GitHub repository from the provided pull request URL. - * @param pullRequestUrl The URL to get the GitHub repository from. - */ -export function getPullRequestRepository(pullRequestUrl: string | GitHubPullRequest): Repository { - if (typeof pullRequestUrl !== 'string') { - pullRequestUrl = pullRequestUrl.url; - } - return getRepository(pullRequestUrl.match(pullRequestUrlRepositoryNameRegex)![1]); -} - -/** - * Get the prefix that all blobs related to the pull request will be put in. - * @param workingPrefix The prefix that this service operates under. - * @param repository The repository that the pull request exists in. - * @param pullRequestNumber The pull request number. - */ -export function getPullRequestPrefix( - workingPrefix: BlobStoragePrefix, - repository: string | Repository, - pullRequestNumber: number, - sdkRepoName: string | undefined -): BlobStoragePrefix { - let prefix = workingPrefix - .getPrefix(getRepositoryFullName(repository) + '/') - .getPrefix(pullRequestNumber.toString() + '/'); - if (sdkRepoName !== undefined) { - prefix = prefix.getPrefix(sdkRepoName + '/'); - } - - return prefix; -} - -/** - * Get the comment HTML for the provided data. - * @param automationWorkingPrefix The working prefix for the SDK Automation application. - * @param specificationPullRequestData The data that describes the specification pull request. - */ -function getPullRequestCommentHTML( - automationWorkingPrefix: BlobStoragePrefix, - specificationPullRequestData?: SpecificationPullRequestData -): string { - return html( - body([ - h4(['In Testing, Please Ignore']), - getPullRequestCommentHeaderHTML(specificationPullRequestData), - getPullRequestCommentMessageHTML(specificationPullRequestData), - getPullRequestCommentSDKRepositoriesHTML(automationWorkingPrefix, specificationPullRequestData) - ]) - ); -} - -function getPullRequestCommentHeaderHTML(specificationPullRequestData?: SpecificationPullRequestData): string { - return h3([ - specificationPullRequestData && ` ${getLogsLink(specificationPullRequestData.generation.logsBlobUrl)}`, - specificationPullRequestData && ` (Generated from ${getHeadCommitLink(specificationPullRequestData)}, `, - specificationPullRequestData && `Iteration ${specificationPullRequestData.generation.number})` - ]); -} - -function getPullRequestCommentMessageHTML( - specificationPullRequestData?: SpecificationPullRequestData -): string | undefined { - return specificationPullRequestData && specificationPullRequestData.generation.message; -} - -function getPullRequestCommentSDKRepositoriesHTML( - automationWorkingPrefix: BlobStoragePrefix, - specificationPullRequestData?: SpecificationPullRequestData -): string { - let result = ''; - const sdkRepositories: SDKRepositoryData[] | undefined = - specificationPullRequestData && specificationPullRequestData.generation.sdkRepositories; - if (any(sdkRepositories)) { - for (const sdkRepository of sdkRepositories) { - result += getPullRequestCommentSDKRepositoryHTML(automationWorkingPrefix, sdkRepository); - } - } - return result; -} - -function getPullRequestCommentSDKRepositoryHTML( - automationWorkingPrefix: BlobStoragePrefix, - sdkRepositoryData: SDKRepositoryData -): BuilderActions { - return details(repositoryDetails => { - repositoryDetails.summary( - b([ - getStateImgElement(automationWorkingPrefix, sdkRepositoryData.status), - ` ${sdkRepositoryData.languageName}: `, - ` ${getLink(sdkRepositoryData.mainRepositoryUrl, sdkRepositoryData.mainRepository)}`, - sdkRepositoryData.logsBlobUrl && ` ${getLogsLink(sdkRepositoryData.logsBlobUrl)}`, - sdkRepositoryData.diffBlobUrl && ` ${getDiffLink(sdkRepositoryData.diffBlobUrl)}` - ]) - ); - repositoryDetails.ul(packageList => { - if (!any(sdkRepositoryData.changedPackages)) { - if (sdkRepositoryData.status === 'pending') { - packageList.li('Package generation pending.'); - } else if (sdkRepositoryData.status === 'inProgress') { - packageList.li('Package generation in progress.'); - } else { - packageList.li('No packages generated.'); - } - } else { - for (const sdkPackage of sdkRepositoryData.changedPackages) { - packageList.li(getPullRequestCommentSDKPackageHTML(automationWorkingPrefix, sdkPackage)); - } - } - }); - }); -} - -function getPullRequestCommentSDKPackageHTML( - automationWorkingPrefix: BlobStoragePrefix, - sdkPackage: SDKRepositoryPackageData -): BuilderActions { - return [ - getStateImgElement(automationWorkingPrefix, sdkPackage.status), - ` ${sdkPackage.name}`, - sdkPackage.logsBlobUrl && ` ${getLogsLink(sdkPackage.logsBlobUrl)}`, - sdkPackage.installationInstructionsBlobUrl && ` ${getInstructionsLink(sdkPackage.installationInstructionsBlobUrl)}`, - sdkPackage.generationPullRequestUrl && ` ${getGenerationPullRequestLink(sdkPackage.generationPullRequestUrl)}`, - sdkPackage.integrationPullRequestUrl && ` ${getIntegrationPullRequestLink(sdkPackage.integrationPullRequestUrl)}`, - packageArtifacts => { - const artifactBlobUrls: string[] | undefined = sdkPackage.artifactBlobUrls; - if (artifactBlobUrls && artifactBlobUrls.length > 0) { - packageArtifacts.ul(artifactList => { - for (const artifactBlobUrl of artifactBlobUrls) { - artifactList.li(getArtifactLink(artifactBlobUrl)); - } - }); - } - } - ]; -} - -function getLogsLink(logsUrl: string): string { - return `[${getLink(logsUrl, 'Logs')}]`; -} - -function getDiffLink(diffUrl: string): string { - return `[${getLink(diffUrl, 'Diff')}]`; -} - -function getGenerationPullRequestLink(generationPullRequestUrl: string): string { - return `[${getLink(generationPullRequestUrl, 'Generation PR')}]`; -} - -function getIntegrationPullRequestLink(integrationPullRequestUrl: string): string { - return `[${getLink(integrationPullRequestUrl, 'Integration PR')}]`; -} - -function getHeadCommitLink(specificationPRData: SpecificationPullRequestData): string { - const generationCommitUrl = `${specificationPRData.htmlUrl}/commits/${specificationPRData.headCommit}`; - return getLink(generationCommitUrl, specificationPRData.headCommit.substring(0, 7)); -} - -function getInstructionsLink(instructionsUrl: string): string { - return `[${getLink(instructionsUrl, 'Instructions')}]`; -} - -function getArtifactLink(artifactUrl: string): string { - return getLink(artifactUrl, getPathName(URLBuilder.parse(artifactUrl).getPath()!)); -} - -function getLink(url: string, content: string): string { - return a(ah => ah.href(url).content(content)); -} - -function getStateImgElement(automationWorkingPrefix: BlobStoragePrefix, state: SDKAutomationState): string { - const imagePixelSize = 16; - return img(stageImage => - stageImage - .src(getSDKAutomationStateImageBlob(automationWorkingPrefix, state).getURL()) - .alt(getSDKAutomationStateString(state)) - .width(imagePixelSize) - .height(imagePixelSize) - ); -} - -const generationViewTemplate = readFileSync(`${__dirname}/templates/generationView.handlebars`).toString(); -const commentSubtitleTemplate = readFileSync(`${__dirname}/templates/commentSubtitle.handlebars`).toString(); -const commentDetailTemplate = readFileSync(`${__dirname}/templates/commentDetail.handlebars`).toString(); -const generationView = Handlebars.compile(generationViewTemplate, { noEscape: true }); -const commentSubtitle = Handlebars.compile(commentSubtitleTemplate, { noEscape: true }); -const commentDetail = Handlebars.compile(commentDetailTemplate, { noEscape: true }); -const githubStateEmoji: { [key in SDKAutomationState]: string } = { - pending: '⌛', - failed: '❌', - inProgress: '🔄', - succeeded: '️✔️', - warning: '⚠️' -}; -const handleBarHelpers = { - renderFilename: (url: string) => getPathName(url), - renderStatus: (status: SDKAutomationState) => `${githubStateEmoji[status]}`, - renderMessages: (messages: string[]) => { - if (messages.length > 100) { - return `Only show 100 items here, please refer to log for details.
-
${messages.slice(0, 100).map(trimNewLine).join('\n')}
`; - } else { - return `
${messages.slice(0, 100).map(trimNewLine).join('\n')}
`; - } - }, - renderMessagesUnifiedPipeline: (messages: string[]) => { - if (messages.length > 50) { - return `Only show 50 items here, please refer to log for details.
-
${messages.slice(0, 50).map(trimNewLine).join('
')}
`; - } else { - return `
${messages.slice(0, 50).map(trimNewLine).join('
')}
`; - } - }, - renderSDKTitleMapping: (sdkRepoName: string) => { - switch (sdkRepoName) { - case 'azure-cli-extensions': - return 'Azure CLI Extension Generation'; - case 'azure-sdk-for-trenton': - return 'Trenton Generation'; - default: - return sdkRepoName; - } - }, - isPublicRelease: (changedPackage: SDKRepositoryPackageData) => { - return !changedPackage.isPrivatePackage; - }, - renderSDKNameMapping: (sdkRepoName: string) => { - switch (sdkRepoName) { - case 'azure-cli-extensions': - return 'Azure CLI'; - case 'azure-sdk-for-trenton': - return 'Trenton'; - case 'azure-resource-manager-schemas': - return 'Schema'; - default: - return 'SDK'; - } - } -}; -Handlebars.registerHelper(handleBarHelpers); -function getPullRequestCommentHTMLForSDK( - sdkRepoName: string, - data: SpecificationPullRequestData, - isShowInstruction: boolean, - version?: string -): string { - const commentBody = generationView({ - ...data, - version, - sdkRepoName, - isShowInstruction - }) - .replace(/>\s+<') - .replace(/\\n\\n/g, '\n'); - - return commentBody; -} - -Handlebars.registerHelper(handleBarHelpers); -function getPullRequestCommentSubtitleForSDK( - prefix: BlobStoragePrefix, - sdkRepoName: string, - data: SpecificationPullRequestData, - isShowInstruction: boolean, - version?: string -): string { - const commentBody = commentSubtitle({ - ...data, - version, - sdkRepoName, - isShowInstruction - }) - .replace(/>\s+<') - .replace(/\\n\\n/g, '\n'); - - return commentBody; -} - -Handlebars.registerHelper(handleBarHelpers); -function getPullRequestCommentBodyForSDK( - prefix: BlobStoragePrefix, - sdkRepoName: string, - data: SpecificationPullRequestData, - version?: string -): string { - const commentBody = commentDetail({ - ...data, - version, - sdkRepoName - }) - .replace(/>\s+<') - .replace(/\\n\\n/g, '\n'); - - return commentBody; -} diff --git a/tools/spec-gen-sdk/src/specificationPullRequestGeneration.ts b/tools/spec-gen-sdk/src/specificationPullRequestGeneration.ts deleted file mode 100644 index 888db9ce0d9..00000000000 --- a/tools/spec-gen-sdk/src/specificationPullRequestGeneration.ts +++ /dev/null @@ -1,482 +0,0 @@ -import { Logger, prefix } from '@azure/logger-js'; -import { - any, - BlobStorageAppendBlob, - BlobStorageBlob, - BlobStorageBlockBlob, - BlobStoragePrefix, - Compressor, - first, - getRepositoryFullName, - map, - Repository, - RepositoryConfiguration, - Runner, - getRepository, - RealGitHub -} from '@ts-common/azure-js-dev-tools'; -import { LanguageConfiguration } from './langSpecs/languageConfiguration'; -import { - createLogsBlob, - getDataBlob, - getGenerationWorkingFolderPath, - getLogsBlob, - getSplitLineCompositeLogger, - logsBlobContentType, - SDKAutomationContext -} from './sdkAutomation'; -import { SDKRepository, SDKRepositoryContext, SDKRepositoryData } from './sdkRepository'; -import { SDKRepositoryMapping } from './sdkRepositoryMapping'; -import { SpecificationPullRequest } from './specificationPullRequest'; -import { SpecificationReadmeMdFile } from './specificationReadmeMdFile'; -import { getSDKRepositoryMapping, SpecificationRepositoryConfiguration } from './specificationRepositoryConfiguration'; -import { SwaggerToSDKConfiguration } from './swaggerToSDKConfiguration'; -import { getRunnerReportLogger } from './runnerReportLogger'; - -/** - * The context that a SpecificationPullRequestGeneration needs to be able to run in. - */ -export interface SpecificationPullRequestGenerationContext extends SDKAutomationContext { - generationWorkingFolderPath: string; - - /** - * Get the proxy URL for the provided blob relative to the provided working prefix. - * @param blob The blob to get the proxy URL for. - * @returns The proxy URL for the provided blob relative to the provided working prefix. - */ - getBlobProxyUrl(blob: BlobStorageBlob): string; -} - -/** - * The data that describes an OpenAPI specification pull request generation. - */ -export interface SpecificationPullRequestGenerationData { - /** - * The unique number that defines which version of the specification pull request this generation - * is happening for. This will be an incremented integer. For example, the generation that occurs - * when the pull request is created is 1. The generation that occurs when the next commit is added - * to the pull request is 2. - */ - readonly number: number | undefined; - /** - * The URL of the blob where this generation's logs will be written to. - */ - readonly logsBlobUrl: string; - /** - * The URL of the blob where this generation's data will be written to. - */ - readonly dataBlobUrl: string; - /** - * The URL of the blob where the generation's pull request comment body will be copied to. - */ - readonly commentHtmlBlobUrl: string; - /** - * The SDK repositories that this generation will run AutoRest in. - */ - readonly sdkRepositories: SDKRepositoryData[]; - /** - * A message that should be displayed in the specification pull request comment. - */ - message?: string; -} - -/** - * A generation that occurs for a specification pull request. - */ -export class SpecificationPullRequestGeneration { - /** - * The data that describes an OpenAPI specification pull request generation. - */ - public data: SpecificationPullRequestGenerationData; - /** - * The logger that should be used to write logs related to this generation. - */ - public readonly logger: Logger; - /** - * The blob where the generation's logs will be written to. - */ - public readonly logsBlob: BlobStorageAppendBlob; - /** - * The blob where the generation's data will be written to. - */ - public readonly dataBlob: BlobStorageBlockBlob; - /** - * The blob where the generation's pull request comment body will be copied to. - */ - public readonly commentHtmlBlob: BlobStorageBlockBlob; - /** - * The SDK repositories that this generation will run AutoRest in. - */ - public readonly sdkRepositories: SDKRepository[]; - /** - * The SpecificationPullRequest object that this generation belongs to. - */ - public specificationPullRequest?: SpecificationPullRequest; - /** - * The prefix that all of this generation's data will be written under. - */ - private readonly prefix: BlobStoragePrefix; - - /** - * Enable Build.BuildID in pipeline. - */ - private readonly buildID: string; - - /** - * Create a new SpecificationPullRequestGeneration from the provided details. - * @param pullRequestPrefix The blob storage prefix for the pull request. - * @param specificationPullRequestNumber The specification pull request's number. - * @param generationNumber This generation's number. - * @param buildID This pipeline build's id. - */ - constructor( - private pullRequestPrefix: BlobStoragePrefix, - public readonly specificationPullRequestNumber: number, - generationNumber: number | undefined, - buildID: string, - public readonly generationWorkingFolderPath: string, - private readonly context: SpecificationPullRequestGenerationContext - ) { - this.prefix = - generationNumber === undefined ? pullRequestPrefix : getGenerationPrefix(pullRequestPrefix, generationNumber); - this.logsBlob = getLogsBlob(this.prefix); - this.logger = getSplitLineCompositeLogger(context.logger, context.getBlobLogger(this.logsBlob)); - this.dataBlob = getDataBlob(this.prefix); - this.commentHtmlBlob = getCommentHtmlBlob(this.prefix); - this.sdkRepositories = []; - this.data = { - number: generationNumber, - dataBlobUrl: context.getBlobProxyUrl(this.dataBlob), - commentHtmlBlobUrl: context.getBlobProxyUrl(this.commentHtmlBlob), - logsBlobUrl: context.getBlobProxyUrl(this.logsBlob), - sdkRepositories: [] - }; - this.buildID = buildID; - } - - /** - * Generate new SDKs in each of the SDK repositories based on the changes from the specification - * pull request. - */ - public async generateSDKRepositories(): Promise { - if (!any(this.sdkRepositories)) { - this.data.message = - 'No readme.md specification configuration files were found ' + - 'that are associated with the files modified in this pull request, ' + - 'or swagger_to_sdk section in readme.md is not configured'; - await this.writeGenerationData(); - return; - } - - await this.forEachSDKRepository((sdkRepository: SDKRepository) => { - return sdkRepository.generate(); - }); - } - - /** - * Update the generation data blobs with the current state of the generation. - */ - public writeGenerationData = async (generationData?: string, generationCommentHtml?: string): Promise => { - if (!generationData && !generationCommentHtml && this.specificationPullRequest) { - await this.specificationPullRequest.writeGenerationData(); - } else { - await this.dataBlob.setContentsFromString(generationData || '', { contentType: 'application/json' }); - await this.commentHtmlBlob.setContentsFromString(generationCommentHtml || '', { contentType: 'text/html' }); - } - } - - /** - * Get the runner object that will be used to execute external-process commands. - */ - public getRunner(): Runner | undefined { - return this.context.runner; - } - - /** - * Create a new Compressor object that can be use compress files and folders. - */ - public createCompressor(): Compressor { - return this.context.createCompressor(); - } - - /** - * Get the SDKRepository object with the provided name. If one doesn't already exist, then one - * will be created. - * @param sdkRepositoryMapping The name of the SDKRepository. - */ - public async getSDKRepository( - sdkRepositoryMapping: SDKRepositoryMapping, - sdkRepositoryName: string, - supportedLanguages: LanguageConfiguration | LanguageConfiguration[] - ): Promise { - supportedLanguages = Array.isArray(supportedLanguages) ? supportedLanguages : [supportedLanguages]; - // const httpClient: HttpClient = this.context.httpClient; - - const mainSDKRepositoryName: string = sdkRepositoryMapping.mainRepository; - const mainBranch: string = sdkRepositoryMapping.mainBranch; - let sdkRepository: SDKRepository | undefined = first( - this.sdkRepositories, - (sdkRepo: SDKRepository) => sdkRepo.data.mainRepository === mainSDKRepositoryName - ); - if (!sdkRepository) { - const languageConfiguration: LanguageConfiguration | undefined = getLanguageConfigurationForRepository( - sdkRepositoryName, - supportedLanguages - ); - if (!languageConfiguration) { - const supportedLanguageNames: string[] = map( - supportedLanguages, - (language: LanguageConfiguration) => language.name - ); - await this.logger.logError( - `No supported programming language matches the repository ` + - `${sdkRepositoryName}|${mainSDKRepositoryName} ` + - `(supported languages: ${JSON.stringify(supportedLanguageNames)}).` - ); - } else { - await this.logger.logInfo( - `SDK repository ${sdkRepositoryName}|${mainSDKRepositoryName} ` + - `matches programming language ${languageConfiguration.name}.` - ); - - const swaggerToSDKConfig = await this.getSwaggerToSDKFileContent( - mainSDKRepositoryName, mainBranch, sdkRepositoryMapping.configFilePath - ); - - if (swaggerToSDKConfig) { - const sdkRepositoryPrefix = this.pullRequestPrefix; - const sdkRepositoryLogsBlob: BlobStorageAppendBlob = await createLogsBlob(sdkRepositoryPrefix); - - const sdkRepositoryData: SDKRepositoryData = { - ...sdkRepositoryMapping, - languageName: languageConfiguration.name, - readmeMdFileUrlsToGenerate: [], - status: 'pending', - messages: [], - generationRepositoryUrl: `https://github.com/${sdkRepositoryMapping.generationRepository}`, - integrationRepositoryUrl: `https://github.com/${sdkRepositoryMapping.integrationRepository}`, - mainRepositoryUrl: `https://github.com/${sdkRepositoryMapping.mainRepository}`, - secondaryRepositoryUrl: `https://github.com/${sdkRepositoryMapping.secondaryRepository}` - }; - this.data.sdkRepositories.push(sdkRepositoryData); - - const sdkRepositoryBlobLogger: Logger = this.context.getBlobLogger(sdkRepositoryLogsBlob); - const sdkRepositoryPrefixLogger: Logger = prefix(this.logger, `[${mainSDKRepositoryName}]`); - const logger: Logger = getSplitLineCompositeLogger( - sdkRepositoryPrefixLogger, - sdkRepositoryBlobLogger, - getRunnerReportLogger(sdkRepositoryData.messages) - ); - const sdkRepositoryContext: SDKRepositoryContext = { - ...this.context, - useMergedRoutine: !!this.specificationPullRequest!.data.merged, - specificationPullRequest: this.specificationPullRequest && this.specificationPullRequest.data, - generationWorkingFolderPath: this.generationWorkingFolderPath, - writeGenerationData: this.writeGenerationData - }; - sdkRepository = new SDKRepository( - sdkRepositoryLogsBlob, - logger, - languageConfiguration, - swaggerToSDKConfig, - sdkRepositoryPrefix, - sdkRepositoryContext, - sdkRepositoryData, - this.buildID - ); - this.sdkRepositories.push(sdkRepository); - } - } - } - return sdkRepository; - } - - /** - * Add an AutoRest readme.md configuration file that should be generated in the context of the - * provided SDK repository. - * @param sdkRepositoryConfiguration The configuration object in the specification's readme.md - * file for this SDK's repository. - * @param specificationReadmeMdFile The AutoRest readme.md configuration file that should be - * generated for the provided sdkRepository. - */ - public async addReadmeMdFileToGenerateForSDKRepository( - sdkRepositoryConfiguration: string | RepositoryConfiguration, - readmeMdFile: SpecificationReadmeMdFile | string, - supportedLanguages: LanguageConfiguration | LanguageConfiguration[], - specificationRepositoryConfiguration?: SpecificationRepositoryConfiguration - ): Promise { - const sdkRepositoryName: string = - typeof sdkRepositoryConfiguration === 'string' ? sdkRepositoryConfiguration : sdkRepositoryConfiguration.repo; - const sdkRepositoryMapping: SDKRepositoryMapping = await getSDKRepositoryMapping( - sdkRepositoryName, - specificationRepositoryConfiguration, - this.logger - ); - const sdkRepository: SDKRepository | undefined = await this.getSDKRepository( - sdkRepositoryMapping, - sdkRepositoryName, - supportedLanguages - ); - if (sdkRepository) { - const readmeMdFileUrl: string = typeof readmeMdFile === 'string' ? readmeMdFile : readmeMdFile.contentsPath; - if (!sdkRepository.data.readmeMdFileUrlsToGenerate.includes(readmeMdFileUrl)) { - await this.logger.logInfo( - `Adding readme.md to generate to ${sdkRepository.data.mainRepository}: ${readmeMdFileUrl}` - ); - sdkRepository.data.readmeMdFileUrlsToGenerate.push(readmeMdFileUrl); - - if (typeof sdkRepositoryConfiguration !== 'string' && sdkRepositoryConfiguration.after_scripts) { - sdkRepository.addReadmdMdAfterScripts(readmeMdFileUrl, sdkRepositoryConfiguration.after_scripts); - } - } - } - } - - /** - * Close (without merging) any SDK generation pull requests that were created by this - * specification pull request. - */ - public async closeSDKGenerationPullRequests(): Promise { - return this.forEachSDKRepository((sdkRepository: SDKRepository) => { - return sdkRepository.closeGenerationPullRequests(this.context.generateLanguagesInParallel); - }); - } - - public async getSwaggerToSDKFileContent( - mainSDKRepositoryName: string, branchName: string, filePath: string - ): Promise { - const repo = getRepository(mainSDKRepositoryName); - await this.logger.logInfo( - `Getting swagger_to_sdk_config.json file from "${repo.owner}/${repo.name}/${branchName}/${filePath}"...` - ); - - const githubClient = await (this.context.github as RealGitHub).getClient(repo); - const { data: configFileContent } = await githubClient.repos.getContent({ - owner: repo.owner, - repo: repo.name, - path: filePath, - ref: branchName - }); - let rawContent: string | undefined; - let result: SwaggerToSDKConfiguration | undefined; - if (configFileContent && !Array.isArray(configFileContent)) { - rawContent = configFileContent.content; - if (rawContent && configFileContent.encoding === 'base64') { - rawContent = Buffer.from(rawContent, 'base64').toString(); - } - if (rawContent) { - result = JSON.parse(rawContent); - } - } - return result; - } - - /** - * Run the provided action on each of the SDKRepositories. The context.generateLanguagesInParallel - * property will determine whether or not the action will be run sequentially or in parallel. - * @param action The action to run on each of the SDKRepositories. - */ - private async forEachSDKRepository(action: (sdkRepository: SDKRepository) => Promise): Promise { - if (this.context.generateLanguagesInParallel) { - await Promise.all( - map(this.sdkRepositories, (sdkRepository: SDKRepository) => { - return action(sdkRepository); - }) - ); - } else { - for (const sdkRepository of this.sdkRepositories) { - await action(sdkRepository); - } - } - } -} - -/** - * Get the language configuration that matches the provided repository based on its name. - * @param repository The name of the repository. - */ -export function getLanguageConfigurationForRepository( - repository: string | Repository, - supportedLanguages: LanguageConfiguration[] -): LanguageConfiguration | undefined { - const lowerCasedRepositoryFullName: string = getRepositoryFullName(repository).toLowerCase(); - return first(supportedLanguages, (language: LanguageConfiguration) => { - let matches: boolean = lowerCasedRepositoryFullName.includes(language.name.toLowerCase()); - if (!matches && language.aliases) { - for (const alias of language.aliases) { - matches = lowerCasedRepositoryFullName.includes(alias.toLowerCase()); - if (matches) { - break; - } - } - } - return matches; - }); -} - -/** - * Get a new SpecificationPullRequestGeneration object based on the provided details. - * @param pullRequestNumber The specification pull request's number. - * @param pullRequestPrefix The blob storage prefix that all data related to the pull request will - * be under. - * @param context The context that the SpecificationPullRequestGeneration object should operate - * under. - */ -export async function getSpecificationPullRequestGeneration( - pullRequestNumber: number, - pullRequestPrefix: BlobStoragePrefix, - context: SpecificationPullRequestGenerationContext, - buildID: string, - generationNumber?: number -): Promise { - if (generationNumber === undefined && !context.isPipelineTriggered) { - generationNumber = await claimGenerationNumber(pullRequestPrefix); - } - const generationWorkingFolderPath: string = context.generationWorkingFolderPath - ? context.generationWorkingFolderPath - : await getGenerationWorkingFolderPath(context.automationWorkingFolderPath); - return new SpecificationPullRequestGeneration( - pullRequestPrefix, - pullRequestNumber, - generationNumber, - buildID, - generationWorkingFolderPath, - context - ); -} - -/** - * Claim a generation number for the provided pull request by creating the logs blob. - * @param pullRequestPrefix The prefix of the pull request that this generation belongs to. - */ -export async function claimGenerationNumber(pullRequestPrefix: BlobStoragePrefix): Promise { - let generationNumber = 1; - let generationInstancePrefix: BlobStoragePrefix = getGenerationPrefix(pullRequestPrefix, generationNumber); - while (!(await getLogsBlob(generationInstancePrefix).create({ contentType: logsBlobContentType })).created) { - ++generationNumber; - generationInstancePrefix = getGenerationPrefix(pullRequestPrefix, generationNumber); - } - - return generationNumber; -} - -/** - * Get the prefix that all blobs related to this generation will be put in. - * @param pullRequestPrefix The prefix that the pull request operates under. - * @param generationNumber The number of generations that have occurred for the pull request. - */ -export function getGenerationPrefix(pullRequestPrefix: BlobStoragePrefix, generationNumber: number): BlobStoragePrefix { - return pullRequestPrefix.getPrefix(generationNumber.toString() + '/'); -} - -/** - * Get the blob that will be used to write the pull request's comment content to. - * @param generationPrefix The prefix that the pull request generation operates under. - */ -export function getCommentHtmlBlob(generationPrefix: BlobStoragePrefix): BlobStorageBlockBlob { - return generationPrefix.getBlockBlob('comment.html'); -} - -export function getSDKRepositoryPrefix(parentPrefix: BlobStoragePrefix, sdkRepositoryName: string): BlobStoragePrefix { - return parentPrefix.getPrefix(`${sdkRepositoryName}/`); -} diff --git a/tools/spec-gen-sdk/src/specificationReadmeMdFile.ts b/tools/spec-gen-sdk/src/specificationReadmeMdFile.ts deleted file mode 100644 index 723986ea96e..00000000000 --- a/tools/spec-gen-sdk/src/specificationReadmeMdFile.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Logger } from '@azure/logger-js'; -import { - findSwaggerToSDKConfiguration, - getRepository, - getRepositoryFullName, - ReadmeMdSwaggerToSDKConfiguration, - Repository, - RepositoryConfiguration, - joinPath -} from '@ts-common/azure-js-dev-tools'; -import { readFileSync } from 'fs'; - -/** - * A readme.md file that is used as an AutoRest configuration file within an OpenAPI specification - * repository. - */ -export class SpecificationReadmeMdFile { - /** - * The URL to the contents of this file. - */ - public readonly contentsPath: string; - /** - * Create a new SpecificationReadmeMdFile with the provided details. - * @param httpClient The HTTPClient to use to get this file's contents. - * @param logger The Logger that will be used to write logs to. - * @param relativeFilePath The path to this file relative to the root of the repository. - */ - constructor(specRepoFolder: string, private readonly logger: Logger, public readonly relativeFilePath: string) { - this.contentsPath = joinPath(specRepoFolder, relativeFilePath); - } - - /** - * Get the contents of this file, if it exists. - * @returns The contents of this file or undefined if the file doesn't exist. - */ - public async getContents(): Promise { - await this.logger.logSection(`Getting file contents for "${this.contentsPath}"...`); - try { - const buffer = readFileSync(this.contentsPath); - return buffer.toString(); - } catch (e) { - await this.logger.logWarning(`File ${this.contentsPath} not found`); - return undefined; - } - } - - /** - * Get the swagger-to-sdk configuration section from this file. - */ - public async getSwaggerToSDKConfiguration(): Promise { - let result: ReadmeMdSwaggerToSDKConfiguration | undefined; - const contents: string | undefined = await this.getContents(); - if (!contents) { - await this.logger.logError(`Merged readme.md response body is empty.`); - } else { - result = findSwaggerToSDKConfiguration(contents); - if (!result) { - await this.logger.logError(`No SwaggerToSDK configuration YAML block found in the merged readme.md.`); - } - } - return result; - } - - /** - * Get the repositories that have been configured for SDK Automation to be run on them for this - * specification readme.md file. - */ - public async getSwaggerToSDKRepositoryConfigurations(): Promise { - let result: RepositoryConfiguration[] | undefined; - const swaggerToSDKConfiguration: - | ReadmeMdSwaggerToSDKConfiguration - | undefined = await this.getSwaggerToSDKConfiguration(); - if (swaggerToSDKConfiguration) { - result = []; - await this.logger.logInfo(`Found ${swaggerToSDKConfiguration.repositories.length} requested SDK repositories:`); - for (const requestedRepository of swaggerToSDKConfiguration.repositories) { - const repository: Repository = getRepository(requestedRepository.repo); - requestedRepository.repo = getRepositoryFullName(repository); - await this.logger.logInfo(` ${requestedRepository.repo}`); - result.push(requestedRepository); - } - } - return result; - } -} diff --git a/tools/spec-gen-sdk/src/specificationRepositoryConfiguration.ts b/tools/spec-gen-sdk/src/specificationRepositoryConfiguration.ts deleted file mode 100644 index 4ee59c6ace4..00000000000 --- a/tools/spec-gen-sdk/src/specificationRepositoryConfiguration.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Logger, getDefaultLogger } from '@azure/logger-js'; -import { - getRepository, - RealGitHub, - Repository, - StringMap -} from '@ts-common/azure-js-dev-tools'; -import { defaultIntegrationBranchPrefix, defaultMainBranch, SDKRepositoryMapping, defaultConfigFilePath } from './sdkRepositoryMapping'; -import { readFileSync } from 'fs'; -import { SDKAutomationContext } from './sdkAutomation'; - -const specConfigPath = 'specificationRepositoryConfiguration.json'; - -/** - * A configuration object that can be put at the root of specification repositories. - */ -export interface SpecificationRepositoryConfiguration { - /** - * This is the base branch of pull requests that SDK Automation will be triggered for. Defaults to - * master. - */ - readonly sdkAutomationBaseBranch?: string; - /** - * A mapping of SDK repository names to the names of the SDK repositories that all interaction - * should go to instead. This is mostly used for private repository support in order to redirect - * any readme.md configuration file requests to the private SDK repository instead of the public - * SDK repository. - */ - readonly sdkRepositoryMappings?: StringMap>; - /** - * Internal use only. If repo mapping missing owner, owner will be added based on this property. - */ - specRepoOwner?: string; - - readonly overrides?: StringMap; -} - -/** - * Get the specification repository configuration object from this pull request's specification - * repository, or undefined if no configuration file could be found. - */ -export async function getSpecificationRepositoryConfiguration( - context: SDKAutomationContext, - repository: Repository | string -): Promise { - const { logger, github } = context; - const repo = getRepository(repository); - - const githubClient = await (github as RealGitHub).getClient(repo); - await logger.logSection( - `Getting specification repository configuration from "${repo.owner}/${repo.name}/${specConfigPath}"...` - ); - const rsp = await githubClient.repos.getContent({ - owner: repo.owner, - repo: repo.name, - path: specConfigPath, - mediaType: { - format: 'raw' - } - }); - - const result = JSON.parse(rsp.data as unknown as string); - - return result; -} - -export async function getLocalSpecificationRepositoryConfiguration( - specRepoFolder: string, - logger?: Logger -): Promise { - if (!logger) { - logger = getDefaultLogger(); - } - - const filePath = `${specRepoFolder}/specificationRepositoryConfiguration.json`; - await logger.logSection(`Getting specification repository configuration from "${filePath}"...`); - - const buffer = readFileSync(filePath); - const result = JSON.parse(buffer.toString()); - - return result; -} - -/** - * Get the SDKRepositoryMapping object associated with the SDK with the provided repository name. - * @param sdkRepositoryName The name of the SDK repository to get the mapping object for. - * @param configuration The configuration object to get the SDKRepositoryMapping object from. - */ -export async function getSDKRepositoryMapping( - sdkRepositoryName: string, - configuration?: SpecificationRepositoryConfiguration, - logger?: Logger -): Promise { - if (typeof sdkRepositoryName !== 'string') { - return sdkRepositoryName; - } - - const resolveSdkRepoName = (repoName: string) => - repoName.indexOf('/') > 0 || configuration === undefined ? repoName : `${configuration.specRepoOwner}/${repoName}`; - - const originalRepositoryName: string = resolveSdkRepoName(sdkRepositoryName); - let result = configuration?.sdkRepositoryMappings?.[sdkRepositoryName] ?? originalRepositoryName; - if (!result) { - return { - generationRepository: originalRepositoryName, - integrationRepository: originalRepositoryName, - mainRepository: originalRepositoryName, - integrationBranchPrefix: defaultIntegrationBranchPrefix, - mainBranch: defaultMainBranch, - secondaryRepository: originalRepositoryName, - secondaryBranch: defaultMainBranch, - configFilePath: defaultConfigFilePath - }; - } - - if (typeof result === 'string') { - result = resolveSdkRepoName(result); - if (logger) { - await logger.logInfo(`Mapping "${originalRepositoryName}" to "${result}".`); - } - return { - generationRepository: result, - integrationRepository: result, - mainRepository: result, - integrationBranchPrefix: defaultIntegrationBranchPrefix, - mainBranch: defaultMainBranch, - secondaryRepository: result, - secondaryBranch: defaultMainBranch, - configFilePath: defaultConfigFilePath - }; - } - - result.mainRepository = resolveSdkRepoName(result.mainRepository ?? originalRepositoryName); - result.integrationRepository = resolveSdkRepoName(result.integrationRepository ?? result.mainRepository); - result.generationRepository = resolveSdkRepoName(result.generationRepository ?? result.integrationRepository); - result.integrationBranchPrefix = result.integrationBranchPrefix ?? defaultIntegrationBranchPrefix; - result.mainBranch = result.mainBranch ?? defaultMainBranch; - result.secondaryRepository = resolveSdkRepoName(result.secondaryRepository ?? result.mainRepository); - result.secondaryBranch = result.secondaryBranch ?? result.mainBranch; - result.configFilePath = result.configFilePath ?? defaultConfigFilePath; - if (logger) { - await logger.logInfo( - `Mapping "${originalRepositoryName}" generation repository to "${result.generationRepository}".` - ); - await logger.logInfo( - `Mapping "${originalRepositoryName}" integration repository to "${result.integrationRepository}".` - ); - await logger.logInfo(`Mapping "${originalRepositoryName}" main repository to "${result.mainRepository}".`); - await logger.logInfo(`Mapping "${originalRepositoryName}" ` + - `secondary repository to "${result.secondaryRepository}".`); - await logger.logInfo(`Using "${result.integrationBranchPrefix}" as the integration branch prefix.`); - await logger.logInfo(`Using "${result.mainBranch}" as the main branch in the main repository.`); - await logger.logInfo(`Using "${result.secondaryBranch}" as the secondary branch in the secondary repository.`); - } - return result as SDKRepositoryMapping; -} diff --git a/tools/spec-gen-sdk/src/swaggerToSDKConfiguration.ts b/tools/spec-gen-sdk/src/swaggerToSDKConfiguration.ts deleted file mode 100644 index 88b65279eae..00000000000 --- a/tools/spec-gen-sdk/src/swaggerToSDKConfiguration.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { AutoRestOptions, StringMap } from '@ts-common/azure-js-dev-tools'; - -/** - * A configuration that describes how SwaggerToSDK should behave for a specific repository. - */ -export interface SwaggerToSDKConfiguration { - meta?: { - /** - * The version of SwaggerToSDK to use. - * The version must be 0.2.0. - */ - version?: string; - - after_scripts_in_repo?: string[]; - /** - * List of commands to execute after the generation is done. Will be executed in the order of the - * list. Current working directory will be the cloned path. See also "envs" node. - * Different from after_scripts, the arguments will be added automatically. - * Note: initialized for Terraform. - */ - after_scripts_in_repo_with_service?: string[]; - - /** - * List of commands to execute after the generation is done. Will be executed in the order of the - * list. Current working directory will be the cloned path. See also "envs" node. - */ - after_scripts?: string[]; - /** - * An optional dictionary of options you want to pass to Autorest. This will be passed in any - * call, but can be override by "autorest_options" in each data. Note that you CAN'T override - * "--output-folder" which is filled contextually. All options prefixed by "sdkrel:" can be a - * relative path that will be solved against SDK folder before being sent to Autorest. - */ - autorest_options?: AutoRestOptions; - /** - * An optional dictionary of options specified for internal sdk generation you want to pass to Autorest. - * This will be passed in any call. Note that you CAN'T override - * "--output-folder" which is filled contextually. All options prefixed by "sdkrel:" can be a - * relative path that will be solved against SDK folder before being sent to Autorest. - * Note: initialized for Terraform. - */ - autorest_options_for_otherSDK?: AutoRestOptions; - /** - * The name of the repository that contains this configuration. - */ - repotag?: string; - /** - * Environment variables for after_scripts. All options prefixed by "sdkrel:" can be a relative - * path that will be resolved against SDK folder before being sent to the scripts. - */ - envs?: StringMap; - /** - * A set of advanced options that can change how SwaggerToSDK interacts with the repository. - */ - advanced_options?: AdvancedOptions; - /** - * An optional list of files/directory to keep when we generate new SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py"). This applies to every Swagger files. - */ - wrapper_filesOrDirs?: string[]; - /** - * An optional list of files/directory to delete from the generated SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py") This applies to every Swagger files. - */ - delete_filesOrDirs?: string[]; - /** - * If the data to consider generated by Autorest are not directly in the root folder. For - * instance, if Autorest generates a network client folder and you want to consider this folder - * as the root of data. This parameter is applied before 'delete_filesOrDirs', consider it in - * your paths. This applies to every Swagger files. - */ - generated_relative_base_directory?: string; - /** - * A file that marks the root of a package. In Node.js this is package.json. In Python it's - * setup.py. - */ - package_root_file?: string; - }; - /** - * It's a dict where keys are a project id. The project id has no constraint, but it's recommended - * to use namespace style, like "datalake.store.account" to provide the best flexibility for the - * --project parameter. - */ - projects?: StringMap; -} - -/** - * The strategy that will be used for determining the base branch that a SDK generation pull - * request will be made against. If "integration_branch" is chosen, then the SDK generation pull - * request will be made against a branch that is used to stage the changes for a specific package - * before it is released. If "main_branch" is chosen, then the SDK generation pull request - * will be made against the specified main branch (or "master" if no main branch is specified). If - * no value is specified, then this will default to "integration_branch". - */ -export type SDKGenerationPullRequestBaseOptions = 'integration_branch' | 'main_branch'; - -/** - * A set of advanced options that can change how SwaggerToSDK interacts with the repository. - */ -export interface AdvancedOptions { - /** - * Add more layers of folders to clone the repo, if necessary. Right now, useful for Go only. - * "sdkrel:" will consider this as the final folder path. - */ - clone_dir?: string; - /** - * Whether or not pull requests will be made against this SDK repository with the changes - * generated from a specification pull request. - */ - create_sdk_pull_requests?: boolean; - /** - * The strategy that will be used for determining the base branch that a SDK generation pull - * request will be made against. If "integration_pull_request" is chosen, then the SDK generation - * pull request will be made against a branch that is used to stage the changes for a specific - * package before it is released. If "master" is chosen, then the SDK generation pull request will - * be made against "master". If no value is specified, then this will default to - * "integration_pull_request". - */ - sdk_generation_pull_request_base?: SDKGenerationPullRequestBaseOptions; - /** - * Wether or not to disable sdk automation to automatically CLOSE or MERGE generation pull - * request. - */ - disable_generation_pr_automation?: boolean; - /** - * An optional list of files/directory to keep when we generate new SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py"). This applies to every Swagger files. - */ - wrapper_filesOrDirs?: string[]; - /** - * An optional list of files/directory to delete from the generated SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py") This applies to every Swagger files. - */ - delete_filesOrDirs?: string[]; - /** - * If the data to consider generated by Autorest are not directly in the root folder. For - * instance, if Autorest generates a network client folder and you want to consider this folder as - * the root of data. This parameter is applied before 'delete_filesOrDirs', consider it in your - * paths. This applies to every Swagger files. - */ - generated_relative_base_directory?: string; - /** - * This is the folder in your SDK repository where you want to put the generated files. - */ - output_dir?: string; - /** - * This is an optional folder where to put metadata about the generation (Autorest version, date - * of generation, etc.). This can be used by our monitoring system to detect package that needs an - * update. Be sure this folder is unique in the entire file, to avoid overwriting a file from - * another project. - */ - build_dir?: string; -} - -/** - * A set of options for giving specific properties to certain service/resource providers. - */ -export interface Project { - /** - * This is an optional parameter which specify the Autorest MD file path for this project. This - * is relative to the rest-folder paramter. - */ - markdown?: string; - /** - * An optional dictionary of options you want to pass to Autorest. This will be passed in any - * call, but can be override by "autorest_options" in each data. Note that you CAN'T override - * "--output-folder" which is filled contextually. All options prefixed by "sdkrel:" can be a - * relative path that will be resolved against SDK folder before being sent to Autorest. - */ - autorest_options?: AutoRestOptions; - /** - * An optional list of files/directory to keep when we generate new SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py"). This applies to every Swagger files. - */ - wrapper_filesOrDirs?: string[]; - /** - * An optional list of files/directory to delete from the generated SDK. This support a - * Bash-like wildcard syntax (i.e. "my*file.py") This applies to every Swagger files. - */ - delete_filesOrDirs?: string[]; - /** - * If the data to consider generated by Autorest are not directly in the root folder. For - * instance, if Autorest generates a network client folder and you want to consider this folder - * as the root of data. This parameter is applied before 'delete_filesOrDirs', consider it in - * your paths. This applies to every Swagger files. - */ - generated_relative_base_directory?: string; - /** - * This is the folder in your SDK repository where you want to put the generated files. - */ - output_dir?: string; - /** - * This is an optional folder where to put metadata about the generation (Autorest version, date - * of generation, etc.). This can be used by our monitoring system to detect package that needs an - * update. Be sure this folder is unique in the entire file, to avoid overwriting a file from - * another project. - */ - build_dir?: string; -} - -export function getCreateSdkPullRequests( - swaggerToSDKConfiguration: SwaggerToSDKConfiguration | undefined, - defaultValue: boolean = false -): boolean { - return getConfigAdvancedOption(swaggerToSDKConfiguration, 'create_sdk_pull_requests') || defaultValue; -} - -export function getSDKGenerationPullRequestBase( - swaggerToSDKConfiguration: SwaggerToSDKConfiguration | undefined, - defaultValue: SDKGenerationPullRequestBaseOptions = 'integration_branch' -): SDKGenerationPullRequestBaseOptions { - return getConfigAdvancedOption(swaggerToSDKConfiguration, 'sdk_generation_pull_request_base') || defaultValue; -} - -type metaType = Exclude; -export function getConfigMeta( - swaggerToSDKConfiguration: SwaggerToSDKConfiguration | undefined, - key: TKey -): metaType[TKey] | undefined { - return swaggerToSDKConfiguration && swaggerToSDKConfiguration.meta && swaggerToSDKConfiguration.meta[key]; -} - -type advancedOptionsType = Exclude; -export function getConfigAdvancedOption( - swaggerToSDKConfiguration: SwaggerToSDKConfiguration | undefined, - key: TKey -): advancedOptionsType[TKey] | undefined { - const advancedOptions = getConfigMeta(swaggerToSDKConfiguration, 'advanced_options'); - return advancedOptions && advancedOptions[key]; -} diff --git a/tools/spec-gen-sdk/src/types/GenerateOutput.ts b/tools/spec-gen-sdk/src/types/GenerateOutput.ts index 593cc35a0e5..8539a6639c0 100644 --- a/tools/spec-gen-sdk/src/types/GenerateOutput.ts +++ b/tools/spec-gen-sdk/src/types/GenerateOutput.ts @@ -1,4 +1,4 @@ -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from '../automation/sdkAutomationState'; import { requireJsonc } from '../utils/requireJsonc'; import { InstallInstructionScriptOutput } from './InstallInstructionScriptOutput'; import { getTypeTransformer } from './validator'; diff --git a/tools/spec-gen-sdk/src/types/Message.ts b/tools/spec-gen-sdk/src/types/Message.ts new file mode 100644 index 00000000000..d1f0bf9804e --- /dev/null +++ b/tools/spec-gen-sdk/src/types/Message.ts @@ -0,0 +1,100 @@ +/** + * Note this corresponds to Category enum in openapi-diff. + * For details, see comment on breakingChangeShared.ts / OadMessage.type. + */ +export type MessageLevel = "Info" | "Warning" | "Error"; + +// Instances of this type are created e.g. by the function oadMessagesToResultMessageRecords +export type JsonPath = { + // Example values of tag: "old" or "new" + tag: string; + // Example value of path: + // sourceBranchHref(this.context, oadMessage.new.location || ""), + // where this.context is of type PRContext and oadMessage is of type OadMessage + path: string; + // Example value of jsonPath: + // oadMessage.new?.path + // where oadMessage is of type OadMessage + jsonPath?: string | undefined +}; + +export type MessageContext = { + toolVersion: string; +}; + +export type Extra = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +}; + +export type BaseMessageRecord = { + level: MessageLevel; + message: string; + time: Date; + context?: MessageContext; + group?: string; + extra?: Extra; + groupName?: string; +}; + +/** See comment on type MessageRecord */ +export type ResultMessageRecord = BaseMessageRecord & { + type: "Result"; + id?: string; + code?: string; + docUrl?: string; + paths: JsonPath[]; +}; + +export type RawMessageRecord = BaseMessageRecord & { + type: "Raw"; +}; + +export type MarkdownMessageRecord = BaseMessageRecord & { + type: "Markdown"; + mode: "replace" | "append"; + detailMessage?: string; +}; + +/** + * Represents a record of detailed information coming out of one of the validation tools, + * like breaking change detector (OAD) or LintDiff. + * + * MessageRecords end up being printed in the contents of tables in relevant validation tool check in GitHub PR. + * These records are transferred from the Azure DevOps Azure.azure-rest-api-specs-pipeline build runs + * to the GitHub via pipe.log file (pipeline.ts / unifiedPipelineResultFileName) and Azure blob. + * + * The pipe.log gets uploaded to the blob via + * publishResult.ts / resultPublisher.uploadLog + * + * The blob contents are read by the pipeline-bot via + * resultComposer.ts / parseCompleteMessageData + * + * Examples: + * Save message record from OAD to pipe.log: + * doBreakingChangeDetection / appendOadMessages + * + * Save exception thrown by OAD to pipe.log, as MessageLine composed of RawMessageRecord[] + * doBreakingChangeDetection / catch block + * + * For details, see: + * https://dev.azure.com/azure-sdk/internal/_wiki/wikis/internal.wiki/1011/How-the-data-in-breaking-change-GH-check-tables-is-getting-populated + */ +export type MessageRecord = ResultMessageRecord | RawMessageRecord | MarkdownMessageRecord; + +/** + * See type MessageRecord + */ +export type MessageLine = MessageRecord | MessageRecord[]; + + +export const sendPipelineVariable = (variable: string, value: string,isOutput=false) => { + console.log(`##vso[task.setVariable variable=${variable}${isOutput?';isoutput=true':''}]${value}`); +}; +export const sendSuccess = () => { + sendPipelineVariable("ValidationResult", "success"); +}; + +export const sendFailure = () => { + sendPipelineVariable("ValidationResult", "failure"); +}; diff --git a/tools/spec-gen-sdk/src/types/PackageData.ts b/tools/spec-gen-sdk/src/types/PackageData.ts index c5fcbdeacf3..b21eaf0b540 100644 --- a/tools/spec-gen-sdk/src/types/PackageData.ts +++ b/tools/spec-gen-sdk/src/types/PackageData.ts @@ -1,10 +1,117 @@ -import { SDKRepositoryPackageData } from '../langSpecs/sdkRepositoryPackage'; -import { PackageResult } from './GenerateOutput'; import * as path from 'path'; +import { PackageResult } from './GenerateOutput'; import { WorkflowContext } from '../automation/workflow'; import { repoKeyToString } from '../utils/githubUtils'; -import { getSuppressionLines, SDKSuppressionContentList } from '../utils/handleSuppressionLines'; +import { SDKAutomationState } from '../automation/sdkAutomationState'; import { parseSemverVersionString } from '../utils/parseSemverVersionString'; +import { getSuppressionLines, SDKSuppressionContentList } from '../utils/handleSuppressionLines'; + +/** + * The data that describes an SDK repository package. + */ +export interface SDKRepositoryPackageData { + /** + * The name of the package. + */ + readonly name: string; + /** + * The relative path to the root of the package folder from the root of the SDK repository. + */ + readonly relativeFolderPath: string; + /** + * The relative path to the root of the extra package folders from the root of the SDK repository. + */ + extraRelativeFolderPaths: string[]; + /** + * The current status of creating and uploading this package. + */ + status: SDKAutomationState; + /** + * Message to be shown for this package. + */ + messages: string[]; + /** + * Does this package has breaking change. + */ + hasBreakingChange?: boolean; + /** + * The URL of the blob where this SDK repository package's logs will be written to. + */ + logsBlobUrl: string; + /** + * The URLs of the blobs where this SDK repository package's artifacts will be written to. + */ + artifactBlobUrls?: string[]; + /** + * The URLs of the generated apiView. + */ + apiViewUrl?: string; + /** + * Used to indicate whether the package should be released as public + */ + isPrivatePackage: boolean; + /** + * The installation instructions for this package. + */ + installationInstructions?: string; + /** + * Lite installation instruction for this package. + */ + liteInstallationInstruction?: string | undefined; + /** + * The URL of the blob where this SDK repository package's installation instructions will be + * written to. + */ + installationInstructionsBlobUrl?: string; + /** + * The URL to the created generation pull request for this SDK repository package. + */ + generationPullRequestUrl?: string; + /** + * The URL to the diff page of the created generation pull request for this SDK repository package. + */ + generationPullRequestDiffUrl?: string; + /** + * The URL to the integration pull request for this SDK repository package. + */ + integrationPullRequestUrl?: string; + /** + * The files in this package that have changed. + */ + readonly changedFilePaths: string[]; + /** + * The name of the generation branch for this package. + */ + readonly generationBranch: string; + /** + * The repository where the SDK's generation pull request and branch will be created. This is the + * first repository where the automatically generated SDK will appear. + */ + readonly generationRepository: string; + /** + * The URL to this package's generation repository. + */ + readonly generationRepositoryUrl: string; + /** + * The name of the integration branch for this package. + */ + readonly integrationBranch: string; + /** + * The repository where the SDK's integration/staging pull request and branch will be created. The + * SDK's integration branch and pull request are where merged SDK generation pull requests will be + * staged before they are merged and published in the main repository. + */ + readonly integrationRepository: string; + /** + * Whether or not this SDK repository package's generation branch should be based off of the + * integration branch or the main branch. + */ + readonly useIntegrationBranch: boolean; + /** + * The main repository for the SDK. This is where the SDK packages are published from. + */ + readonly mainRepository: string; +} export type PackageData = SDKRepositoryPackageData & { artifactPaths: string[]; diff --git a/tools/spec-gen-sdk/src/types/sdkSuppressions.ts b/tools/spec-gen-sdk/src/types/sdkSuppressions.ts new file mode 100644 index 00000000000..7e844a9f144 --- /dev/null +++ b/tools/spec-gen-sdk/src/types/sdkSuppressions.ts @@ -0,0 +1,87 @@ +/** + * This file contains types for the contents of the SDK suppressions file, sdk-suppressions.yml. + * For details, see: + * - https://microsoftapc-my.sharepoint.com/:w:/g/personal/raychen_microsoft_com/EbOAA9SkhQhGlgxtf7mc0kUB-25bFue0EFbXKXS3TFLTQA + */ + +import Ajv from "ajv"; +import { SdkName, sdkLabels } from "./sdks"; + +export const sdkSuppressionsFileName = "sdk-suppressions.yaml"; + +export type SdkSuppressionsYml = { + suppressions: SdkSuppressionsSection; +}; + +export type SdkSuppressionsSection = { + [sdkName in SdkName]?: SdkPackageSuppressionsEntry[]; +}; + +export type SdkPackageSuppressionsEntry = { + package: string; + "breaking-changes": string[]; +}; + +export function validateSdkSuppressionsFile(suppressionContent: string | object | undefined | null): { + result: boolean, + message: string +} { + if (suppressionContent === null) { + return { + result: false, + message: 'This suppression file is a empty file' + }; + } + + if (!suppressionContent) { + return { + result: false, + message: 'This suppression file is not a valid yaml.' + }; + } + + const suppressionFileSchema = { + type: 'object', + properties: { + suppressions: { + type: 'object', + propertyNames: { + enum: Object.keys(sdkLabels) + }, + patternProperties: { + "^.*$": { + type: 'array', + items: { + type: 'object', + properties: { + package: { type: 'string' }, + "breaking-changes": { type: 'array', items: { type: 'string' } } + }, + required: ['package', 'breaking-changes'], + additionalProperties: false + } + } + } + } + }, + required: ['suppressions'], + additionalProperties: false + }; + + const suppressionAjv = new Ajv({ allErrors: true }); + const suppressionAjvCompile = suppressionAjv.compile(suppressionFileSchema); + + const isValid = suppressionAjvCompile(suppressionContent); + + if (isValid) { + return { + result: true, + message: 'This suppression file is a valid yaml.' + }; + } else { + return { + result: false, + message: 'This suppression file is a valid yaml but the schema is wrong: ' + suppressionAjv.errorsText(suppressionAjvCompile.errors, { separator: '\n' }) + }; + } +} diff --git a/tools/spec-gen-sdk/src/types/sdks.ts b/tools/spec-gen-sdk/src/types/sdks.ts new file mode 100644 index 00000000000..e5ebbe40ceb --- /dev/null +++ b/tools/spec-gen-sdk/src/types/sdks.ts @@ -0,0 +1,66 @@ +/** + * This file is the single source of truth for the labels used by the SDK generation tooling + * in the Azure/azure-rest-api-specs and Azure/azure-rest-api-specs-pr repositories. + * + * For additional context, see: + * - https://gist.github.com/raych1/353949d19371b69fb82a10dd70032a51 + * - https://github.com/Azure/azure-sdk-tools/issues/6327 + * - https://microsoftapc-my.sharepoint.com/:w:/g/personal/raychen_microsoft_com/EbOAA9SkhQhGlgxtf7mc0kUB-25bFue0EFbXKXS3TFLTQA + */ +export type SdkName = + | "azure-sdk-for-go" + | "azure-sdk-for-java" + | "azure-sdk-for-js" + | "azure-sdk-for-net" + | "azure-sdk-for-net-track2" + | "azure-sdk-for-python"; + +export const sdkLabels: { + [sdkName in SdkName]: { + breakingChange: string | undefined; + breakingChangeApproved: string | undefined; + breakingChangeSuppression: string | undefined; + breakingChangeSuppressionApproved: string | undefined; + }; +} = { + "azure-sdk-for-go": { + breakingChange: "BreakingChange-Go-Sdk", + breakingChangeApproved: "BreakingChange-Go-Sdk-Approved", + breakingChangeSuppression: "BreakingChange-Go-Sdk-Suppression", + breakingChangeSuppressionApproved: + "BreakingChange-Go-Sdk-Suppression-Approved", + }, + "azure-sdk-for-java": { + breakingChange: "BreakingChange-Java-Sdk", + breakingChangeApproved: "BreakingChange-Java-Sdk-Approved", + breakingChangeSuppression: "BreakingChange-Java-Sdk-Suppression", + breakingChangeSuppressionApproved: + "BreakingChange-Java-Sdk-Suppression-Approved", + }, + "azure-sdk-for-js": { + breakingChange: "BreakingChange-JavaScript-Sdk", + breakingChangeApproved: "BreakingChange-JavaScript-Sdk-Approved", + breakingChangeSuppression: "BreakingChange-JavaScript-Sdk-Suppression", + breakingChangeSuppressionApproved: + "BreakingChange-JavaScript-Sdk-Suppression-Approved", + }, + "azure-sdk-for-net": { + breakingChange: undefined, + breakingChangeApproved: undefined, + breakingChangeSuppression: undefined, + breakingChangeSuppressionApproved: undefined, + }, + "azure-sdk-for-net-track2": { + breakingChange: undefined, + breakingChangeApproved: undefined, + breakingChangeSuppression: undefined, + breakingChangeSuppressionApproved: undefined + }, + "azure-sdk-for-python": { + breakingChange: "BreakingChange-Python-Sdk", + breakingChangeApproved: "BreakingChange-Python-Sdk-Approved", + breakingChangeSuppression: "BreakingChange-Python-Sdk-Suppression", + breakingChangeSuppressionApproved: + "BreakingChange-Python-Sdk-Suppression-Approved", + } +} diff --git a/tools/spec-gen-sdk/src/types/validator.ts b/tools/spec-gen-sdk/src/types/validator.ts index b1ad46bfe99..bb54f93c53a 100644 --- a/tools/spec-gen-sdk/src/types/validator.ts +++ b/tools/spec-gen-sdk/src/types/validator.ts @@ -1,4 +1,21 @@ import { default as ajvInit, ValidateFunction } from 'ajv'; + +export const getTypeTransformer = (schema: object, name: string) => { + let validator: ValidateFunction | undefined; + return (obj: unknown) => { + addSchema(); + if (validator === undefined) { + validator = ajv.compile(schema); + } + if (!validator(obj)) { + const error = validator.errors![0]; + throw new Error(`ConfigError: Invalid ${name}: ${error.dataPath} ${error.message}. If the SDK artifacts haven't been successfully generated, please fix the errors to ensure they are generated correctly. Refer to the schema definitions at https://github.com/Azure/azure-rest-api-specs/tree/main/documentation/sdkautomation for guidance.`); + } + + return obj as T; + }; +}; + import * as TriggerType from './TriggerType'; import * as InstallInstructionScriptInput from './InstallInstructionScriptInput'; import * as InstallInstructionScriptOutput from './InstallInstructionScriptOutput'; @@ -20,18 +37,4 @@ const addSchema = () => { } }; -export const getTypeTransformer = (schema: object, name: string) => { - let validator: ValidateFunction | undefined; - return (obj: unknown) => { - addSchema(); - if (validator === undefined) { - validator = ajv.compile(schema); - } - if (!validator(obj)) { - const error = validator.errors![0]; - throw new Error(`ConfigError: Invalid ${name}: ${error.dataPath} ${error.message}. If the SDK artifacts haven't been successfully generated, please fix the errors to ensure they are generated correctly. Refer to the schema definitions at https://github.com/Azure/azure-rest-api-specs/tree/main/documentation/sdkautomation for guidance.`); - } - return obj as T; - }; -}; diff --git a/tools/spec-gen-sdk/src/utils/arrays.ts b/tools/spec-gen-sdk/src/utils/arrays.ts new file mode 100644 index 00000000000..32ebb2da2f1 --- /dev/null +++ b/tools/spec-gen-sdk/src/utils/arrays.ts @@ -0,0 +1,38 @@ +/** + * Get whether or not the provided array contains any values. + * @param values The array to check. + * @returns Whether or not the provided array contains any values. + */ +export function any(values: T[] | undefined): values is T[] { + return !!(values && values.length > 0); +} + + +/** + * Get all of the values within the provided array of values that match the provided condition. + * @param values The array of values to filter. + * @param condition The condition to look for within the array of values. + * @returns The array of values from the original values that match the provided condition. + */ +export function where(values: T[], condition: (value: T) => boolean): T[] { + const result: T[] = []; + for (const value of values) { + if (condition(value)) { + result.push(value); + } + } + return result; +} + +/** + * Ensure that a value that is either a single value or an array is an array by wrapping single + * values in an array. + * @param value The value to ensure is an array. + * @param conversion The function that will be used to convert the non-array value to an array. This + * defaults to just creating a new array with the single value. + * @returns The array value. + */ +export function toArray(value: T | T[], conversion: (valueToConvert: T) => T[] = (valueToConvert: T) => [valueToConvert]): T[] { + return value instanceof Array ? value : conversion(value); +} + \ No newline at end of file diff --git a/tools/spec-gen-sdk/src/utils/fsUtils.ts b/tools/spec-gen-sdk/src/utils/fsUtils.ts index 0d228d5be0e..361dba10310 100644 --- a/tools/spec-gen-sdk/src/utils/fsUtils.ts +++ b/tools/spec-gen-sdk/src/utils/fsUtils.ts @@ -1,5 +1,6 @@ import path from 'path'; import fs from 'fs'; +import { any } from './arrays'; import { WorkflowContext } from '../automation/workflow'; import { SimpleGit } from 'simple-git'; import { TreeType, gitTreeResultToStringArray } from './gitUtils'; @@ -177,3 +178,704 @@ export const deleteTmpJsonFile = (context: WorkflowContext, fileName: string) => fs.unlinkSync(filePath); } }; + +/** + * Join the provided path segments using a forward slash (/) as a path separator. + * @param pathSegments The path segments to resolve. + * @returns The resolved path. + */ +export function joinPath(...pathSegments: string[]): string { + return normalizePath(path.posix.join(...pathSegments)); + } + + /** + * Resolve the provided path segments using a forward slash (/) as a path separator. + * @param pathSegments The path segments to resolve. + * @returns The resolved path. + */ + export function resolvePath(...pathSegments: string[]): string { + return normalizePath(path.posix.resolve(...pathSegments)); + } + + /** + * Get the relative path from the provided basePath to the provided absolutePath. For example, + * pathRelativeTo("/my/path", "/") will return "my/path". + */ + export function pathRelativeTo(absolutePath: string, basePath: string): string { + let result: string = normalizePath(path.relative(normalizePath(basePath), normalizePath(absolutePath))); + if (result.endsWith("/..")) { + result += "/"; + } + return result; + } + + /** + * Replace all of the backslashes (\) with forward slashes (/), unless the provided osPlatform is + * win32. If the osPlatform is win32, then all forward slashes (/) will be replaced with backslahes + * (\). + * @param pathString The path to normalize. + * @returns The normalized path. + */ + export function normalizePath(pathString: string, osPlatform?: string): string { + let result: string; + if (!pathString) { + result = pathString; + } else if (osPlatform === "win32") { + result = pathString.replace(/\//g, "\\"); + } else { + result = pathString.replace(/\\/g, "/"); + } + return result; + } + + /** + * Return the provided path without its file extension. + * @param path The path. + */ + export function pathWithoutFileExtension(path: string): string { + const lastDot: number = path.lastIndexOf("."); + return lastDot === -1 ? path : path.substring(0, lastDot); + } + + /** + * Get the root path of the provided path string. If the provided path string is relative (not + * rooted), then undefined will be returned. + * @param pathString The path to get the root of. + */ + export function getRootPath(pathString: string): string | undefined { + let result: string | undefined; + if (pathString) { + result = path.win32.parse(pathString).root || undefined; + if (!result) { + result = path.posix.parse(pathString).root || undefined; + } + } + return result; + } + + /** + * Check whether or not the provided pathString is rooted (absolute). + * @param pathString The path to check. + * @returns Whether or not the provided pathString is rooted (absolute). + */ + export function isRooted(pathString: string): boolean { + return !!getRootPath(pathString); + } + + /** + * Get the name/last segment of the provided path string. + * @param pathString The path to get the name/last segment of. + * @returns The name/last segment of the provided path string. + */ + export function getName(pathString: string): string { + return getPathName(pathString); + } + + /** + * Get the name/last segment of the provided path string. + * @param pathString The path to get the name/last segment of. + * @returns The name/last segment of the provided path string. + */ + export function getPathName(pathString: string): string { + const lastSlashIndex: number = Math.max(pathString.lastIndexOf("/"), pathString.lastIndexOf("\\")); + return lastSlashIndex === -1 ? pathString : pathString.substring(lastSlashIndex + 1); + } + + /** + * Get the path to the parent folder of the provided path string. + * @param pathString The path to the get the parent folder path of. + * @returns The path to the parent folder of the provided path string. + */ + export function getParentFolderPath(pathString: string): string { + return path.dirname(pathString); + } + + async function _entryExists(entryPath: string, condition?: (stats: fs.Stats) => (boolean | Promise)): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.lstat(entryPath, (error: NodeJS.ErrnoException | null, stats: fs.Stats) => { + if (error) { + if (error.code === "ENOENT" || error.code === "ENOTDIR") { + resolve(false); + } else { + reject(error); + } + } else { + resolve(!condition || condition(stats)); + } + }); + }); + } + + function _entryExistsSync(entryPath: string, condition?: (stats: fs.Stats) => boolean): boolean { + let result = false; + try { + const stat: fs.Stats = fs.lstatSync(entryPath); + result = !!(!condition || condition(stat)); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + // Ignore error + } + return result; + } + + /** + * Get whether or not a file entry (file or folder) exists at the provided entryPath. + * @param entryPath The path to the file entry to check. + * @returns Whether or not a file entry (file or folder) exists at the provided entryPath. + */ + export function entryExists(entryPath: string): Promise { + return _entryExists(entryPath); + } + + /** + * Check whether or not a symbolic link exists at the provided path. + * @param symbolicLinkPath The path to check. + * @returns Whether or not a symbolic link exists at the provided path. + */ + export function symbolicLinkExists(symbolicLinkPath: string): Promise { + return _entryExists(symbolicLinkPath, (stats: fs.Stats) => stats.isSymbolicLink()); + } + + + /** + * Check whether or not a file exists at the provided filePath. + * @param filePath The path to check. + * @returns Whether or not a file exists at the provided filePath. + */ + export function fileExists(filePath: string): Promise { + return _entryExists(filePath, (stats: fs.Stats) => stats.isFile()); + } + + /** + * Check whether or not a file exists at the provided filePath. + * @param filePath The path to check. + * @returns Whether or not a file exists at the provided filePath. + */ + export function fileExistsSync(filePath: string): boolean { + return _entryExistsSync(filePath, (stats: fs.Stats) => stats.isFile()); + } + + /** + * Check whether or not a folder exists at the provided folderPath. + * @param folderPath The path to check. + * @returns Whether or not a folder exists at the provided folderPath. + */ + export function folderExists(folderPath: string): Promise { + return _entryExists(folderPath, (stats: fs.Stats) => stats.isDirectory()); + } + + export function _createFolder(folderPath: string): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.mkdir(folderPath, (error: NodeJS.ErrnoException | null) => { + if (error) { + if (error.code === "EEXIST") { + resolve(false); + } else { + reject(error); + } + } else { + resolve(true); + } + }); + }); + } + + /** + * Create a folder at the provided folderPath. If the folder is successfully created, then true will + * be returned. If the folder already exists, then false will be returned. + * @param folderPath The path to create a folder at. + */ + export async function createFolder(folderPath: string): Promise { + let result: boolean | Promise | undefined; + try { + result = await _createFolder(folderPath); + } catch (createFolderError) { + if (createFolderError.code !== "ENOENT") { + result = Promise.reject(createFolderError); + } else { + try { + await createFolder(getParentFolderPath(folderPath)); + try { + result = await _createFolder(folderPath); + } catch (createFolderError2) { + result = Promise.reject(createFolderError2); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (createParentFolderError) { + result = Promise.reject(createFolderError); + } + } + } + return result; + } + + /** + * Create a temporary folder and return the absolute path to the folder. If a parentFolderPath is + * provided, then the temporary folder will be created as a child of the parentFolderPath. If + * parentFolderPath is not provided, then the current working folder will be used as the + * parentFolderPath. + * @param The folder that the temporary folder will be created as a child of. Defaults to the + * current working folder. + */ + export async function createTemporaryFolder(parentFolderPath?: string): Promise { + if (!parentFolderPath) { + parentFolderPath = process.cwd(); + } else if (!isRooted(parentFolderPath)) { + parentFolderPath = joinPath(process.cwd(), parentFolderPath); + } + + let result = ""; + let i = 1; + while (!result) { + const tempFolderPath: string = joinPath(parentFolderPath, i.toString()); + if (await createFolder(tempFolderPath)) { + result = tempFolderPath; + break; + } else { + ++i; + } + } + return result; + } + + /** + * Copy the entry at the source entry path to the destination entry path. + * @param sourceEntryPath The path to the entry to copy from. + * @param destinationEntryPath The path to entry to copy to. + */ + export async function copyEntry(sourceEntryPath: string, destinationEntryPath: string): Promise { + let result: Promise; + if (await fileExists(sourceEntryPath)) { + result = copyFile(sourceEntryPath, destinationEntryPath); + } else if (await folderExists(sourceEntryPath)) { + result = copyFolder(sourceEntryPath, destinationEntryPath); + } else { + // eslint-disable-next-line no-undef + const error: NodeJS.ErrnoException = new Error(`ENOENT: no such file or directory: ${sourceEntryPath}`); + error.code = "ENOENT"; + error.path = sourceEntryPath; + result = Promise.reject(error); + } + return result; + } + + /** + * Copy the file at the source file path to the destination file path. + * @param sourceFilePath The path to the file to copy from. + * @param destinationFilePath The path to file to copy to. + * @param createDestinationFolder Whether or not the destination parent folder will be created if it + * doesn't exist. + */ + export async function copyFile(sourceFilePath: string, destinationFilePath: string, createDestinationFolder = true): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.copyFile(sourceFilePath, destinationFilePath, async (error: NodeJS.ErrnoException | null) => { + if (!error) { + resolve(); + } else if (error.code !== "ENOENT" || !(await fileExists(sourceFilePath)) || !createDestinationFolder) { + reject(error); + } else { + const destinationFolderPath: string = getParentFolderPath(destinationFilePath); + if (await folderExists(destinationFolderPath)) { + reject(error); + } else { + try { + await createFolder(destinationFolderPath); + await copyFile(sourceFilePath, destinationFilePath, false); + resolve(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error2) { + reject(error); + } + } + } + }); + }); + } + + /** + * Copy the folder at the source folder path to the destination folder path. + * @param sourceFolderPath The path to the folder to copy from. + * @param destinationFolderPath The path to the folder to copy to. This folder and its parent + * folders will be created if they don't already exist. + */ + export async function copyFolder(sourceFolderPath: string, destinationFolderPath: string): Promise { + let result: Promise; + const childEntryPaths: string[] | undefined = await getChildEntryPaths(sourceFolderPath); + if (!childEntryPaths) { + // eslint-disable-next-line no-undef + const error: NodeJS.ErrnoException = new Error(`ENOENT: no such file or directory: ${sourceFolderPath}`); + error.code = "ENOENT"; + error.path = sourceFolderPath; + result = Promise.reject(error); + } else { + for (const childEntryPath of childEntryPaths) { + const childEntryName: string = getPathName(childEntryPath); + await copyEntry(childEntryPath, joinPath(destinationFolderPath, childEntryName)); + } + result = Promise.resolve(); + } + return result; + } + + /** + * Get whether or not the provided string completely matches the provided regularExpression. + */ + function matches(regularExpression: RegExp, possibleMatch: string): boolean { + const matchResult = possibleMatch.match(regularExpression); + return !!(matchResult && matchResult[0].length === possibleMatch.length); + } + + export async function findEntryInPath(entryName: string | RegExp, startFolderPath: string | undefined, condition: (entryPath: string) => (boolean | Promise)): Promise { + let result: string | undefined; + let folderPath: string = startFolderPath || process.cwd(); + + searchLoop: + while (true) { + if (typeof entryName === "string") { + const folderEntryPath: string = joinPath(folderPath, entryName); + if (await Promise.resolve(condition(folderEntryPath))) { + result = folderEntryPath; + break searchLoop; + } + } else { + const folderEntryPaths: string[] | undefined = await getChildEntryPaths(folderPath); + if (any(folderEntryPaths)) { + for (const folderEntryPath of folderEntryPaths) { + if (matches(entryName, folderEntryPath)) { + if (await Promise.resolve(condition(folderEntryPath))) { + result = folderEntryPath; + break searchLoop; + } + } else { + const folderEntryName: string = getPathName(folderEntryPath); + if (matches(entryName, folderEntryName)) { + if (await Promise.resolve(condition(folderEntryPath))) { + result = folderEntryPath; + break searchLoop; + } + } + } + } + } + } + + const parentFolderPath: string = getParentFolderPath(folderPath); + if (!parentFolderPath || folderPath === parentFolderPath) { + break searchLoop; + } else { + folderPath = parentFolderPath; + } + } + + return result; + } + + function findEntryInPathSync(entryName: string, startFolderPath: string | undefined, condition: (entryPath: string) => boolean): string | undefined { + let result: string | undefined; + let folderPath: string = startFolderPath || process.cwd(); + while (folderPath) { + const possibleResult: string = joinPath(folderPath, entryName); + if (condition(possibleResult)) { + result = possibleResult; + break; + } else { + const parentFolderPath: string = getParentFolderPath(folderPath); + if (!parentFolderPath || folderPath === parentFolderPath) { + break; + } else { + folderPath = parentFolderPath; + } + } + } + return result; + } + + /** + * Find the closest file with the provided name by searching the immediate child folders of the + * folder at the provided startFolderPath. If no file is found with the provided fileName, then the + * search will move up to the parent folder of the startFolderPath. This will continue until either + * the file is found, or the folder being searched does not have a parent folder (if it is a root + * folder). + * @param fileName The name of the file to look for. + * @param startFolderPath The path to the folder where the search will begin. + * @returns The path to the closest file with the provided fileName, or undefined if no file could + * be found. + */ + export function findFileInPath(fileName: string | RegExp, startFolderPath?: string): Promise { + return findEntryInPath(fileName, startFolderPath, fileExists); + } + + /** + * Find the closest file with the provided name by searching the immediate child folders of the + * folder at the provided startFolderPath. If no file is found with the provided fileName, then the + * search will move up to the parent folder of the startFolderPath. This will continue until either + * the file is found, or the folder being searched does not have a parent folder (if it is a root + * folder). + * @param fileName The name of the file to look for. + * @param startFolderPath The path to the folder where the search will begin. + * @returns The path to the closest file with the provided fileName, or undefined if no file could + * be found. + */ + export function findFileInPathSync(fileName: string, startFolderPath?: string): string | undefined { + return findEntryInPathSync(fileName, startFolderPath, fileExistsSync); + } + + /** + * Find the closest folder with the provided name by searching the immediate child folders of the + * folder at the provided startFolderPath. If no folder is found with the provided folderName, then + * the search will move up to the parent folder of the startFolderPath. This will continue until + * either the folder is found, or the folder being searched does not have a parent folder (it is a + * root folder). + * @param folderName The name of the folder to look for. + * @param startFolderPath The path to the folder where the search will begin. + * @returns The path to the closest folder with the provided folderName, or undefined if no folder + * could be found. + */ + export function findFolderInPath(folderName: string | RegExp, startFolderPath?: string): Promise { + return findEntryInPath(folderName, startFolderPath, folderExists); + } + + /** + * Optional parameters to the getChildFilePaths() function. + */ + export interface GetChildEntriesOptions { + /** + * Whether or not to search sub-folders of the provided folderPath. + */ + recursive?: boolean | ((folderPath: string) => (boolean | Promise)); + + /** + * A condition that a child entry path must pass before it will be added to the result. + */ + condition?: (entryPath: string) => (boolean | Promise); + + /** + * A condition that a child file path must pass before it will be added to the result. + */ + fileCondition?: (filePath: string) => (boolean | Promise); + + /** + * A condition that a child folder path must pass before it will be added to the result. + */ + folderCondition?: (folderPath: string) => (boolean | Promise); + + /** + * The array where the matching child folder paths will be added. + */ + result?: string[]; + } + + /** + * Get the child entries of the folder at the provided folderPath. If the provided folder doesn't + * exist, then undefined will be returned. + * @param folderPath The path to the folder. + * @returns The paths to the child entries of the folder at the provided folder path, or undefined + * if the folder at the provided folder path doesn't exist. + */ + export function getChildEntryPaths(folderPath: string, options: GetChildEntriesOptions = {}): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.readdir(folderPath, async (error: NodeJS.ErrnoException | null, entryNames: string[]) => { + if (error) { + if (error.code === "ENOENT" || error.code === "ENOTDIR") { + resolve(undefined); + } else { + reject(error); + } + } else { + const result: string[] = options.result || []; + for (const entryName of entryNames) { + const entryPath: string = joinPath(folderPath, entryName); + try { + if (await fileExists(entryPath)) { + const addFile: boolean = + (!options.condition || await Promise.resolve(options.condition(entryPath))) && + (!options.fileCondition || await Promise.resolve(options.fileCondition(entryPath))); + if (addFile) { + result.push(entryPath); + } + } else if (await folderExists(entryPath)) { + const addFolder: boolean = + (!options.condition || await Promise.resolve(options.condition(entryPath))) && + (!options.folderCondition || await Promise.resolve(options.folderCondition(entryPath))); + if (addFolder) { + result.push(entryPath); + } + + if (options.recursive && (typeof options.recursive !== "function" || await Promise.resolve(options.recursive(entryPath)))) { + options.result = result; + await getChildEntryPaths(entryPath, options); + } + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + // If an error occurs while trying to get information about an entry, then just skip the + // entry. It's most likely a permissions problem, which means we shouldn't be dealing + // with that entry anyways. + } + } + resolve(result); + } + }); + }); + } + + /** + * Get the child folders of the folder at the provided folderPath. If the provided folder doesn't + * exist, then undefined will be returned. + * @param folderPath The path to the folder. + * @returns The paths to the child folders of the folder at the provided folder path, or undefined + * if the folder at the provided folder path doesn't exist. + */ + export async function getChildFolderPaths(folderPath: string, options: GetChildEntriesOptions = {}): Promise { + return getChildEntryPaths(folderPath, { + ...options, + fileCondition: () => false, + }); + } + + /** + * Get the child folders of the folder at the provided folderPath. If the provided folder doesn't + * exist, then undefined will be returned. + * @param folderPath The path to the folder. + * @returns The paths to the child folders of the folder at the provided folder path, or undefined + * if the folder at the provided folder path doesn't exist. + */ + export function getChildFilePaths(folderPath: string, options: GetChildEntriesOptions = {}): Promise { + return getChildEntryPaths(folderPath, { + ...options, + folderCondition: () => false, + }); + } + + /** + * Read the contents of the provided file. + * @param filePath The path to the file to read. + */ + export function readFileContents(filePath: string): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.readFile(filePath, { encoding: "utf8" }, (error: NodeJS.ErrnoException | null, content: string) => { + if (error) { + if (error.code === "ENOENT") { + resolve(undefined); + } else { + reject(error); + } + } else { + resolve(content); + } + }); + }); + } + + /** + * Write the provided contents to the file at the provided filePath. + * @param filePath The path to the file to write. + * @param contents The contents to write to the file. + */ + export function writeFileContents(filePath: string, contents: string): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.writeFile(filePath, contents, (error: NodeJS.ErrnoException | null) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + } + + export async function deleteEntry(path: string): Promise { + return await folderExists(path) + ? await deleteFolder(path) + : await deleteFile(path); + } + + /** + * Delete the file at the provided file path. + * @param {string} filePath The path to the file to delete. + */ + export function deleteFile(filePath: string): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.unlink(filePath, (error: NodeJS.ErrnoException | null) => { + if (error) { + if (error.code === "ENOENT") { + resolve(false); + } else { + reject(error); + } + } else { + resolve(true); + } + }); + }); + } + + /** + * Delete each of the provided file paths. + * @param filePaths The file paths that should be deleted. + */ + export async function deleteFiles(...filePaths: string[]): Promise { + if (filePaths && filePaths.length > 0) { + for (const filePath of filePaths) { + await deleteFile(filePath); + } + } + } + + function _deleteFolder(folderPath: string): Promise { + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-undef + fs.rmdir(folderPath, (error: NodeJS.ErrnoException | null) => { + if (error) { + if (error.code === "ENOENT") { + resolve(false); + } else { + reject(error); + } + } else { + resolve(true); + } + }); + }); + } + + /** + * Delete the folder at the provided folder path. + * @param {string} folderPath The path to the folder to delete. + */ + export async function deleteFolder(folderPath: string): Promise { + let result: boolean | Error; + try { + result = await _deleteFolder(folderPath); + } catch (deleteFolderError) { + if (deleteFolderError.code === "ENOENT") { + result = false; + } else if (deleteFolderError.code !== "ENOTEMPTY") { + result = deleteFolderError; + } else { + try { + const childEntryPaths: string[] = (await getChildEntryPaths(folderPath))!; + for (const childEntryPath of childEntryPaths) { + await deleteEntry(childEntryPath); + } + try { + result = await _deleteFolder(folderPath); + } catch (deleteFolderError2) { + result = deleteFolderError2; + } + } catch (deleteChildEntryError) { + result = deleteChildEntryError; + } + } + } + return typeof result === "boolean" + ? Promise.resolve(result) + : Promise.reject(result); + } diff --git a/tools/spec-gen-sdk/src/utils/githubUtils.ts b/tools/spec-gen-sdk/src/utils/githubUtils.ts index cb6359ff87c..61263265b48 100644 --- a/tools/spec-gen-sdk/src/utils/githubUtils.ts +++ b/tools/spec-gen-sdk/src/utils/githubUtils.ts @@ -1,10 +1,49 @@ -import { GitHub, getRepositoryFullName, first, GitHubPullRequest } from '@ts-common/azure-js-dev-tools'; -import { Logger } from '@azure/logger-js'; import { Octokit } from '@octokit/rest'; import { createAppAuth } from '@octokit/auth-app'; import * as winston from 'winston'; import { SdkAutoContext } from '../automation/entrypoint'; + +/** + * The name and optional organization that the repository belongs to. + */ +export interface Repository { + /** + * The entity that owns the repository. + */ + owner: string; + /** + * The name of the repository. + */ + name: string; +} + +/** + * Get a GitHubRepository object from the provided string or GitHubRepository object. + * @param repository The repository name or object. + */ +export function getRepository(repository: string | Repository): Repository { + let result: Repository; + if (!repository) { + result = { + name: repository, + owner: "" + }; + } else if (typeof repository === "string") { + let slashIndex: number = repository.indexOf("/"); + if (slashIndex === -1) { + slashIndex = repository.indexOf("\\"); + } + result = { + name: repository.substr(slashIndex + 1), + owner: slashIndex === -1 ? "" : repository.substr(0, slashIndex) + }; + } else { + result = repository; + } + return result; +} + /** * Label that can be added to a pull request */ @@ -41,113 +80,6 @@ export const pullRequestLabelsInfo = { export type PullRequestLabel = keyof typeof pullRequestLabelsInfo; -/** - * Ensure that the labels that can be added to an SDK repository's generation pull request exist in - * the provided SDK repository. - * @param github The GitHub client to use. - * @param sdkRepository The SDK repository to create labels in. - */ -export async function ensurePullRequestLabelsExist( - github: GitHub, - sdkRepository: string | RepoKey, - pRLabelsInfo: object, - logger: Logger -): Promise { - sdkRepository = getRepositoryFullName(sdkRepository); - await logger.logVerbose(`Getting labels from "${sdkRepository}"...`); - const sdkRepositoryLabels = await github.getLabels(sdkRepository); - - await Promise.all( - (Object.keys(pRLabelsInfo) as PullRequestLabel[]).map((labelName) => - (async () => { - const labelInfo: PullRequestLabelInfo = pRLabelsInfo[labelName]; - - await logger.logVerbose(`Looking for label named "${labelName}"...`); - const existingLabel = first(sdkRepositoryLabels, (l) => l.name === labelName); - - if (!existingLabel) { - await logger.logInfo(`Didn't find label ${labelName} in ${sdkRepository}. Creating it...`); - await github.createLabel(sdkRepository, labelName, labelInfo.color); - } else if (existingLabel.color !== labelInfo.color) { - await logger.logInfo(`Found label ${labelName}, but the color wasn't correct. Updating...`); - await github.updateLabelColor(sdkRepository, existingLabel.name, labelInfo.color); - } else { - await logger.logVerbose(`Found label ${labelName} and it had the correct color.`); - } - })() - ) - ); -} - -export async function updatePullRequestLabels( - github: GitHub, - sdkRepository: string | RepoKey, - pullRequest: GitHubPullRequest, - targetLabelNames: PullRequestLabel[], - logger: Logger -): Promise { - sdkRepository = getRepositoryFullName(sdkRepository); - - const currentLabelNames = pullRequest.labels - .filter((label) => pullRequestLabelsInfo[label.name as PullRequestLabel] !== undefined) - .map((label) => label.name as PullRequestLabel); - - const labelsToRemove = currentLabelNames.filter((labelName) => targetLabelNames.indexOf(labelName) === -1); - const labelsToAdd = targetLabelNames.filter((labelName) => currentLabelNames.indexOf(labelName) === -1); - - const labelStrs = labelsToAdd.map((label) => `+${label}`).concat(labelsToRemove.map((label) => `-${label}`)); - if (labelStrs.length === 0) { - await logger.logVerbose(`No label change for PR ${pullRequest.number} in ${sdkRepository}`); - return; - } - - await logger.logInfo(`Label changes for PR ${pullRequest.number} in ${sdkRepository}: ${labelStrs.join(', ')}`); - try { - await github.addPullRequestLabels(sdkRepository, pullRequest, labelsToAdd); - } catch (e) { - // Retry because maybe the label doesn't exist. - logger.logInfo(`Retry to add labels ${labelsToAdd} for PR ${pullRequest.number} in ${sdkRepository}. Error: ${e.message}`); - await ensurePullRequestLabelsExist(github, sdkRepository, pullRequestLabelsInfo, logger); - await github.addPullRequestLabels(sdkRepository, pullRequest, labelsToAdd); - } - await github.removePullRequestLabels(sdkRepository, pullRequest, labelsToRemove); -} - -export async function addPullRequestLabel( - github: GitHub, - sdkRepository: string | RepoKey, - pullRequest: GitHubPullRequest, - githubLabel: GithubLabel, - logger: Logger -): Promise { - sdkRepository = getRepositoryFullName(sdkRepository); - const labelExist = first(pullRequest.labels, (l) => l.name === githubLabel.name); - - if (!labelExist) { - const pullRequestLabelInfo = {}; - pullRequestLabelInfo[githubLabel.name] = { color: githubLabel.color }; - await ensurePullRequestLabelsExist(github, sdkRepository, pullRequestLabelInfo, logger); - await logger.logInfo(`Add Label ${githubLabel.name} for PR ${pullRequest.number} in ${sdkRepository}`); - await github.addPullRequestLabels(sdkRepository, pullRequest, githubLabel.name); - } -} - -/** - * @deprecated If possible, favor using `removePullRequestLabelOctokit` instead. - * Reason: this deprecated function uses GitHub from \@ts-common/azure-js-dev-tools - * instead of the newer Octokit. - */ -export async function removePullRequestLabel( - github: GitHub, - sdkRepository: string | RepoKey, - pullRequest: GitHubPullRequest, - githubLabel: GithubLabel, - logger: Logger -): Promise { - await logger.logInfo(`Try to remove Label ${githubLabel.name} for PR ${pullRequest.number} in ${sdkRepository}`); - await github.removePullRequestLabels(sdkRepository, pullRequest, githubLabel.name); -} - export interface RepoKey { /** * The entity that owns the repository. diff --git a/tools/spec-gen-sdk/src/utils/handleSuppressionLines.ts b/tools/spec-gen-sdk/src/utils/handleSuppressionLines.ts index e55413d3497..b0f52949a72 100644 --- a/tools/spec-gen-sdk/src/utils/handleSuppressionLines.ts +++ b/tools/spec-gen-sdk/src/utils/handleSuppressionLines.ts @@ -1,6 +1,6 @@ import { diffStringArrays } from './utils'; -import { SdkSuppressionsYml, SdkPackageSuppressionsEntry } from '@azure/swagger-validation-common'; +import { SdkSuppressionsYml, SdkPackageSuppressionsEntry } from '../types/sdkSuppressions'; import { WorkflowContext } from '../automation/workflow'; export type SDKSuppressionContentList = Map diff --git a/tools/spec-gen-sdk/src/utils/readme.ts b/tools/spec-gen-sdk/src/utils/readme.ts new file mode 100644 index 00000000000..6fe4cacb3f5 --- /dev/null +++ b/tools/spec-gen-sdk/src/utils/readme.ts @@ -0,0 +1,81 @@ +import * as commonmark from "commonmark"; +import * as jsYaml from "js-yaml"; + +/** + * The parsed version of the swagger-to-sdk YAML block within an AutoRest readme.md file. + */ +export interface ReadmeMdSwaggerToSDKConfiguration { + /** + * The repositories specified. + */ + repositories: RepositoryConfiguration[]; +} + +/** + * An individual repository configuration within an AutoRest readme.md swagger-to-sdk YAML block + * configuration. + */ +export interface RepositoryConfiguration { + /** + * The name of the GitHub repository this configuration applies to. If no organization is + * specified, then Azure will be used. + */ + repo: string; + /** + * The list of commands that will be run (in order) after an SDK has been generated. + */ + after_scripts: string[]; +} + +function findSwaggerToSDKYamlBlocks(parsedMarkdownNode: commonmark.Node | undefined | null): commonmark.Node[] { + const result: commonmark.Node[] = []; + if (parsedMarkdownNode) { + const nodesToVisit: commonmark.Node[] = [parsedMarkdownNode]; + while (nodesToVisit.length > 0) { + const node: commonmark.Node = nodesToVisit.shift()!; + + if (node.firstChild) { + nodesToVisit.push(node.firstChild); + } + if (node.next) { + nodesToVisit.push(node.next); + } + + if (node.type === "code_block" && node.info && node.info.toLowerCase().indexOf("$(swagger-to-sdk)") !== -1) { + result.push(node); + } + } + } + return result; +} + +/** + * Parse the contents of an AutoRest readme.md configuration file and return the parsed swagger to + * sdk configuration section. + * @param readmeMdFileContents The contents of an AutoRest readme.md configuration file. + */ +export function findSwaggerToSDKConfiguration(readmeMdFileContents: string | undefined): ReadmeMdSwaggerToSDKConfiguration | undefined { + let result: ReadmeMdSwaggerToSDKConfiguration | undefined; + if (readmeMdFileContents) { + const markdownParser = new commonmark.Parser(); + const parsedReadmeMd: commonmark.Node = markdownParser.parse(readmeMdFileContents); + const swaggerToSDKYamlBlocks: commonmark.Node[] = findSwaggerToSDKYamlBlocks(parsedReadmeMd); + const repositories: RepositoryConfiguration[] = []; + for (const swaggerToSDKYamlBlock of swaggerToSDKYamlBlocks) { + const yamlBlockContents: string | null = swaggerToSDKYamlBlock.literal; + if (yamlBlockContents) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const yaml: any = jsYaml.safeLoad(yamlBlockContents); + if (yaml) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const swaggerToSDK: any = yaml["swagger-to-sdk"]; + if (swaggerToSDK && Array.isArray(swaggerToSDK)) { + repositories.push(...swaggerToSDK); + } + } + } + } + result = { repositories }; + } + return result; +} diff --git a/tools/spec-gen-sdk/src/utils/reportFormat.ts b/tools/spec-gen-sdk/src/utils/reportFormat.ts index 45968e09327..e72ef8d6aab 100644 --- a/tools/spec-gen-sdk/src/utils/reportFormat.ts +++ b/tools/spec-gen-sdk/src/utils/reportFormat.ts @@ -2,6 +2,6 @@ export function formatSuppressionLine(suppressionLines: string[]): string[] { return suppressionLines .map(lineItem => lineItem.startsWith('+\t') ? lineItem.replace('+\t', '') : lineItem) - .map(newlineItem => newlineItem.includes('\n') ? `\"${newlineItem.replace(/\n/g, '\\n')}\"` : newlineItem) + .map(newlineItem => newlineItem.includes('\n') ? `"${newlineItem.replace(/\n/g, '\\n')}"` : newlineItem) .map(_newlineItem => `- ${_newlineItem}`) } diff --git a/tools/spec-gen-sdk/src/utils/resolveChangedTags.ts b/tools/spec-gen-sdk/src/utils/resolveChangedTags.ts deleted file mode 100644 index b32432250ab..00000000000 --- a/tools/spec-gen-sdk/src/utils/resolveChangedTags.ts +++ /dev/null @@ -1,26 +0,0 @@ -// import { AutoRestOptions } from '@ts-common/azure-js-dev-tools'; -// import { Configuration, MessageEmitter } from '@microsoft.azure/autorest-core/dist/lib/configuration'; -// import { RealFileSystem } from '@microsoft.azure/autorest-core/dist/lib/file-system'; - -export const resolveChangedTags = async ( -): Promise => { - throw new Error('tags-changed-in-batch is not supported yet.'); - - // Comment out for not supported yet - // const config = new Configuration(new RealFileSystem(), `file://${readmeMdFileUrl}`); - // const more = new Array<{}>(); - // for (const each of Object.keys(autorestOptions)) { - // if (autorestOptions[each] === '') { - // more.push({ 'try-require' : `readme.${each}.md` }); - // autorestOptions[each] = true; - // } - // } - - // const configView = await config.CreateView(new MessageEmitter(), true, autorestOptions, ...more); - // const batchConfig = configView.batch; - // if (!(batchConfig instanceof Array)) { - // throw new Error('"tags-changed-in-batch" was used but cannot find "batch" section in readme'); - // } - - // return batchConfig.map(configLine => configLine.tag as string); -}; diff --git a/tools/spec-gen-sdk/src/utils/runScript.ts b/tools/spec-gen-sdk/src/utils/runScript.ts index 2c9d74fad54..863a7e4541d 100644 --- a/tools/spec-gen-sdk/src/utils/runScript.ts +++ b/tools/spec-gen-sdk/src/utils/runScript.ts @@ -3,7 +3,7 @@ import { spawn } from 'child_process'; import { FailureType, setFailureType, WorkflowContext } from '../automation/workflow'; import { RunLogFilterOptions, RunLogOptions, RunOptions } from '../types/SwaggerToSdkConfig'; import { Readable } from 'stream'; -import { SDKAutomationState } from '../sdkAutomationState'; +import { SDKAutomationState } from '../automation/sdkAutomationState'; export type RunResult = Exclude; export type StatusContainer = { status: SDKAutomationState }; @@ -64,7 +64,7 @@ export const runSdkAutoCustomScript = async ( const scriptSplit = scriptPath.split(' '); args.unshift(...scriptSplit.splice(1)); - // tslint:disable: no-null-keyword + // eslint-disable-next-line no-undef let cmdRet: { code: number | null; signal: NodeJS.Signals | null } = { code: null, signal: null diff --git a/tools/spec-gen-sdk/src/utils/typespecUtils.ts b/tools/spec-gen-sdk/src/utils/typespecUtils.ts index 75bf15df78b..c56947a644a 100644 --- a/tools/spec-gen-sdk/src/utils/typespecUtils.ts +++ b/tools/spec-gen-sdk/src/utils/typespecUtils.ts @@ -3,7 +3,7 @@ import { SpecConfig } from '../types/SpecConfig'; import { join } from "path"; import { readFileSync } from 'fs'; import { WorkflowContext } from '../automation/workflow'; -import { parseYamlContent } from '@azure/swagger-validation-common'; +import { parseYamlContent } from './utils'; export const findSDKToGenerateFromTypeSpecProject = (content: string | undefined, specConfig: SpecConfig) => { if (!specConfig?.typespecEmitterToSdkRepositoryMapping || !content) { @@ -34,12 +34,12 @@ export const findSDKToGenerateFromTypeSpecProject = (content: string | undefined }; export function getTypeSpecProjectServiceName(outputFolder: string): string { - const match = outputFolder.match(/[^\/]*\/([^\/]*)\//); + const match = outputFolder.match(/[^/]*\/([^/]*)\//); return match ? match[1] : ''; } export function getTypeSpecProjectResourceProvider(typespecProject: string): string { - const match = typespecProject.match(/[^\/]*\/([^\/]*)\/(.*)/); + const match = typespecProject.match(/[^/]*\/([^/]*)\/(.*)/); return match ? match[2] : ''; } diff --git a/tools/spec-gen-sdk/src/utils/utils.ts b/tools/spec-gen-sdk/src/utils/utils.ts index d1f514706c5..3d787ce0fb7 100644 --- a/tools/spec-gen-sdk/src/utils/utils.ts +++ b/tools/spec-gen-sdk/src/utils/utils.ts @@ -1,94 +1,179 @@ +import { SequenceMatcher } from "difflib"; +import _ from "lodash"; +import * as YAML from "js-yaml"; +import { getTypeSpecOutputFolder } from "./typespecUtils"; +import { WorkflowContext } from "../automation/workflow"; -import { SequenceMatcher } from 'difflib'; -import _ from 'lodash'; -import { getTypeSpecOutputFolder } from './typespecUtils'; -import { WorkflowContext } from '../automation/workflow'; - -export function diffStringArrays(left: string[], right: string[]): { - diffResult: string[], - hasDiff: boolean +export function diffStringArrays( + left: string[], + right: string[] +): { + diffResult: string[]; + hasDiff: boolean; } { - left.sort(); - right.sort(); - // tslint:disable-next-line: no-null-keyword - const matcher = new SequenceMatcher(null, left, right); - const diffResult: string[] = []; - let hasDiff = false; - for (const [op, i0, i1, j0, j1] of matcher.getOpcodes()) { - if (op === 'equal') { - for (let x = i0; x < i1; ++x) { - diffResult.push(`\t${left[x]}`); - } - } else { - if (op === "replace" || op === "insert") { - hasDiff = true; - for (let x = j0; x < j1; ++x) { - diffResult.push(`+\t${right[x]}`); + left.sort(); + right.sort(); + // tslint:disable-next-line: no-null-keyword + const matcher = new SequenceMatcher(null, left, right); + const diffResult: string[] = []; + let hasDiff = false; + for (const [op, i0, i1, j0, j1] of matcher.getOpcodes()) { + if (op === "equal") { + for (let x = i0; x < i1; ++x) { + diffResult.push(`\t${left[x]}`); + } + } else { + if (op === "replace" || op === "insert") { + hasDiff = true; + for (let x = j0; x < j1; ++x) { + diffResult.push(`+\t${right[x]}`); + } + } } - } } - } - return { - diffResult, - hasDiff - }; + return { + diffResult, + hasDiff, + }; } -export function getValueByKey(arrayOfObjects: { [key: string]: T }[], targetKey: string): T | undefined { - const foundObject = _.find(arrayOfObjects, targetKey); - return foundObject ? foundObject[targetKey] : undefined; +export function getValueByKey( + arrayOfObjects: { [key: string]: T }[], + targetKey: string +): T | undefined { + const foundObject = _.find(arrayOfObjects, targetKey); + return foundObject ? foundObject[targetKey] : undefined; } -export function removeAnsiEscapeCodes(messages: string[] | string): string[] | string { - const ansiEscapeCodeRegex = /\x1b\[(\d{1,2}(;\d{0,2})*)?[A-HJKSTfimnsu]/g; - if (typeof messages === 'string') { - return messages.replace(ansiEscapeCodeRegex, ''); - } - return messages.map(item => item.replace(ansiEscapeCodeRegex, '')); +export function removeAnsiEscapeCodes( + messages: string[] | string +): string[] | string { + // eslint-disable-next-line no-control-regex + const ansiEscapeCodeRegex = /\x1b\[(\d{1,2}(;\d{0,2})*)?[A-HJKSTfimnsu]/g; + if (typeof messages === "string") { + return messages.replace(ansiEscapeCodeRegex, ""); + } + return messages.map((item) => item.replace(ansiEscapeCodeRegex, "")); } export function extractServiceName(path: string): string { - const match = path.match(/specification\/([^\/]*)\//); - return match ? match[1] : ''; + const match = path.match(/specification\/([^/]*)\//); + return match ? match[1] : ""; } // Flag of the readme.md under root of 'resource-manager' or 'data-plane' -const IsReadmeUnderRoot = /specification\/([^\/]*)\/([^\/]*)\/readme\.md/g; +const IsReadmeUnderRoot = /specification\/([^/]*)\/([^/]*)\/readme\.md/g; -export function removeDuplicatesFromRelatedFiles(relatedTypeSpecProjectFolder: string[] | undefined, relatedReadmeMdFiles: string[] | undefined, context: WorkflowContext): string[] { - const _relatedTypeSpecProjectFolder = relatedTypeSpecProjectFolder || []; - const _relatedReadmeMdFiles = relatedReadmeMdFiles || []; - const filteredReadmeMdFiles = _relatedReadmeMdFiles.filter(readmeFile => { - const readmeServiceName = extractServiceName(readmeFile); - const isResourceManager = readmeFile.includes('/resource-manager/'); - const isDataPlane = readmeFile.includes('/data-plane/'); - let typespecOutputFolderRegExp: RegExp; +export function removeDuplicatesFromRelatedFiles( + relatedTypeSpecProjectFolder: string[] | undefined, + relatedReadmeMdFiles: string[] | undefined, + context: WorkflowContext +): string[] { + const _relatedTypeSpecProjectFolder = relatedTypeSpecProjectFolder || []; + const _relatedReadmeMdFiles = relatedReadmeMdFiles || []; + const filteredReadmeMdFiles = _relatedReadmeMdFiles.filter((readmeFile) => { + const readmeServiceName = extractServiceName(readmeFile); + const isResourceManager = readmeFile.includes("/resource-manager/"); + const isDataPlane = readmeFile.includes("/data-plane/"); + let typespecOutputFolderRegExp: RegExp; - return !_relatedTypeSpecProjectFolder.some(typespecFile => { - const typespecServiceName = extractServiceName(typespecFile); - const isManagement = typespecFile.endsWith('.Management'); + return !_relatedTypeSpecProjectFolder.some((typespecFile) => { + const typespecServiceName = extractServiceName(typespecFile); + const isManagement = typespecFile.endsWith(".Management"); - if (readmeServiceName === typespecServiceName) { - if (isManagement && isResourceManager) { - context.logger.info(`Exclude the readmeFile from SDK generation: ${readmeFile} because it is duplicated with typespec: ${typespecFile}.`); - return true; - } + if (readmeServiceName === typespecServiceName) { + if (isManagement && isResourceManager) { + context.logger.info( + `Exclude the readmeFile from SDK generation: ${readmeFile} because it is duplicated with typespec: ${typespecFile}.` + ); + return true; + } - if (isDataPlane && IsReadmeUnderRoot.test(readmeFile)) { - context.logger.info(`Exclude the readmeFile from SDK generation: ${readmeFile} because it is under data-plane root and is duplicated with typespec: ${typespecFile}.`); - return true; - } + if (isDataPlane && IsReadmeUnderRoot.test(readmeFile)) { + context.logger.info( + `Exclude the readmeFile from SDK generation: ${readmeFile} because it is under data-plane root and is duplicated with typespec: ${typespecFile}.` + ); + return true; + } - const typespecOutputFolder = getTypeSpecOutputFolder(typespecFile, context); - typespecOutputFolderRegExp = typespecOutputFolderRegExp || new RegExp(typespecOutputFolder, 'ig'); - if (isDataPlane && typespecOutputFolderRegExp.test(readmeFile)) { - context.logger.info(`Exclude the readmeFile from SDK generation: ${readmeFile} because it is duplicated with typespec: ${typespecFile}, typespecOutputFolder: ${typespecOutputFolder}.`); - return true; - } - } - return false; + const typespecOutputFolder = getTypeSpecOutputFolder( + typespecFile, + context + ); + typespecOutputFolderRegExp = + typespecOutputFolderRegExp || + new RegExp(typespecOutputFolder, "ig"); + if ( + isDataPlane && + typespecOutputFolderRegExp.test(readmeFile) + ) { + context.logger.info( + `Exclude the readmeFile from SDK generation: ${readmeFile} because it is duplicated with typespec: ${typespecFile}, typespecOutputFolder: ${typespecOutputFolder}.` + ); + return true; + } + } + return false; + }); }); - }); - return filteredReadmeMdFiles; + return filteredReadmeMdFiles; +} + +/** + * @param yamlContent + * @returns {result: string | object | undefined | null, message: string} + * special return + * if the content is empty, return {result: null, message: string + * if the file parse error, return {result: undefined, message: string + */ +export function parseYamlContent( + yamlContent: string, + path: string +): { + result: string | object | undefined | null; + message: string; +} { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let content: any = undefined; + // if yaml file is not a valid yaml, catch error and return undefined + try { + content = YAML.safeLoad(yamlContent); + } catch (error) { + console.error( + `The file parsing failed in the ${path}. Details: ${error}` + ); + return { + result: content, + message: `The file parsing failed in the ${path}. Details: ${error}`, + }; + } + + // if yaml file is empty, run yaml.safeload success but get undefined + // to identify whether it is empty return null to distinguish. + if (!content) { + console.info( + `The file in the ${path} has been successfully parsed, but it is an empty file.` + ); + return { + result: null, + message: `The file in the ${path} has been successfully parsed, but it is an empty file.`, + }; + } + + return { + result: content, + message: "The file has been successfully parsed.", + }; +} + +/** + * Replace all of the instances of searchValue in value with the provided replaceValue. + * @param {string | undefined} value The value to search and replace in. + * @param {string} searchValue The value to search for in the value argument. + * @param {string} replaceValue The value to replace searchValue with in the value argument. + * @returns {string | undefined} The value where each instance of searchValue was replaced with replacedValue. + */ +export function replaceAll(value: string | undefined, searchValue: string, replaceValue: string): string | undefined { + return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || ""); } diff --git a/tools/spec-gen-sdk/test/dotnetTests.ts b/tools/spec-gen-sdk/test/dotnetTests.ts deleted file mode 100644 index e0c5e8f078e..00000000000 --- a/tools/spec-gen-sdk/test/dotnetTests.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { assert } from 'chai'; -import { getInstallationInstructions } from '../lib/langSpecs/dotnet'; - -describe('dotnet.ts', function() { - it('getInstallationInstructions()', function() { - const instructions: string[] = getInstallationInstructions({ - packageName: 'fake-package-name', - artifactUrls: ['fake-package-url'], - generationRepositoryUrl: 'fake-repository-url', - sdkRepositoryGenerationPullRequestHeadBranch: 'fake-sdk-pull-request-head-branch' - }); - assert.deepEqual(instructions, [ - '## Installation Instructions', - 'In order to use the [generated nuget package](fake-package-url) in your app, you will have to use it from a private feed.', - `To create a private feed, see the following link:`, - `[https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds)`, - `This will allow you to create a new local feed and add the location of the new feed as one of the sources.`, - '## Direct Download', - 'The generated package can be directly downloaded from here:', - '- [fake-package-name](fake-package-url)' - ]); - }); -}); diff --git a/tools/spec-gen-sdk/test/fakeBlobProxyTests.ts b/tools/spec-gen-sdk/test/fakeBlobProxyTests.ts deleted file mode 100644 index 3b3352e867f..00000000000 --- a/tools/spec-gen-sdk/test/fakeBlobProxyTests.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { BlobStorageBlob, BlobStoragePrefix, InMemoryBlobStorage } from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { FakeBlobProxy } from '../lib/fakeBlobProxy'; - -describe('fakeBlobProxy.ts', function() { - describe('FakeBlobProxy', function() { - describe('getProxyURL()', function() { - it('with blob with SAS URL', function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/?sig=fake-signature&sv=fake-version'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blob: BlobStorageBlob = blobPrefix.getBlob('path'); - const blobProxy = new FakeBlobProxy(); - const proxyUrl: string = blobProxy.getProxyURL(blobPrefix, blob); - assert.strictEqual(proxyUrl, 'https://fake.storage.com/container/path'); - }); - - it('with blob with non-SAS URL', function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blob: BlobStorageBlob = blobPrefix.getBlob('path'); - const blobProxy = new FakeBlobProxy(); - const proxyUrl: string = blobProxy.getProxyURL(blobPrefix, blob); - assert.strictEqual(proxyUrl, 'https://fake.storage.com/container/path'); - }); - }); - - describe('resolveProxyURL()', function() { - it('with undefined', async function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blobProxy = new FakeBlobProxy(); - const blobUrl: string | undefined = await blobProxy.resolveProxyURL(blobPrefix, undefined as any); - assert.strictEqual(blobUrl, undefined); - }); - - it(`with "blah"`, async function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blobProxy = new FakeBlobProxy(); - const blobUrl: string | undefined = await blobProxy.resolveProxyURL(blobPrefix, 'blah'); - assert.strictEqual(blobUrl, 'blah'); - }); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/goTests.ts b/tools/spec-gen-sdk/test/goTests.ts deleted file mode 100644 index ffed201bb9f..00000000000 --- a/tools/spec-gen-sdk/test/goTests.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { assert } from 'chai'; -import { getInstallationInstructions } from '../lib/langSpecs/go'; - -describe('go.ts', function() { - it('getInstallationInstructions()', function() { - const instructions: string[] = getInstallationInstructions({ - packageName: 'fake-package-name', - artifactUrls: ['fake-package-url'], - generationRepositoryUrl: 'fake-repository-url', - sdkRepositoryGenerationPullRequestHeadBranch: 'fake-sdk-pull-request-head-branch' - }); - assert.deepEqual(instructions, [ - '## Installation Instructions', - 'You can install the package `fake-package-name` of this PR by downloading the [package](fake-package-url) and extracting it to the root of your azure-sdk-for-go directory.', - '## Direct Download', - 'The generated package can be directly downloaded from here:', - '- [fake-package-name](fake-package-url)' - ]); - }); -}); diff --git a/tools/spec-gen-sdk/test/javaTests.ts b/tools/spec-gen-sdk/test/javaTests.ts deleted file mode 100644 index 9a9f28f8d0b..00000000000 --- a/tools/spec-gen-sdk/test/javaTests.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { assert } from 'chai'; -import { InstallationInstructionsOptions } from '../lib/langSpecs/installationInstructions'; -import { getInstallationInstructions } from '../lib/langSpecs/java'; - -describe('java.ts', function() { - describe('getInstallationInstructions()', function() { - it('with fake-package', function() { - const installationInstructionsOptions: InstallationInstructionsOptions = { - packageName: 'fake-package-name', - artifactUrls: ['fake/package/url'], - generationRepositoryUrl: 'fake/repository/url', - sdkRepositoryGenerationPullRequestHeadBranch: 'fake-sdk-pull-request-head-branch' - }; - assert.deepEqual(getInstallationInstructions(installationInstructionsOptions), [ - `## Installation Instructions`, - `You can install the package \`fake-package-name\` of this PR by downloading the artifact jar files. Then ensure that the jar files are on your project's classpath.`, - `## Direct Download`, - `The generated package artifacts can be directly downloaded from here:`, - `- [url](fake/package/url)` - ]); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/javascriptTests.ts b/tools/spec-gen-sdk/test/javascriptTests.ts deleted file mode 100644 index 85ee22088ae..00000000000 --- a/tools/spec-gen-sdk/test/javascriptTests.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { assert } from 'chai'; -import { getInstallationInstructions } from '../lib/langSpecs/javascript'; - -describe('javascript.ts', function() { - it('getInstallationInstructions()', function() { - const instructions: string[] = getInstallationInstructions({ - packageName: 'fake-package-name', - artifactUrls: ['fake/package/url'], - generationRepositoryUrl: 'fake-repository-url', - sdkRepositoryGenerationPullRequestHeadBranch: 'fake-sdk-pull-request-head-branch' - }); - assert.deepEqual(instructions, [ - '## Installation Instructions', - 'You can install the package `fake-package-name` of this PR using the following command:', - '```bash', - 'npm install fake/package/url', - '```', - '## Direct Download', - 'The generated package can be directly downloaded from here:', - '- [url](fake/package/url)' - ]); - }); -}); diff --git a/tools/spec-gen-sdk/test/packageCommandTests.ts b/tools/spec-gen-sdk/test/packageCommandTests.ts deleted file mode 100644 index a08a469dcc1..00000000000 --- a/tools/spec-gen-sdk/test/packageCommandTests.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger, Logger } from '@azure/logger-js'; -import { - assertEx, - BlobStorageAppendBlob, - BlobStorageBlob, - BlobStoragePrefix, - FakeCompressor, - FakeRunner, - InMemoryBlobStorage, - RealRunner, - ExecutableGit -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { csharp } from '../lib'; -import { createPackageCommandOptions, PackageCommand, runPackageCommands } from '../lib/langSpecs/packageCommand'; -import { PackageCommandOptions } from '../lib/packageCommandOptions'; -import { SDKRepository } from '../lib/sdkRepository'; -import { - SDKRepositoryPackage, - SDKRepositoryPackageContext, - SDKRepositoryPackageData -} from '../lib/langSpecs/sdkRepositoryPackage'; -import { createSDKRepository } from './repositoryCommandTests'; - -describe('packageCommand.ts', function() { - it('createPackageCommandOptions()', function() { - const sdkRepository: SDKRepository = createSDKRepository(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(); - - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - assertEx.defined(packageCommandOptions.captureError, 'packageCommandOptions.captureError'); - assertEx.defined(packageCommandOptions.captureOutput, 'packageCommandOptions.captureOutput'); - assert.strictEqual(packageCommandOptions.changedFilePaths, sdkRepositoryPackage.data.changedFilePaths); - assertEx.defined(packageCommandOptions.compressor, 'packageCommandOptions.compressor'); - assert.strictEqual(packageCommandOptions.environmentVariables, undefined); - assert.strictEqual(packageCommandOptions.executionFolderPath, sdkRepositoryPackage.getRootedPackageFolderPath()); - assertEx.defined(packageCommandOptions.log, 'packageCommandOptions.log'); - assert.strictEqual(packageCommandOptions.logger, sdkRepositoryPackage.logger); - assert.strictEqual(packageCommandOptions.packageData, sdkRepositoryPackage.data); - assert.strictEqual(packageCommandOptions.relativePackageFolderPath, sdkRepositoryPackage.data.relativeFolderPath); - assert.strictEqual(packageCommandOptions.repositoryData, sdkRepository.data); - assert.strictEqual(packageCommandOptions.repositoryFolderPath, sdkRepositoryPackage.repositoryFolderPath); - assert.strictEqual( - packageCommandOptions.rootedPackageFolderPath, - sdkRepositoryPackage.getRootedPackageFolderPath() - ); - assertEx.defined(packageCommandOptions.runner, 'packageCommandOptions.runner'); - assert.strictEqual(packageCommandOptions.showCommand, true); - assert.strictEqual(packageCommandOptions.showEnvironmentVariables, undefined); - assert.strictEqual(packageCommandOptions.showResult, true); - }); - - describe('runPackageCommands()', function() { - it('with one string command that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, 'dir', packageCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [`j/u: dir`, `Exit Code: 0`]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'inProgress'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command that returns 1', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 1, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, 'dir', packageCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [ - `j/u: dir`, - `Exit Code: 1`, - `Failed to create the package t.` - ]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'failed'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command that returns an error', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new RealRunner(); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, 'food', packageCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [ - `j/u: food`, - `Error: spawn food ENOENT`, - `Exit Code: undefined`, - `Failed to create the package t.`, - ` Error: spawn food ENOENT` - ]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'failed'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command array that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, ['dir'], packageCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [`j/u: dir`, `Exit Code: 0`]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'inProgress'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command array that returns 1', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 1, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, ['dir'], packageCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [ - `j/u: dir`, - `Exit Code: 1`, - `Failed to create the package t.` - ]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'failed'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with two string command array that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - runner.set({ executable: 'foo', result: { exitCode: 0, stdout: 'foo-stdout', stderr: 'foo-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - - const result: boolean = await runPackageCommands(sdkRepositoryPackage, ['dir', 'foo'], packageCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [`j/u: dir`, `Exit Code: 0`, `j/u: foo`, `Exit Code: 0`]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'inProgress'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one function command that throws an error', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepository: SDKRepository = createSDKRepository(undefined, sdkRepositoryLogger); - const sdkRepositoryPackageLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepositoryPackage: SDKRepositoryPackage = createSDKRepositoryPackage(sdkRepositoryPackageLogger); - const packageCommandOptions: PackageCommandOptions = createPackageCommandOptions( - sdkRepository, - sdkRepositoryPackage - ); - const command: PackageCommand = () => { - throw new Error('hello'); - }; - const result: boolean = await runPackageCommands(sdkRepositoryPackage, command, packageCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.deepEqual(sdkRepositoryPackageLogger.allLogs, [`Error: hello`]); - assert.strictEqual(sdkRepositoryPackage.data.status, 'failed'); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - }); -}); - -function createSDKRepositoryPackage(logger?: Logger): SDKRepositoryPackage { - const blobStorage = new InMemoryBlobStorage(); - const sdkRepositoryFolderPath = 'j'; - const sdkRepositoryPackageLogsBlob: BlobStorageAppendBlob = blobStorage.getAppendBlob('k'); - const sdkRepositoryPackageSpecPRIterationPrefix: BlobStoragePrefix = blobStorage.getPrefix('l'); - const sdkRepositoryPackageSpecPRPrefix: BlobStoragePrefix = blobStorage.getPrefix('l2'); - const sdkRepositoryPackageContext: SDKRepositoryPackageContext = { - createCompressor: () => new FakeCompressor(), - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL(), - git: new ExecutableGit(), - writeGenerationData: () => Promise.resolve() - }; - const sdkRepositoryPackageData: SDKRepositoryPackageData = { - changedFilePaths: [], - generationBranch: 'm', - generationRepository: 'n', - generationRepositoryUrl: 'o', - integrationBranch: 'p', - integrationRepository: 'q', - useIntegrationBranch: true, - logsBlobUrl: 'r', - mainRepository: 's', - name: 't', - relativeFolderPath: 'u', - status: 'inProgress' - }; - return new SDKRepositoryPackage( - sdkRepositoryFolderPath, - csharp, - sdkRepositoryPackageLogsBlob, - sdkRepositoryPackageSpecPRIterationPrefix, - sdkRepositoryPackageSpecPRPrefix, - logger || getInMemoryLogger(), - sdkRepositoryPackageContext, - sdkRepositoryPackageData - ); -} diff --git a/tools/spec-gen-sdk/test/pythonTests.ts b/tools/spec-gen-sdk/test/pythonTests.ts deleted file mode 100644 index 2415af9af5b..00000000000 --- a/tools/spec-gen-sdk/test/pythonTests.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { assert } from 'chai'; -import { InstallationInstructionsOptions } from '../lib/langSpecs/installationInstructions'; -import { getInstallationInstructions, getPackageName } from '../lib/langSpecs/python'; - -describe('python.ts', function() { - it('getPackageName()', function() { - assert.strictEqual(getPackageName('/1/1/', 'sdk/network/azure-mgmt-dns'), 'azure-mgmt-dns'); - }); - - describe('getInstallationInstructions()', function() { - it('with azure-graphrbac', function() { - const expectedInstallationInstructions: string[] = [ - '(message created by the CI based on PR content)', - '# Installation instruction', - '## Package azure-graphrbac', - 'You can install the package `azure-graphrbac` of this PR using the following command:', - '\t`pip install "git+https://github.com/Azure/azure-sdk-for-python@restapi_auto_graphrbac/data-plane#egg=azure-graphrbac&subdirectory=azure-graphrbac"`', - '', - 'You can build a wheel to distribute for test using the following command:', - '\t`pip wheel --no-deps "git+https://github.com/Azure/azure-sdk-for-python@restapi_auto_graphrbac/data-plane#egg=azure-graphrbac&subdirectory=azure-graphrbac"`', - '', - 'If you have a local clone of this repository, you can also do:', - '', - '- `git checkout restapi_auto_graphrbac/data-plane`', - '- `pip install -e ./azure-graphrbac`', - '', - '', - 'Or build a wheel file to distribute for testing:', - '', - '- `git checkout restapi_auto_graphrbac/data-plane`', - '- `pip wheel --no-deps ./azure-graphrbac`', - '', - '', - '# Direct download', - '', - 'Your files can be directly downloaded here:', - '', - '- [azure_graphrbac-0.52.0-py2.py3-none-any.whl](http://azuresdkinfrajobstore1.blob.core.windows.net/azure/azure-sdk-for-python/pullrequests/4574/dist/azure_graphrbac-0.52.0-py2.py3-none-any.whl)', - '' - ]; - const options: InstallationInstructionsOptions = { - packageName: 'azure-graphrbac', - artifactUrls: [ - 'http://azuresdkinfrajobstore1.blob.core.windows.net/azure/azure-sdk-for-python/pullrequests/4574/dist/azure_graphrbac-0.52.0-py2.py3-none-any.whl' - ], - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-python', - sdkRepositoryGenerationPullRequestHeadBranch: 'restapi_auto_graphrbac/data-plane' - }; - assert.deepEqual(getInstallationInstructions(options), expectedInstallationInstructions); - }); - - it('with azure-mgmt-alertsmanagement', function() { - const expectedInstallationInstructions: string[] = [ - '(message created by the CI based on PR content)', - '# Installation instruction', - '## Package azure-mgmt-alertsmanagement', - 'You can install the package `azure-mgmt-alertsmanagement` of this PR using the following command:', - '\t`pip install "git+https://github.com/Azure/azure-sdk-for-python@restapi_auto_5384#egg=azure-mgmt-alertsmanagement&subdirectory=azure-mgmt-alertsmanagement"`', - '', - 'You can build a wheel to distribute for test using the following command:', - '\t`pip wheel --no-deps "git+https://github.com/Azure/azure-sdk-for-python@restapi_auto_5384#egg=azure-mgmt-alertsmanagement&subdirectory=azure-mgmt-alertsmanagement"`', - '', - 'If you have a local clone of this repository, you can also do:', - '', - '- `git checkout restapi_auto_5384`', - '- `pip install -e ./azure-mgmt-alertsmanagement`', - '', - '', - 'Or build a wheel file to distribute for testing:', - '', - '- `git checkout restapi_auto_5384`', - '- `pip wheel --no-deps ./azure-mgmt-alertsmanagement`', - '', - '', - '# Direct download', - '', - 'Your files can be directly downloaded here:', - '', - '- [azure_mgmt_alertsmanagement-2018_05_05-py2.py3-none-any.whl](http://azuresdkinfrajobstore1.blob.core.windows.net/azure/azure-sdk-for-python/pullrequests/4572/dist/azure_mgmt_alertsmanagement-2018_05_05-py2.py3-none-any.whl)', - '' - ]; - const options: InstallationInstructionsOptions = { - packageName: 'azure-mgmt-alertsmanagement', - artifactUrls: [ - 'http://azuresdkinfrajobstore1.blob.core.windows.net/azure/azure-sdk-for-python/pullrequests/4572/dist/azure_mgmt_alertsmanagement-2018_05_05-py2.py3-none-any.whl' - ], - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-python', - sdkRepositoryGenerationPullRequestHeadBranch: 'restapi_auto_5384' - }; - assert.deepEqual(getInstallationInstructions(options), expectedInstallationInstructions); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/realBlobProxyTests.ts b/tools/spec-gen-sdk/test/realBlobProxyTests.ts deleted file mode 100644 index 3ecde64abe2..00000000000 --- a/tools/spec-gen-sdk/test/realBlobProxyTests.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { - BlobStorageBlob, - BlobStoragePrefix, - InMemoryBlobStorage, - BlobStorageContainer, - assertEx, - URLBuilder -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { RealBlobProxy } from '../lib/realBlobProxy'; -import { SharedKeyCredential } from '@azure/storage-blob'; - -describe('realBlobProxy.ts', function() { - describe('RealBlobProxy', function() { - describe('getProxyURL()', function() { - it('with blob with SAS URL', function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/?sig=fake-signature&sv=fake-version'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blob: BlobStorageBlob = blobPrefix.getBlob('path'); - const blobProxy = new RealBlobProxy('foo://kebab.com/prefix/'); - const proxyUrl: string = blobProxy.getProxyURL(blobPrefix, blob); - assert.strictEqual(proxyUrl, 'foo://kebab.com/prefix/path'); - }); - - it('with blob with non-SAS URL', function() { - const blobStorage = new InMemoryBlobStorage('https://fake.storage.com/'); - const blobPrefix: BlobStoragePrefix = blobStorage.getPrefix('container/'); - const blob: BlobStorageBlob = blobPrefix.getBlob('path'); - const blobProxy = new RealBlobProxy('foo://kebab.com/prefix/'); - const proxyUrl: string = blobProxy.getProxyURL(blobPrefix, blob); - assert.strictEqual(proxyUrl, 'foo://kebab.com/prefix/path'); - }); - }); - - describe('resolveProxyURL()', function() { - it('with undefined', async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake', 'fake-account-key') - ); - const blobContainer: BlobStorageContainer = blobStorage.getContainer('container'); - await blobContainer.create(); - const blobProxy = new RealBlobProxy('foo://kebab.com/prefix/'); - const blobUrl: string | undefined = await blobProxy.resolveProxyURL(blobContainer, undefined as any); - assert.strictEqual(blobUrl, undefined); - }); - - it(`with "blah"`, async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake', 'fake-account-key') - ); - const blobContainer: BlobStorageContainer = blobStorage.getContainer('container'); - await blobContainer.create(); - const blobProxy = new RealBlobProxy('foo://kebab.com/prefix/'); - const blobUrl: string | undefined = await blobProxy.resolveProxyURL(blobContainer, 'blah'); - assert.strictEqual(blobUrl, undefined); - }); - - it(`with "foo://kebab.com/prefix/container/blob"`, async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake', 'fake-account-key') - ); - const blobContainer: BlobStorageContainer = blobStorage.getContainer('container'); - await blobContainer.create(); - const blobProxy = new RealBlobProxy('foo://kebab.com/prefix/'); - const blobUrl: string = (await blobProxy.resolveProxyURL(blobContainer, 'foo://kebab.com/prefix/blob'))!; - assertEx.definedAndNotEmpty(blobUrl, 'blobUrl'); - const blobUrlBuilder: URLBuilder = URLBuilder.parse(blobUrl); - assert.strictEqual(blobUrlBuilder.getScheme(), 'https'); - assert.strictEqual(blobUrlBuilder.getHost(), 'fake.storage.com'); - assert.strictEqual(blobUrlBuilder.getPort(), undefined); - assert.strictEqual(blobUrlBuilder.getPath(), '/container/blob'); - assertEx.definedAndNotEmpty(blobUrlBuilder.getQuery()); - }); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/repositoryCommandTests.ts b/tools/spec-gen-sdk/test/repositoryCommandTests.ts deleted file mode 100644 index 15fa5de7611..00000000000 --- a/tools/spec-gen-sdk/test/repositoryCommandTests.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger, Logger } from '@azure/logger-js'; -import { - assertEx, - BlobStorageAppendBlob, - BlobStorageBlob, - BlobStoragePrefix, - FakeCompressor, - FakeGitHub, - FakeHttpClient, - FakeRunner, - InMemoryBlobStorage, - RealRunner, - Runner, - ExecutableGit -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { dotnet } from '../lib/langSpecs/dotnet'; -import { LanguageConfiguration } from '../lib/langSpecs/languageConfiguration'; -import { - createRepositoryCommandOptions, - RepositoryCommand, - runRepositoryCommands -} from '../lib/langSpecs/repositoryCommand'; -import { RepositoryCommandOptions } from '../lib/repositoryCommandOptions'; -import { getBlobLogger } from '../lib/sdkAutomation'; -import { SDKRepository, SDKRepositoryContext, SDKRepositoryData } from '../lib/sdkRepository'; -import { SwaggerToSDKConfiguration } from '../lib/swaggerToSDKConfiguration'; - -describe('repositoryCommand.ts', function() { - it('createRepositoryCommandOptions()', function() { - const sdkRepository: SDKRepository = createSDKRepository(); - const repositoryFolderPath = 'a'; - - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - assertEx.defined(repositoryCommandOptions.captureError, 'repositoryCommandOptions.captureError'); - assertEx.defined(repositoryCommandOptions.captureOutput, 'repositoryCommandOptions.captureOutput'); - assertEx.defined(repositoryCommandOptions.compressor, 'repositoryCommandOptions.compressor'); - assert.strictEqual(repositoryCommandOptions.environmentVariables, undefined); - assert.strictEqual(repositoryCommandOptions.executionFolderPath, repositoryFolderPath); - assertEx.defined(repositoryCommandOptions.log, 'repositoryCommandOptions.log'); - assert.strictEqual(repositoryCommandOptions.logger, sdkRepository.logger); - assert.strictEqual(repositoryCommandOptions.repositoryData, sdkRepository.data); - assert.strictEqual(repositoryCommandOptions.repositoryFolderPath, repositoryFolderPath); - assertEx.defined(repositoryCommandOptions.runner, 'repositoryCommandOptions.runner'); - assert.strictEqual(repositoryCommandOptions.showCommand, true); - assert.strictEqual(repositoryCommandOptions.showEnvironmentVariables, undefined); - assert.strictEqual(repositoryCommandOptions.showResult, true); - }); - - describe('runRepositoryCommands()', function() { - it('with one string command that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, 'dir', repositoryCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, [`${repositoryFolderPath}: dir`, `Exit Code: 0`]); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command that returns 1', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 1, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, 'dir', repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, [ - `${repositoryFolderPath}: dir`, - `Exit Code: 1`, - `Failed to run the command for ${sdkRepository.data.mainRepository}.` - ]); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - - it('with one string command that returns an error', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new RealRunner(); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, 'food', repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, [ - `${repositoryFolderPath}: food`, - `Error: spawn food ENOENT`, - `Exit Code: undefined`, - `Failed to run the command for ${sdkRepository.data.mainRepository}.`, - ` Error: spawn food ENOENT` - ]); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - - it('with one string command array that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, ['dir'], repositoryCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, [`${repositoryFolderPath}: dir`, `Exit Code: 0`]); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one string command array that returns 1', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 1, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, ['dir'], repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, [ - `${repositoryFolderPath}: dir`, - `Exit Code: 1`, - `Failed to run the command for ${sdkRepository.data.mainRepository}.` - ]); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - - it('with one string command array that returns an error', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new RealRunner(); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, ['food'], repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, [ - `${repositoryFolderPath}: food`, - `Error: spawn food ENOENT`, - `Exit Code: undefined`, - `Failed to run the command for ${sdkRepository.data.mainRepository}.`, - ` Error: spawn food ENOENT` - ]); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - - it('with two string command array that returns 0', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const runner = new FakeRunner(); - runner.set({ executable: 'dir', result: { exitCode: 0, stdout: 'dir-stdout', stderr: 'dir-stderr' } }); - runner.set({ executable: 'foo', result: { exitCode: 0, stdout: 'foo-stdout', stderr: 'foo-stderr' } }); - const sdkRepository: SDKRepository = createSDKRepository(runner, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - - const result: boolean = await runRepositoryCommands(sdkRepository, ['dir', 'foo'], repositoryCommandOptions); - - assert.strictEqual(result, true); - assert.deepEqual(sdkRepositoryLogger.allLogs, [ - `${repositoryFolderPath}: dir`, - `Exit Code: 0`, - `${repositoryFolderPath}: foo`, - `Exit Code: 0` - ]); - assert.strictEqual(sdkRepository.data.status, 'inProgress'); - }); - - it('with one function command that throws an error', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepository: SDKRepository = createSDKRepository(undefined, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - const command: RepositoryCommand = () => { - throw new Error('hello'); - }; - - const result: boolean = await runRepositoryCommands(sdkRepository, command, repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, [`Error: hello`]); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - - it('with one function marks the repository as failed', async function() { - const sdkRepositoryLogger: InMemoryLogger = getInMemoryLogger(); - const sdkRepository: SDKRepository = createSDKRepository(undefined, sdkRepositoryLogger); - const repositoryFolderPath = 'a'; - const repositoryCommandOptions: RepositoryCommandOptions = createRepositoryCommandOptions( - sdkRepository, - repositoryFolderPath - ); - const command: RepositoryCommand = (options: RepositoryCommandOptions) => { - options.repositoryData.status = 'failed'; - }; - - const result: boolean = await runRepositoryCommands(sdkRepository, command, repositoryCommandOptions); - - assert.strictEqual(result, false); - assert.deepEqual(sdkRepositoryLogger.allLogs, []); - assert.strictEqual(sdkRepository.data.status, 'failed'); - }); - }); -}); - -export function createSDKRepository(runner?: Runner, logger?: Logger): SDKRepository { - const blobStorage = new InMemoryBlobStorage(); - const sdkRepositoryLogsBlob: BlobStorageAppendBlob = blobStorage.getAppendBlob('a'); - const language: LanguageConfiguration = dotnet; - const swaggerToSDKConfiguration: SwaggerToSDKConfiguration = {}; - const sdkRepositorySpecPRIterationPrefix: BlobStoragePrefix = blobStorage.getPrefix('b'); - const sdkRepositorySpecPRPrefix: BlobStoragePrefix = blobStorage.getPrefix('b'); - const sdkRepositoryContext: SDKRepositoryContext = { - createCompressor: () => new FakeCompressor(), - deleteClonedRepositories: false, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL(), - github: new FakeGitHub(), - git: new ExecutableGit(), - httpClient: new FakeHttpClient(), - runner: runner || new FakeRunner(), - writeGenerationData: () => Promise.resolve(), - getBlobLogger, - createGenerationPullRequests: true, - specificationPullRequest: { - baseRepository: 'spec-pr-base-repository', - headCommit: 'spec-pr-head-commit', - headRepository: 'spec-pr-head-repository', - htmlUrl: 'spec-pr-html-url', - number: 7, - title: 'spec-pr-title' - } - }; - const sdkRepositoryData: SDKRepositoryData = { - generationRepository: 'c', - generationRepositoryUrl: 'd', - integrationRepository: 'e', - integrationRepositoryUrl: 'f', - mainRepository: 'g', - mainRepositoryUrl: 'h', - integrationBranchPrefix: 'sdkAutomationTest', - mainBranch: 'master', - languageName: language.name, - readmeMdFileUrlsToGenerate: [], - status: 'inProgress', - swaggerToSDKConfigFileUrl: 'i' - }; - return new SDKRepository( - sdkRepositoryLogsBlob, - logger || getInMemoryLogger(), - dotnet, - swaggerToSDKConfiguration, - sdkRepositorySpecPRIterationPrefix, - sdkRepositorySpecPRPrefix, - sdkRepositoryContext, - sdkRepositoryData - ); -} diff --git a/tools/spec-gen-sdk/test/rubyTests.ts b/tools/spec-gen-sdk/test/rubyTests.ts deleted file mode 100644 index 0e3b6d0dabe..00000000000 --- a/tools/spec-gen-sdk/test/rubyTests.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { assert } from 'chai'; -import { getPackageNameToGenerate, getInstallationInstructions } from '../lib/langSpecs/ruby'; -import { InstallationInstructionsOptions } from '../lib/langSpecs/installationInstructions'; - -describe('ruby.ts', function() { - it('getPackageNameToGenerate()', function() { - const readmeRubyMdFileContents = `## Ruby - -These settings apply only when \`--ruby\` is specified on the command line. - -\`\`\`yaml -package-name: azure_mgmt_customproviders -package-version: 2018-09-01-preview -azure-arm: true -\`\`\` - -### Tag: package-2018-09-01-preview and ruby - -These settings apply only when \`--tag=package-2018-09-01-preview --ruby\` is specified on the command line. -Please also specify \`--ruby-sdks-folder=\`. - -\`\`\`yaml $(tag) == 'package-2018-09-01-preview' && $(ruby) -namespace: Microsoft.CustomProviders -output-folder: $(ruby-sdks-folder)/customproviders -\`\`\``; - assert.strictEqual(getPackageNameToGenerate(readmeRubyMdFileContents), 'customproviders'); - }); - - it('getInstallationInstructions()', function() { - const options: InstallationInstructionsOptions = { - artifactUrls: [ - 'https://openapistoragetest.blob.core.windows.net/sdkautomation/test/test-repo-billy/azure-rest-api-specs/113/28/test-repo-billy/azure-sdk-for-ruby/azure_sdk/azure_sdk-0.25.0.gem' - ], - generationRepositoryUrl: 'fake-generation-repository-url', - packageName: 'fake-package-name', - sdkRepositoryGenerationPullRequestHeadBranch: 'fake-head-branch' - }; - assert.deepEqual(getInstallationInstructions(options), [ - `## Installation Instructions`, - `The Gem file for \`azure_sdk\` can be downloaded [here](https://openapistoragetest.blob.core.windows.net/sdkautomation/test/test-repo-billy/azure-rest-api-specs/113/28/test-repo-billy/azure-sdk-for-ruby/azure_sdk/azure_sdk-0.25.0.gem).`, - `After downloading the gem file, you can add it to your Ruby project by running the following command:`, - `\`\`\`gem 'azure_sdk', '0.25.0', '/azure_sdk-0.25.0.gem'\`\`\``, - `## Direct Download`, - `The generated gem can be directly downloaded from here:`, - `- [azure_sdk-0.25.0.gem](https://openapistoragetest.blob.core.windows.net/sdkautomation/test/test-repo-billy/azure-rest-api-specs/113/28/test-repo-billy/azure-sdk-for-ruby/azure_sdk/azure_sdk-0.25.0.gem)` - ]); - }); -}); diff --git a/tools/spec-gen-sdk/test/sdkAutomationTests.ts b/tools/spec-gen-sdk/test/sdkAutomationTests.ts deleted file mode 100644 index ad1a7349a00..00000000000 --- a/tools/spec-gen-sdk/test/sdkAutomationTests.ts +++ /dev/null @@ -1,703 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { SharedKeyCredential } from '@azure/storage-blob'; -import { - assertEx, - BlobStorageContainer, - BlobStoragePrefix, - deleteFolder, - FakeGitHub, - FakeHttpClient, - folderExists, - getRootPath, - GitHub, - InMemoryBlobStorage, - joinPath, - NodeHttpClient, - URLBuilder -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { SpecificationPREvent } from '../lib'; -import { go } from '../lib/langSpecs/go'; -import { java } from '../lib/langSpecs/java'; -import { javascript } from '../lib/langSpecs/javascript'; -import { RealBlobProxy } from '../lib/realBlobProxy'; -import { - getAllLanguages, - getAutomationWorkingFolderPath, - getGenerationWorkingFolderPath, - getGitHub, - getRootFolderPath, - getSupportedLanguages, - SDKAutomation, - trimNewLine -} from '../lib/sdkAutomation'; -import { createTestBlobStorageContainer, testSpecificationPullRequest } from './test'; - -describe('sdkAutomation.ts', function() { - describe('SDKAutomation', function() { - describe('constructor()', function() { - it('with no options', function() { - const sdkAutomation = new SDKAutomation('fake-automation-working-folder-path'); - assert.strictEqual(sdkAutomation.automationWorkingFolderPath, 'fake-automation-working-folder-path'); - assertEx.defined(sdkAutomation.compressorCreator, 'sdkAutomation.compressorCreator'); - assert.strictEqual(sdkAutomation.deleteClonedRepositories, true); - assert(sdkAutomation.github instanceof FakeGitHub, 'sdkAutomation.github instanceof FakeGitHub'); - assert( - sdkAutomation.httpClient instanceof NodeHttpClient, - 'sdkAutomation.httpClient instanceof NodeHttpClient' - ); - assert.strictEqual(sdkAutomation.logger, undefined); - assert.strictEqual(sdkAutomation.runner, undefined); - assert.deepEqual(sdkAutomation.supportedLanguageConfigurations, getAllLanguages()); - }); - }); - - describe('resolveBlobProxyUrl()', function() { - it('with workingPrefix with non-existing container', async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake-account-name', 'fake-account-key') - ); - const workingPrefix: BlobStoragePrefix = blobStorage.getPrefix('privatecontainer/prefix/'); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - blobProxy: new RealBlobProxy('https://kebab.com/sdkAutomation/') - }); - const sasUrl: string = (await sdkAutomation.resolveBlobProxyUrl( - workingPrefix, - 'https://kebab.com/sdkAutomation/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz' - ))!; - assertEx.definedAndNotEmpty(sasUrl, 'sasUrl'); - const sasUrlBuilder: URLBuilder = URLBuilder.parse(sasUrl); - assert.strictEqual(sasUrlBuilder.getScheme(), 'https'); - assert.strictEqual(sasUrlBuilder.getHost(), 'fake.storage.com'); - assert.strictEqual(sasUrlBuilder.getPort(), undefined); - assert.strictEqual( - sasUrlBuilder.getPath(), - '/privatecontainer/prefix/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz' - ); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('se') as string, 'se'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sp'), 'r'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sr'), 'b'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sig') as string, 'sig'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('st') as string, 'st'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sv') as string, 'sv'); - }); - - it('with workingPrefix with non-existing blob', async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake-account-name', 'fake-account-key') - ); - const container: BlobStorageContainer = blobStorage.getContainer('privatecontainer'); - await container.create(); - const workingPrefix: BlobStoragePrefix = container.getPrefix('prefix/'); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - blobProxy: new RealBlobProxy('https://kebab.com/sdkAutomation/') - }); - const sasUrl: string = (await sdkAutomation.resolveBlobProxyUrl( - workingPrefix, - 'https://kebab.com/sdkAutomation/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz' - ))!; - assertEx.definedAndNotEmpty(sasUrl, 'sasUrl'); - const sasUrlBuilder: URLBuilder = URLBuilder.parse(sasUrl); - assert.strictEqual(sasUrlBuilder.getScheme(), 'https'); - assert.strictEqual(sasUrlBuilder.getHost(), 'fake.storage.com'); - assert.strictEqual(sasUrlBuilder.getPort(), undefined); - assert.strictEqual( - sasUrlBuilder.getPath(), - '/privatecontainer/prefix/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz' - ); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('se') as string, 'se'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sp'), 'r'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sr'), 'b'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sig') as string, 'sig'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('st') as string, 'st'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sv') as string, 'sv'); - }); - - it('with workingPrefix with existing blob', async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake-account-name', 'fake-account-key') - ); - const container: BlobStorageContainer = blobStorage.getContainer('privatecontainer'); - await container.create(); - const workingPrefix: BlobStoragePrefix = container.getPrefix('prefix/'); - const blobRelativePath = - 'Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz'; - await workingPrefix.createBlockBlob(blobRelativePath); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - blobProxy: new RealBlobProxy('https://kebab.com/sdkAutomation/') - }); - const sasUrl: string = (await sdkAutomation.resolveBlobProxyUrl( - workingPrefix, - `https://kebab.com/sdkAutomation/${blobRelativePath}` - ))!; - assertEx.definedAndNotEmpty(sasUrl, 'sasUrl'); - const sasUrlBuilder: URLBuilder = URLBuilder.parse(sasUrl); - assert.strictEqual(sasUrlBuilder.getScheme(), 'https'); - assert.strictEqual(sasUrlBuilder.getHost(), 'fake.storage.com'); - assert.strictEqual(sasUrlBuilder.getPort(), undefined); - assert.strictEqual( - sasUrlBuilder.getPath(), - '/privatecontainer/prefix/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz' - ); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('se') as string, 'se'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sp'), 'r'); - assert.strictEqual(sasUrlBuilder.getQueryParameterValue('sr'), 'b'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sig') as string, 'sig'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('st') as string, 'st'); - assertEx.definedAndNotEmpty(sasUrlBuilder.getQueryParameterValue('sv') as string, 'sv'); - }); - - it('with proxyBlobUrl with incorrect path format', async function() { - const blobStorage = new InMemoryBlobStorage( - 'https://fake.storage.com/', - new SharedKeyCredential('fake-account-name', 'fake-account-key') - ); - const container: BlobStorageContainer = blobStorage.getContainer('privatecontainer'); - await container.create(); - const workingPrefix: BlobStoragePrefix = container.getPrefix('prefix/'); - const blobRelativePath = - 'Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-node/azure-arm-mysql/azure-arm-mysql-3.2.0.tgz'; - await workingPrefix.createBlockBlob(blobRelativePath); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - blobProxy: new RealBlobProxy('https://kebab.com/sdkAutomation/') - }); - const sasUrl: string | undefined = await sdkAutomation.resolveBlobProxyUrl( - workingPrefix, - `https://kebab.com/blah/${blobRelativePath}` - ); - assert.strictEqual(sasUrl, undefined); - }); - }); - - describe('handleEvent()', function() { - it('with undefined event', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger - }); - let value = 0; - const result: number | undefined = await sdkAutomation.handleEvent(undefined, () => { - ++value; - return value + 5; - }); - assertEx.containsAll(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `No HttpClient provided. Using NodeHttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Processing pull request event because the event is undefined.`, - `Using FakeGitHub client.` - ]); - assert.strictEqual(value, 1); - assert.strictEqual(result, 6); - }); - - it('with non-GitHub repository pull request url', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger - }); - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: { - ...testSpecificationPullRequest, - html_url: 'https://not.a.github/repository/pull/request/url' - } - } - }; - let value = 0; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assert.deepEqual(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `No HttpClient provided. Using NodeHttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Failed to get the pull request repository from the pull request url (https://not.a.github/repository/pull/request/url).` - ]); - assert.strictEqual(value, 0); - assert.strictEqual(result, undefined); - }); - - it('with no specificationRepositoryConfiguration.json file and PR base branch is master', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: testSpecificationPullRequest - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assertEx.containsAll(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 404`, - `Could not find a specificationRepositoryConfiguration.json. Ignoring event.` - ]); - assert.strictEqual(value, 0); - assert.strictEqual(result, undefined); - }); - - it('with no specificationRepositoryConfiguration.json file and PR base branch is not master', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: { - ...testSpecificationPullRequest, - base: { - label: 'fake-label', - ref: 'fake-ref', - sha: 'fake-sha' - } - } - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assert.deepEqual(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/fake-ref/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 404`, - `Could not find a specificationRepositoryConfiguration.json. Ignoring event.` - ]); - assert.strictEqual(value, 0); - assert.strictEqual(result, undefined); - }); - - it('with no sdkAutomationBaseBranch property and PR base branch is master', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({}) - ); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: testSpecificationPullRequest - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assertEx.containsAll(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `No sdkAutomationBaseBranch property specified in the specificationRepositoryConfiguration.json. Defaulting sdkAutomationBaseBranch to "master".`, - `Processing pull request event because the pull request base branch (master) is equal to the sdkAutomationBaseBranch (master).`, - `Updating logger...`, - `Using FakeGitHub client.` - ]); - assert.strictEqual(value, 1); - assert.strictEqual(result, 6); - }); - - it('with sdkAutomationBaseBranch property and PR base branch is not equal', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkAutomationBaseBranch: 'fake-ref' - }) - ); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: testSpecificationPullRequest - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assert.deepEqual(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Ignoring pull request event because the pull request base branch (master) is not equal to the sdkAutomationBaseBranch (fake-ref).` - ]); - assert.strictEqual(value, 0); - assert.strictEqual(result, undefined); - }); - - it('with sdkAutomationBaseBranch property and PR base branch is equal', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/fake-ref/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkAutomationBaseBranch: 'fake-ref' - }) - ); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: { - ...testSpecificationPullRequest, - base: { - label: 'fake-label', - ref: 'fake-ref', - sha: 'fake-sha' - } - } - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assertEx.containsAll(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/fake-ref/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Processing pull request event because the pull request base branch (fake-ref) is equal to the sdkAutomationBaseBranch (fake-ref).`, - `Updating logger...`, - `Using FakeGitHub client.` - ]); - assert.strictEqual(value, 1); - assert.strictEqual(result, 6); - }); - - it('with no sdkAutomationBaseBranch property and PR base branch is not master', async function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const container: BlobStorageContainer = await createTestBlobStorageContainer(); - const httpClient = new FakeHttpClient(); - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/fake-ref/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({}) - ); - const sdkAutomation = new SDKAutomation('fake-working-folder-path', { - logger, - httpClient - }); - let value = 0; - const event: SpecificationPREvent | undefined = { - workingPrefix: container, - logger, - webhookBody: { - action: 'opened', - number: 50, - pull_request: { - ...testSpecificationPullRequest, - base: { - label: 'fake-label', - ref: 'fake-ref', - sha: 'fake-sha' - } - } - } - }; - const result: number | undefined = await sdkAutomation.handleEvent(event, () => { - ++value; - return value + 5; - }); - assert.deepEqual(logger.allLogs, [ - `No provided GitHub. Using FakeGitHub instance.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/fake-ref/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `No sdkAutomationBaseBranch property specified in the specificationRepositoryConfiguration.json. Defaulting sdkAutomationBaseBranch to "master".`, - `Ignoring pull request event because the pull request base branch (fake-ref) is not equal to the sdkAutomationBaseBranch (master).` - ]); - assert.strictEqual(value, 0); - assert.strictEqual(result, undefined); - }); - }); - }); - - describe('getGitHub()', function() { - it('with no arguments', function() { - const github: GitHub = getGitHub(); - assertEx.defined(github, 'github'); - assert(github instanceof FakeGitHub); - }); - - it('with undefined', function() { - const github: GitHub = getGitHub(undefined); - assertEx.defined(github, 'github'); - assert(github instanceof FakeGitHub); - }); - - it('with null', function() { - // tslint:disable-next-line:no-null-keyword - const github: GitHub = getGitHub(null as any); - assertEx.defined(github, 'github'); - assert(github instanceof FakeGitHub); - }); - - it('with FakeGitHub', function() { - const github = new FakeGitHub(); - assert.strictEqual(getGitHub(github), github); - }); - }); - - describe('getSupportedLanguages()', function() { - it('with no arguments', function() { - assert.deepEqual(getSupportedLanguages(), getAllLanguages()); - }); - - it('with undefined', function() { - assert.deepEqual(getSupportedLanguages(undefined), getAllLanguages()); - }); - - it('with null', function() { - // tslint:disable-next-line:no-null-keyword - assert.deepEqual(getSupportedLanguages(null as any), getAllLanguages()); - }); - - it('with LanguageConfiguration', function() { - assert.deepEqual(getSupportedLanguages(go), [go]); - }); - - it('with LanguageConfiguration[]', function() { - assert.deepEqual(getSupportedLanguages([java]), [java]); - }); - - it("with function that doesn't return anything", function() { - assert.deepEqual( - getSupportedLanguages(() => {}), - getAllLanguages() - ); - }); - - it('with function that returns a LanguageConfiguration', function() { - assert.deepEqual( - getSupportedLanguages(() => javascript), - [javascript] - ); - }); - - it('with function that returns a LanguageConfiguration[]', function() { - assert.deepEqual( - getSupportedLanguages(() => [go, javascript]), - [go, javascript] - ); - }); - }); - - describe('getAutomationWorkingFolderPath()', function() { - it('with no arguments', function() { - assert.strictEqual(getAutomationWorkingFolderPath(), process.cwd()); - }); - - it('with undefined', function() { - assert.strictEqual(getAutomationWorkingFolderPath(undefined), process.cwd()); - }); - - it('with null', function() { - // tslint:disable-next-line:no-null-keyword - assert.strictEqual(getAutomationWorkingFolderPath(null as any), process.cwd()); - }); - - it(`with ""`, function() { - assert.strictEqual(getAutomationWorkingFolderPath(''), process.cwd()); - }); - - it(`with "apples/and/bananas"`, function() { - assert.strictEqual( - getAutomationWorkingFolderPath('apples/and/bananas'), - joinPath(process.cwd(), 'apples/and/bananas') - ); - }); - - it(`with root path of process.cwd()`, function() { - const rootPath: string = getRootPath(process.cwd())!; - assert.strictEqual(getAutomationWorkingFolderPath(rootPath), rootPath); - }); - - it(`with getRootFolderPath()`, function() { - const rootFolderPath: string = getRootFolderPath(); - assert.strictEqual(getAutomationWorkingFolderPath(rootFolderPath), rootFolderPath); - }); - }); - - describe('getGenerationWorkingFolderPath()', function() { - it('with no arguments', async function() { - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(); - try { - assert.strictEqual(generationWorkingFolderPath, joinPath(process.cwd(), '1')); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder(generationWorkingFolderPath), true); - } - }); - - it('with undefined', async function() { - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(undefined); - try { - assert.strictEqual(generationWorkingFolderPath, joinPath(process.cwd(), '1')); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder(generationWorkingFolderPath), true); - } - }); - - it('with null', async function() { - // tslint:disable-next-line:no-null-keyword - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(null as any); - try { - assert.strictEqual(generationWorkingFolderPath, joinPath(process.cwd(), '1')); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder(generationWorkingFolderPath), true); - } - }); - - it(`with ""`, async function() { - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(''); - try { - assert.strictEqual(generationWorkingFolderPath, joinPath(process.cwd(), '1')); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder(generationWorkingFolderPath), true); - } - }); - - it(`with "oranges"`, async function() { - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath('oranges'); - try { - assert.strictEqual(generationWorkingFolderPath, joinPath(process.cwd(), 'oranges/1')); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder('oranges'), true); - } - }); - - it(`with getRootFolderPath()`, async function() { - const rootFolderPath: string = getRootFolderPath(); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(rootFolderPath); - try { - const rootFolderPathOption: string = joinPath(rootFolderPath, '1'); - const cwdOption: string = joinPath(process.cwd(), '1'); - assert( - generationWorkingFolderPath === rootFolderPathOption || generationWorkingFolderPath === cwdOption, - `generationWorkingFolderPath (${generationWorkingFolderPath}) must be either "${rootFolderPathOption}" or "${cwdOption}.` - ); - assert.strictEqual(await folderExists(generationWorkingFolderPath), true); - } finally { - assert.strictEqual(await deleteFolder(generationWorkingFolderPath), true); - } - }); - }); - - describe('trimNewLine()', function() { - it('with empty string', function() { - assert.strictEqual(trimNewLine(''), ''); - }); - - it('with non-empty string with no newline', function() { - assert.strictEqual(trimNewLine('abcd'), 'abcd'); - }); - - it('with only \\n', function() { - assert.strictEqual(trimNewLine('\n'), ''); - }); - - it('with only \\r\\n', function() { - assert.strictEqual(trimNewLine('\r\n'), ''); - }); - - it("with 'a\\r\\n'", function() { - assert.strictEqual(trimNewLine('a\r\n'), 'a'); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/sdkRepositoryTests.ts b/tools/spec-gen-sdk/test/sdkRepositoryTests.ts deleted file mode 100644 index efe3a8c340d..00000000000 --- a/tools/spec-gen-sdk/test/sdkRepositoryTests.ts +++ /dev/null @@ -1,2368 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { - autorestExecutable, - BlobStorageAppendBlob, - BlobStorageBlob, - BlobStorageContainer, - BlobStoragePrefix, - Command, - Compressor, - deleteFolder, - FakeCompressor, - FakeGitHub, - FakeHttpClient, - FakeRunner, - GitHubPullRequest, - HttpClient, - InMemoryBlobStorage, - joinPath, - ExecutableGit -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { go } from '../lib/langSpecs/go'; -import { python } from '../lib/langSpecs/python'; -import { - ensureStateImagesExist, - getAutomationWorkingFolderPath, - getBlobLogger, - getGenerationWorkingFolderPath, - getLogsBlob, - getOpenAPISDKAutomationVersion, - getRootFolderPath, - SDKAutomation -} from '../lib/sdkAutomation'; -import { - createCommandProperties, - replaceCommandVariables, - replaceStringVariables, - SDKRepository, - SDKRepositoryContext, - SDKRepositoryData -} from '../lib/sdkRepository'; -import { getSpecificationPullRequest, SpecificationPullRequest } from '../lib/specificationPullRequest'; -import { SDKGenerationPullRequestBaseOptions, SwaggerToSDKConfiguration } from '../lib/swaggerToSDKConfiguration'; -import { - createTestBlobStorageContainer, - createTestGitHub, - createTestHttpClient, - createTestRunner, - testSpecificationPullRequest -} from './test'; - -describe('sdkRepository.ts', function() { - it('constructor()', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const swaggerToSDKConfiguration: SwaggerToSDKConfiguration = {}; - const blobStorage = new InMemoryBlobStorage(); - const specPRIterationPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc/def/blah'); - const specPRPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc/blah'); - const logsBlob: BlobStorageAppendBlob = getLogsBlob(specPRIterationPrefix); - const sdkRepositoryContext: SDKRepositoryContext = { - writeGenerationData(): Promise { - return Promise.resolve(); - }, - deleteClonedRepositories: true, - createCompressor(): Compressor { - return new FakeCompressor(); - }, - httpClient: createTestHttpClient(), - github: new FakeGitHub(), - git: new ExecutableGit(), - specificationPullRequest: { - baseRepository: 'Azure/azure-rest-api-specs', - headRepository: 'Azure/azure-rest-api-specs', - headCommit: 'fake-head-commit', - number: 235, - title: 'fake-title', - htmlUrl: 'fake-html-url' - }, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - getBlobLogger, - createGenerationPullRequests: true - }; - const sdkRepositoryData: SDKRepositoryData = { - mainRepository: 'fake-repository-name', - mainRepositoryUrl: 'blah', - generationRepository: 'fake-repository-name', - generationRepositoryUrl: 'blah', - integrationRepository: 'fake-repository-name', - integrationRepositoryUrl: 'blah', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'Go', - readmeMdFileUrlsToGenerate: [], - status: 'pending', - logsBlobUrl: logsBlob.getURL(), - swaggerToSDKConfigFileUrl: 'blah/swagger_to_sdk_config.json' - }; - const sdkRepository = new SDKRepository( - logsBlob, - logger, - go, - swaggerToSDKConfiguration, - specPRIterationPrefix, - specPRPrefix, - sdkRepositoryContext, - sdkRepositoryData - ); - assert.strictEqual(sdkRepository.logger, logger); - assert.strictEqual(sdkRepository.data, sdkRepositoryData); - }); - - describe('generate()', function() { - describe('with sdk_generation_pull_request_base property set to undefined', function() { - it('with the same main, integration, and generation repositories', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, undefined); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" to "Azure/azure-sdk-for-python".`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "sdkAutomation/azure-mgmt-rdbms" already exists in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "sdkAutomation/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" onto SDK integration branch "sdkAutomation/azure-mgmt-rdbms" from "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/sdkAutomation/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "Azure/azure-sdk-for-python" from "sdkAutomation/azure-mgmt-rdbms@4994" to "sdkAutomation/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in Azure/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('Azure/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomation/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'sdkAutomation/azure-mgmt-rdbms'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - - it('with the main repository different from integration and generation repositories', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'integration/azure-sdk-for-python', - generationRepository: 'integration/azure-sdk-for-python', - integrationBranchPrefix: 'sdkAutomationTest' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - httpClient.add('HEAD', 'https://github.com/integration/azure-sdk-for-python', 200); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - runner.set({ - executable: 'git', - args: ['config', '--get', 'remote.origin.url'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stderr: '', - stdout: 'https://github.com/integration/azure-sdk-for-python' - } - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, undefined); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "sdkAutomationTest" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/integration/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomationTest/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomationTest/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomationTest/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "sdkAutomationTest/azure-mgmt-rdbms" already exists in "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "sdkAutomationTest/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/sdkAutomationTest/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "sdkAutomationTest/azure-mgmt-rdbms@4994" onto SDK integration branch "sdkAutomationTest/azure-mgmt-rdbms" from "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomationTest/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs sdkAutomationTest/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/sdkAutomationTest/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomationTest/azure-mgmt-rdbms@4994" to integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomationTest/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "integration/azure-sdk-for-python" from "sdkAutomationTest/azure-mgmt-rdbms@4994" to "sdkAutomationTest/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label GenerationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label IntegrationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRInProgress in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRClosed in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRMerged in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in integration/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of integration/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of integration/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - assert.deepEqual(await github.getPullRequests('Azure/azure-sdk-for-python'), []); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('integration/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomationTest/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'sdkAutomationTest/azure-mgmt-rdbms'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - - it('with different main, integration, and generation repositories', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'integration/azure-sdk-for-python', - generationRepository: 'generation/azure-sdk-for-python', - integrationBranchPrefix: 'apples' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - httpClient.add('HEAD', 'https://github.com/integration/azure-sdk-for-python', 200); - httpClient.add('HEAD', 'https://github.com/generation/azure-sdk-for-python', 200); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - runner.set({ - executable: 'git', - args: ['config', '--get', 'remote.origin.url'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stderr: '', - stdout: 'https://github.com/integration/azure-sdk-for-python' - } - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, undefined); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "generation/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "apples" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/generation/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/generation/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "apples/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b apples/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout apples/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "apples/azure-mgmt-rdbms" already exists in "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "apples/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/apples/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "apples/azure-mgmt-rdbms@4994" onto SDK integration branch "apples/azure-mgmt-rdbms" from "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout apples/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs apples/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/apples/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "apples/azure-mgmt-rdbms@4994" to generation/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation apples/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "integration/azure-sdk-for-python" from "generation:apples/azure-mgmt-rdbms@4994" to "apples/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: false`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label GenerationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label IntegrationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRInProgress in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRClosed in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRMerged in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in integration/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of generation/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of generation/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - assert.deepEqual(await github.getPullRequests('Azure/azure-sdk-for-python'), []); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('integration/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'apples/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'apples/azure-mgmt-rdbms'); - assert.deepEqual(await github.getPullRequests('generation/azure-sdk-for-python'), []); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - }); - - describe(`with sdk_generation_pull_request_base property set to "integration_branch"`, function() { - it(`with the same main, integration, and generation repositories"`, async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'integration_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" to "Azure/azure-sdk-for-python".`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "sdkAutomation/azure-mgmt-rdbms" already exists in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "sdkAutomation/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" onto SDK integration branch "sdkAutomation/azure-mgmt-rdbms" from "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/sdkAutomation/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "Azure/azure-sdk-for-python" from "sdkAutomation/azure-mgmt-rdbms@4994" to "sdkAutomation/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in Azure/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - - it('with the main repository different from integration and generation repositories', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'integration/azure-sdk-for-python', - generationRepository: 'integration/azure-sdk-for-python' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - httpClient.add('HEAD', 'https://github.com/integration/azure-sdk-for-python', 200); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - runner.set({ - executable: 'git', - args: ['config', '--get', 'remote.origin.url'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stderr: '', - stdout: 'https://github.com/integration/azure-sdk-for-python' - } - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'integration_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "sdkAutomation" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/integration/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "sdkAutomation/azure-mgmt-rdbms" already exists in "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "sdkAutomation/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" onto SDK integration branch "sdkAutomation/azure-mgmt-rdbms" from "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/sdkAutomation/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "integration/azure-sdk-for-python" from "sdkAutomation/azure-mgmt-rdbms@4994" to "sdkAutomation/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label GenerationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label IntegrationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRInProgress in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRClosed in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRMerged in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in integration/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of integration/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of integration/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - assert.deepEqual(await github.getPullRequests('Azure/azure-sdk-for-python'), []); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('integration/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomation/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'sdkAutomation/azure-mgmt-rdbms'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - - it('with different main, integration, and generation repositories', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'integration/azure-sdk-for-python', - generationRepository: 'generation/azure-sdk-for-python' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - httpClient.add('HEAD', 'https://github.com/integration/azure-sdk-for-python', 200); - httpClient.add('HEAD', 'https://github.com/generation/azure-sdk-for-python', 200); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - runner.set({ - executable: 'git', - args: ['config', '--get', 'remote.origin.url'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stderr: '', - stdout: 'https://github.com/integration/azure-sdk-for-python' - } - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'integration_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "generation/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "sdkAutomation" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/generation/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/generation/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/integration/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if the SDK integration branch "sdkAutomation/azure-mgmt-rdbms" already exists in "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager branch --remotes`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - SDK integration branch exists: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing existing SDK integration branch "sdkAutomation/azure-mgmt-rdbms" onto main branch "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout --track integration/sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs main/master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git pull`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Rebasing SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" onto SDK integration branch "sdkAutomation/azure-mgmt-rdbms" from "integration/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git rebase --strategy-option=theirs sdkAutomation/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff integration/sdkAutomation/azure-mgmt-rdbms --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to generation/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "integration/azure-sdk-for-python" from "generation:sdkAutomation/azure-mgmt-rdbms@4994" to "sdkAutomation/azure-mgmt-rdbms"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: false`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label GenerationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label IntegrationPR in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRInProgress in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRClosed in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Didn't find label SpecPRMerged in integration/azure-sdk-for-python. Creating it...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in integration/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of generation/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of generation/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - assert.deepEqual(await github.getPullRequests('Azure/azure-sdk-for-python'), []); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('integration/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomation/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'sdkAutomation/azure-mgmt-rdbms'); - assert.deepEqual(await github.getPullRequests('generation/azure-sdk-for-python'), []); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - }); - - describe(`with sdk_generation_pull_request_base property set to "main_branch" but no "main_branch" specified`, function() { - it(`with the same main, integration, and generation repositories"`, async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'main_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" to "Azure/azure-sdk-for-python".`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "Azure/azure-sdk-for-python" from "sdkAutomation/azure-mgmt-rdbms@4994" to "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in Azure/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('Azure/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomation/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'master'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - }); - - describe(`with sdk_generation_pull_request_base property set to "main_branch" and "main_branch" set to "master"`, function() { - it(`with the same main, integration, and generation repositories"`, async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'Azure/azure-sdk-for-python', - generationRepository: 'Azure/azure-sdk-for-python', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'main_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "Azure/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "Azure/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "sdkAutomation" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "sdkAutomation/azure-mgmt-rdbms@4994" to Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation sdkAutomation/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "Azure/azure-sdk-for-python" from "sdkAutomation/azure-mgmt-rdbms@4994" to "master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in Azure/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('Azure/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'sdkAutomation/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'master'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - - it(`with the same main, integration, and generation repositories but only main repository available"`, async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationRepository: 'integration/azure-sdk-for-python', - generationRepository: 'generation/azure-sdk-for-python', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java' - } - }) - ); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'main_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "generation/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "integration/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "sdkAutomation" as the integration branch prefix.`, - `Using "master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `SDK repository azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Could not find a swagger_to_sdk_config.json file at https://raw.githubusercontent.com/azure-sdk-for-go/master/swagger_to_sdk_config.json.`, - `SDK repository azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Could not find a swagger_to_sdk_config.json file at https://raw.githubusercontent.com/azure-sdk-for-js/master/swagger_to_sdk_config.json.`, - `SDK repository azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Could not find a swagger_to_sdk_config.json file at https://raw.githubusercontent.com/azure-sdk-for-node/master/swagger_to_sdk_config.json.`, - `Azure/azure-sdk-for-python - Integration repository https://github.com/integration/azure-sdk-for-python doesn't exist. Using fallback https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - Generation repository https://github.com/generation/azure-sdk-for-python doesn't exist. Using fallback https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - No SDK repository artifact files detected.`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('Azure/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 0); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - }); - - describe(`with sdk_generation_pull_request_base property set to "main_branch" and "main_branch" set to "non-master"`, function() { - it(`with the same main, integration, and generation repositories`, async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer.getPrefix(''); - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': { - mainRepository: 'Azure/azure-sdk-for-python', - integrationBranchPrefix: 'apples', - mainBranch: 'non-master' - }, - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient, - createGenerationPullRequests: true - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - await specificationPullRequest.populateSDKRepositoryReadmeMdFilesToGenerate(); - const sdkRepository: SDKRepository = (await specificationPullRequest.generation.getSDKRepository( - 'Azure/azure-sdk-for-python', - python - ))!; - setSDKGenerationPullRequestBase(sdkRepository.swaggerToSDKConfiguration, 'main_branch'); - - await sdkRepository.generate(generationWorkingFolderPath, 1); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" generation repository to "Azure/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" integration repository to "Azure/azure-sdk-for-python".`, - `Mapping "azure-sdk-for-python" main repository to "Azure/azure-sdk-for-python".`, - `Using "apples" as the integration branch prefix.`, - `Using "non-master" as the main branch in the main repository.`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/non-master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/non-master -b main-non-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/non-master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "apples/azure-mgmt-rdbms@4994" based off of "non-master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-non-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b apples/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/non-master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout apples/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/non-master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Pushing generation branch "apples/azure-mgmt-rdbms@4994" to Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git push --set-upstream generation apples/azure-mgmt-rdbms@4994 --force`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Checking if generation pull request exists...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation pull request in "Azure/azure-sdk-for-python" from "apples/azure-mgmt-rdbms@4994" to "non-master"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - maintainerCanModify: true`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Created generation pull request at fake-html-url.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Adding installation instructions comment to generation pull request...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Label changes for PR 1 in Azure/azure-sdk-for-python: +GenerationPR, +SpecPRInProgress`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.` - ]); - const pullRequests: GitHubPullRequest[] = await github.getPullRequests('Azure/azure-sdk-for-python'); - assert.strictEqual(pullRequests.length, 1); - assert.strictEqual(pullRequests[0].head.ref, 'apples/azure-mgmt-rdbms@4994'); - assert.strictEqual(pullRequests[0].base.ref, 'non-master'); - } finally { - await deleteFolder(generationWorkingFolderPath); - } - } finally { - await workingContainer.delete(); - } - }); - }); - }); - - describe('createCommandProperties()', function() { - it('with empty object', function() { - assert.deepEqual(createCommandProperties({}), {}); - }); - - it('with object with string properties', function() { - assert.deepEqual(createCommandProperties({ a: 'A', b: 'B' }), { a: 'A', b: 'B' }); - }); - - it('with object with number properties', function() { - assert.deepEqual(createCommandProperties({ a: 1, b: 2 }), { a: '1', b: '2' }); - }); - - it('with object with boolean properties', function() { - assert.deepEqual(createCommandProperties({ a: true, b: false }), { a: 'true', b: 'false' }); - }); - - it('with object with mixed properties', function() { - assert.deepEqual( - createCommandProperties({ - a: true, - b: false, - c: 1, - d: 'D', - e: {}, - f: [], - g: undefined - }), - { - a: 'true', - b: 'false', - c: '1', - d: 'D' - } - ); - }); - }); - - describe('replaceStringVariables()', function() { - it('with empty source string', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual(replaceStringVariables('', {}, logger), ''); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with no property references', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual(replaceStringVariables('hello there', {}, logger), 'hello there'); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with not found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual(replaceStringVariables('hello $(NAME)', {}, logger), 'hello $(NAME)'); - assert.deepEqual(logger.allLogs, [`Found no property replacement for "NAME" in "hello $(NAME)".`]); - }); - - it('with source string with found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME)', - { - FIRST_NAME: 'Dan' - }, - logger - ), - 'hello Dan' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with different-cased found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME)', - { - first_name: 'Dan' - }, - logger - ), - 'hello Dan' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with removed underscore found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME)', - { - FIRSTNAME: 'Dan' - }, - logger - ), - 'hello Dan' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with removed dash found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST-NAME)', - { - FIRSTNAME: 'Dan' - }, - logger - ), - 'hello Dan' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it('with source string with removed symbol and different-cased found property reference', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME)', - { - firstName: 'Dan' - }, - logger - ), - 'hello Dan' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it('with multiple property references', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME) $(LAST_NAME)!', - { - firstName: 'Abe', - lastName: 'Lincoln' - }, - logger - ), - 'hello Abe Lincoln!' - ); - assert.deepEqual(logger.allLogs, []); - }); - - it("with multiple property references where first reference isn't found", function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME) $(LAST_NAME)!', - { - lastName: 'Lincoln' - }, - logger - ), - 'hello $(FIRST_NAME) Lincoln!' - ); - assert.deepEqual(logger.allLogs, [ - `Found no property replacement for "FIRST_NAME" in "hello $(FIRST_NAME) $(LAST_NAME)!".` - ]); - }); - - it("with multiple property references where middle reference isn't found", function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME) $(MIDDLE_NAME) $(LAST_NAME)!', - { - firstName: 'Abe', - lastName: 'Lincoln' - }, - logger - ), - 'hello Abe $(MIDDLE_NAME) Lincoln!' - ); - assert.deepEqual(logger.allLogs, [ - `Found no property replacement for "MIDDLE_NAME" in "hello $(FIRST_NAME) $(MIDDLE_NAME) $(LAST_NAME)!".` - ]); - }); - - it("with multiple property references where last reference isn't found", function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FIRST_NAME) $(LAST_NAME)!', - { - firstName: 'Abe' - }, - logger - ), - 'hello Abe $(LAST_NAME)!' - ); - assert.deepEqual(logger.allLogs, [ - `Found no property replacement for "LAST_NAME" in "hello $(FIRST_NAME) $(LAST_NAME)!".` - ]); - }); - - it('with recursive property references', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - assert.strictEqual( - replaceStringVariables( - 'hello $(FULL_NAME)!', - { - fullName: '$(FIRST_NAME) $(LAST_NAME)', - firstName: 'Abe', - lastName: 'Lincoln' - }, - logger - ), - 'hello Abe Lincoln!' - ); - assert.deepEqual(logger.allLogs, []); - }); - }); - - it('replaceCommandVariables()', function() { - const logger: InMemoryLogger = getInMemoryLogger(); - const command: Command = { - executable: 'hello/$(apples)', - args: ['banan$(as)', '$(or)anges'] - }; - replaceCommandVariables(command, { apples: 'APPLES', as: 'AS', or: 'OR' }, logger); - assert.deepEqual(command, { - executable: 'hello/APPLES', - args: ['bananAS', 'ORanges'] - }); - assert.deepEqual(logger.allLogs, []); - }); -}); - -function setSDKGenerationPullRequestBase( - configuration: SwaggerToSDKConfiguration, - value: SDKGenerationPullRequestBaseOptions | undefined -): void { - if (!configuration.meta) { - configuration.meta = {}; - } - if (!configuration.meta.advanced_options) { - configuration.meta.advanced_options = {}; - } - configuration.meta.advanced_options.create_sdk_pull_requests = true; - configuration.meta.advanced_options.sdk_generation_pull_request_base = value; -} diff --git a/tools/spec-gen-sdk/test/specificationPullRequestGenerationTests.ts b/tools/spec-gen-sdk/test/specificationPullRequestGenerationTests.ts deleted file mode 100644 index 27b20f61343..00000000000 --- a/tools/spec-gen-sdk/test/specificationPullRequestGenerationTests.ts +++ /dev/null @@ -1,607 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { - assertEx, - BlobStorageBlob, - BlobStorageContainer, - BlobStoragePrefix, - deleteFolder, - FakeCompressor, - FakeGitHub, - HttpClient, - ExecutableGit -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { javascript } from '../lib/langSpecs/javascript'; -import { getBlobLogger } from '../lib/sdkAutomation'; -import { SDKRepository } from '../lib/sdkRepository'; -import { - getSpecificationPullRequestGeneration, - SpecificationPullRequestGeneration -} from '../lib/specificationPullRequestGeneration'; -import { createTestBlobStorageContainer, createTestHttpClient, testSpecificationPullRequestNumber } from './test'; - -describe('specificationPullRequestGeneration.ts', function() { - describe('getSpecificationPullRequestGeneration()', function() { - it('with first generation', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - assertEx.defined(generation, 'generation'); - assert.deepEqual(generation.data, { - number: 1, - logsBlobUrl: 'https://fake.storage.com/abc/def/1/logs.txt', - dataBlobUrl: 'https://fake.storage.com/abc/def/1/data.json', - commentHtmlBlobUrl: 'https://fake.storage.com/abc/def/1/comment.html', - sdkRepositories: [] - }); - assert.strictEqual(generation.specificationPullRequest, undefined); - assert.strictEqual(await generation.logsBlob.exists(), true); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with second generation', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - await getSpecificationPullRequestGeneration(testSpecificationPullRequestNumber, prefix, { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - }); - - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - assertEx.defined(generation, 'generation'); - assert.deepEqual(generation.data, { - number: 2, - logsBlobUrl: 'https://fake.storage.com/abc/def/2/logs.txt', - dataBlobUrl: 'https://fake.storage.com/abc/def/2/data.json', - commentHtmlBlobUrl: 'https://fake.storage.com/abc/def/2/comment.html', - sdkRepositories: [] - }); - assert.strictEqual(generation.specificationPullRequest, undefined); - assert.strictEqual(await generation.logsBlob.exists(), true); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - }); - - describe('writeGenerationData()', function() { - it('with no data, no comment html, and no specification pull request', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.writeGenerationData(); - - assert.strictEqual((await blobStorageContainer.getBlobContentsAsString('def/1/data.json')).contents, ''); - assert.strictEqual((await blobStorageContainer.getBlobContentsAsString('def/1/comment.html')).contents, ''); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with data, no comment html, and no specification pull request', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.writeGenerationData('generation data'); - - assert.strictEqual( - (await blobStorageContainer.getBlobContentsAsString('def/1/data.json')).contents, - 'generation data' - ); - assert.strictEqual((await blobStorageContainer.getBlobContentsAsString('def/1/comment.html')).contents, ''); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with no data, comment html, and no specification pull request', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.writeGenerationData(undefined, 'comment html'); - - assert.strictEqual((await blobStorageContainer.getBlobContentsAsString('def/1/data.json')).contents, ''); - assert.strictEqual( - (await blobStorageContainer.getBlobContentsAsString('def/1/comment.html')).contents, - 'comment html' - ); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with data, comment html, and no specification pull request', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const prefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - prefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.writeGenerationData('generation data', 'comment html'); - - assert.strictEqual( - (await blobStorageContainer.getBlobContentsAsString('def/1/data.json')).contents, - 'generation data' - ); - assert.strictEqual( - (await blobStorageContainer.getBlobContentsAsString('def/1/comment.html')).contents, - 'comment html' - ); - assert.deepEqual(logger.allLogs, []); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - }); - - describe('getSDKRepository()', function() { - it('with SDK Repository not seen before', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - const sdkRepository: SDKRepository = (await generation.getSDKRepository('fake/js-sdk-repository', javascript))!; - - assertEx.defined(sdkRepository, 'sdkRepository'); - assert.deepEqual(sdkRepository.data, { - mainRepository: 'fake/js-sdk-repository', - mainRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - generationRepository: 'fake/js-sdk-repository', - generationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationRepository: 'fake/js-sdk-repository', - integrationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'JavaScript', - readmeMdFileUrlsToGenerate: [], - status: 'pending', - swaggerToSDKConfigFileUrl: - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json' - }); - assert.deepEqual(generation.data.sdkRepositories, [sdkRepository.data]); - assert.deepEqual(logger.allLogs, [ - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with SDK Repository previously seen', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - const sdkRepository1: SDKRepository = (await generation.getSDKRepository( - 'fake/js-sdk-repository', - javascript - ))!; - - const sdkRepository2: SDKRepository = (await generation.getSDKRepository( - 'fake/js-sdk-repository', - javascript - ))!; - - assert.strictEqual(sdkRepository2, sdkRepository1); - assert.deepEqual(generation.data.sdkRepositories, [sdkRepository1.data]); - assert.deepEqual(logger.allLogs, [ - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - }); - - describe('addReadmeMdFileToGenerateForSDKRepository()', function() { - it('with unseen SDK repository', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url', - javascript - ); - - assert.deepEqual(generation.data.sdkRepositories, [ - { - mainRepository: 'fake/js-sdk-repository', - mainRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - generationRepository: 'fake/js-sdk-repository', - generationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationRepository: 'fake/js-sdk-repository', - integrationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'JavaScript', - status: 'pending', - readmeMdFileUrlsToGenerate: ['fake-readme.md-file-url'], - swaggerToSDKConfigFileUrl: - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json' - } - ]); - assert.deepEqual(logger.allLogs, [ - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".`, - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to fake/js-sdk-repository: fake-readme.md-file-url` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with seen SDK repository and unseen readme.md url', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.getSDKRepository('fake/js-sdk-repository', javascript); - - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url', - javascript - ); - - assert.deepEqual(generation.data.sdkRepositories, [ - { - mainRepository: 'fake/js-sdk-repository', - mainRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - generationRepository: 'fake/js-sdk-repository', - generationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationRepository: 'fake/js-sdk-repository', - integrationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'JavaScript', - status: 'pending', - readmeMdFileUrlsToGenerate: ['fake-readme.md-file-url'], - swaggerToSDKConfigFileUrl: - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json' - } - ]); - assert.deepEqual(logger.allLogs, [ - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...`, - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".`, - `Adding readme.md to generate to fake/js-sdk-repository: fake-readme.md-file-url` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with seen SDK repository and seen readme.md url', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url', - javascript - ); - - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url', - javascript - ); - - assert.deepEqual(generation.data.sdkRepositories, [ - { - mainRepository: 'fake/js-sdk-repository', - mainRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - generationRepository: 'fake/js-sdk-repository', - generationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationRepository: 'fake/js-sdk-repository', - integrationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'JavaScript', - status: 'pending', - readmeMdFileUrlsToGenerate: ['fake-readme.md-file-url'], - swaggerToSDKConfigFileUrl: - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json' - } - ]); - assert.deepEqual(logger.allLogs, [ - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".`, - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to fake/js-sdk-repository: fake-readme.md-file-url`, - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - - it('with seen SDK repository and multiple readme.md urls', async function() { - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const pullRequestPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const generation: SpecificationPullRequestGeneration = await getSpecificationPullRequestGeneration( - testSpecificationPullRequestNumber, - pullRequestPrefix, - { - httpClient, - github: new FakeGitHub(), - git: new ExecutableGit(), - logger, - deleteClonedRepositories: true, - automationWorkingFolderPath: 'fake-automation-working-folder-path', - compressorCreator: () => new FakeCompressor(), - getBlobLogger, - getBlobProxyUrl: (blob: BlobStorageBlob) => blob.getURL({ sasToken: false }), - createGenerationPullRequests: true, - generateLanguagesInParallel: false - } - ); - try { - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url1', - javascript - ); - await generation.addReadmeMdFileToGenerateForSDKRepository( - 'fake/js-sdk-repository', - 'fake-readme.md-file-url2', - javascript - ); - - assert.deepEqual(generation.data.sdkRepositories, [ - { - mainRepository: 'fake/js-sdk-repository', - mainRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - generationRepository: 'fake/js-sdk-repository', - generationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationRepository: 'fake/js-sdk-repository', - integrationRepositoryUrl: 'https://github.com/fake/js-sdk-repository', - integrationBranchPrefix: 'sdkAutomation', - mainBranch: 'master', - languageName: 'JavaScript', - status: 'pending', - readmeMdFileUrlsToGenerate: ['fake-readme.md-file-url1', 'fake-readme.md-file-url2'], - swaggerToSDKConfigFileUrl: - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json' - } - ]); - assert.deepEqual(logger.allLogs, [ - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".`, - `SDK repository fake/js-sdk-repository matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to fake/js-sdk-repository: fake-readme.md-file-url1`, - `Mapping "fake/js-sdk-repository" to "fake/js-sdk-repository".`, - `Adding readme.md to generate to fake/js-sdk-repository: fake-readme.md-file-url2` - ]); - } finally { - await deleteFolder('fake-automation-working-folder-path'); - } - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/specificationPullRequestTests.ts b/tools/spec-gen-sdk/test/specificationPullRequestTests.ts deleted file mode 100644 index f27e04d0b30..00000000000 --- a/tools/spec-gen-sdk/test/specificationPullRequestTests.ts +++ /dev/null @@ -1,1773 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { - assertEx, - autorestExecutable, - BlobPath, - BlobStorageAppendBlob, - BlobStorageBlockBlob, - BlobStorageContainer, - BlobStoragePrefix, - deleteFolder, - FakeGitHub, - FakeRunner, - getRepository, - getRepositoryBranch, - GitHubLabel, - GitHubPullRequest, - HttpClient, - InMemoryBlobStorage, - joinPath, - map, - mvnExecutable, - URLBuilder, - FakeHttpClient -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { pullRequestLabelsInfo } from '../lib/githubUtils'; -import { - ensureStateImagesExist, - getAutomationWorkingFolderPath, - getDataBlob, - getGenerationWorkingFolderPath, - getLogsBlob, - getOpenAPISDKAutomationVersion, - getRootFolderPath, - SDKAutomation -} from '../lib/sdkAutomation'; -import { - getPullRequestPrefix, - getSpecificationPullRequest, - SpecificationPullRequest, - SpecificationPullRequestData -} from '../lib/specificationPullRequest'; -import { - getCommentHtmlBlob, - getGenerationPrefix, - getSDKRepositoryPrefix, - getSwaggerToSDKConfigurationURL -} from '../lib/specificationPullRequestGeneration'; -import { SpecificationReadmeMdFile } from '../lib/specificationReadmeMdFile'; -import { - createTestBlobStorageContainer, - createTestGitHub, - createTestHttpClient, - createTestRunner, - deleteWorkingContainer, - deleteWorkingFolder, - storageUrl, - testSpecificationPullRequest, - testSpecificationPullRequestMergeCommitSha, - testSpecificationPullRequestRepository -} from './test'; - -describe('specificationPullRequest.ts', function() { - describe('getSpecificationPullRequest()', function() { - it('with first generation', async function() { - const workingFolderPath: string = joinPath(process.cwd(), 'fakeAutomationWorkingFolderPath'); - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const sdkAutomation = new SDKAutomation(workingFolderPath, { - github, - logger - }); - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const workingPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - workingPrefix, - testSpecificationPullRequest, - true - ); - try { - assertEx.defined(specificationPullRequest, 'specificationPullRequest'); - assert.strictEqual( - await blobStorageContainer.blobExists( - `def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/1/logs.txt` - ), - true - ); - assert.deepEqual(specificationPullRequest.data, { - specPRRepository: { - owner: 'Azure', - name: 'azure-rest-api-specs' - }, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - baseBranch: { - owner: 'Azure', - name: 'master' - }, - commentId: 1, - dataBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/data.json`, - diffUrl: testSpecificationPullRequest.diff_url, - generation: { - commentHtmlBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/1/comment.html`, - dataBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/1/data.json`, - logsBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/1/logs.txt`, - number: 1, - sdkRepositories: [] - }, - headBranch: { - owner: 'pixia', - name: 'master' - }, - headCommit: testSpecificationPullRequest.head.sha, - htmlUrl: testSpecificationPullRequest.html_url, - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - baseRepository: { - owner: 'Azure', - name: 'azure-rest-api-specs' - }, - headRepository: { - owner: 'pixia', - name: 'azure-rest-api-specs' - }, - title: testSpecificationPullRequest.title - }); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `No HttpClient provided. Using NodeHttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - await deleteFolder(workingFolderPath); - } - }); - - it('with second generation', async function() { - const workingFolderPath: string = joinPath(process.cwd(), 'apples'); - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const sdkAutomation = new SDKAutomation(workingFolderPath, { - github, - logger - }); - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const workingPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - await getSpecificationPullRequest(sdkAutomation, workingPrefix, testSpecificationPullRequest, true); - - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - workingPrefix, - testSpecificationPullRequest, - true - ); - try { - assertEx.defined(specificationPullRequest, 'specificationPullRequest'); - assert.strictEqual( - await blobStorageContainer.blobExists( - `def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/2/logs.txt` - ), - true - ); - assert.deepEqual(specificationPullRequest.data, { - specPRRepository: { - owner: 'Azure', - name: 'azure-rest-api-specs' - }, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - baseBranch: { - owner: 'Azure', - name: 'master' - }, - commentId: 1, - dataBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/data.json`, - diffUrl: testSpecificationPullRequest.diff_url, - generation: { - commentHtmlBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/2/comment.html`, - dataBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/2/data.json`, - logsBlobUrl: `https://fake.storage.com/abc/def/${testSpecificationPullRequestRepository}/${testSpecificationPullRequest.number}/2/logs.txt`, - number: 2, - sdkRepositories: [] - }, - headBranch: { - owner: 'pixia', - name: 'master' - }, - headCommit: testSpecificationPullRequest.head.sha, - htmlUrl: testSpecificationPullRequest.html_url, - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - baseRepository: { - name: 'azure-rest-api-specs', - owner: 'Azure' - }, - headRepository: { - name: 'azure-rest-api-specs', - owner: 'pixia' - }, - title: testSpecificationPullRequest.title - }); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `No HttpClient provided. Using NodeHttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - await deleteFolder(workingFolderPath); - } - }); - }); - - it('getChangedFilesRelativePaths()', async function() { - this.timeout(5000); - - const workingFolderPath: string = joinPath(process.cwd(), 'grapes'); - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const sdkAutomation = new SDKAutomation(workingFolderPath, { - github, - logger - }); - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const workingPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - workingPrefix, - testSpecificationPullRequest, - true - ); - try { - const changedFilesRelativePaths: string[] = await specificationPullRequest.getChangedFilesRelativePaths(); - - assert.deepEqual(changedFilesRelativePaths, [ - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json` - ]); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `No HttpClient provided. Using NodeHttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json` - ]); - } finally { - await deleteFolder(workingFolderPath); - } - }); - - it('getReadmeMdRelativeFilePathsToGenerate()', async function() { - const workingFolderPath: string = joinPath(process.cwd(), 'kiwi'); - const github: FakeGitHub = await createTestGitHub(); - const httpClient: HttpClient = createTestHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const sdkAutomation = new SDKAutomation(workingFolderPath, { - github, - httpClient, - logger - }); - const blobStorageContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - const workingPrefix: BlobStoragePrefix = blobStorageContainer.getPrefix('def/'); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - workingPrefix, - testSpecificationPullRequest, - true - ); - try { - const readmeMdRelativeFilePathsToGenerate: SpecificationReadmeMdFile[] = await specificationPullRequest.getReadmeMdFilesToGenerate(); - - assert.deepEqual( - map( - readmeMdRelativeFilePathsToGenerate, - (readmeFile: SpecificationReadmeMdFile) => readmeFile.relativeFilePath - ), - ['specification/mysql/resource-manager/readme.md'] - ); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md` - ]); - } finally { - await deleteFolder(workingFolderPath); - } - }); - - describe('generateModifiedServices()', function() { - it('fake', function() { - return generateModifiedServicesTest(false); - }); - - (URLBuilder.parse(storageUrl).getQueryParameterValue('sig') ? it : it.skip)('real', function() { - this.timeout(1000 * 60 * 9); - return generateModifiedServicesTest(true); - }); - - async function generateModifiedServicesTest(real: boolean): Promise { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(real); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(real); - const autorest: string = autorestExecutable({ - autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') - }); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest, - generationWorkingFolderPath: generationWorkingFolderPath, - github, - real - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - true - ); - - await specificationPullRequest.generateModifiedServices(); - - const pythonFolderPath: string = joinPath(generationWorkingFolderPath, '1'); - const javaFolderPath: string = joinPath(generationWorkingFolderPath, '2'); - const goFolderPath: string = joinPath(generationWorkingFolderPath, 'src/github.com/Azure/azure-sdk-for-go'); - const jsFolderPath: string = joinPath(generationWorkingFolderPath, 'azure-sdk-for-js'); - const nodeFolderPath: string = joinPath(generationWorkingFolderPath, 'azure-sdk-for-node'); - const mvn: string = mvnExecutable(); - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Getting diff_url (https://github.com/Azure/azure-rest-api-specs/pull/4994.diff) contents...`, - `diff_url response status code is 200.`, - `diff_url response body contains 5 changed files:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `diff_url response body contains 5 changed files in the specification folder:`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json`, - `specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json`, - `Found 1 readme.md files to generate:`, - `specification/mysql/resource-manager/readme.md`, - `Looking for repositories to generate in "specification/mysql/resource-manager/readme.md"...`, - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 5 requested SDK repositories:`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node`, - `Mapping "azure-sdk-for-python" to "Azure/azure-sdk-for-python".`, - `SDK repository Azure/azure-sdk-for-python matches programming language Python.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-python: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-java" to "Azure/azure-sdk-for-java".`, - `SDK repository Azure/azure-sdk-for-java matches programming language Java.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-java: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-go" to "Azure/azure-sdk-for-go".`, - `SDK repository Azure/azure-sdk-for-go matches programming language Go.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-go: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-js" to "Azure/azure-sdk-for-js".`, - `SDK repository Azure/azure-sdk-for-js matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-js: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Mapping "azure-sdk-for-node" to "Azure/azure-sdk-for-node".`, - `SDK repository Azure/azure-sdk-for-node matches programming language JavaScript.`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json"...`, - `Adding readme.md to generate to Azure/azure-sdk-for-node: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-python ${pythonFolderPath}`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-python`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-python - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-python - Resolving "autorest" version "preview" to "2.0.4302".`, - `Azure/azure-sdk-for-python - Getting dist-tags for "@microsoft.azure/autorest.python" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags"...`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-python - "@microsoft.azure/autorest.python@~3.0.56" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: ${autorest} --version=2.0.4302 --use=@microsoft.azure/autorest.python@~3.0.56 --python --python-mode=update --multiapi --python-sdks-folder=${pythonFolderPath} https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-python - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git add *`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}: git reset *`, - `Azure/azure-sdk-for-python - The following files were changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Package name for "${pythonFolderPath}/azure-mgmt-rdbms" is "azure-mgmt-rdbms".`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating SDK generation branch "sdkAutomation/azure-mgmt-rdbms@4994" based off of "master" in "Azure/azure-sdk-for-python"...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout -b sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}/azure-mgmt-rdbms: git add *`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - 1 files staged for commit:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git checkout sdkAutomation/azure-mgmt-rdbms@4994`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - No after_scripts to run.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Output:`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Found 1 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - ${pythonFolderPath}: python ./build_package.py --dest ${pythonFolderPath}/azure-mgmt-rdbms azure-mgmt-rdbms`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Exit Code: 0`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Done uploading ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/fake-python-package.whl.`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Creating package installation instructions...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - azure-mgmt-rdbms - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure-mgmt-rdbms/instructions.md...`, - `Azure/azure-sdk-for-python - Creating SDK repository artifact zip file (${pythonFolderPath}/azure.azure-sdk-for-python.artifacts.zip) from:`, - `Azure/azure-sdk-for-python - ${pythonFolderPath}/azure-mgmt-rdbms/fake-python-package.whl`, - `Azure/azure-sdk-for-python - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-python/azure.azure-sdk-for-python.artifacts.zip...`, - `Azure/azure-sdk-for-python - Deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}...`, - `Azure/azure-sdk-for-python - Finished deleting clone of Azure/azure-sdk-for-python at folder ${pythonFolderPath}.`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-java ${javaFolderPath}`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-java`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-java`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-java`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-java - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-java - No version specified for "autorest". Defaulting to "latest".`, - `Azure/azure-sdk-for-java - Resolving "autorest" version "latest" to "2.0.4283".`, - `Azure/azure-sdk-for-java - Getting dist-tags for "@microsoft.azure/autorest.java" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.java/dist-tags"...`, - `Azure/azure-sdk-for-java - "@microsoft.azure/autorest.java@2.1.85" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: ${autorest} --java --verbose --multiapi --use=@microsoft.azure/autorest.java@2.1.85 --azure-libraries-for-java-folder=${javaFolderPath} --version=2.0.4283 https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-java - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git add *`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-java - ${javaFolderPath}: git reset *`, - `Azure/azure-sdk-for-java - The following files were changed:`, - `Azure/azure-sdk-for-java - ${javaFolderPath}/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java`, - `Azure/azure-sdk-for-java - ${javaFolderPath}/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java`, - `Azure/azure-sdk-for-java - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-java - ${javaFolderPath}/mysql/resource-manager/v2017_12_01`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Package name for "${javaFolderPath}/mysql/resource-manager/v2017_12_01" is "mysql/resource-manager/v2017_12_01".`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Creating SDK generation branch "sdkAutomation/mysql/resource-manager/v2017_12_01@4994" based off of "master" in "Azure/azure-sdk-for-java"...`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git checkout -b sdkAutomation/mysql/resource-manager/v2017_12_01@4994`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}/mysql/resource-manager/v2017_12_01: git add *`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - 2 files staged for commit:`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git checkout sdkAutomation/mysql/resource-manager/v2017_12_01@4994`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - No after_scripts to run.`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Exit Code: 0`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Output:`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Found 2 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - ${javaFolderPath}/mysql/resource-manager/v2017_12_01: ${mvn} source:jar javadoc:jar package -f ${javaFolderPath}/mysql/resource-manager/v2017_12_01 -DskipTests --batch-mode`, - `Azure/azure-sdk-for-java - mysql/resource-manager/v2017_12_01 - Exit Code: 1`, - `Azure/azure-sdk-for-java - No SDK repository artifact files detected.`, - `Azure/azure-sdk-for-java - Deleting clone of Azure/azure-sdk-for-java at folder ${javaFolderPath}...`, - `Azure/azure-sdk-for-java - Finished deleting clone of Azure/azure-sdk-for-java at folder ${javaFolderPath}.`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-go ${goFolderPath}`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-go`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-go`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-go`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-go - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-go - No version specified for "autorest". Defaulting to "latest".`, - `Azure/azure-sdk-for-go - Resolving "autorest" version "latest" to "2.0.4283".`, - `Azure/azure-sdk-for-go - Getting dist-tags for "@microsoft.azure/autorest.go" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.go/dist-tags"...`, - `Azure/azure-sdk-for-go - "@microsoft.azure/autorest.go@~2.1.131" contains version range symbols (such as "^", "~", and "*"). Version range symbols are not resolved by SDK Automation.`, - `Azure/azure-sdk-for-go - "@microsoft.azure/autorest.go@~2.1.131" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-go - ${goFolderPath}: ${autorest} --use=@microsoft.azure/autorest.go@~2.1.131 --go --verbose --multiapi --use-onever --preview-chk --go-sdk-folder=${goFolderPath} --version=2.0.4283 https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-go - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git add *`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-go - ${goFolderPath}: git reset *`, - `Azure/azure-sdk-for-go - The following files were changed:`, - `Azure/azure-sdk-for-go - ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/latest/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/latest/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/preview/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - ${goFolderPath}/profiles/preview/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-go - ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Package name for "${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql" is "mysql/mgmt/2017-12-01".`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Creating SDK generation branch "sdkAutomation/mysql/mgmt/2017-12-01@4994" based off of "master" in "Azure/azure-sdk-for-go"...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git checkout -b sdkAutomation/mysql/mgmt/2017-12-01@4994`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql: git add *`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - 7 files staged for commit:`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git checkout sdkAutomation/mysql/mgmt/2017-12-01@4994`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Running after_scripts...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: dep ensure`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Exit Code: 0`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: go generate ./profiles/generate.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Exit Code: 0`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: gofmt -w ./profiles/`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Exit Code: 0`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: gofmt -w ./services/`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Exit Code: 0`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git add *`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git commit -m "Modifications after running after_scripts"`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - ${goFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Exit Code: 0`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Output:`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/latest/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/mysql/mgmt/mysql/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - profiles/preview/servicebus/mgmt/servicebus/models.go`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Found 7 files that are different in the generation branch than its parent branch.`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Creating folder ${goFolderPath}/zip...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Not copying anything from the profiles folder since no profile files were changed.`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Copying ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql to ${goFolderPath}/zip/services/mysql/mgmt/2017-12-01/mysql...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Compressing ${goFolderPath}/zip to ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql/mysql.mgmt.2017-12-01.zip...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Deleting ${goFolderPath}/zip...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Uploading ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql/mysql.mgmt.2017-12-01.zip to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-go/mysql/mgmt/2017-12-01/mysql.mgmt.2017-12-01.zip...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Done uploading ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql/mysql.mgmt.2017-12-01.zip to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-go/mysql/mgmt/2017-12-01/mysql.mgmt.2017-12-01.zip.`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Creating package installation instructions...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/1/Azure/azure-sdk-for-go/mysql/mgmt/2017-12-01/instructions.md...`, - `Azure/azure-sdk-for-go - mysql/mgmt/2017-12-01 - Uploading package installation instructions to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-go/mysql/mgmt/2017-12-01/instructions.md...`, - `Azure/azure-sdk-for-go - Creating SDK repository artifact zip file (${goFolderPath}/azure.azure-sdk-for-go.artifacts.zip) from:`, - `Azure/azure-sdk-for-go - ${goFolderPath}/services/mysql/mgmt/2017-12-01/mysql/mysql.mgmt.2017-12-01.zip`, - `Azure/azure-sdk-for-go - Uploading SDK repository artifact zip file to https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/Azure/azure-sdk-for-go/azure.azure-sdk-for-go.artifacts.zip...`, - `Azure/azure-sdk-for-go - Deleting clone of Azure/azure-sdk-for-go at folder ${goFolderPath}...`, - `Azure/azure-sdk-for-go - Finished deleting clone of Azure/azure-sdk-for-go at folder ${goFolderPath}.`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-js ${jsFolderPath}`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-js`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-js`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-js`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-js - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-js - No version specified for "autorest". Defaulting to "latest".`, - `Azure/azure-sdk-for-js - Resolving "autorest" version "latest" to "2.0.4283".`, - `Azure/azure-sdk-for-js - Getting dist-tags for "@microsoft.azure/autorest.typescript" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.typescript/dist-tags"...`, - `Azure/azure-sdk-for-js - "@microsoft.azure/autorest.typescript@4.0.0" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: ${autorest} --typescript --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.typescript@4.0.0 --typescript-sdks-folder=${jsFolderPath} --version=2.0.4283 https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-js - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git add *`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-js - ${jsFolderPath}: git reset *`, - `Azure/azure-sdk-for-js - No changes were detected after AutoRest ran.`, - `Azure/azure-sdk-for-js - Deleting clone of Azure/azure-sdk-for-js at folder ${jsFolderPath}...`, - `Azure/azure-sdk-for-js - Finished deleting clone of Azure/azure-sdk-for-js at folder ${jsFolderPath}.`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git clone --quiet https://github.com/Azure/azure-sdk-for-node ${nodeFolderPath}`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git remote add generation https://github.com/Azure/azure-sdk-for-node`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git remote add integration https://github.com/Azure/azure-sdk-for-node`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git remote add main https://github.com/Azure/azure-sdk-for-node`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git fetch --all`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git checkout --track main/master -b main-master`, - `Azure/azure-sdk-for-node - Getting dist-tags for "autorest" from "https://registry.npmjs.org/-/package/autorest/dist-tags"...`, - `Azure/azure-sdk-for-node - No version specified for "autorest". Defaulting to "latest".`, - `Azure/azure-sdk-for-node - Resolving "autorest" version "latest" to "2.0.4283".`, - `Azure/azure-sdk-for-node - Getting dist-tags for "@microsoft.azure/autorest.nodejs" from "https://registry.npmjs.org/-/package/@microsoft.azure/autorest.nodejs/dist-tags"...`, - `Azure/azure-sdk-for-node - "@microsoft.azure/autorest.nodejs@2.2.131" does not have a dist-tag to resolve to.`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: ${autorest} --nodejs --license-header=MICROSOFT_MIT_NO_VERSION --use=@microsoft.azure/autorest.nodejs@2.2.131 --node-sdks-folder=${nodeFolderPath} --version=2.0.4283 https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md`, - `Azure/azure-sdk-for-node - Getting diff after AutoRest ran...`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git add *`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git --no-pager diff main/master --staged --ignore-all-space`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}: git reset *`, - `Azure/azure-sdk-for-node - The following files were changed:`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}/lib/services/mysqlManagement/lib/models/firewallRuleListResult.js`, - `Azure/azure-sdk-for-node - Found 1 package folder that changed:`, - `Azure/azure-sdk-for-node - ${nodeFolderPath}/lib/services/mysqlManagement`, - `Azure/azure-sdk-for-node - azure-arm-mysql - Package name for "${nodeFolderPath}/lib/services/mysqlManagement" is "azure-arm-mysql".`, - `Azure/azure-sdk-for-node - azure-arm-mysql - Creating SDK generation branch "sdkAutomation/azure-arm-mysql@4994" based off of "master" in "Azure/azure-sdk-for-node"...`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git checkout main-master`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git checkout -b sdkAutomation/azure-arm-mysql@4994`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}/lib/services/mysqlManagement: git add *`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-node - azure-arm-mysql - 0 files staged for commit:`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git commit -m "Generated from d82d1491879729cdf44da9a664e815112acde158" -m "hello world"`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git checkout sdkAutomation/azure-arm-mysql@4994`, - `Azure/azure-sdk-for-node - azure-arm-mysql - No after_scripts to run.`, - `Azure/azure-sdk-for-node - azure-arm-mysql - ${nodeFolderPath}: git --no-pager diff main/master --staged --name-only --ignore-all-space`, - `Azure/azure-sdk-for-node - azure-arm-mysql - Exit Code: 0`, - `Azure/azure-sdk-for-node - azure-arm-mysql - No differences were detected between the generation branch and its parent branch after the after_scripts were run.`, - `Azure/azure-sdk-for-node - No SDK repository artifact files detected.`, - `Azure/azure-sdk-for-node - Deleting clone of Azure/azure-sdk-for-node at folder ${nodeFolderPath}...`, - `Azure/azure-sdk-for-node - Finished deleting clone of Azure/azure-sdk-for-node at folder ${nodeFolderPath}.` - ]); - assert.strictEqual(await specificationPullRequest.dataBlob.exists(), true); - assert.strictEqual(await specificationPullRequest.generation.dataBlob.exists(), true); - assert.strictEqual(await specificationPullRequest.generation.commentHtmlBlob.exists(), true); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - } - }); - - describe('closeSDKGenerationPullRequests()', function() { - it('with no open generation pull requests', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.closeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open non-generation pull request', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: 'Azure:fake-head', - ref: 'fake-head', - sha: 'fake-head-sha' - }, - html_url: 'fake-html-url', - id: 1, - labels: [], - merge_commit_sha: 'fake-merge-commit-sha', - number: 2, - state: 'open', - title: 'fake-title', - url: 'fake-url' - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.closeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open generation pull request', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - automationWorkingPrefix, - testSpecificationPullRequestRepository, - testSpecificationPullRequest.number - ); - const dataBlob: BlobStorageBlockBlob = getDataBlob(pullRequestPrefix); - const iterationNumber = 5; - const generationPrefix: BlobStoragePrefix = getGenerationPrefix(pullRequestPrefix, iterationNumber); - const generationDataBlob: BlobStorageBlockBlob = getDataBlob(generationPrefix); - const generationLogsBlob: BlobStorageAppendBlob = getLogsBlob(generationPrefix); - await generationLogsBlob.create(); - const generationCommentBlob: BlobStorageBlockBlob = getCommentHtmlBlob(generationPrefix); - const specificationPullRequestData: SpecificationPullRequestData = { - baseBranch: getRepositoryBranch(testSpecificationPullRequest.base.label), - baseRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - dataBlobUrl: dataBlob.getURL(), - diffUrl: 'fake-diff-url', - headBranch: getRepositoryBranch(testSpecificationPullRequest.head.label), - headCommit: testSpecificationPullRequest.head.sha, - headRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.head.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - htmlUrl: 'fake-html-url', - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - specPRRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - title: 'fake-title', - generation: { - dataBlobUrl: generationDataBlob.getURL(), - logsBlobUrl: generationLogsBlob.getURL(), - commentHtmlBlobUrl: generationCommentBlob.getURL(), - number: iterationNumber, - sdkRepositories: [ - { - generationRepository: 'Azure/azure-sdk-for-go', - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - integrationBranchPrefix: 'sdkAutomationTest/', - integrationRepository: 'Azure/azure-sdk-for-go', - integrationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - languageName: 'Go', - mainBranch: 'latest', - mainRepository: 'Azure/azure-sdk-for-go', - mainRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - readmeMdFileUrlsToGenerate: [], - status: 'succeeded', - swaggerToSDKConfigFileUrl: getSwaggerToSDKConfigurationURL('Azure/azure-sdk-for-go', 'latest') - } - ] - } - }; - await dataBlob.setContentsFromString(JSON.stringify(specificationPullRequestData)); - - const goSDKRepositoryPrefix: BlobStoragePrefix = getSDKRepositoryPrefix( - generationPrefix, - 'Azure/azure-sdk-for-go' - ); - const goLogsBlob: BlobStorageAppendBlob = getLogsBlob(goSDKRepositoryPrefix); - await goLogsBlob.create(); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const specPRInProgressLabel: GitHubLabel = await github.createLabel( - 'Azure/azure-sdk-for-go', - 'SpecPRInProgress', - pullRequestLabelsInfo['SpecPRInProgress'].color - ); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: `Azure:fake-head@${testSpecificationPullRequest.number}`, - ref: `fake-head@${testSpecificationPullRequest.number}`, - sha: 'fake-head-sha' - }, - html_url: `https://github.com/Azure/azure-sdk-for-go/pull/1`, - id: 1, - labels: [specPRInProgressLabel], - merge_commit_sha: 'fake-merge-commit-sha', - number: 2, - state: 'open', - title: 'fake-title', - url: `https://api.github.com/repos/Azure/azure-sdk-for-go/pulls/1` - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.closeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json"...`, - `Azure/azure-sdk-for-go - Getting generation pull requests for specification pull request fake-html-url...`, - `Azure/azure-sdk-for-go - Closing pull request https://github.com/Azure/azure-sdk-for-go/pull/1...`, - `Azure/azure-sdk-for-go - Deleting branch "fake-head@4994" in Azure/azure-sdk-for-go...`, - `Azure/azure-sdk-for-go - Label changes for PR 2 in Azure/azure-sdk-for-go: +GenerationPR, +SpecPRClosed, -SpecPRInProgress` - ]); - - const fakePullRequestAfterClosing: GitHubPullRequest = await github.getPullRequest( - 'Azure/azure-sdk-for-go', - fakePullRequest.number - ); - assert.strictEqual(fakePullRequestAfterClosing.state, 'closed'); - assert.deepEqual( - map(fakePullRequestAfterClosing.labels, (label: GitHubLabel) => label.name), - ['GenerationPR', 'SpecPRClosed'] - ); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open generation pull request but disabled pull requestion automation', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - automationWorkingPrefix, - testSpecificationPullRequestRepository, - testSpecificationPullRequest.number - ); - const dataBlob: BlobStorageBlockBlob = getDataBlob(pullRequestPrefix); - const iterationNumber = 5; - const generationPrefix: BlobStoragePrefix = getGenerationPrefix(pullRequestPrefix, iterationNumber); - const generationDataBlob: BlobStorageBlockBlob = getDataBlob(generationPrefix); - const generationLogsBlob: BlobStorageAppendBlob = getLogsBlob(generationPrefix); - await generationLogsBlob.create(); - const generationCommentBlob: BlobStorageBlockBlob = getCommentHtmlBlob(generationPrefix); - const specificationPullRequestData: SpecificationPullRequestData = { - baseBranch: getRepositoryBranch(testSpecificationPullRequest.base.label), - baseRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - dataBlobUrl: dataBlob.getURL(), - diffUrl: 'fake-diff-url', - headBranch: getRepositoryBranch(testSpecificationPullRequest.head.label), - headCommit: testSpecificationPullRequest.head.sha, - headRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.head.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - htmlUrl: 'fake-html-url', - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - specPRRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - title: 'fake-title', - generation: { - dataBlobUrl: generationDataBlob.getURL(), - logsBlobUrl: generationLogsBlob.getURL(), - commentHtmlBlobUrl: generationCommentBlob.getURL(), - number: iterationNumber, - sdkRepositories: [ - { - generationRepository: 'Azure/azure-sdk-for-go', - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - integrationBranchPrefix: 'sdkAutomationTest/', - integrationRepository: 'Azure/azure-sdk-for-go', - integrationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - languageName: 'Go', - mainBranch: 'latest', - mainRepository: 'Azure/azure-sdk-for-go', - mainRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - readmeMdFileUrlsToGenerate: [], - status: 'succeeded', - swaggerToSDKConfigFileUrl: getSwaggerToSDKConfigurationURL('Azure/azure-sdk-for-go', 'latest') - } - ] - } - }; - await dataBlob.setContentsFromString(JSON.stringify(specificationPullRequestData)); - - const goSDKRepositoryPrefix: BlobStoragePrefix = getSDKRepositoryPrefix( - generationPrefix, - 'Azure/azure-sdk-for-go' - ); - const goLogsBlob: BlobStorageAppendBlob = getLogsBlob(goSDKRepositoryPrefix); - await goLogsBlob.create(); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const specPRInProgressLabel: GitHubLabel = await github.createLabel( - 'Azure/azure-sdk-for-go', - 'SpecPRInProgress', - pullRequestLabelsInfo['SpecPRInProgress'].color - ); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: `Azure:fake-head@${testSpecificationPullRequest.number}`, - ref: `fake-head@${testSpecificationPullRequest.number}`, - sha: 'fake-head-sha' - }, - html_url: `https://github.com/Azure/azure-sdk-for-go/pull/1`, - id: 1, - labels: [specPRInProgressLabel], - merge_commit_sha: 'fake-merge-commit-sha', - number: 2, - state: 'open', - title: 'fake-title', - url: `https://api.github.com/repos/Azure/azure-sdk-for-go/pulls/1` - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - advanced_options: { - disable_generation_pr_automation: true - } - } - }) - ); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.closeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json"...`, - `Azure/azure-sdk-for-go - Getting generation pull requests for specification pull request fake-html-url...`, - `Azure/azure-sdk-for-go - Skip to close generation pull request at https://github.com/Azure/azure-sdk-for-go/pull/1 as it's disabled in config.`, - `Azure/azure-sdk-for-go - Label changes for PR 2 in Azure/azure-sdk-for-go: +GenerationPR, +SpecPRClosed, -SpecPRInProgress` - ]); - - const fakePullRequestAfterClosing: GitHubPullRequest = await github.getPullRequest( - 'Azure/azure-sdk-for-go', - fakePullRequest.number - ); - assert.strictEqual(fakePullRequestAfterClosing.state, 'open'); - assert.deepEqual( - map(fakePullRequestAfterClosing.labels, (label: GitHubLabel) => label.name), - ['GenerationPR', 'SpecPRClosed'] - ); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - }); - - describe('mergeSDKGenerationPullRequests()', function() { - it('with no open generation pull requests', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.mergeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open non-generation pull request', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: 'Azure:fake-head', - ref: 'fake-head', - sha: 'fake-head-sha' - }, - html_url: 'fake-html-url', - id: 1, - labels: [], - merge_commit_sha: 'fake-merge-commit-sha', - number: 2, - state: 'open', - title: 'fake-title', - url: 'fake-url' - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.mergeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805` - ]); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open generation pull request', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - automationWorkingPrefix, - testSpecificationPullRequestRepository, - testSpecificationPullRequest.number - ); - const dataBlob: BlobStorageBlockBlob = getDataBlob(pullRequestPrefix); - const iterationNumber = 5; - const generationPrefix: BlobStoragePrefix = getGenerationPrefix(pullRequestPrefix, iterationNumber); - const generationDataBlob: BlobStorageBlockBlob = getDataBlob(generationPrefix); - const generationLogsBlob: BlobStorageAppendBlob = getLogsBlob(generationPrefix); - await generationLogsBlob.create(); - const generationCommentBlob: BlobStorageBlockBlob = getCommentHtmlBlob(generationPrefix); - const specificationPullRequestData: SpecificationPullRequestData = { - baseBranch: getRepositoryBranch(testSpecificationPullRequest.base.label), - baseRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - dataBlobUrl: dataBlob.getURL(), - diffUrl: 'fake-diff-url', - headBranch: getRepositoryBranch(testSpecificationPullRequest.head.label), - headCommit: testSpecificationPullRequest.head.sha, - headRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.head.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - htmlUrl: 'fake-html-url', - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - specPRRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - title: 'fake-title', - generation: { - dataBlobUrl: generationDataBlob.getURL(), - logsBlobUrl: generationLogsBlob.getURL(), - commentHtmlBlobUrl: generationCommentBlob.getURL(), - number: iterationNumber, - sdkRepositories: [ - { - generationRepository: 'Azure/azure-sdk-for-go', - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - integrationBranchPrefix: 'sdkAutomationTest/', - integrationRepository: 'Azure/azure-sdk-for-go', - integrationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - languageName: 'Go', - mainBranch: 'latest', - mainRepository: 'Azure/azure-sdk-for-go', - mainRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - readmeMdFileUrlsToGenerate: [], - status: 'succeeded', - swaggerToSDKConfigFileUrl: getSwaggerToSDKConfigurationURL('Azure/azure-sdk-for-go', 'latest') - } - ] - } - }; - await dataBlob.setContentsFromString(JSON.stringify(specificationPullRequestData)); - - const goSDKRepositoryPrefix: BlobStoragePrefix = getSDKRepositoryPrefix( - generationPrefix, - 'Azure/azure-sdk-for-go' - ); - const goLogsBlob: BlobStorageAppendBlob = getLogsBlob(goSDKRepositoryPrefix); - await goLogsBlob.create(); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const specPRInProgressLabel: GitHubLabel = await github.createLabel( - 'Azure/azure-sdk-for-go', - 'SpecPRInProgress', - pullRequestLabelsInfo['SpecPRInProgress'].color - ); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: `Azure:fake-head@${testSpecificationPullRequest.number}`, - ref: `fake-head@${testSpecificationPullRequest.number}`, - sha: 'fake-head-sha' - }, - html_url: `https://github.com/Azure/azure-sdk-for-go/pull/1`, - id: 1, - labels: [specPRInProgressLabel], - merge_commit_sha: 'fake-merge-commit-sha', - number: 1, - state: 'open', - title: 'fake-title', - url: `https://api.github.com/repos/Azure/azure-sdk-for-go/pulls/1` - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createCommit('Azure/azure-sdk-for-go', 'fake-latest-sha', 'test'); - await github.createBranch('Azure/azure-sdk-for-go', 'latest', 'fake-latest-sha'); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: HttpClient = createTestHttpClient(); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.mergeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json"...`, - `Azure/azure-sdk-for-go - Getting generation pull requests for specification pull request fake-html-url...`, - `Azure/azure-sdk-for-go - Merging https://github.com/Azure/azure-sdk-for-go/pull/1...`, - `Azure/azure-sdk-for-go - Deleting generation branch "fake-head@4994" from "Azure/azure-sdk-for-go"...`, - `Azure/azure-sdk-for-go - Label changes for PR 1 in Azure/azure-sdk-for-go: +GenerationPR, +SpecPRMerged, -SpecPRInProgress`, - `Azure/azure-sdk-for-go - Looking for integration pull requests that use "Azure:fake-base" as their head label...`, - `Azure/azure-sdk-for-go - Found no open integration pull requests that match. Creating a new integration pull request in "Azure/azure-sdk-for-go" from "Azure:fake-base" to "latest"...`, - `Azure/azure-sdk-for-go - maintainerCanModify: true`, - `Azure/azure-sdk-for-go - Created integration pull request at fake-html-url.`, - `Azure/azure-sdk-for-go - Label changes for PR 2 in Azure/azure-sdk-for-go: +IntegrationPR`, - `Azure/azure-sdk-for-go - Adding integration pull request link to generation pull request comment...` - ]); - - const fakePullRequestAfterMerging: GitHubPullRequest = await github.getPullRequest( - 'Azure/azure-sdk-for-go', - fakePullRequest.number - ); - assert.strictEqual(fakePullRequestAfterMerging.state, 'closed'); - assert.deepEqual( - map(fakePullRequestAfterMerging.labels, (label: GitHubLabel) => label.name), - ['GenerationPR', 'SpecPRMerged'] - ); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - - it('with open generation pull request but disabled generation pr automation', async function() { - const workingContainer: BlobStorageContainer = await createTestBlobStorageContainer(); - try { - const automationWorkingPrefix: BlobStoragePrefix = workingContainer; - await ensureStateImagesExist(automationWorkingPrefix); - - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - automationWorkingPrefix, - testSpecificationPullRequestRepository, - testSpecificationPullRequest.number - ); - const dataBlob: BlobStorageBlockBlob = getDataBlob(pullRequestPrefix); - const iterationNumber = 5; - const generationPrefix: BlobStoragePrefix = getGenerationPrefix(pullRequestPrefix, iterationNumber); - const generationDataBlob: BlobStorageBlockBlob = getDataBlob(generationPrefix); - const generationLogsBlob: BlobStorageAppendBlob = getLogsBlob(generationPrefix); - await generationLogsBlob.create(); - const generationCommentBlob: BlobStorageBlockBlob = getCommentHtmlBlob(generationPrefix); - const specificationPullRequestData: SpecificationPullRequestData = { - baseBranch: getRepositoryBranch(testSpecificationPullRequest.base.label), - baseRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - dataBlobUrl: dataBlob.getURL(), - diffUrl: 'fake-diff-url', - headBranch: getRepositoryBranch(testSpecificationPullRequest.head.label), - headCommit: testSpecificationPullRequest.head.sha, - headRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.head.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - htmlUrl: 'fake-html-url', - mergeCommit: testSpecificationPullRequestMergeCommitSha, - number: testSpecificationPullRequest.number, - specPRCommit: testSpecificationPullRequestMergeCommitSha, - specPRRepository: { - owner: getRepositoryBranch(testSpecificationPullRequest.base.label).owner, - name: getRepository(testSpecificationPullRequestRepository).name - }, - title: 'fake-title', - generation: { - dataBlobUrl: generationDataBlob.getURL(), - logsBlobUrl: generationLogsBlob.getURL(), - commentHtmlBlobUrl: generationCommentBlob.getURL(), - number: iterationNumber, - sdkRepositories: [ - { - generationRepository: 'Azure/azure-sdk-for-go', - generationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - integrationBranchPrefix: 'sdkAutomationTest/', - integrationRepository: 'Azure/azure-sdk-for-go', - integrationRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - languageName: 'Go', - mainBranch: 'latest', - mainRepository: 'Azure/azure-sdk-for-go', - mainRepositoryUrl: 'https://github.com/Azure/azure-sdk-for-go', - readmeMdFileUrlsToGenerate: [], - status: 'succeeded', - swaggerToSDKConfigFileUrl: getSwaggerToSDKConfigurationURL('Azure/azure-sdk-for-go', 'latest') - } - ] - } - }; - await dataBlob.setContentsFromString(JSON.stringify(specificationPullRequestData)); - - const goSDKRepositoryPrefix: BlobStoragePrefix = getSDKRepositoryPrefix( - generationPrefix, - 'Azure/azure-sdk-for-go' - ); - const goLogsBlob: BlobStorageAppendBlob = getLogsBlob(goSDKRepositoryPrefix); - await goLogsBlob.create(); - - const automationWorkingFolderPath: string = getAutomationWorkingFolderPath(getRootFolderPath()); - const generationWorkingFolderPath: string = await getGenerationWorkingFolderPath(automationWorkingFolderPath); - await deleteFolder(generationWorkingFolderPath); - try { - const github: FakeGitHub = await createTestGitHub(); - const specPRInProgressLabel: GitHubLabel = await github.createLabel( - 'Azure/azure-sdk-for-go', - 'SpecPRInProgress', - pullRequestLabelsInfo['SpecPRInProgress'].color - ); - const fakePullRequest: GitHubPullRequest = { - base: { - label: 'Azure:fake-base', - ref: 'fake-base', - sha: 'fake-base-sha' - }, - diff_url: 'fake-diff-url', - head: { - label: `Azure:fake-head@${testSpecificationPullRequest.number}`, - ref: `fake-head@${testSpecificationPullRequest.number}`, - sha: 'fake-head-sha' - }, - html_url: `https://github.com/Azure/azure-sdk-for-go/pull/1`, - id: 1, - labels: [specPRInProgressLabel], - merge_commit_sha: 'fake-merge-commit-sha', - number: 1, - state: 'open', - title: 'fake-title', - url: `https://api.github.com/repos/Azure/azure-sdk-for-go/pulls/1` - }; - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.head.sha, 'hello'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.head.ref, fakePullRequest.head.sha); - await github.createCommit('Azure/azure-sdk-for-go', fakePullRequest.base.sha, 'there'); - await github.createBranch('Azure/azure-sdk-for-go', fakePullRequest.base.ref, fakePullRequest.base.sha); - await github.createCommit('Azure/azure-sdk-for-go', 'fake-latest-sha', 'test'); - await github.createBranch('Azure/azure-sdk-for-go', 'latest', 'fake-latest-sha'); - await github.createFakePullRequest('Azure/azure-sdk-for-go', fakePullRequest); - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient = createTestHttpClient() as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - advanced_options: { - disable_generation_pr_automation: true - } - } - }) - ); - const runner: FakeRunner = createTestRunner({ - specificationPullRequest: testSpecificationPullRequest, - autorest: autorestExecutable({ autorestPath: joinPath(process.cwd(), 'node_modules/.bin/autorest') }), - generationWorkingFolderPath: generationWorkingFolderPath, - github - }); - const sdkAutomation = new SDKAutomation(automationWorkingFolderPath, { - github, - logger, - runner, - httpClient - }); - const specificationPullRequest: SpecificationPullRequest = await getSpecificationPullRequest( - sdkAutomation, - automationWorkingPrefix, - testSpecificationPullRequest, - false - ); - - await specificationPullRequest.mergeSDKGenerationPullRequests(); - - assert.deepEqual(logger.allLogs, [ - `Using provided GitHub.`, - `No provided Git. Using ExecutableGit instance.`, - `Using supported languages: [".NET","Go","Java","JavaScript","Python","Ruby"]`, - `Using provided HttpClient.`, - `No BlobProxy provided. Using a FakeBlobProxy.`, - `Received pull request change webhook request from GitHub for "https://github.com/Azure/azure-rest-api-specs/pull/4994".`, - `Using openapi-sdk-automation version ${await getOpenAPISDKAutomationVersion()}.`, - `Using FakeGitHub client.`, - `Getting generation state from https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/data.json...`, - `Pull request event contained mergeCommit: 5d204450e3ea6709a034208af441ebaaa87bd805`, - `Getting swagger_to_sdk_config.json file from "https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json"...`, - `Azure/azure-sdk-for-go - Getting generation pull requests for specification pull request fake-html-url...`, - `Azure/azure-sdk-for-go - Skip to merge generation pull request at https://github.com/Azure/azure-sdk-for-go/pull/1 as it's disabled in config.`, - `Azure/azure-sdk-for-go - Label changes for PR 1 in Azure/azure-sdk-for-go: +GenerationPR, +SpecPRMerged, -SpecPRInProgress`, - `Azure/azure-sdk-for-go - Looking for integration pull requests that use "Azure:fake-base" as their head label...`, - `Azure/azure-sdk-for-go - Found no open integration pull requests that match. Creating a new integration pull request in "Azure/azure-sdk-for-go" from "Azure:fake-base" to "latest"...`, - `Azure/azure-sdk-for-go - maintainerCanModify: true`, - `Azure/azure-sdk-for-go - Created integration pull request at fake-html-url.`, - `Azure/azure-sdk-for-go - Label changes for PR 2 in Azure/azure-sdk-for-go: +IntegrationPR`, - `Azure/azure-sdk-for-go - Adding integration pull request link to generation pull request comment...` - ]); - - const fakePullRequestAfterMerging: GitHubPullRequest = await github.getPullRequest( - 'Azure/azure-sdk-for-go', - fakePullRequest.number - ); - assert.strictEqual(fakePullRequestAfterMerging.state, 'open'); - assert.deepEqual( - map(fakePullRequestAfterMerging.labels, (label: GitHubLabel) => label.name), - ['GenerationPR', 'SpecPRMerged'] - ); - } finally { - if (deleteWorkingFolder) { - await deleteFolder(generationWorkingFolderPath); - } - } - } finally { - if (deleteWorkingContainer) { - await workingContainer.delete(); - } - } - }); - }); - - describe('getPullRequestPrefix()', function() { - it('with container prefix without trailing slash', function() { - const blobStorage = new InMemoryBlobStorage(); - const workingPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc'); - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - workingPrefix, - 'Azure/azure-rest-api-specs', - 4994 - ); - assert.strictEqual(pullRequestPrefix.storage, blobStorage); - assert.deepEqual(pullRequestPrefix.path, new BlobPath('abc', 'Azure/azure-rest-api-specs/4994/')); - assert.strictEqual(pullRequestPrefix.getURL(), 'https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/'); - }); - - it('with container prefix with trailing slash', function() { - const blobStorage = new InMemoryBlobStorage(); - const workingPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc/'); - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - workingPrefix, - 'Azure/azure-rest-api-specs', - 4994 - ); - assert.strictEqual(pullRequestPrefix.storage, blobStorage); - assert.deepEqual(pullRequestPrefix.path, new BlobPath('abc', 'Azure/azure-rest-api-specs/4994/')); - assert.strictEqual(pullRequestPrefix.getURL(), 'https://fake.storage.com/abc/Azure/azure-rest-api-specs/4994/'); - }); - - it('with container and blob prefix without trailing slash', function() { - const blobStorage = new InMemoryBlobStorage(); - const workingPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc/def'); - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - workingPrefix, - 'Azure/azure-rest-api-specs', - 4994 - ); - assert.strictEqual(pullRequestPrefix.storage, blobStorage); - assert.deepEqual(pullRequestPrefix.path, new BlobPath('abc', 'defAzure/azure-rest-api-specs/4994/')); - assert.strictEqual( - pullRequestPrefix.getURL(), - 'https://fake.storage.com/abc/defAzure/azure-rest-api-specs/4994/' - ); - }); - - it('with container and blob prefix with trailing slash', function() { - const blobStorage = new InMemoryBlobStorage(); - const workingPrefix: BlobStoragePrefix = blobStorage.getPrefix('abc/def/'); - const pullRequestPrefix: BlobStoragePrefix = getPullRequestPrefix( - workingPrefix, - 'Azure/azure-rest-api-specs', - 4994 - ); - assert.strictEqual(pullRequestPrefix.storage, blobStorage); - assert.deepEqual(pullRequestPrefix.path, new BlobPath('abc', 'def/Azure/azure-rest-api-specs/4994/')); - assert.strictEqual( - pullRequestPrefix.getURL(), - 'https://fake.storage.com/abc/def/Azure/azure-rest-api-specs/4994/' - ); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/specificationReadmeMdFileTests.ts b/tools/spec-gen-sdk/test/specificationReadmeMdFileTests.ts deleted file mode 100644 index 108b1aa47d5..00000000000 --- a/tools/spec-gen-sdk/test/specificationReadmeMdFileTests.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { - assertEx, - HttpClient, - NodeHttpClient, - ReadmeMdSwaggerToSDKConfiguration, - RepositoryConfiguration -} from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { SpecificationReadmeMdFile } from '../lib/specificationReadmeMdFile'; - -describe('specificationReadmeMdFile.ts', function() { - this.timeout(10000); - - it('constructor()', function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/my-repo'; - const versionRef = 'my/branch/name'; - const relativeFilePath = 'path/to/my/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - assert.strictEqual(specificationReadmeMdFile.relativeFilePath, relativeFilePath); - assert.strictEqual( - specificationReadmeMdFile.contentsUrl, - `https://raw.githubusercontent.com/${repository}/${versionRef}/${relativeFilePath}` - ); - assert.deepEqual(logger.allLogs, []); - }); - - describe('getContents()', function() { - it("when file doesn't exist", async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/my-repo'; - const versionRef = 'my/branch/name'; - const relativeFilePath = 'path/to/my/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - assert.strictEqual(await specificationReadmeMdFile.getContents(), undefined); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/my-repo/my/branch/name/path/to/my/readme.md"...`, - `Merged readme.md response status code is 404.` - ]); - }); - - it('when file exists', async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/azure-rest-api-specs'; - const versionRef = 'master'; - const relativeFilePath = 'specification/advisor/resource-manager/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - const contents: string = (await specificationReadmeMdFile.getContents())!; - assertEx.definedAndNotEmpty(contents, 'contents'); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/advisor/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.` - ]); - }); - }); - - describe('getSwaggerToSDKConfiguration()', function() { - it("when file doesn't exist", async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/my-repo'; - const versionRef = 'my/branch/name'; - const relativeFilePath = 'path/to/my/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - assert.strictEqual(await specificationReadmeMdFile.getSwaggerToSDKConfiguration(), undefined); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/my-repo/my/branch/name/path/to/my/readme.md"...`, - `Merged readme.md response status code is 404.`, - `Merged readme.md response body is empty.` - ]); - }); - - it("when file exists but doesn't have a swagger-to-sdk configuration section", async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/azure-rest-api-specs'; - const versionRef = 'master'; - const relativeFilePath = 'README.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - const swaggerToSDKConfiguration: ReadmeMdSwaggerToSDKConfiguration = (await specificationReadmeMdFile.getSwaggerToSDKConfiguration())!; - assertEx.defined(swaggerToSDKConfiguration, 'swaggerToSDKConfiguration'); - assert.deepEqual(swaggerToSDKConfiguration.repositories, []); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/README.md"...`, - `Merged readme.md response status code is 200.` - ]); - }); - - it('when file exists and has swagger-to-sdk configuration section', async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/azure-rest-api-specs'; - const versionRef = 'master'; - const relativeFilePath = 'specification/advisor/resource-manager/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - const swaggerToSDKConfiguration: ReadmeMdSwaggerToSDKConfiguration = (await specificationReadmeMdFile.getSwaggerToSDKConfiguration())!; - assertEx.defined(swaggerToSDKConfiguration, 'swaggerToSDKConfiguration'); - assertEx.defined(swaggerToSDKConfiguration.repositories, 'swaggerToSDKConfiguration.repositories'); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/advisor/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.` - ]); - }); - }); - - describe('getSwaggerToSDKRepositoryConfigurations()', function() { - it("when file doesn't exist", async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/my-repo'; - const versionRef = 'my/branch/name'; - const relativeFilePath = 'path/to/my/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - assert.strictEqual(await specificationReadmeMdFile.getSwaggerToSDKRepositoryConfigurations(), undefined); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/my-repo/my/branch/name/path/to/my/readme.md"...`, - `Merged readme.md response status code is 404.`, - `Merged readme.md response body is empty.` - ]); - }); - - it("when file exists but doesn't have a swagger-to-sdk configuration section", async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/azure-rest-api-specs'; - const versionRef = 'master'; - const relativeFilePath = 'README.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - const repositoryConfigurations: RepositoryConfiguration[] = (await specificationReadmeMdFile.getSwaggerToSDKRepositoryConfigurations())!; - assert.deepEqual(repositoryConfigurations, []); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/README.md"...`, - `Merged readme.md response status code is 200.`, - `Found 0 requested SDK repositories:` - ]); - }); - - it('when file exists and has swagger-to-sdk configuration section', async function() { - const httpClient: HttpClient = new NodeHttpClient(); - const logger: InMemoryLogger = getInMemoryLogger(); - const repository = 'Azure/azure-rest-api-specs'; - const versionRef = 'master'; - const relativeFilePath = 'specification/advisor/resource-manager/readme.md'; - const specificationReadmeMdFile = new SpecificationReadmeMdFile( - httpClient, - logger, - repository, - versionRef, - relativeFilePath - ); - const repositoryConfigurations: RepositoryConfiguration[] = (await specificationReadmeMdFile.getSwaggerToSDKRepositoryConfigurations())!; - assertEx.defined(repositoryConfigurations, 'repositoryConfigurations'); - assert.notDeepEqual(repositoryConfigurations, []); - assert.deepEqual(logger.allLogs, [ - `Getting file contents for "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/advisor/resource-manager/readme.md"...`, - `Merged readme.md response status code is 200.`, - `Found 6 requested SDK repositories:`, - ` azure-sdk-for-net`, - ` azure-sdk-for-python`, - ` azure-sdk-for-java`, - ` azure-sdk-for-go`, - ` azure-sdk-for-js`, - ` azure-sdk-for-node` - ]); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/specificationRepositoryConfigurationTests.ts b/tools/spec-gen-sdk/test/specificationRepositoryConfigurationTests.ts deleted file mode 100644 index 3d450f66e63..00000000000 --- a/tools/spec-gen-sdk/test/specificationRepositoryConfigurationTests.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { getInMemoryLogger, InMemoryLogger } from '@azure/logger-js'; -import { FakeHttpClient } from '@ts-common/azure-js-dev-tools'; -import { assert } from 'chai'; -import { - getSpecificationRepositoryConfiguration, - SpecificationRepositoryConfiguration -} from '../lib/specificationRepositoryConfiguration'; -import { createTestHttpClient } from './test'; - -describe('specificationRepositoryConfiguration.ts', () => { - describe('getSpecificationRepositoryConfiguration()', () => { - it("when specificationRepositoryConfiguration.json file doesn't exists", async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 404 - ); - - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - assert.strictEqual(specificationRepositoryConfiguration, undefined); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 404` - ]); - }); - - it('when specificationRepositoryConfiguration.json file exists but is empty', async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - '' - ); - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - - assert.strictEqual(specificationRepositoryConfiguration, undefined); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Specification repository configuration file exists, but it has no content.` - ]); - }); - - it('when specificationRepositoryConfiguration.json file exists but has non-JSON content', async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - 'hello!' - ); - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - - assert.strictEqual(specificationRepositoryConfiguration, undefined); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200`, - `Failed to parse the specification repository configuration file's contents.` - ]); - }); - - it(`when specificationRepositoryConfiguration.json file exists with {}`, async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({}) - ); - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - - assert.deepEqual(specificationRepositoryConfiguration, {}); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200` - ]); - }); - - it(`when specificationRepositoryConfiguration.json file exists with { sdkRepositoryMappings: {} }`, async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: {} - }) - ); - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - - assert.deepEqual(specificationRepositoryConfiguration, { - sdkRepositoryMappings: {} - }); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200` - ]); - }); - - it(`when specificationRepositoryConfiguration.json file exists with { sdkRepositoryMappings: { "azure-sdk-for-js": "Azure/azure-sdk-for-js" } }`, async () => { - const logger: InMemoryLogger = getInMemoryLogger(); - const httpClient: FakeHttpClient = createTestHttpClient(false) as FakeHttpClient; - httpClient.add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js' - } - }) - ); - const specificationRepositoryConfiguration: - | SpecificationRepositoryConfiguration - | undefined = await getSpecificationRepositoryConfiguration( - httpClient, - 'Azure/azure-rest-api-specs', - 'master', - logger - ); - - assert.deepEqual(specificationRepositoryConfiguration, { - sdkRepositoryMappings: { - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js' - } - }); - assert.deepEqual(logger.allLogs, [ - `Getting specification repository configuration from "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json"...`, - `Specification repository configuration response status code: 200` - ]); - }); - }); -}); diff --git a/tools/spec-gen-sdk/test/test.ts b/tools/spec-gen-sdk/test/test.ts deleted file mode 100644 index dc97333d257..00000000000 --- a/tools/spec-gen-sdk/test/test.ts +++ /dev/null @@ -1,1105 +0,0 @@ -import { - AzureBlobStorage, - BlobStorage, - BlobStorageContainer, - createFolder, - FakeGitHub, - FakeHttpClient, - FakeRepository, - FakeRunner, - GitHubPullRequest, - GitHubPullRequestCommit, - HttpClient, - InMemoryBlobStorage, - joinPath, - mvnExecutable, - NodeHttpClient, - npmExecutable, - writeFileContents -} from '@ts-common/azure-js-dev-tools'; -import { pullRequestLabelsInfo, PullRequestLabel } from '../lib/githubUtils'; - -export const storageUrl = `https://sdkautomationdev.blob.core.windows.net/`; -export const deleteWorkingFolder = true; -export const deleteWorkingContainer = true; - -export const testSpecificationPullRequestBaseCommit: GitHubPullRequestCommit = { - label: 'Azure:master', - ref: 'master', - sha: '1b8809ee779437bc13f9af9373a5d47472a6b889' -}; - -export const testSpecificationPullRequestHeadCommit: GitHubPullRequestCommit = { - label: 'pixia:master', - ref: 'master', - sha: 'd82d1491879729cdf44da9a664e815112acde158' -}; - -export const testSpecificationPullRequestMergeCommitSha = '5d204450e3ea6709a034208af441ebaaa87bd805'; -export const testSpecificationPullRequestNumber = 4994; -export const testSpecificationPullRequestRepository = 'Azure/azure-rest-api-specs'; - -export const testSpecificationPullRequest: GitHubPullRequest = { - base: testSpecificationPullRequestBaseCommit, - head: testSpecificationPullRequestHeadCommit, - merge_commit_sha: testSpecificationPullRequestMergeCommitSha, - id: 242467286, - labels: [], - number: testSpecificationPullRequestNumber, - state: 'closed', - title: 'Fix mysql sku values', - url: `https://api.github.com/repos/${testSpecificationPullRequestRepository}/pulls/${testSpecificationPullRequestNumber}`, - html_url: `https://github.com/${testSpecificationPullRequestRepository}/pull/${testSpecificationPullRequestNumber}`, - diff_url: `https://github.com/${testSpecificationPullRequestRepository}/pull/${testSpecificationPullRequestNumber}.diff`, - milestone: undefined, - assignees: undefined -}; - -export function createTestBlobStorage(real?: boolean): BlobStorage { - return real ? new AzureBlobStorage(storageUrl) : new InMemoryBlobStorage(); -} - -export function getTestBlobStorageContainer(real?: boolean): BlobStorageContainer { - const blobStorage: BlobStorage = createTestBlobStorage(real); - return blobStorage.getContainer('abc'); -} - -export async function createTestBlobStorageContainer(real?: boolean): Promise { - const container: BlobStorageContainer = getTestBlobStorageContainer(real); - await container.create({ accessPolicy: 'container' }); - return container; -} - -export async function createTestGitHub(): Promise { - const result = new FakeGitHub(); - await result.createUser('fake_user'); - await result.setCurrentUser('fake_user'); - - await result.createRepository(testSpecificationPullRequestRepository); - await result.createCommit( - testSpecificationPullRequestRepository, - testSpecificationPullRequestBaseCommit.sha, - 'hello world again' - ); - await result.createBranch( - testSpecificationPullRequestRepository, - testSpecificationPullRequestBaseCommit.ref, - testSpecificationPullRequestBaseCommit.sha - ); - - const fork: FakeRepository = await result.forkRepository(testSpecificationPullRequestRepository, 'pixia'); - await result.createCommit(fork.name, testSpecificationPullRequestHeadCommit.sha, 'hello world'); - await result.createBranch( - fork.name, - testSpecificationPullRequestHeadCommit.ref, - testSpecificationPullRequestHeadCommit.sha - ); - - await result.createFakePullRequest(testSpecificationPullRequestRepository, testSpecificationPullRequest); - - await result.createRepository('Azure/azure-sdk-for-python'); - await result.createCommit('Azure/azure-sdk-for-python', 'fake-python-master-commit', 'abc'); - await result.createCommit('Azure/azure-sdk-for-python', 'fake-python-non-master-commit', 'def'); - await result.createCommit('Azure/azure-sdk-for-python', 'fake-branch-commit-sha', 'def'); - await result.createBranch('Azure/azure-sdk-for-python', 'master', 'fake-python-master-commit'); - await result.createBranch('Azure/azure-sdk-for-python', 'non-master', 'fake-python-non-master-commit'); - await result.createBranch( - 'Azure/azure-sdk-for-python', - 'Azure/azure-sdk-for-python:non-master', - 'fake-python-non-master-commit' - ); - await result.createBranch('Azure/azure-sdk-for-python', 'sdkAutomation/azure-mgmt-rdbms', 'fake-branch-commit-sha'); - await result.createBranch( - 'Azure/azure-sdk-for-python', - 'sdkAutomation/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - await result.createBranch('Azure/azure-sdk-for-python', 'apples/azure-mgmt-rdbms@4994', 'fake-branch-commit-sha'); - - await result.forkRepository('Azure/azure-sdk-for-python', 'integration'); - await result.createCommit('integration/azure-sdk-for-python', 'fake-branch-commit-sha', 'def'); - await result.createBranch('integration/azure-sdk-for-python', 'master', 'fake-branch-commit-sha'); - await result.createBranch( - 'integration/azure-sdk-for-python', - 'sdkAutomation/azure-mgmt-rdbms', - 'fake-branch-commit-sha' - ); - await result.createBranch( - 'integration/azure-sdk-for-python', - 'sdkAutomation/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - await result.createBranch('integration/azure-sdk-for-python', 'apples/azure-mgmt-rdbms', 'fake-branch-commit-sha'); - await result.createBranch( - 'integration/azure-sdk-for-python', - 'apples/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - await result.createBranch( - 'integration/azure-sdk-for-python', - 'sdkAutomationTest/azure-mgmt-rdbms', - 'fake-branch-commit-sha' - ); - await result.createBranch( - 'integration/azure-sdk-for-python', - 'sdkAutomationTest/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - - await result.forkRepository('integration/azure-sdk-for-python', 'generation'); - await result.createCommit('generation/azure-sdk-for-python', 'fake-branch-commit-sha', 'def'); - await result.createBranch('generation/azure-sdk-for-python', 'master', 'fake-branch-commit-sha'); - await result.createBranch( - 'generation/azure-sdk-for-python', - 'sdkAutomation/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - await result.createBranch('generation/azure-sdk-for-python', 'apples/azure-mgmt-rdbms', 'fake-branch-commit-sha'); - await result.createBranch( - 'generation/azure-sdk-for-python', - 'apples/azure-mgmt-rdbms@4994', - 'fake-branch-commit-sha' - ); - - await result.createRepository('Azure/azure-sdk-for-java'); - await result.createCommit('Azure/azure-sdk-for-java', 'fake-java-commit-sha', 'fake-message'); - await result.createBranch('Azure/azure-sdk-for-java', 'master', 'fake-java-commit-sha'); - - await result.createRepository('Azure/azure-sdk-for-go'); - await result.createCommit('Azure/azure-sdk-for-go', 'fake-go-commit-sha', 'fake-message'); - await result.createBranch('Azure/azure-sdk-for-go', 'master', 'fake-go-commit-sha'); - - await result.createRepository('Azure/azure-sdk-for-js'); - await result.createCommit('Azure/azure-sdk-for-js', 'fake-js-commit-sha', 'fake-message'); - await result.createBranch('Azure/azure-sdk-for-js', 'master', 'fake-js-commit-sha'); - - await result.createRepository('Azure/azure-sdk-for-node'); - await result.createCommit('Azure/azure-sdk-for-node', 'fake-node-commit-sha', 'fake-message'); - await result.createBranch('Azure/azure-sdk-for-node', 'master', 'fake-node-commit-sha'); - - for (const repository of [ - 'Azure/azure-sdk-for-python', - 'Azure/azure-sdk-for-java', - 'Azure/azure-sdk-for-go', - 'Azure/azure-sdk-for-js', - 'Azure/azure-sdk-for-node' - ]) { - for (const labelName of Object.keys(pullRequestLabelsInfo) as PullRequestLabel[]) { - const labelInfo = pullRequestLabelsInfo[labelName]; - await result.createLabel(repository, labelName, labelInfo.color); - } - } - - return result; -} - -export function createTestHttpClient(real?: boolean): HttpClient { - return real - ? new NodeHttpClient() - : new FakeHttpClient() - .add( - 'GET', - 'https://registry.npmjs.org/-/package/autorest/dist-tags', - 200, - undefined, - `{"latest":"2.0.4283","last":"2.0.4215","previous":"2.0.4215","preview":"2.0.4302","beta":"3.0.5196"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.python/dist-tags', - 200, - undefined, - `{"latest":"3.0.52","preview":"4.0.68"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.java/dist-tags', - 200, - undefined, - `{"latest":"2.1.0","preview":"2.1.85"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.go/dist-tags', - 200, - undefined, - `{"latest":"2.0.24","preview":"3.0.48","HEAD":"2.1.131","v3":"3.0.63"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.nodejs/dist-tags', - 200, - undefined, - `{"latest":"2.2.131","preview":"2.2.146"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.typescript/dist-tags', - 200, - undefined, - `{"latest":"4.0.0"}` - ) - .add( - 'GET', - 'https://registry.npmjs.org/-/package/@microsoft.azure/autorest.ruby/dist-tags', - 200, - undefined, - `{"latest":"3.0.20","preview":"3.1.40"}` - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specificationRepositoryConfiguration.json', - 200, - undefined, - JSON.stringify({ - sdkRepositoryMappings: { - 'azure-sdk-for-python': 'Azure/azure-sdk-for-python', - 'azure-sdk-for-java': 'Azure/azure-sdk-for-java', - 'azure-sdk-for-go': 'Azure/azure-sdk-for-go', - 'azure-sdk-for-js': 'Azure/azure-sdk-for-js', - 'azure-sdk-for-node': 'Azure/azure-sdk-for-node' - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/fake/js-sdk-repository/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - typescript: '', - 'license-header': 'MICROSOFT_MIT_NO_VERSION', - 'sdkrel:typescript-sdks-folder': '.', - use: '@microsoft.azure/autorest.typescript@4.0.0' - }, - advanced_options: { - create_sdk_pull_requests: true - } - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-js/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - typescript: '', - 'license-header': 'MICROSOFT_MIT_NO_VERSION', - 'sdkrel:typescript-sdks-folder': '.', - use: '@microsoft.azure/autorest.typescript@4.0.0' - }, - advanced_options: { - clone_dir: 'azure-sdk-for-js', - create_sdk_pull_requests: true - } - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - version: 'preview', - use: '@microsoft.azure/autorest.python@~3.0.56', - python: '', - 'python-mode': 'update', - multiapi: '', - 'sdkrel:python-sdks-folder': '.' - } - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-python/non-master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - version: 'preview', - use: '@microsoft.azure/autorest.python@~3.0.56', - python: '', - 'python-mode': 'update', - multiapi: '', - 'sdkrel:python-sdks-folder': '.' - } - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-go/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - after_scripts: [ - 'dep ensure', - 'go generate ./profiles/generate.go', - 'gofmt -w ./profiles/', - 'gofmt -w ./services/' - ], - autorest_options: { - use: '@microsoft.azure/autorest.go@~2.1.131', - go: '', - verbose: '', - 'sdkrel:go-sdk-folder': '.', - multiapi: '', - 'use-onever': '', - 'preview-chk': '' - }, - repotag: 'azure-sdk-for-go', - envs: { - 'sdkrel:GOPATH': '../../../..' - }, - advanced_options: { - clone_dir: './src/github.com/Azure/azure-sdk-for-go' - }, - version: '0.2.0' - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-go/latest/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - after_scripts: [ - 'dep ensure', - 'go generate ./profiles/generate.go', - 'gofmt -w ./profiles/', - 'gofmt -w ./services/' - ], - autorest_options: { - use: '@microsoft.azure/autorest.go@~2.1.131', - go: '', - verbose: '', - 'sdkrel:go-sdk-folder': '.', - multiapi: '', - 'use-onever': '', - 'preview-chk': '' - }, - repotag: 'azure-sdk-for-go', - envs: { - 'sdkrel:GOPATH': '../../../..' - }, - advanced_options: { - clone_dir: './src/github.com/Azure/azure-sdk-for-go' - }, - version: '0.2.0' - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - java: '', - verbose: '', - multiapi: '', - 'sdkrel:azure-libraries-for-java-folder': '.', - use: '@microsoft.azure/autorest.java@2.1.85' - } - } - }) - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-sdk-for-node/master/swagger_to_sdk_config.json', - 200, - undefined, - JSON.stringify({ - meta: { - autorest_options: { - nodejs: '', - 'license-header': 'MICROSOFT_MIT_NO_VERSION', - use: '@microsoft.azure/autorest.nodejs@2.2.131', - 'sdkrel:node-sdks-folder': '.' - }, - advanced_options: { - clone_dir: 'azure-sdk-for-node' - } - } - }) - ) - .add( - 'GET', - testSpecificationPullRequest.diff_url, - 200, - undefined, - ` -diff --git a/specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json b/specification/mysql/resource-manager/Microsoft.DBforMySQL/preview/2017-12-01-preview/examples/ServerCreate.json -diff --git a/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json b/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreate.json -diff --git a/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json b/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateGeoRestoreMode.json -diff --git a/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json b/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreatePointInTimeRestore.json -diff --git a/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json b/specification/mysql/resource-manager/Microsoft.DBforMySQL/stable/2017-12-01/examples/ServerCreateReplicaMode.json` - ) - .add( - 'HEAD', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md', - 200, - undefined, - '' - ) - .add( - 'GET', - 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5d204450e3ea6709a034208af441ebaaa87bd805/specification/mysql/resource-manager/readme.md', - 200, - undefined, - ` -\`\`\`yaml $(swagger-to-sdk) -swagger-to-sdk: - - repo: azure-sdk-for-python - - repo: azure-sdk-for-java - - repo: azure-sdk-for-go - - repo: azure-sdk-for-js - - repo: azure-sdk-for-node -\`\`\`` - ) - .add('HEAD', 'https://github.com/Azure/azure-sdk-for-js') - .add('HEAD', 'https://github.com/Azure/azure-sdk-for-python') - .add('HEAD', 'https://github.com/Azure/azure-sdk-for-go') - .add('HEAD', 'https://github.com/Azure/azure-sdk-for-java') - .add('HEAD', 'https://github.com/Azure/azure-sdk-for-node'); -} - -export interface CreateTestRunnerOptions { - specificationPullRequest: GitHubPullRequest; - autorest: string; - generationWorkingFolderPath: string; - github: FakeGitHub; - real?: boolean; -} - -export function createTestRunner(options: CreateTestRunnerOptions): FakeRunner { - const pythonFolderPath: string = joinPath(options.generationWorkingFolderPath, '1'); - const javaFolderPath: string = joinPath(options.generationWorkingFolderPath, '2'); - const goFolderPath: string = joinPath(options.generationWorkingFolderPath, 'src/github.com/Azure/azure-sdk-for-go'); - const nodeFolderPath: string = joinPath(options.generationWorkingFolderPath, 'azure-sdk-for-node'); - const jsFolderPath: string = joinPath(options.generationWorkingFolderPath, 'azure-sdk-for-js'); - const rubyFolderPath: string = joinPath(options.generationWorkingFolderPath, '6'); - - const runner = new FakeRunner(); - - runner.set({ - executable: 'git', - args: ['remote', 'add', 'generation', 'https://github.com/Azure/azure-sdk-for-python'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'generation', 'https://github.com/generation/azure-sdk-for-python'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'generation', 'https://github.com/integration/azure-sdk-for-python'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'generation', 'https://github.com/Azure/azure-sdk-for-java'] - }); - runner.set({ executable: 'git', args: ['remote', 'add', 'generation', 'https://github.com/Azure/azure-sdk-for-go'] }); - runner.set({ executable: 'git', args: ['remote', 'add', 'generation', 'https://github.com/Azure/azure-sdk-for-js'] }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'generation', 'https://github.com/Azure/azure-sdk-for-node'] - }); - - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/Azure/azure-sdk-for-python'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/Azure/azure-sdk-for-java'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/Azure/azure-sdk-for-go'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/Azure/azure-sdk-for-js'] - }); - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/Azure/azure-sdk-for-node'] - }); - - runner.set({ - executable: 'git', - args: ['remote', 'add', 'integration', 'https://github.com/integration/azure-sdk-for-python'] - }); - - runner.set({ executable: 'git', args: ['remote', 'add', 'main', 'https://github.com/Azure/azure-sdk-for-python'] }); - runner.set({ executable: 'git', args: ['remote', 'add', 'main', 'https://github.com/Azure/azure-sdk-for-java'] }); - runner.set({ executable: 'git', args: ['remote', 'add', 'main', 'https://github.com/Azure/azure-sdk-for-go'] }); - runner.set({ executable: 'git', args: ['remote', 'add', 'main', 'https://github.com/Azure/azure-sdk-for-js'] }); - runner.set({ executable: 'git', args: ['remote', 'add', 'main', 'https://github.com/Azure/azure-sdk-for-node'] }); - - runner.set({ executable: 'git', args: ['fetch', '--all'] }); - - runner.set({ executable: 'git', args: ['checkout', '--track', 'integration/sdkAutomation/azure-mgmt-rdbms'] }); - runner.set({ executable: 'git', args: ['checkout', '--track', 'integration/sdkAutomationTest/azure-mgmt-rdbms'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomationMainBranch'] }); - - runner.set({ executable: `git`, args: ['pull'] }); - - runner.set({ executable: `git`, args: ['push'] }); - runner.set({ - executable: `git`, - args: ['push', '--set-upstream', 'generation', 'sdkAutomation/azure-mgmt-rdbms@4994', '--force'] - }); - runner.set({ - executable: `git`, - args: ['push', '--set-upstream', 'generation', 'apples/azure-mgmt-rdbms@4994', '--force'] - }); - runner.set({ - executable: `git`, - args: ['push', '--set-upstream', 'generation', 'sdkAutomationTest/azure-mgmt-rdbms@4994', '--force'] - }); - runner.set({ - executable: 'git', - args: ['config', '--get', 'remote.origin.url'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stderr: '', - stdout: 'https://github.com/Azure/azure-sdk-for-python' - } - }); - - if (options.real) { - runner.passthroughUnrecognized(); - } else { - runner.set({ executable: `git`, args: ['branch'], result: { exitCode: 0, stdout: '* master' } }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'branch', '--remotes'], - result: { - exitCode: 0, - stdout: `integration/sdkAutomation/azure-mgmt-rdbms -integration/apples/azure-mgmt-rdbms -integration/sdkAutomationTest/azure-mgmt-rdbms` - } - }); - runner.set({ executable: `git`, args: ['checkout', '--track', 'main/non-master', '-b', 'main-non-master'] }); - runner.set({ executable: `git`, args: ['checkout', '--track', 'main/master', '-b', 'main-master'] }); - runner.set({ executable: `git`, args: ['checkout', 'main-master'] }); - runner.set({ executable: `git`, args: ['checkout', 'main-non-master'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'apples/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'apples/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '--track', 'integration/apples/azure-mgmt-rdbms'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomationTest/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomationTest/azure-mgmt-rdbms@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/azure-mgmt-rdbms'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/azure-mgmt-rdbms'] }); - runner.set({ - executable: `git`, - args: ['checkout', '-b', 'sdkAutomation/mysql/resource-manager/v2017_12_01@4994'] - }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/mysql/resource-manager/v2017_12_01@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/mysql/resource-manager/v2017_12_01'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/mysql/resource-manager/v2017_12_01'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/mysql/mgmt/2017-12-01@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/mysql/mgmt/2017-12-01@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/mysql/mgmt/2017-12-01'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/mysql/mgmt/2017-12-01'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/azure-arm-mysql@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/azure-arm-mysql@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/azure-arm-mysql'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/azure-arm-mysql'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/@azure/arm-mysql@4994'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/@azure/arm-mysql@4994'] }); - runner.set({ executable: `git`, args: ['checkout', '-b', 'sdkAutomation/@azure/arm-mysql'] }); - runner.set({ executable: `git`, args: ['checkout', 'sdkAutomation/@azure/arm-mysql'] }); - runner.set({ executable: `git`, args: ['commit', '-m', 'Modifications after running after_scripts'] }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/integration/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/integration/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/generation/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/generation/azure-sdk-for-python', pythonFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'setup.py'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-java', javaFolderPath], - result: async () => { - const mySqlPackageFolderPath: string = joinPath(javaFolderPath, 'mysql/resource-manager/v2017_12_01'); - await createFolder(mySqlPackageFolderPath); - await writeFileContents(joinPath(mySqlPackageFolderPath, 'pom.xml'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-go', goFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(goFolderPath, 'services/mysql/mgmt/2017-12-01/mysql'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'client.go'), ''); - await createFolder(joinPath(goFolderPath, 'profiles')); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-node', nodeFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(nodeFolderPath, 'lib/services/mysqlManagement'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'package.json'), `{"name": "azure-arm-mysql"}`); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-js', jsFolderPath], - result: async () => { - const packageFolderPath: string = joinPath(jsFolderPath, 'packages/@azure/arm-mysql'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'package.json'), `{"name":"@azure/arm-mysql"}`); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['clone', '--quiet', 'https://github.com/Azure/azure-sdk-for-ruby', rubyFolderPath] - }); - runner.set({ - executable: options.autorest, - args: [ - '--version=2.0.4302', - '--use=@microsoft.azure/autorest.python@~3.0.56', - '--python', - '--python-mode=update', - '--multiapi', - `--python-sdks-folder=${pythonFolderPath}`, - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: options.autorest, - args: [ - '--java', - '--verbose', - '--multiapi', - '--use=@microsoft.azure/autorest.java@2.1.85', - `--azure-libraries-for-java-folder=${javaFolderPath}`, - '--version=2.0.4283', - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: options.autorest, - args: [ - `--use=@microsoft.azure/autorest.go@~2.1.131`, - `--go`, - `--verbose`, - `--multiapi`, - `--use-onever`, - `--preview-chk`, - `--go-sdk-folder=${goFolderPath}`, - `--version=2.0.4283`, - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: options.autorest, - args: [ - `--nodejs`, - `--license-header=MICROSOFT_MIT_NO_VERSION`, - `--use=@microsoft.azure/autorest.nodejs@2.2.131`, - `--node-sdks-folder=${nodeFolderPath}`, - `--version=2.0.4283`, - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: options.autorest, - args: [ - '--typescript', - '--license-header=MICROSOFT_MIT_NO_VERSION', - '--use=@microsoft.azure/autorest.typescript@4.0.0', - `--typescript-sdks-folder=${jsFolderPath}`, - '--version=2.0.4283', - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: options.autorest, - args: [ - '--version=preview', - '--use=@microsoft.azure/autorest.ruby@3.0.20', - '--ruby', - '--multiapi', - `--ruby-sdks-folder=${rubyFolderPath}`, - `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/${options.specificationPullRequest.merge_commit_sha}/specification/mysql/resource-manager/readme.md` - ] - }); - runner.set({ - executable: `git`, - args: ['checkout', 'package.json'] - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--ignore-all-space'], - executionFolderPath: goFolderPath, - result: { - exitCode: 0, - stdout: `diff --git a/services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go b/services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go -diff --git a/profiles/latest/mysql/mgmt/mysql/models.go b/profiles/latest/mysql/mgmt/mysql/models.go -diff --git a/profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go b/profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go -diff --git a/profiles/latest/servicebus/mgmt/servicebus/models.go b/profiles/latest/servicebus/mgmt/servicebus/models.go -diff --git a/profiles/preview/mysql/mgmt/mysql/models.go b/profiles/preview/mysql/mgmt/mysql/models.go -diff --git a/profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go b/profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go -diff --git a/profiles/preview/servicebus/mgmt/servicebus/models.go b/profiles/preview/servicebus/mgmt/servicebus/models.go` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--name-only', '--ignore-all-space'], - executionFolderPath: goFolderPath, - result: { - exitCode: 0, - stdout: `services/mysql/mgmt/2017-12-01/mysql/locationbasedperformancetier.go -profiles/latest/mysql/mgmt/mysql/models.go -profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go -profiles/latest/servicebus/mgmt/servicebus/models.go -profiles/preview/mysql/mgmt/mysql/models.go -profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go -profiles/preview/servicebus/mgmt/servicebus/models.go` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--ignore-all-space'], - executionFolderPath: nodeFolderPath, - result: { - exitCode: 0, - stdout: `diff --git a/lib/services/mysqlManagement/lib/models/firewallRuleListResult.js b/lib/services/mysqlManagement/lib/models/firewallRuleListResult.js` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--name-only', '--ignore-all-space'], - executionFolderPath: nodeFolderPath, - result: { - exitCode: 0, - stdout: `` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--ignore-all-space'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `diff --git a/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py b/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--name-only', '--ignore-all-space'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/non-master', '--staged', '--ignore-all-space'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `diff --git a/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py b/azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/non-master', '--staged', '--name-only', '--ignore-all-space'], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: [ - '--no-pager', - 'diff', - 'integration/sdkAutomation/azure-mgmt-rdbms', - '--staged', - '--name-only', - '--ignore-all-space' - ], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: [ - '--no-pager', - 'diff', - 'integration/sdkAutomationTest/azure-mgmt-rdbms', - '--staged', - '--name-only', - '--ignore-all-space' - ], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: [ - '--no-pager', - 'diff', - 'integration/apples/azure-mgmt-rdbms', - '--staged', - '--name-only', - '--ignore-all-space' - ], - executionFolderPath: pythonFolderPath, - result: { - exitCode: 0, - stdout: `azure-mgmt-rdbms/azure/mgmt/rdbms/mysql/operations/servers_operations.py` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--ignore-all-space'], - executionFolderPath: jsFolderPath, - result: { - exitCode: 0 - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--ignore-all-space'], - executionFolderPath: javaFolderPath, - result: { - exitCode: 0, - stdout: `diff --git a/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java b/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java -diff --git a/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java b/mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java` - } - }); - runner.set({ - executable: `git`, - args: ['--no-pager', 'diff', 'main/master', '--staged', '--name-only', '--ignore-all-space'], - executionFolderPath: javaFolderPath, - result: { - exitCode: 0, - stdout: `mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/CheckNameAvailabilitys.java -mysql/resource-manager/v2017_12_01/src/main/java/com/microsoft/azure/management/mysql/v2017_12_01/Configuration.java` - } - }); - runner.set({ - executable: npmExecutable(), - args: ['pack'], - executionFolderPath: joinPath(jsFolderPath, 'packages/@azure/arm-mysql'), - result: async () => { - const packageFolderPath: string = joinPath(jsFolderPath, 'packages/@azure/arm-mysql'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'azure-arm-mysql-3.2.0.tgz'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: npmExecutable(), - args: ['pack'], - executionFolderPath: joinPath(nodeFolderPath, 'lib/services/mysqlManagement'), - result: async () => { - const packageFolderPath: string = joinPath(nodeFolderPath, 'lib/services/mysqlManagement'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'azure-arm-mysql-3.2.0.tgz'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: mvnExecutable(), - args: [ - 'source:jar', - 'javadoc:jar', - 'package', - '-f', - joinPath(javaFolderPath, 'mysql/resource-manager/v2017_12_01'), - '-DskipTests', - '--batch-mode' - ], - result: () => { - return { exitCode: 1 }; - } - }); - runner.set({ - executable: `python`, - args: ['./build_package.py', '--dest', joinPath(pythonFolderPath, 'azure-mgmt-rdbms'), 'azure-mgmt-rdbms'], - result: async () => { - const packageFolderPath: string = joinPath(pythonFolderPath, 'azure-mgmt-rdbms'); - await createFolder(packageFolderPath); - await writeFileContents(joinPath(packageFolderPath, 'fake-python-package.whl'), ''); - return { exitCode: 0 }; - } - }); - runner.set({ - executable: `git`, - args: ['checkout', '-b', 'sdkAutomation/@azure/arm-mysql'], - executionFolderPath: jsFolderPath - }); - runner.set({ - executable: `git`, - args: ['checkout', '-b', 'sdkAutomation/@azure/arm-mysql/4994'], - executionFolderPath: jsFolderPath - }); - runner.set({ - executable: `git`, - args: ['checkout', '-b', 'restapi_auto_mysql/resource-manager'], - executionFolderPath: jsFolderPath - }); - runner.set({ - executable: `git`, - args: ['checkout', '-b', `restapi_auto_${options.specificationPullRequest.number}`], - executionFolderPath: jsFolderPath - }); - runner.set({ executable: `git`, args: ['add', '*'] }); - runner.set({ executable: `git`, args: ['reset', '*'] }); - runner.set({ - executable: `git`, - args: ['commit', '-m', `Generated from ${options.specificationPullRequest.head.sha}`, '-m', 'hello world'] - }); - runner.set({ - executable: 'git', - args: ['rebase', '--strategy-option=theirs', 'main/master'] - }); - runner.set({ - executable: 'git', - args: ['rebase', '--strategy-option=theirs', 'sdkAutomation/azure-mgmt-rdbms'] - }); - runner.set({ - executable: 'git', - args: ['rebase', '--strategy-option=theirs', 'sdkAutomationTest/azure-mgmt-rdbms'] - }); - runner.set({ - executable: 'git', - args: ['rebase', '--strategy-option=theirs', 'apples/azure-mgmt-rdbms'] - }); - runner.set({ executable: 'dep', args: ['ensure'] }); - runner.set({ - executable: 'go', - args: ['generate', './profiles/generate.go'], - result: async () => { - await createFolder(joinPath(goFolderPath, 'profiles/latest/mysql/mgmt/mysql/')); - await writeFileContents(joinPath(goFolderPath, 'profiles/latest/mysql/mgmt/mysql/models.go'), 'contents'); - - await createFolder(joinPath(goFolderPath, 'profiles/latest/mysql/mgmt/mysql/mysqlapi/')); - await writeFileContents( - joinPath(goFolderPath, 'profiles/latest/mysql/mgmt/mysql/mysqlapi/models.go'), - 'contents' - ); - - await createFolder(joinPath(goFolderPath, 'profiles/latest/servicebus/mgmt/servicebus/')); - await writeFileContents( - joinPath(goFolderPath, 'profiles/latest/servicebus/mgmt/servicebus/models.go'), - 'contents' - ); - - await createFolder(joinPath(goFolderPath, 'profiles/preview/mysql/mgmt/mysql/')); - await writeFileContents(joinPath(goFolderPath, 'profiles/preview/mysql/mgmt/mysql/models.go'), 'contents'); - - await createFolder(joinPath(goFolderPath, 'profiles/preview/mysql/mgmt/mysql/mysqlapi/')); - await writeFileContents( - joinPath(goFolderPath, 'profiles/preview/mysql/mgmt/mysql/mysqlapi/models.go'), - 'contents' - ); - - await createFolder(joinPath(goFolderPath, 'profiles/preview/servicebus/mgmt/servicebus/')); - await writeFileContents( - joinPath(goFolderPath, 'profiles/preview/servicebus/mgmt/servicebus/models.go'), - 'contents' - ); - - return { exitCode: 0 }; - } - }); - runner.set({ executable: 'gofmt', args: ['-w', './profiles/'] }); - runner.set({ executable: 'gofmt', args: ['-w', './services/'] }); - } - return runner; -} diff --git a/tools/spec-gen-sdk/tsconfig.integration.json b/tools/spec-gen-sdk/tsconfig.integration.json deleted file mode 100644 index 45805ff8dd0..00000000000 --- a/tools/spec-gen-sdk/tsconfig.integration.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "rootDir": "." - } -} diff --git a/tools/spec-gen-sdk/tsconfig.json b/tools/spec-gen-sdk/tsconfig.json index 69f2764fbe4..9f8630abf84 100644 --- a/tools/spec-gen-sdk/tsconfig.json +++ b/tools/spec-gen-sdk/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { "target": "es2022", - "module": "commonjs", + "module": "NodeNext", + "moduleResolution": "NodeNext", "lib": ["es2022"], "esModuleInterop": true, "resolveJsonModule": true,