diff --git a/tools/sdk-generation-pipeline/.eslintignore b/tools/sdk-generation-pipeline/.eslintignore new file mode 100644 index 000000000..0fd4c33c4 --- /dev/null +++ b/tools/sdk-generation-pipeline/.eslintignore @@ -0,0 +1,4 @@ +dist/ +tmp +*.js +node_modules \ No newline at end of file diff --git a/tools/sdk-generation-pipeline/.eslintrc.json b/tools/sdk-generation-pipeline/.eslintrc.json new file mode 100644 index 000000000..7207402c6 --- /dev/null +++ b/tools/sdk-generation-pipeline/.eslintrc.json @@ -0,0 +1,68 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true + }, + "extends": [ + "google" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "2019" + }, + "plugins": [ + "@typescript-eslint", + "simple-import-sort" + ], + "rules": { + "indent": ["error", 4], + "max-len": ["error", 160], + "comma-dangle": ["error", "never"], + "require-jsdoc": ["error", { + "require": { + "FunctionDeclaration": false, + "MethodDefinition": false, + "ClassDeclaration": false, + "ArrowFunctionExpression": false, + "FunctionExpression": false + } + }], + "object-curly-spacing": ["error", "always"], + "simple-import-sort/imports": "error", + "new-cap": "off", + "valid-jsdoc": "off", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": ["class", "interface", "enum", "enumMember", "typeParameter", "typeLike", "default"], + "format": ["PascalCase"], + "filter": { + "regex": "^_$", + "match": false + } + }, + { + "selector": [ "variable", "parameter", "function", "method", "property", "memberLike"], + "format": ["camelCase"], + "filter": { + "regex": "^_$", + "match": false + } + }, + { + "selector": ["default"], + "modifiers": ["global", "const"], + "format": ["UPPER_CASE"], + "filter": { + "regex": "^_$", + "match": false + } + }, + { + "selector": ["objectLiteralProperty"], + "format": null + } + ] + } +} diff --git a/tools/sdk-generation-pipeline/Dockerfile b/tools/sdk-generation-pipeline/Dockerfile new file mode 100644 index 000000000..91d2f0e97 --- /dev/null +++ b/tools/sdk-generation-pipeline/Dockerfile @@ -0,0 +1,78 @@ +FROM mcr.microsoft.com/dotnet/runtime:3.1-focal + +RUN apt-get update -y && apt upgrade -y && apt install curl -y +RUN apt install build-essential -y + +# install java +ENV JAVA_HOME /usr/java/openjdk-17 +ENV PATH $JAVA_HOME/bin:$PATH +ENV LANG en_US.UTF-8 +ENV JAVA_VERSION 17.0.1 +RUN curl -fL -o openjdk.tgz https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d4267845be086888add4f/12/GPL/openjdk-17.0.1_linux-x64_bin.tar.gz +RUN mkdir -p "$JAVA_HOME" +RUN tar --extract --file openjdk.tgz --directory "$JAVA_HOME" --strip-components 1 --no-same-owner +RUN rm openjdk.tgz +## install maven +ENV M2_HOME /usr/maven +ENV MAVEN_HOME=/usr/maven +ENV PATH $M2_HOME/bin:$PATH +RUN mkdir -p "$MAVEN_HOME" +RUN curl -fL -o maven.tgz https://dlcdn.apache.org/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.tar.gz +RUN tar --extract --file maven.tgz --directory "$MAVEN_HOME" --strip-components 1 --no-same-owner +RUN rm maven.tgz + +# install node +RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - +RUN apt -y install nodejs + +# install python +RUN apt install python3-pip -y && apt install python3-venv -y && pip3 install --upgrade pip + +# install powershell +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y wget apt-transport-https software-properties-common +RUN wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb +RUN dpkg -i packages-microsoft-prod.deb +RUN apt-get update && apt-get install -y powershell +RUN rm packages-microsoft-prod.deb + +# install .NET +RUN wget https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh && chmod 777 ./dotnet-install.sh +RUN bash ./dotnet-install.sh +RUN bash ./dotnet-install.sh -c 3.1 +ENV DOTNET_ROOT=/root/.dotnet PATH=$PATH:/root/.dotnet +RUN rm /dotnet-install.sh +RUN apt-get install -y dotnet-sdk-6.0 + +# install git +RUN add-apt-repository ppa:git-core/ppa -y && apt update && apt upgrade -y && apt install git -y +RUN git config --global credential.helper store && git config --global core.fileMode false + +# install depended packages +RUN pip3 install --upgrade wheel PyYAML requests +RUN npm install -g typescript +RUN npm install -g @microsoft/rush +RUN npm install -g autorest + +RUN mkdir "/mock-host" && cd /mock-host && npm install @azure-tools/mock-service-host + +# install chrome +RUN curl -LO https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y ./google-chrome-stable_current_amd64.deb +RUN rm google-chrome-stable_current_amd64.deb +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable + +# install vscode code server and extensions +COPY scripts/install-vscode-server.sh /install-vscode-server.sh +RUN sh /install-vscode-server.sh + +# install docker because it's required by test proxy +RUN curl -fsSL https://test.docker.com -o docker.sh && sh docker.sh + +COPY packages/sdk-generation-cli/*.tgz /pack.tgz +RUN npm install -g /pack.tgz + +COPY scripts/entrypoint.sh /entrypoint.sh +COPY scripts/rerun-tasks /usr/bin/rerun-tasks +COPY scripts/change-owner.sh /change-owner.sh + +ENTRYPOINT ["bash", "/entrypoint.sh"] \ No newline at end of file diff --git a/tools/sdk-generation-pipeline/ci.yml b/tools/sdk-generation-pipeline/ci.yml index d3a64486c..728a78e72 100644 --- a/tools/sdk-generation-pipeline/ci.yml +++ b/tools/sdk-generation-pipeline/ci.yml @@ -35,24 +35,20 @@ variables: - name: NodeVersion value: '14.x' - name: VAR_ARTIFACT_NAME - value: 'drop' + value: 'packages' + - name: VAR_DOCKER_IMAGE_ARTIFACT_NAME + value: 'dockerImages' - name: VAR_BUILD_ARTIFACT_STAGING_DIRECTORY value: $(Build.ArtifactStagingDirectory) +pool: + name: "azsdk-pool-mms-ubuntu-2004-general" + vmImage: "MMSUbuntu20.04" + stages: - - stage: InstallAndBuild + - stage: Build jobs: - job: Build - strategy: - matrix: - linux: - imageName: 'ubuntu-latest' - mac: - imageName: 'macos-latest' - windows: - imageName: 'windows-latest' - pool: - vmImage: $(imageName) steps: - task: NodeTool@0 inputs: @@ -69,6 +65,16 @@ stages: displayName: 'rush update' workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + - script: | + rushx lint + displayName: 'Lint @azure-tools/sdk-generation-lib' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-lib + + - script: | + rushx lint + displayName: 'Lint @azure-tools/sdk-generation-cli' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-cli + - script: | rush build displayName: 'rush build' @@ -84,26 +90,127 @@ stages: displayName: 'Pack @azure-tools/sdk-generation-cli' workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-cli - - script: 'cp azure-tools-sdk-generation-lib-*.tgz $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' - displayName: 'copy @azure-tools/sdk-generation-lib to staging dir' + - script: | + mkdir -p $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/packages + cp azure-tools-sdk-generation-lib-*.tgz $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/packages/ + displayName: 'Copy @azure-tools/sdk-generation-lib to staging dir' workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-lib - condition: contains(variables['imageName'], 'ubuntu') - - - script: 'cp azure-tools-sdk-generation-cli-*.tgz $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' - displayName: 'copy @azure-tools/sdk-generation-cli to staging dir' - workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-cli - condition: contains(variables['imageName'], 'ubuntu') - task: PublishBuildArtifacts@1 + displayName: 'Publish packages' inputs: - PathtoPublish: '$(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' + PathtoPublish: '$(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/packages' ArtifactName: '$(VAR_ARTIFACT_NAME)' publishLocation: 'Container' - condition: contains(variables['imageName'], 'ubuntu') + + - script: 'docker build -t sdkgeneration.azurecr.io/sdk-generation:$(Build.BuildId) .' + displayName: 'Build docker image' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - script: | + mkdir -p $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/docker-images + docker image save sdkgeneration.azurecr.io/sdk-generation:$(Build.BuildId) -o $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/docker-images/image.tar + displayName: 'Save docker image' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - task: PublishBuildArtifacts@1 + displayName: 'Publish docker image' + inputs: + PathtoPublish: '$(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/docker-images' + ArtifactName: '$(VAR_DOCKER_IMAGE_ARTIFACT_NAME)' + publishLocation: 'Container' + + - stage: Test + dependsOn: Build + condition: succeeded() + jobs: + - job: UnitTestForCli + displayName: Unit Test For Cli Package + condition: always() + steps: + - task: NodeTool@0 + inputs: + versionSpec: '$(NodeVersion)' + displayName: 'Install Node.js' + + - bash: | + npm install -g @microsoft/rush + npm install -g typescript@4.6.2 + displayName: 'Install dependencies' + + - script: | + rush update + displayName: 'rush update' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - script: | + rush build + displayName: 'rush build' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - script: | + npm i -g autorest + rushx test:unit + displayName: 'Test @azure-tools/sdk-generation-cli' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-cli + + - job: IntegrationTest + condition: always() + displayName: Integration Test for + strategy: + matrix: + JS: + sdkRepo: 'azure-sdk-for-js' + JAVA: + sdkRepo: 'azure-sdk-for-java' + PYTHON: + sdkRepo: 'azure-sdk-for-python' + GO: + sdkRepo: 'azure-sdk-for-go' + Net: + sdkRepo: 'azure-sdk-for-net' + steps: + - task: NodeTool@0 + inputs: + versionSpec: '$(NodeVersion)' + displayName: 'Install Node.js' + + - bash: | + npm install -g @microsoft/rush + npm install -g typescript@4.6.2 + displayName: 'Install dependencies' + + - script: | + rush update + displayName: 'rush update' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - script: | + rush build + displayName: 'rush build' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline + + - task: DownloadBuildArtifacts@0 + inputs: + buildType: 'current' + downloadType: 'single' + artifactName: '$(VAR_DOCKER_IMAGE_ARTIFACT_NAME)' + downloadPath: '$(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)' + displayName: 'Download image' + + - bash: | + docker load --input $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/$(VAR_DOCKER_IMAGE_ARTIFACT_NAME)/image.tar + displayName: 'Docker Load' + + - bash: | + set -e + rushx test:integration --docker-image="sdkgeneration.azurecr.io/sdk-generation:$(Build.BuildId)" --sdk-repo=$(sdkRepo) + displayName: 'Run integration test' + workingDirectory: $(System.DefaultWorkingDirectory)/tools/sdk-generation-pipeline/packages/sdk-generation-cli - ${{if ne(variables['Build.Reason'], 'PullRequest')}}: - stage: Release - dependsOn: InstallAndBuild + dependsOn: Test condition: succeeded() jobs: - job: approve @@ -136,7 +243,7 @@ stages: echo -e "\e[32m[$(date -u)] LOG: publish the package" echo "//registry.npmjs.org/:_authToken=$(azure-sdk-npm-token)" >> ~/.npmrc - for file in $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/$(VAR_ARTIFACT_NAME)/*.tgz + for file in $(VAR_BUILD_ARTIFACT_STAGING_DIRECTORY)/$(VAR_ARTIFACT_NAME)/$(VAR_ARTIFACT_NAME)/*.tgz do echo -e "\e[32m[$(date -u)] LOG: File: $file" npm publish $file --access public || { echo 'publish $file failed' ; } diff --git a/tools/sdk-generation-pipeline/common/config/rush/pnpm-lock.yaml b/tools/sdk-generation-pipeline/common/config/rush/pnpm-lock.yaml index b74c3d8cd..0329fa4fb 100644 --- a/tools/sdk-generation-pipeline/common/config/rush/pnpm-lock.yaml +++ b/tools/sdk-generation-pipeline/common/config/rush/pnpm-lock.yaml @@ -10,12 +10,22 @@ specifiers: '@rush-temp/sdk-generation-lib': file:./projects/sdk-generation-lib.tgz '@types/jest': ^25.2.1 '@types/node': ^16.11.7 + '@typescript-eslint/eslint-plugin': ^5.25.0 + '@typescript-eslint/parser': ^5.25.0 ajv: ^6.12.6 axios: ^0.24.0 class-validator: ^0.13.2 colors: 1.4.0 + command-line-args: ~5.2.1 convict: ^6.2.3 copyfiles: ^2.4.1 + dotenv: ^16.0.0 + eslint: ^8.16.0 + eslint-config-google: ^0.14.0 + eslint-plugin-import: ^2.26.0 + eslint-plugin-n: ^15.0.0 + eslint-plugin-promise: ^6.0.0 + eslint-plugin-simple-import-sort: ^7.0.0 hot-shots: ^8.5.2 jest: ~26.6.3 jsonc-parser: ^3.0.0 @@ -27,7 +37,6 @@ specifiers: ts-node: ~10.7.0 typeorm: ^0.2.37 typescript: ~4.6.3 - winston: ^3.7.2 dependencies: '@azure/event-hubs': 5.5.2 @@ -39,24 +48,33 @@ dependencies: '@rush-temp/sdk-generation-lib': file:projects/sdk-generation-lib.tgz '@types/jest': 25.2.3 '@types/node': 16.11.26 + '@typescript-eslint/eslint-plugin': 5.25.0_1a0f7f9b6396bf2b425c3efebd1af716 + '@typescript-eslint/parser': 5.25.0_eslint@8.16.0+typescript@4.6.3 ajv: 6.12.6 axios: 0.24.0 class-validator: 0.13.2 colors: 1.4.0 + command-line-args: 5.2.1 convict: 6.2.3 copyfiles: 2.4.1 + dotenv: 16.0.0 + eslint: 8.16.0 + eslint-config-google: 0.14.0_eslint@8.16.0 + eslint-plugin-import: 2.26.0_eslint@8.16.0 + eslint-plugin-n: 15.2.0_eslint@8.16.0 + eslint-plugin-promise: 6.0.0_eslint@8.16.0 + eslint-plugin-simple-import-sort: 7.0.0_eslint@8.16.0 hot-shots: 8.5.2 jest: 26.6.3_ts-node@10.7.0 jsonc-parser: 3.0.0 memory-fs: 0.5.0 mongodb: 3.7.3 - node-yaml: 3.2.0 + node-yaml: 3.2.0_eslint@8.16.0 rimraf: 3.0.2 - ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.4 - ts-node: 10.7.0_2212e31c3c65c18c26161ee18ee11528 + ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.3 + ts-node: 10.7.0_ddaac8e123aeb260f586984cee874848 typeorm: 0.2.45_mongodb@3.7.3 - typescript: 4.6.4 - winston: 3.7.2 + typescript: 4.6.3 packages: @@ -65,7 +83,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.10 + '@jridgewell/trace-mapping': 0.3.9 dev: false /@azure/abort-controller/1.0.4: @@ -217,25 +235,25 @@ packages: '@babel/highlight': 7.17.9 dev: false - /@babel/compat-data/7.17.10: - resolution: {integrity: sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==} + /@babel/compat-data/7.17.7: + resolution: {integrity: sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==} engines: {node: '>=6.9.0'} dev: false - /@babel/core/7.17.10: - resolution: {integrity: sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA==} + /@babel/core/7.17.9: + resolution: {integrity: sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.10 - '@babel/helper-compilation-targets': 7.17.10_@babel+core@7.17.10 + '@babel/generator': 7.17.9 + '@babel/helper-compilation-targets': 7.17.7_@babel+core@7.17.9 '@babel/helper-module-transforms': 7.17.7 '@babel/helpers': 7.17.9 - '@babel/parser': 7.17.10 + '@babel/parser': 7.17.9 '@babel/template': 7.16.7 - '@babel/traverse': 7.17.10 - '@babel/types': 7.17.10 + '@babel/traverse': 7.17.9 + '@babel/types': 7.17.0 convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -245,23 +263,23 @@ packages: - supports-color dev: false - /@babel/generator/7.17.10: - resolution: {integrity: sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==} + /@babel/generator/7.17.9: + resolution: {integrity: sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 - '@jridgewell/gen-mapping': 0.1.1 + '@babel/types': 7.17.0 jsesc: 2.5.2 + source-map: 0.5.7 dev: false - /@babel/helper-compilation-targets/7.17.10_@babel+core@7.17.10: - resolution: {integrity: sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==} + /@babel/helper-compilation-targets/7.17.7_@babel+core@7.17.9: + resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.17.10 - '@babel/core': 7.17.10 + '@babel/compat-data': 7.17.7 + '@babel/core': 7.17.9 '@babel/helper-validator-option': 7.16.7 browserslist: 4.20.3 semver: 6.3.0 @@ -271,7 +289,7 @@ packages: resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-function-name/7.17.9: @@ -279,21 +297,21 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.16.7 - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-hoist-variables/7.16.7: resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-module-imports/7.16.7: resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-module-transforms/7.17.7: @@ -306,8 +324,8 @@ packages: '@babel/helper-split-export-declaration': 7.16.7 '@babel/helper-validator-identifier': 7.16.7 '@babel/template': 7.16.7 - '@babel/traverse': 7.17.10 - '@babel/types': 7.17.10 + '@babel/traverse': 7.17.9 + '@babel/types': 7.17.0 transitivePeerDependencies: - supports-color dev: false @@ -321,14 +339,14 @@ packages: resolution: {integrity: sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-split-export-declaration/7.16.7: resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@babel/helper-validator-identifier/7.16.7: @@ -346,8 +364,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.16.7 - '@babel/traverse': 7.17.10 - '@babel/types': 7.17.10 + '@babel/traverse': 7.17.9 + '@babel/types': 7.17.0 transitivePeerDependencies: - supports-color dev: false @@ -361,118 +379,118 @@ packages: js-tokens: 4.0.0 dev: false - /@babel/parser/7.17.10: - resolution: {integrity: sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==} + /@babel/parser/7.17.9: + resolution: {integrity: sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==} engines: {node: '>=6.0.0'} hasBin: true dev: false - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.10: + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.9: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.10: + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.9: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.10: + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.9: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.10: + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.9: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.10: + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.9: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.10: + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.9: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.10: + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.9: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: false @@ -481,30 +499,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/parser': 7.17.10 - '@babel/types': 7.17.10 + '@babel/parser': 7.17.9 + '@babel/types': 7.17.0 dev: false - /@babel/traverse/7.17.10: - resolution: {integrity: sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==} + /@babel/traverse/7.17.9: + resolution: {integrity: sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.10 + '@babel/generator': 7.17.9 '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-function-name': 7.17.9 '@babel/helper-hoist-variables': 7.16.7 '@babel/helper-split-export-declaration': 7.16.7 - '@babel/parser': 7.17.10 - '@babel/types': 7.17.10 + '@babel/parser': 7.17.9 + '@babel/types': 7.17.0 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: false - /@babel/types/7.17.10: - resolution: {integrity: sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==} + /@babel/types/7.17.0: + resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.16.7 @@ -549,6 +567,38 @@ packages: kuler: 2.0.0 dev: false + /@eslint/eslintrc/1.3.0: + resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.3.2 + globals: 13.15.0 + ignore: 5.2.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@humanwhocodes/config-array/0.9.5: + resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: false + /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -722,7 +772,7 @@ packages: resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==} engines: {node: '>= 10.14.2'} dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@jest/types': 26.6.2 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 @@ -766,39 +816,73 @@ packages: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/set-array': 1.1.1 - '@jridgewell/sourcemap-codec': 1.4.13 + '@jridgewell/set-array': 1.1.0 + '@jridgewell/sourcemap-codec': 1.4.11 dev: false - /@jridgewell/resolve-uri/3.0.7: - resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==} + /@jridgewell/resolve-uri/3.0.6: + resolution: {integrity: sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==} engines: {node: '>=6.0.0'} dev: false - /@jridgewell/set-array/1.1.1: - resolution: {integrity: sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==} + /@jridgewell/set-array/1.1.0: + resolution: {integrity: sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==} engines: {node: '>=6.0.0'} dev: false - /@jridgewell/sourcemap-codec/1.4.13: - resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==} + /@jridgewell/sourcemap-codec/1.4.11: + resolution: {integrity: sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==} dev: false - /@jridgewell/trace-mapping/0.3.10: - resolution: {integrity: sha512-Q0YbBd6OTsXm8Y21+YUSDXupHnodNC2M4O18jtd3iwJ3+vMZNdKGols0a9G6JOK0dcJ3IdUUHoh908ZI6qhk8Q==} + /@jridgewell/trace-mapping/0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: - '@jridgewell/resolve-uri': 3.0.7 - '@jridgewell/sourcemap-codec': 1.4.13 + '@jridgewell/resolve-uri': 3.0.6 + '@jridgewell/sourcemap-codec': 1.4.11 dev: false - /@octetstream/eslint-config/3.0.0: + /@kwsites/file-exists/1.1.1: + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@kwsites/promise-deferred/1.1.1: + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + dev: false + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: false + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: false + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + dev: false + + /@octetstream/eslint-config/3.0.0_eslint@8.16.0: resolution: {integrity: sha512-VX8gZ6h9PNKrWb+N9AoWM2DA+eVBAqAL0OLHwLjh+iwLrICQRFYzJDxxHIpD7rN413PCppr2vp6cy8UGdZGd+A==} peerDependencies: eslint: ^5.4.0 dependencies: babel-eslint: 9.0.0 - eslint-config-airbnb-base: 13.2.0_eslint-plugin-import@2.26.0 - eslint-plugin-import: 2.26.0 + eslint: 8.16.0 + eslint-config-airbnb-base: 13.2.0_0ce4f552c18297c00de8a172104cf37a + eslint-plugin-import: 2.26.0_eslint@8.16.0 eslint-plugin-promise: 4.3.1 transitivePeerDependencies: - supports-color @@ -986,8 +1070,8 @@ packages: /@types/babel__core/7.1.19: resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} dependencies: - '@babel/parser': 7.17.10 - '@babel/types': 7.17.10 + '@babel/parser': 7.17.9 + '@babel/types': 7.17.0 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.17.1 @@ -996,20 +1080,26 @@ packages: /@types/babel__generator/7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 dev: false /@types/babel__template/7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.17.10 - '@babel/types': 7.17.10 + '@babel/parser': 7.17.9 + '@babel/types': 7.17.0 dev: false /@types/babel__traverse/7.17.1: resolution: {integrity: sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 + dev: false + + /@types/convict/5.2.2: + resolution: {integrity: sha512-yz26pc2bwg8YyYz/X5s/MJsUy40n54vxDdQCRENtqGfKdrmpPqXdOV8LDuHqTA0acoFxybLsJ5hc9ZYK6amDCw==} + dependencies: + '@types/node': 16.11.26 dev: false /@types/graceful-fs/4.1.5: @@ -1048,8 +1138,12 @@ packages: pretty-format: 25.5.0 dev: false + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: false + /@types/json5/0.0.29: - resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: false /@types/jsonwebtoken/8.5.8: @@ -1105,6 +1199,132 @@ packages: resolution: {integrity: sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==} dev: false + /@typescript-eslint/eslint-plugin/5.25.0_1a0f7f9b6396bf2b425c3efebd1af716: + resolution: {integrity: sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.25.0_eslint@8.16.0+typescript@4.6.3 + '@typescript-eslint/scope-manager': 5.25.0 + '@typescript-eslint/type-utils': 5.25.0_eslint@8.16.0+typescript@4.6.3 + '@typescript-eslint/utils': 5.25.0_eslint@8.16.0+typescript@4.6.3 + debug: 4.3.4 + eslint: 8.16.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.0 + regexpp: 3.2.0 + semver: 7.3.7 + tsutils: 3.21.0_typescript@4.6.3 + typescript: 4.6.3 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/parser/5.25.0_eslint@8.16.0+typescript@4.6.3: + resolution: {integrity: sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.25.0 + '@typescript-eslint/types': 5.25.0 + '@typescript-eslint/typescript-estree': 5.25.0_typescript@4.6.3 + debug: 4.3.4 + eslint: 8.16.0 + typescript: 4.6.3 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/scope-manager/5.25.0: + resolution: {integrity: sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.25.0 + '@typescript-eslint/visitor-keys': 5.25.0 + dev: false + + /@typescript-eslint/type-utils/5.25.0_eslint@8.16.0+typescript@4.6.3: + resolution: {integrity: sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/utils': 5.25.0_eslint@8.16.0+typescript@4.6.3 + debug: 4.3.4 + eslint: 8.16.0 + tsutils: 3.21.0_typescript@4.6.3 + typescript: 4.6.3 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/types/5.25.0: + resolution: {integrity: sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: false + + /@typescript-eslint/typescript-estree/5.25.0_typescript@4.6.3: + resolution: {integrity: sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.25.0 + '@typescript-eslint/visitor-keys': 5.25.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.7 + tsutils: 3.21.0_typescript@4.6.3 + typescript: 4.6.3 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/utils/5.25.0_eslint@8.16.0+typescript@4.6.3: + resolution: {integrity: sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 5.25.0 + '@typescript-eslint/types': 5.25.0 + '@typescript-eslint/typescript-estree': 5.25.0_typescript@4.6.3 + eslint: 8.16.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.16.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@typescript-eslint/visitor-keys/5.25.0: + resolution: {integrity: sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.25.0 + eslint-visitor-keys: 3.3.0 + dev: false + /abab/2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: false @@ -1116,6 +1336,14 @@ packages: acorn-walk: 7.2.0 dev: false + /acorn-jsx/5.3.2_acorn@8.7.1: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.7.1 + dev: false + /acorn-walk/7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} @@ -1183,7 +1411,7 @@ packages: dev: false /any-promise/1.3.0: - resolution: {integrity: sha1-q8av7tzqUugJzcA3au0845Y10X8=} + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: false /anymatch/2.0.0: @@ -1235,17 +1463,27 @@ packages: engines: {node: '>=0.10.0'} dev: false + /array-back/3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} + dev: false + /array-includes/3.1.5: resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 get-intrinsic: 1.1.1 is-string: 1.0.7 dev: false + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: false + /array-unique/0.3.2: resolution: {integrity: sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=} engines: {node: '>=0.10.0'} @@ -1257,7 +1495,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 es-shim-unscopables: 1.0.0 dev: false @@ -1299,27 +1537,27 @@ packages: deprecated: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates. dependencies: '@babel/code-frame': 7.16.7 - '@babel/parser': 7.17.10 - '@babel/traverse': 7.17.10 - '@babel/types': 7.17.10 + '@babel/parser': 7.17.9 + '@babel/traverse': 7.17.9 + '@babel/types': 7.17.0 eslint-scope: 3.7.1 eslint-visitor-keys: 1.3.0 transitivePeerDependencies: - supports-color dev: false - /babel-jest/26.6.3_@babel+core@7.17.10: + /babel-jest/26.6.3_@babel+core@7.17.9: resolution: {integrity: sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==} engines: {node: '>= 10.14.2'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@jest/transform': 26.6.2 '@jest/types': 26.6.2 '@types/babel__core': 7.1.19 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 26.6.2_@babel+core@7.17.10 + babel-preset-jest: 26.6.2_@babel+core@7.17.9 chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -1345,40 +1583,40 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@babel/template': 7.16.7 - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 '@types/babel__core': 7.1.19 '@types/babel__traverse': 7.17.1 dev: false - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.10: + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.9: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.10 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.10 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.10 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.17.10 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.10 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.10 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.10 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.10 + '@babel/core': 7.17.9 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.9 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.9 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.17.9 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.9 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.9 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.9 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.9 dev: false - /babel-preset-jest/26.6.2_@babel+core@7.17.10: + /babel-preset-jest/26.6.2_@babel+core@7.17.9: resolution: {integrity: sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==} engines: {node: '>= 10.14.2'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 babel-plugin-jest-hoist: 26.6.2 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.10 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.9 dev: false /balanced-match/1.0.2: @@ -1459,10 +1697,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001338 - electron-to-chromium: 1.4.136 + caniuse-lite: 1.0.30001332 + electron-to-chromium: 1.4.124 escalade: 3.1.1 - node-releases: 2.0.4 + node-releases: 2.0.3 picocolors: 1.0.0 dev: false @@ -1485,7 +1723,7 @@ packages: dev: false /buffer-equal-constant-time/1.0.1: - resolution: {integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=} + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} dev: false /buffer-from/1.1.2: @@ -1506,6 +1744,12 @@ packages: ieee754: 1.2.1 dev: false + /builtins/4.1.0: + resolution: {integrity: sha512-1bPRZQtmKaO6h7qV1YHXNtr6nCK28k0Zo95KM4dXfILcZZwoHJBN1m3lfLv9LPkcOZlrSr+J1bzMaZFO98Yq0w==} + dependencies: + semver: 7.3.7 + dev: false + /cache-base/1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -1543,8 +1787,8 @@ packages: engines: {node: '>=10'} dev: false - /caniuse-lite/1.0.30001338: - resolution: {integrity: sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==} + /caniuse-lite/1.0.30001332: + resolution: {integrity: sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==} dev: false /capture-exit/2.0.0: @@ -1584,6 +1828,10 @@ packages: engines: {node: '>=10'} dev: false + /chmodr/1.2.0: + resolution: {integrity: sha512-Y5uI7Iq/Az6HgJEL6pdw7THVd7jbVOTPwsmcPOBjQL8e3N+pz872kzK5QxYGEy21iRys+iHWV0UZQXDFJo1hyA==} + dev: false + /ci-info/2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} dev: false @@ -1605,7 +1853,7 @@ packages: /class-validator/0.13.2: resolution: {integrity: sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==} dependencies: - libphonenumber-js: 1.9.53 + libphonenumber-js: 1.10.6 validator: 13.7.0 dev: false @@ -1709,6 +1957,16 @@ packages: delayed-stream: 1.0.0 dev: false + /command-line-args/5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + find-replace: 3.0.0 + lodash.camelcase: 4.3.0 + typical: 4.0.0 + dev: false + /component-emitter/1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} dev: false @@ -1916,6 +2174,13 @@ packages: engines: {node: '>=0.3.1'} dev: false + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: false + /doctrine/2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -1923,6 +2188,13 @@ packages: esutils: 2.0.3 dev: false + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: false + /domexception/2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} @@ -1930,6 +2202,11 @@ packages: webidl-conversions: 5.0.0 dev: false + /dotenv/16.0.0: + resolution: {integrity: sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==} + engines: {node: '>=12'} + dev: false + /dotenv/8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -1941,8 +2218,8 @@ packages: safe-buffer: 5.2.1 dev: false - /electron-to-chromium/1.4.136: - resolution: {integrity: sha512-GnITX8rHnUrIVnTxU9UlsTnSemHUA2iF+6QrRqxFbp/mf0vfuSc/goEyyQhUX3TUUCE3mv/4BNuXOtaJ4ur0eA==} + /electron-to-chromium/1.4.124: + resolution: {integrity: sha512-VhaE9VUYU6d2eIb+4xf83CATD+T+3bTzvxvlADkQE+c2hisiw3sZmvEDtsW704+Zky9WZGhBuQXijDVqSriQLA==} dev: false /emittery/0.7.2: @@ -1977,8 +2254,8 @@ packages: is-arrayish: 0.2.1 dev: false - /es-abstract/1.20.0: - resolution: {integrity: sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==} + /es-abstract/1.20.1: + resolution: {integrity: sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 @@ -1997,7 +2274,7 @@ packages: is-shared-array-buffer: 1.0.2 is-string: 1.0.7 is-weakref: 1.0.2 - object-inspect: 1.12.0 + object-inspect: 1.12.1 object-keys: 1.1.1 object.assign: 4.1.2 regexp.prototype.flags: 1.4.3 @@ -2036,6 +2313,11 @@ packages: engines: {node: '>=8'} dev: false + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: false + /escodegen/2.0.0: resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} engines: {node: '>=6.0'} @@ -2049,7 +2331,7 @@ packages: source-map: 0.6.1 dev: false - /eslint-config-airbnb-base/13.2.0_eslint-plugin-import@2.26.0: + /eslint-config-airbnb-base/13.2.0_0ce4f552c18297c00de8a172104cf37a: resolution: {integrity: sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w==} engines: {node: '>= 4'} peerDependencies: @@ -2057,11 +2339,35 @@ packages: eslint-plugin-import: ^2.17.2 dependencies: confusing-browser-globals: 1.0.11 - eslint-plugin-import: 2.26.0 + eslint: 8.16.0 + eslint-plugin-import: 2.26.0_eslint@8.16.0 object.assign: 4.1.2 object.entries: 1.1.5 dev: false + /eslint-config-google/0.14.0_eslint@8.16.0: + resolution: {integrity: sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==} + engines: {node: '>=0.10.0'} + peerDependencies: + eslint: '>=5.16.0' + dependencies: + eslint: 8.16.0 + dev: false + + /eslint-config-standard/17.0.0_06f9958da8803ef60b2f7e6cf399f505: + resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} + peerDependencies: + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: ^15.0.0 + eslint-plugin-promise: ^6.0.0 + dependencies: + eslint: 8.16.0 + eslint-plugin-import: 2.26.0_eslint@8.16.0 + eslint-plugin-n: 15.2.0_eslint@8.16.0 + eslint-plugin-promise: 6.0.0_eslint@8.16.0 + dev: false + /eslint-import-resolver-node/0.3.6: resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} dependencies: @@ -2077,7 +2383,18 @@ packages: find-up: 2.1.0 dev: false - /eslint-plugin-import/2.26.0: + /eslint-plugin-es/4.1.0_eslint@8.16.0: + resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + eslint: 8.16.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 + dev: false + + /eslint-plugin-import/2.26.0_eslint@8.16.0: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -2087,6 +2404,7 @@ packages: array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 + eslint: 8.16.0 eslint-import-resolver-node: 0.3.6 eslint-module-utils: 2.7.3 has: 1.0.3 @@ -2098,11 +2416,45 @@ packages: tsconfig-paths: 3.14.1 dev: false + /eslint-plugin-n/15.2.0_eslint@8.16.0: + resolution: {integrity: sha512-lWLg++jGwC88GDGGBX3CMkk0GIWq0y41aH51lavWApOKcMQcYoL3Ayd0lEdtD3SnQtR+3qBvWQS3qGbR2BxRWg==} + engines: {node: '>=12.22.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + builtins: 4.1.0 + eslint: 8.16.0 + eslint-plugin-es: 4.1.0_eslint@8.16.0 + eslint-utils: 3.0.0_eslint@8.16.0 + ignore: 5.2.0 + is-core-module: 2.9.0 + minimatch: 3.1.2 + resolve: 1.22.0 + semver: 6.3.0 + dev: false + /eslint-plugin-promise/4.3.1: resolution: {integrity: sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==} engines: {node: '>=6'} dev: false + /eslint-plugin-promise/6.0.0_eslint@8.16.0: + resolution: {integrity: sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.16.0 + dev: false + + /eslint-plugin-simple-import-sort/7.0.0_eslint@8.16.0: + resolution: {integrity: sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 8.16.0 + dev: false + /eslint-scope/3.7.1: resolution: {integrity: sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=} engines: {node: '>=4.0.0'} @@ -2111,17 +2463,120 @@ packages: estraverse: 4.3.0 dev: false + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: false + + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: false + + /eslint-utils/2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + dependencies: + eslint-visitor-keys: 1.3.0 + dev: false + + /eslint-utils/3.0.0_eslint@8.16.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.16.0 + eslint-visitor-keys: 2.1.0 + dev: false + /eslint-visitor-keys/1.3.0: resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} engines: {node: '>=4'} dev: false + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: false + + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: false + + /eslint/8.16.0: + resolution: {integrity: sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.3.0 + '@humanwhocodes/config-array': 0.9.5 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.16.0 + eslint-visitor-keys: 3.3.0 + espree: 9.3.2 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.15.0 + ignore: 5.2.0 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + v8-compile-cache: 2.3.0 + transitivePeerDependencies: + - supports-color + dev: false + + /espree/9.3.2: + resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.7.1 + acorn-jsx: 5.3.2_acorn@8.7.1 + eslint-visitor-keys: 3.3.0 + dev: false + /esprima/4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true dev: false + /esquery/1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: false + /esrecurse/4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -2244,6 +2699,17 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: false + /fast-glob/3.2.11: + resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: false + /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: false @@ -2252,6 +2718,12 @@ packages: resolution: {integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=} dev: false + /fastq/1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + dependencies: + reusify: 1.0.4 + dev: false + /fb-watchman/2.0.1: resolution: {integrity: sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==} dependencies: @@ -2262,6 +2734,13 @@ packages: resolution: {integrity: sha512-5rOQWkBVz3FnYWTi/ELZmq4CoK1Pb+xKNZWuJRsOwo0+8DrP43CrWJtyLVvb5U7z7ggE5llahfDbLjaVNzXVJQ==} dev: false + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: false + /file-uri-to-path/1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} dev: false @@ -2284,6 +2763,13 @@ packages: to-regex-range: 5.0.1 dev: false + /find-replace/3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + dev: false + /find-up/2.1.0: resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=} engines: {node: '>=4'} @@ -2299,6 +2785,18 @@ packages: path-exists: 4.0.0 dev: false + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.5 + rimraf: 3.0.2 + dev: false + + /flatted/3.2.5: + resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} + dev: false + /fn.name/1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} dev: false @@ -2313,15 +2811,17 @@ packages: optional: true dev: false + /for-each/0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.4 + dev: false + /for-in/1.0.2: resolution: {integrity: sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=} engines: {node: '>=0.10.0'} dev: false - /foreach/2.0.5: - resolution: {integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k=} - dev: false - /form-data/3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} @@ -2368,10 +2868,14 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 functions-have-names: 1.2.3 dev: false + /functional-red-black-tree/1.0.1: + resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=} + dev: false + /functions-have-names/1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: false @@ -2426,6 +2930,20 @@ packages: engines: {node: '>=0.10.0'} dev: false + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: false + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: false + /glob/7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} dependencies: @@ -2442,6 +2960,25 @@ packages: engines: {node: '>=4'} dev: false + /globals/13.15.0: + resolution: {integrity: sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: false + + /globby/11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.11 + ignore: 5.2.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: false + /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: false @@ -2584,6 +3121,19 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: false + /ignore/5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + engines: {node: '>= 4'} + dev: false + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: false + /import-local/3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -2854,14 +3404,14 @@ packages: has-symbols: 1.0.3 dev: false - /is-typed-array/1.1.8: - resolution: {integrity: sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==} + /is-typed-array/1.1.9: + resolution: {integrity: sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 - es-abstract: 1.20.0 - foreach: 2.0.5 + es-abstract: 1.20.1 + for-each: 0.3.3 has-tostringtag: 1.0.0 dev: false @@ -2921,7 +3471,7 @@ packages: resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -2933,8 +3483,8 @@ packages: resolution: {integrity: sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.17.10 - '@babel/parser': 7.17.10 + '@babel/core': 7.17.9 + '@babel/parser': 7.17.9 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -3014,10 +3564,10 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.17.10 + '@babel/core': 7.17.9 '@jest/test-sequencer': 26.6.3_ts-node@10.7.0 '@jest/types': 26.6.2 - babel-jest: 26.6.3_@babel+core@7.17.10 + babel-jest: 26.6.3_@babel+core@7.17.9 chalk: 4.1.2 deepmerge: 4.2.2 glob: 7.2.0 @@ -3032,7 +3582,7 @@ packages: jest-validate: 26.6.2 micromatch: 4.0.5 pretty-format: 26.6.2 - ts-node: 10.7.0_2212e31c3c65c18c26161ee18ee11528 + ts-node: 10.7.0_ddaac8e123aeb260f586984cee874848 transitivePeerDependencies: - bufferutil - canvas @@ -3143,7 +3693,7 @@ packages: resolution: {integrity: sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==} engines: {node: '>= 10.14.2'} dependencies: - '@babel/traverse': 7.17.10 + '@babel/traverse': 7.17.9 '@jest/environment': 26.6.2 '@jest/source-map': 26.6.2 '@jest/test-result': 26.6.2 @@ -3272,7 +3822,7 @@ packages: jest-runtime: 26.6.3_ts-node@10.7.0 jest-util: 26.6.2 jest-worker: 26.6.2 - source-map-support: 0.5.21 + source-map-support: 0.5.13 throat: 5.0.0 transitivePeerDependencies: - bufferutil @@ -3334,7 +3884,7 @@ packages: resolution: {integrity: sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==} engines: {node: '>= 10.14.2'} dependencies: - '@babel/types': 7.17.10 + '@babel/types': 7.17.0 '@jest/types': 26.6.2 '@types/babel__traverse': 7.17.1 '@types/prettier': 2.6.0 @@ -3489,6 +4039,10 @@ packages: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: false + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=} + dev: false + /json5/1.0.1: resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} hasBin: true @@ -3592,8 +4146,16 @@ packages: type-check: 0.3.2 dev: false - /libphonenumber-js/1.9.53: - resolution: {integrity: sha512-3cuMrA2CY3TbKVC0wKye5dXYgxmVVi4g13gzotprQSguFHMqf0pIrMM2Z6ZtMsSWqvtIqi5TuQhGjMhxz0O9Mw==} + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: false + + /libphonenumber-js/1.10.6: + resolution: {integrity: sha512-CIjT100/SmntsUjsLVs2t3ufeN4KdNXUxhD07tH153pdbaCWuAjv0jK/gPuywR3IImB/U/MQM+x9RfhMs5XZiA==} dev: false /lines-and-columns/1.2.4: @@ -3615,6 +4177,10 @@ packages: p-locate: 4.1.0 dev: false + /lodash.camelcase/4.3.0: + resolution: {integrity: sha1-soqmKIorn8ZRA1x3EfZathkDMaY=} + dev: false + /lodash.clonedeep/4.5.0: resolution: {integrity: sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=} dev: false @@ -3643,6 +4209,10 @@ packages: resolution: {integrity: sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=} dev: false + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: false + /lodash.once/4.1.1: resolution: {integrity: sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=} dev: false @@ -3714,6 +4284,11 @@ packages: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: false + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: false + /micromatch/3.1.10: resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} engines: {node: '>=0.10.0'} @@ -3893,17 +4468,17 @@ packages: dev: false optional: true - /node-releases/2.0.4: - resolution: {integrity: sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==} + /node-releases/2.0.3: + resolution: {integrity: sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==} dev: false - /node-yaml/3.2.0: + /node-yaml/3.2.0_eslint@8.16.0: resolution: {integrity: sha512-5c7TNdFOLOaY/TN0fBDrfJg+N6Z1+Ch7O/QuN2wostfo9Q4qbpOTAjk1WZ3bxgSfRPrJF4rgWdL26N2Svdljhw==} dependencies: co: 4.6.0 js-yaml: 3.14.1 junk: 3.0.0 - promise-fs: 2.1.0 + promise-fs: 2.1.0_eslint@8.16.0 transitivePeerDependencies: - eslint - supports-color @@ -3969,8 +4544,8 @@ packages: kind-of: 3.2.2 dev: false - /object-inspect/1.12.0: - resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} + /object-inspect/1.12.1: + resolution: {integrity: sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==} dev: false /object-keys/1.1.1: @@ -4001,7 +4576,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 dev: false /object.pick/1.3.0: @@ -4017,7 +4592,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 dev: false /once/1.4.0: @@ -4058,6 +4633,18 @@ packages: word-wrap: 1.2.3 dev: false + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: false + /p-each-series/2.2.0: resolution: {integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==} engines: {node: '>=8'} @@ -4106,6 +4693,13 @@ packages: engines: {node: '>=6'} dev: false + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: false + /parse-json/5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -4164,6 +4758,11 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: false + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: false @@ -4195,6 +4794,11 @@ packages: engines: {node: '>= 0.8.0'} dev: false + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: false + /pretty-format/25.5.0: resolution: {integrity: sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==} engines: {node: '>= 8.3'} @@ -4224,11 +4828,11 @@ packages: engines: {node: '>= 0.6.0'} dev: false - /promise-fs/2.1.0: + /promise-fs/2.1.0_eslint@8.16.0: resolution: {integrity: sha512-Wl6Y+dSQnw1cJjXdMbXABoH2fRXC3G3KjQHH32qPT6UYyDrh9Iouj/rvI+KKJiVFwQ1/3KiPe1dybp6cHYvUag==} engines: {node: '>= 6'} dependencies: - '@octetstream/eslint-config': 3.0.0 + '@octetstream/eslint-config': 3.0.0_eslint@8.16.0 '@octetstream/promisify': 2.0.2 transitivePeerDependencies: - eslint @@ -4273,6 +4877,10 @@ packages: deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: false + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: false + /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: false @@ -4351,6 +4959,11 @@ packages: functions-have-names: 1.2.3 dev: false + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: false + /remove-trailing-separator/1.1.0: resolution: {integrity: sha1-wkvOKig62tW8P1jg1IJJuSN52O8=} dev: false @@ -4386,6 +4999,11 @@ packages: resolve-from: 5.0.0 dev: false + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: false + /resolve-from/5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -4410,6 +5028,11 @@ packages: engines: {node: '>=0.12'} dev: false + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false + /rhea-promise/2.1.0: resolution: {integrity: sha512-CRMwdJ/o4oO/xKcvAwAsd0AHy5fVvSlqso7AadRmaaLGzAzc9LCoW7FOFnucI8THasVmOeCnv5c/fH/n7FcNaA==} dependencies: @@ -4436,6 +5059,12 @@ packages: engines: {node: 6.* || >= 7.*} dev: false + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: false + /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: false @@ -4569,13 +5198,23 @@ packages: dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.1 - object-inspect: 1.12.0 + object-inspect: 1.12.1 dev: false /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: false + /simple-git/3.7.1: + resolution: {integrity: sha512-+Osjtsumbtew2y9to0pOYjNzSIr4NkKGBg7Po5SUtjQhaJf2QBmiTX/9E9cv9rmc7oUiSGFIB9e7ys5ibnT9+A==} + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /simple-swizzle/0.2.2: resolution: {integrity: sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=} dependencies: @@ -4632,8 +5271,8 @@ packages: urix: 0.1.0 dev: false - /source-map-support/0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + /source-map-support/0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 @@ -4740,7 +5379,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 dev: false /string.prototype.trimstart/1.0.5: @@ -4748,7 +5387,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.0 + es-abstract: 1.20.1 dev: false /string_decoder/0.10.31: @@ -4794,6 +5433,11 @@ packages: engines: {node: '>=6'} dev: false + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: false + /supports-color/5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4846,6 +5490,10 @@ packages: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} dev: false + /text-table/0.2.0: + resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} + dev: false + /thenify-all/1.6.0: resolution: {integrity: sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=} engines: {node: '>=0.8'} @@ -4935,7 +5583,7 @@ packages: resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==} dev: false - /ts-jest/26.5.6_jest@26.6.3+typescript@4.6.4: + /ts-jest/26.5.6_jest@26.6.3+typescript@4.6.3: resolution: {integrity: sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==} engines: {node: '>= 10'} hasBin: true @@ -4953,11 +5601,11 @@ packages: make-error: 1.3.6 mkdirp: 1.0.4 semver: 7.3.7 - typescript: 4.6.4 + typescript: 4.6.3 yargs-parser: 20.2.9 dev: false - /ts-node/10.7.0_2212e31c3c65c18c26161ee18ee11528: + /ts-node/10.7.0_ddaac8e123aeb260f586984cee874848: resolution: {integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==} hasBin: true peerDependencies: @@ -4983,7 +5631,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.6.4 + typescript: 4.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: false @@ -4997,10 +5645,24 @@ packages: strip-bom: 3.0.0 dev: false + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + /tslib/2.3.1: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} dev: false + /tsutils/3.21.0_typescript@4.6.3: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.6.3 + dev: false + /tunnel/0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} @@ -5013,11 +5675,23 @@ packages: prelude-ls: 1.1.2 dev: false + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: false + /type-detect/4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} dev: false + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: false + /type-fest/0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -5106,18 +5780,23 @@ packages: tslib: 2.3.1 uuid: 8.3.2 xml2js: 0.4.23 - yargs: 17.4.1 + yargs: 17.5.1 zen-observable-ts: 1.1.0 transitivePeerDependencies: - supports-color dev: false - /typescript/4.6.4: - resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} + /typescript/4.6.3: + resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} engines: {node: '>=4.2.0'} hasBin: true dev: false + /typical/4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} + dev: false + /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -5209,9 +5888,9 @@ packages: inherits: 2.0.4 is-arguments: 1.1.1 is-generator-function: 1.0.10 - is-typed-array: 1.1.8 + is-typed-array: 1.1.9 safe-buffer: 5.2.1 - which-typed-array: 1.1.7 + which-typed-array: 1.1.8 dev: false /uuid/8.3.2: @@ -5223,6 +5902,10 @@ packages: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: false + /v8-compile-cache/2.3.0: + resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} + dev: false + /v8-to-istanbul/7.1.2: resolution: {integrity: sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==} engines: {node: '>=10.10.0'} @@ -5317,16 +6000,16 @@ packages: resolution: {integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=} dev: false - /which-typed-array/1.1.7: - resolution: {integrity: sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==} + /which-typed-array/1.1.8: + resolution: {integrity: sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 - es-abstract: 1.20.0 - foreach: 2.0.5 + es-abstract: 1.20.1 + for-each: 0.3.3 has-tostringtag: 1.0.0 - is-typed-array: 1.1.8 + is-typed-array: 1.1.9 dev: false /which/1.3.1: @@ -5505,8 +6188,8 @@ packages: yargs-parser: 20.2.9 dev: false - /yargs/17.4.1: - resolution: {integrity: sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==} + /yargs/17.5.1: + resolution: {integrity: sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==} engines: {node: '>=12'} dependencies: cliui: 7.0.4 @@ -5535,56 +6218,49 @@ packages: dev: false file:projects/sdk-generation-cli.tgz: - resolution: {integrity: sha512-VfpS68fFGl9Q1vrmOnW9lFAcUB5JzTdhlX1Zg1uhdLYXS9YKTOJj7oVWxG7NngzE3R2yKKhAVjUr/dc8z1x7Vg==, tarball: file:projects/sdk-generation-cli.tgz} + resolution: {integrity: sha512-4XOWwyUp/Z0F1OFhF+4RVXWkOysD/5x2AbvfHDnhO1flGrDCn6poMsswgHDszkOHgKZ8eU8rNCL5pRPfA+zr4A==, tarball: file:projects/sdk-generation-cli.tgz} name: '@rush-temp/sdk-generation-cli' version: 0.0.0 dependencies: '@azure/storage-blob': 12.9.0 + '@types/convict': 5.2.2 '@types/jest': 25.2.3 '@types/node': 16.11.26 + '@typescript-eslint/eslint-plugin': 5.25.0_1a0f7f9b6396bf2b425c3efebd1af716 + '@typescript-eslint/parser': 5.25.0_eslint@8.16.0+typescript@4.6.3 ajv: 6.12.6 axios: 0.24.0 + chmodr: 1.2.0 + command-line-args: 5.2.1 convict: 6.2.3 + dotenv: 16.0.0 + eslint: 8.16.0 + eslint-config-google: 0.14.0_eslint@8.16.0 + eslint-config-standard: 17.0.0_06f9958da8803ef60b2f7e6cf399f505 + eslint-plugin-import: 2.26.0_eslint@8.16.0 + eslint-plugin-n: 15.2.0_eslint@8.16.0 + eslint-plugin-promise: 6.0.0_eslint@8.16.0 + eslint-plugin-simple-import-sort: 7.0.0_eslint@8.16.0 jest: 26.6.3_ts-node@10.7.0 - mongodb: 3.7.3 rimraf: 3.0.2 - ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.4 - ts-node: 10.7.0_2212e31c3c65c18c26161ee18ee11528 - typeorm: 0.2.45_mongodb@3.7.3 - typescript: 4.6.4 + simple-git: 3.7.1 + ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.3 + ts-node: 10.7.0_ddaac8e123aeb260f586984cee874848 + typescript: 4.6.3 + winston: 3.7.2 transitivePeerDependencies: - - '@sap/hana-client' - '@swc/core' - '@swc/wasm' - - aws4 - - better-sqlite3 - - bson-ext - bufferutil - canvas - debug - encoding - - hdb-pool - - ioredis - - kerberos - - mongodb-client-encryption - - mongodb-extjson - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - snappy - - sql.js - - sqlite3 - supports-color - - typeorm-aurora-data-api-driver - utf-8-validate dev: false file:projects/sdk-generation-lib.tgz: - resolution: {integrity: sha512-Me7AZiHgYUUqn94pminjHGdoL2j7mNDcuWGKBJvo9ANm7vVJdfG70sNN0gBoPnSBX/+h9E+DZiW47EIkP8f0Ug==, tarball: file:projects/sdk-generation-lib.tgz} + resolution: {integrity: sha512-G7bu+3yDRgs/BPqDhNfEZVyeeazg0gM8wH1KkFEsFQBmqTAypZXCWnO/IrJDGg/Vi8pudgnqvVGaf4rDA5jttQ==, tarball: file:projects/sdk-generation-lib.tgz} name: '@rush-temp/sdk-generation-lib' version: 0.0.0 dependencies: @@ -5595,22 +6271,30 @@ packages: '@octokit/rest': 18.12.0 '@types/jest': 25.2.3 '@types/node': 16.11.26 + '@typescript-eslint/eslint-plugin': 5.25.0_1a0f7f9b6396bf2b425c3efebd1af716 + '@typescript-eslint/parser': 5.25.0_eslint@8.16.0+typescript@4.6.3 ajv: 6.12.6 class-validator: 0.13.2 colors: 1.4.0 convict: 6.2.3 copyfiles: 2.4.1 + eslint: 8.16.0 + eslint-config-google: 0.14.0_eslint@8.16.0 + eslint-plugin-import: 2.26.0_eslint@8.16.0 + eslint-plugin-n: 15.2.0_eslint@8.16.0 + eslint-plugin-promise: 6.0.0_eslint@8.16.0 + eslint-plugin-simple-import-sort: 7.0.0_eslint@8.16.0 hot-shots: 8.5.2 jest: 26.6.3_ts-node@10.7.0 jsonc-parser: 3.0.0 memory-fs: 0.5.0 mongodb: 3.7.3 - node-yaml: 3.2.0 + node-yaml: 3.2.0_eslint@8.16.0 rimraf: 3.0.2 - ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.4 - ts-node: 10.7.0_2212e31c3c65c18c26161ee18ee11528 + ts-jest: 26.5.6_jest@26.6.3+typescript@4.6.3 + ts-node: 10.7.0_ddaac8e123aeb260f586984cee874848 typeorm: 0.2.45_mongodb@3.7.3 - typescript: 4.6.4 + typescript: 4.6.3 winston: 3.7.2 transitivePeerDependencies: - '@sap/hana-client' @@ -5622,7 +6306,6 @@ packages: - bufferutil - canvas - encoding - - eslint - hdb-pool - ioredis - kerberos diff --git a/tools/sdk-generation-pipeline/documents/docker/README.md b/tools/sdk-generation-pipeline/documents/docker/README.md new file mode 100644 index 000000000..6dbc933e2 --- /dev/null +++ b/tools/sdk-generation-pipeline/documents/docker/README.md @@ -0,0 +1,129 @@ +We provide a docker image, which can be used to generate code, run mock test. This docker image can be used for local +development, and running in pipeline. + +This document only describes the usages of docker image, if you want to get more information about the design details of +docker, please go to [design specs of docker image](docker-image-design.md). + +# Prerequisites +Suggest to run the command by using wsl docker if you are using Windows machine because the docker container will request your local file system frequently, and wsl docker is much faster than running it in Windows directly. + +# Docker IMAGE COMMANDS + +The docker image will be used in different scenarios: + +1. Run docker container in local (generate codes and do grow up development). +2. Run docker container in pipeline. + +## RUN DOCKER CONTAINER IN LOCAL + +### RUN DOCKER CONTAINER TO GENERATE CODES AND DO GROW UP DEVELOPMENT + +Command + +```shell +docker run -it --privileged -v {local_spec_repo_path}:/spec-repo -v {local_work_folder}:/work-dir docker.image:latest --readme={relative_readme} --sdk={sdk_to_generate} +``` + +Parameter description: + +| Parameter | Description | Example | +|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------| +| { local_spec_repo_path } | Required. It's used to point to the swagger folder. | /home/test/azure-rest-api-specs | +| { local_work_folder} | Required. It's used to point to the work folder, which will store all sdk repositories. If there is no sdk repository in the folder, the docker image will clone it | /home/test/sdk-repos | +| { relative_readme } | Required. It's used to specify the readme.md file and docker image uses it to generate SDKs. it's the relative path from {path_to_local_spec_repo} | specification/agrifood/resource-manager/readme.md | +| { sdk_to_generate } | Required. It's used to specify which language of sdk you want to generate. Supported value for management sdk: js, java, python, .net, and go. Supported value for dataplane sdk: js, java, python, and .net. If you want to generate multi-packages, use comma to separate them. (__Not recommend to generate multi packages in one docker container because the docker will failed when encoutering error in generating one sdk, and the remaining sdk will be generated__) | js,java | + +Example Command: +```shell +docker run -it --privileged -v /home/test/azure-rest-api-specs:/spec-repo -v /home/test/work-dir:/work-dir docker.image:latest --readme="specification/agrifood/resource-manager/readme.md" --sdk=js,java +``` + +After running command, docker container generates SDKs. When SDKs are generated, the docker container doesn't exit, and you can open your browser and request `http://127.0.0.1:8080/?folder=/work-dir` for further grow up development. +If you want to re-generate codes after grow up development or changing swagger, please run command in docker container: +```shell +rerun-tasks -readme={relative_readme} --sdk={sdk_to_generate} +``` +rerun-tasks is a script, which invokes task engine to re-run tasks. + +**Attention**: rerun-tasks may clear your manual change, which depends whether there is `clear-output-folder: true` in the `readme..md`. Also, if your manual codes in a file which has the same name as generated one, it will also be overridden. + +### RUN DOCKER CONTAINER TO DO GROW UP DEVELOPMENT +There are two scenarios here: +1. Service team has generated codes locally by using docker image and has exited the docker container. But they want to do grow up development now. +2. Service team has generated codes by using sdk generation pipeline, and sdk generation pipeline creates a work branch. Service team hope to do grow up based on the work branch. + +Compared to scenario 1, scenario 2 needs user to clone and checkout the work branch by themselves. It’s very simple with git: +```shell +cd {local_work_folder} +git clone -b {work-branch} {repo-url} +``` +Parameter description: + +| Parameter | Description | Example | +|-----------------------|-----------------------------------------------------------------------------------------|-----------------------------------------------| +| { local_work_folder } | Required. It's used to point to the work folder, which stores all sdk repositories. | /home/test/work-dir | +| {work_branch } | Required. It's used to point the work branch name generated by SDK generation pipeline. | sdkAuto/workbranch | +| {repo_url} | Required. It's used to point the repository url that work branch is in. | https://github.com/Azure/azure-sdk-for-js.git | + +Then run docker commands to do grow up development: +```shell +docker run -it --privileged -v {local_spec_repo_path}:/spec-repo -v {local_work_folder}:/work-dir docker.image:latest --readme={relative_readme} +``` +Parameter description: + +| Parameter | Description | Example | +|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------| +| { local_spec_repo_path } | Optional. If you want to change the swagger and re-generate codes, you need to mount the swagger repo. If you only want to do grow up development, no need to mount it. | /home/test/azure-rest-api-specs | +| { local_work_folder } | Required. It's used to point to the work folder, which stores all sdk repositories. | /home/test/work-dir | +| { relative_readme } | Optional. It's used to specify the readme.md file and docker image uses it to start mock server. it's the relative path from {path_to_local_spec_repo}. If not specified, mock server will not start. | specification/agrifood/resource-manager/readme.md | + +Example Command: +```shell +docker run -it --privileged -v /home/test/azure-rest-api-specs:/spec-repo -v /home/test/work-dir:/work-dir docker.image:latest +``` + +After running command, docker container generates SDKs. When SDKs are generated, the docker container doesn't exit, and you can open your browser and request `http://127.0.0.1:8080/?folder=/work-dir` for further grow up development. +If you want to re-generate codes after grow up development or changing swagger, please run command in docker container: +```shell +rerun-tasks -readme={relative_readme} --sdk={sdk_to_generate} +``` +rerun-tasks is a script, which invokes task engine to re-run tasks. + +**Attention**: rerun-tasks may clear your manual change, which depends whether there is `clear-output-folder: true` in the `readme..md`. Also, if your manual codes in a file which has the same name as generated one, it will also be overridden. + +## RUN DOCKER CONTAINER IN PIPELINE +The docker image also can be used by SDK Generation Pipeline. Moreover, if the service team wants to integrate the docker image in their CI pipeline, the method of integration is the same here. + +Before running docker command, pipeline must prepare the spec repo and sdk repo. + +Command: + +```shell +docker run --privileged -v {spec_repo_path}:/spec-repo -v {sdk_repo_path}:/sdk-repo -v {output_folder_path}:/tmp/output docker.image:latest --readme={relative_readme} +``` + +Parameter description: + +| Parameter | Description | Example | +|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------| +| { spec_repo_path } | Required. It's used to point to the swagger folder. | /home/test/azure-rest-api-specs | +| { sdk_repo_path } | Required. It's used to point to the sdk repository. | /home/test/sdk-repos | +| { relative_readme } | Required. It's used to specify the readme.md file and docker image uses it to generate SDKs. it's the relative path from {path_to_local_spec_repo} | specification/agrifood/resource-manager/readme.md | + +Example Command: +```shell +docker run -v /var/run/docker.sock:/var/run/docker.sock -v /home/vsts/work/azure-rest-api-specs:/spec-repo -v /home/vsts/work/azure-sdk-for-js:/sdk-repo -v /home/vsts/work/output:/tmp/output docker.image:latest --readme=specification/agrifood/resource-manager/readme.md +``` + +After running the command in pipeline, docker will execute tasks automatically. Also, there will be output files generated, which will be used by pipeline's other job, such as upload codes, parsing logs. +The following is the full list of generated files: + +| File Types | Files | Description | Schema/Example | +|-------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| +| Logs | init-task.log | It contains all logs while executing init task. | 2022-03-24 03:35:12 xxxxxxx | +| Logs | generateAndBuild-task.log | It contains all logs while executing generate and build task. | 2022-03-24 03:35:12 xxxxxxx | +| Logs | mockTest-task.log | It contains all logs while executing mock test task. | 2022-03-24 03:35:12 xxxxxxx | +| Outputs | initOutput.json | It contains the output of init task | [InitOutputSchema.json](../task-engine/schema/InitOutputSchema.json) | +| Outputs | generateAndBuildOutput.json | It contains the output of generateAndBuildOutput script, such as the path to generated codes, artifacts and so on. | [GenerateAndBuildOutputSchema.json](../task-engine/schema/GenerateAndBuildOutputSchema.json) | +| Outputs | mockTestOutput.json | It contains the output of mock test task | [TestOutputSchema.json](../task-engine/schema/TestOutputSchema.json) | +| Outputs | taskResults.json | It contains each task execution result | { "init": "success" } | diff --git a/tools/sdk-generation-pipeline/documents/docker/docker-image-design.md b/tools/sdk-generation-pipeline/documents/docker/docker-image-design.md new file mode 100644 index 000000000..2ff2a0c24 --- /dev/null +++ b/tools/sdk-generation-pipeline/documents/docker/docker-image-design.md @@ -0,0 +1,16 @@ +# ARCHITECTURE DIAGRAM +![docker design](docker-image-design.md) + +The core of the docker image is task engine, which contains four tasks: Init Task, Generate and Build Task, Mock Test Task. There is a configuration file in each sdk repository, and it defines which task should be executed. To serve different users/pipeline, we provide different docker commands. Also, after the tasks are executed, there are some outputs, such as generated codes, task execution result, which can be used by following steps in pipeline or service team. + +# TASK ENGINE +There are mainly four tasks defined in task engine: Init Task, Generate and Build Task, Mock Test Task, Live Test Task. Task engine executes these tasks based on a configuration file in sdk repository, and you can find [the schema of configuration file here](../task-engine/schema/CodegenToSdkConfigSchema.json), and [the example](../task-engine/README.md). + +As the docker image will be used in different scenarios, we hope to extract the most common part into the docker image, and the specific parts will be removed. + +About the schemas of input/output of each task, please refer to [schemas](../task-engine/schema). + +# DOCKER IMAGE LAYERS +The docker image will be based on Ubuntu, and it also contains all the development environment for different languages of sdk. So the overall structure of layers is the following: + +![layer](images/docker-image-layers.drawio.png) diff --git a/tools/sdk-generation-pipeline/documents/docker/images/docker-design.drawio.png b/tools/sdk-generation-pipeline/documents/docker/images/docker-design.drawio.png new file mode 100644 index 000000000..b50ad9a31 Binary files /dev/null and b/tools/sdk-generation-pipeline/documents/docker/images/docker-design.drawio.png differ diff --git a/tools/sdk-generation-pipeline/documents/docker/images/docker-image-layers.drawio.png b/tools/sdk-generation-pipeline/documents/docker/images/docker-image-layers.drawio.png new file mode 100644 index 000000000..0dae8cf81 Binary files /dev/null and b/tools/sdk-generation-pipeline/documents/docker/images/docker-image-layers.drawio.png differ diff --git a/tools/sdk-generation-pipeline/documents/docker/images/extension-remote-containers.png b/tools/sdk-generation-pipeline/documents/docker/images/extension-remote-containers.png new file mode 100755 index 000000000..ae1a1e0df Binary files /dev/null and b/tools/sdk-generation-pipeline/documents/docker/images/extension-remote-containers.png differ diff --git a/tools/sdk-generation-pipeline/documents/docker/vscode-connect-docker-container.md b/tools/sdk-generation-pipeline/documents/docker/vscode-connect-docker-container.md new file mode 100644 index 000000000..3d6604f44 --- /dev/null +++ b/tools/sdk-generation-pipeline/documents/docker/vscode-connect-docker-container.md @@ -0,0 +1,27 @@ +# Use Vscode to Connect Docker Container +It's not easy to develop within docker container. However, vscode provides us a way to connect to docker container, and you can use it to write codes easily. + +## Prerequisites +- Install vscode in your computer. +- Install extension **Remote - Containers**. + ![vsocde connects docker containers](images/extension-remote-containers.png) + +## Steps +Please follow the following steps to connect your vscode to docker container. +1. Press `F1` and select `Remote-Containers: Attach to Running Container`. +2. Select your running docker image, and attach to it. +3. After vscode connects to docker container, open folder `/work-dir/{sdk-repository}`. + 1. For .Net, you can only open the generated SDK namespace folder, such as `Azure.Verticals.AgriFood.Farming`. + +Then you can write your codes in vscode. + +## FAQ +1. Vscode C# extension cannot load the project correctly. + + Answer: Vscode C# extension is based on OmniSharp, which sometimes make us confused. To resolve it: + 1. Run `dotnet build` to rebuild the project + 2. In vscode, press `ctrl + shift + p` and then type `Restart Omnisharp`. + +2. Vscode cannot load java project correctly. + + Answer: Java repository is very large and vscode extension for Java needs to spend much time to load the project. You can check the progress in the terminal of `Java Build Status`. \ No newline at end of file diff --git a/tools/sdk-generation-pipeline/documents/task-engine/README.md b/tools/sdk-generation-pipeline/documents/task-engine/README.md index 195b1b755..14fc77063 100644 --- a/tools/sdk-generation-pipeline/documents/task-engine/README.md +++ b/tools/sdk-generation-pipeline/documents/task-engine/README.md @@ -16,9 +16,6 @@ SDK Automation is launched in azure pipeline. It runs tasks in the following ste 4. Launch __mockTestTask__ to run mock test with [mockTestInput.json](#mocktestinput). The script should produce [mockTestOutput.json](#mocktestoutput). Then the [mockTestOutput.json](#mocktestoutput) will be parsed and the test result will be stored in database. -5. Launch __liveTestTask__ to run mock test with [liveTestInput.json](#livetestinput). The script should produce [liveTestOutput.json](#livetestoutput). Then the [liveTestOutput.json](#livetestoutput) will be parsed and the test result will be stored in database. - - ## Definitions ### CodegenToSdkConfig diff --git a/tools/sdk-generation-pipeline/documents/task-engine/schema/CodegenToSdkConfigSchema.json b/tools/sdk-generation-pipeline/documents/task-engine/schema/CodegenToSdkConfigSchema.json index 0152eea12..04159ae72 100644 --- a/tools/sdk-generation-pipeline/documents/task-engine/schema/CodegenToSdkConfigSchema.json +++ b/tools/sdk-generation-pipeline/documents/task-engine/schema/CodegenToSdkConfigSchema.json @@ -72,15 +72,10 @@ // Script path related to repo root "type": "string" }, - "script": { - // the script type, e.g. pwsh - "type": "string" - }, "envs": { - // Not Implemented // Extra environment variable to be passed to the script (except initScript). // By default the following envs will be passed: - // PATH, SHELL, PWD (current directory) + // PWD (current directory) "type": "array", "items": { "type": "string" @@ -94,26 +89,6 @@ "logFilter": { // filter for error msg and warning msg. "$ref": "#/definitions/LogFilter" - }, - "exitWithNonZeroCode": { - "properties": { - // How should SDK Automation handle non-zero exitCode. - "storeLog": { - // Should we store this error. - "type": "boolean", - "default": true - }, - "result": { - // If script has non-error exitCode how should we mark the script's result. - "type": "string", - "enum": ["error", "warning", "ignore"], - "default": "error" - } - }, - "storeAllLog": { - "show": true, - "result": "error" - } } }, "required": ["path"] diff --git a/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildInputSchema.json b/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildInputSchema.json index 1680c7784..cbb35569d 100644 --- a/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildInputSchema.json +++ b/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildInputSchema.json @@ -2,7 +2,7 @@ "type": "object", "properties": { "specFolder": { - // Path to local spec folder. path to the parent of resourceProvider folders. e.g. azure-rest-api-specs/specifications + // Path to local spec folder. path to the parent of service folders. e.g. azure-rest-api-specs/specifications "type": "string" }, "headSha": { diff --git a/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildOutputSchema.json b/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildOutputSchema.json index 2b2f8dd70..744cc75c3 100644 --- a/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildOutputSchema.json +++ b/tools/sdk-generation-pipeline/documents/task-engine/schema/GenerateAndBuildOutputSchema.json @@ -1,69 +1,69 @@ { - "type": "object", - "properties": { - "packages": { - "type": "array", - "items": { - "$ref": "#/definitions/PackageResult" - } - } - }, - "required": ["packages"], - "definitions": { - "PackageResult": { - "properties": { - "packageName": { - // Name of package. Will be used in branch name, PR title and the folder name to store the generated codes. - "type": "string" - }, - "result": { - // Status of package. By default it's succeeded. - "type": "string", - "enum": ["failed", "succeeded", "warning"], - "default": "succeeded" - }, - "path": { - // List of package content paths. - // If the path points to a folder then - // all the content under the folder will be included. - "type": "array", - "items": { - "type": "string" - } - }, - "packageFolder": { - // The path of package folder. - "type": "string" - }, - "changelog": { - "type": "object", - "properties": { - "content": { - // Content of changelog in markdown - "type": "string" - }, - "hasBreakingChange": { - // Does the new package has breaking change - "type": "boolean" - }, - "breakingChangeItems": { - "type": "array", - "items": { - "type": "string" - } + "type": "object", + "properties": { + "packages": { + "type": "array", + "items": { + "$ref": "#/definitions/PackageResult" } - }, - "required": ["content"] - }, - "artifacts": { - // The path to artifacts - "type": "array", - "items": { - "type": "string" - } } - }, - "required": ["packageName", "path", "packageFolder"] + }, + "required": ["packages"], + "definitions": { + "PackageResult": { + "properties": { + "packageName": { + // Name of package. Will be used in branch name, PR title and the folder name to store the generated codes. + "type": "string" + }, + "result": { + // Status of package. By default it's succeeded. + "type": "string", + "enum": ["failed", "succeeded"], + "default": "succeeded" + }, + "path": { + // List of package content paths. + // If the path points to a folder then + // all the content under the folder will be included. + "type": "array", + "items": { + "type": "string" + } + }, + "packageFolder": { + // The path of package folder. + "type": "string" + }, + "changelog": { + "type": "object", + "properties": { + "content": { + // Content of changelog in markdown + "type": "string" + }, + "hasBreakingChange": { + // Does the new package has breaking change + "type": "boolean" + }, + "breakingChangeItems": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["content"] + }, + "artifacts": { + // The path to artifacts + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["packageName", "path", "packageFolder"] + } } - } } diff --git a/tools/sdk-generation-pipeline/documents/task-engine/schema/TestOutputSchema.json b/tools/sdk-generation-pipeline/documents/task-engine/schema/TestOutputSchema.json index 478efa89a..7dd2a753b 100644 --- a/tools/sdk-generation-pipeline/documents/task-engine/schema/TestOutputSchema.json +++ b/tools/sdk-generation-pipeline/documents/task-engine/schema/TestOutputSchema.json @@ -17,6 +17,5 @@ "codeCoverage": { "type": "number" } - }, - "required": ["total", "success", "fail", "apiCoverage", "codeCoverage"] + } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/README.md b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/README.md new file mode 100644 index 000000000..b495da760 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/README.md @@ -0,0 +1,79 @@ +# @azure-tools/sdk-generation-cli + +This packages includes some commands used by sdk generation pipeline. + +## Install + +```shell +npm i @azure-tools/sdk-generation-cli +``` + +## Commands + +### docker-cli +It's used by docker image, and for the details, please refer to [How to Use Docker Image for SDK Generation](../../documents/docker/README.md). + +### run-mock-host +Run this command to start the mock host. +Usage: +```shell +run-mock-host --readme= --spec-repo= --mock-host-path= +``` +For more details, please refer to [mock service host document](https://github.com/Azure/azure-sdk-tools/tree/main/tools/mock-service-host). + +### getRepoName +Get repository name from the http url and set it as azure pipeline variable. +Usage: +```shell +getRepoName +``` + +### generateResult +Parse the logs produced by tasks, and generate a summarized task result in json format. +Usage: +```shell +generateResult \ + --buildId= \ + --taskName= \ + --logfile= \ + --resultOutputPath= \ + [--dockerResultFile=] \ + [--exeResult=] \ + [--taskOutputPath=] \ + [--logFilterStr=] +``` + +### publishResult +Publish pipeline result to storage. [eventhub] is supported. +NOTE: will get eventhub connection string from environment, variable is [EVENTHUB_SAS_URL] +Usage: +```shell +publishResult \ + --storageType=eventhub \ + --pipelineStatus= \ + --buildId= \ + --trigger= \ + --logPath= \ + --resultsPath= +``` + +### uploadArtifact +Upload artifact to blob. +NOTE: will get blob connection string from environment, variable is [AZURE_STORAGE_BLOB_SAS_URL] +Usage: +```shell +uploadArtifact \ + --generateAndBuildOutputFile= \ + --buildId= \ + --language= +``` + +### prepareArtifactFiles +Determine which files to upload, copy it to artifact directory. +Usage: +```shell +prepareArtifactFiles \ + --artifactDir= \ + --generateAndBuildOutputFile= \ + --language= +``` diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/jest.config.js b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/jest.config.js index 8f06e5a43..2658e6882 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/jest.config.js +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/jest.config.js @@ -13,7 +13,7 @@ module.exports = { "/**/*.test.ts", ], modulePathIgnorePatterns: [ - "/tmp/*" + "(/.*)*/tmp/*" ], collectCoverage: true, collectCoverageFrom: [ diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/package.json b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/package.json index 0179edeaa..73b214cf6 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/package.json +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/package.json @@ -1,54 +1,69 @@ { - "name": "@azure-tools/sdk-generation-cli", - "version": "1.0.0", - "description": "", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "rimraf dist && tsc", - "prepack": "npm run build", - "pack": "npm pack 2>&1", - "test:prepare-environment": "ts-node test/utils/prepareEnvironment.ts", - "test": "npm run test:prepare-environment && jest " - }, - "author": "Microsoft", - "license": "MIT", - "files": [ - "dist/**/*.js", - "dist/**/*.json", - "dist/**/*.js.map", - "dist/**/*.d.ts", - "dist/**/*.d.ts.map", - "dist/**/*.handlebars", - "LICENSE", - "README.md" - ], - "bin": { - "getRepoName": "dist/getRepoNameCli.js", - "generateResult": "dist/generateResultCli.js", - "publishResult": "dist/publishResultCli.js", - "uploadArtifact": "dist/uploadArtifactCli.js", - "prepareArtifactFiles": "dist/prepareArtifactFilesCli.js" - }, - "dependencies": { - "@azure/storage-blob": "^12.8.0", - "@azure-tools/sdk-generation-lib": "^1.0.4", - "ajv": "^6.12.6", - "axios": "^0.24.0", - "convict": "^6.2.3", - "mongodb": "^3.6.10", - "typeorm": "^0.2.37" - }, - "bundledDependencies": [ - "@azure-tools/sdk-generation-lib" - ], - "devDependencies": { - "@types/jest": "^25.2.1", - "@types/node": "^16.11.7", - "jest": "~26.6.3", - "rimraf": "^3.0.2", - "ts-jest": "~26.5.4", - "ts-node": "~10.7.0", - "typescript": "~4.6.3" - } + "name": "@azure-tools/sdk-generation-cli", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "rimraf dist && tsc", + "prepack": "npm run build", + "pack": "npm pack 2>&1", + "test:unit-prepare-environment": "ts-node test/unit/utils/prepareEnvironment.ts", + "test:unit": "npm run test:unit-prepare-environment && jest", + "test:integration": "ts-node test/integration/integrationTest.ts", + "test": "npm run test:unit && npm run test:integration", + "lint": "eslint . -c ../../.eslintrc.json --ignore-path ../../.eslintignore --ext .ts", + "lint:fix": "eslint . -c ../../.eslintrc.json --ignore-path ../../.eslintignore --ext .ts --fix" + }, + "author": "Microsoft", + "license": "MIT", + "files": [ + "dist/**/*.js", + "dist/**/*.json", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "dist/**/*.handlebars", + "LICENSE", + "README.md" + ], + "bin": { + "getRepoName": "dist/cli/pipelineCli/getRepoNameCli.js", + "generateResult": "dist/cli/pipelineCli/generateResultCli.js", + "publishResult": "dist/cli/pipelineCli/publishResultCli.js", + "uploadArtifact": "dist/cli/pipelineCli/uploadArtifactCli.js", + "prepareArtifactFiles": "dist/cli/pipelineCli/prepareArtifactFilesCli.js", + "docker-cli": "dist/cli/dockerCli/dockerCli.js", + "run-mock-host": "dist/cli/dockerCli/runMockHostCli.js" + }, + "dependencies": { + "@azure/storage-blob": "^12.8.0", + "ajv": "^6.12.6", + "convict": "^6.2.3", + "@azure-tools/sdk-generation-lib": "^1.0.0", + "axios": "^0.24.0", + "dotenv": "^16.0.0", + "winston": "~3.7.2", + "command-line-args": "~5.2.1" + }, + "bundledDependencies": [ + "@azure-tools/sdk-generation-lib" + ], + "devDependencies": { + "@types/node": "^16.11.7", + "rimraf": "^3.0.2", + "jest": "~26.6.3", + "ts-jest": "~26.5.4", + "@types/jest": "^25.2.1", + "typescript": "~4.6.3", + "ts-node": "~10.7.0", + "eslint": "^8.16.0", + "@typescript-eslint/eslint-plugin": "^5.25.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "@typescript-eslint/parser": "^5.25.0", + "eslint-plugin-simple-import-sort": "^7.0.0" + } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerContext.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerContext.ts new file mode 100644 index 000000000..c85d7e423 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerContext.ts @@ -0,0 +1,104 @@ +import { initializeLogger } from '@azure-tools/sdk-generation-lib'; +import fs from 'fs'; +import path from 'path'; +import { Logger } from 'winston'; + +import { DockerCliInput } from '../schema/dockerCliInput'; +import { sdkToRepoMap } from './constants'; +import { DockerRunningModel } from './DockerRunningModel'; + +export class DockerContext { + mode: DockerRunningModel; + readmeMdPath?: string; + tag?: string; + sdkList: string[]; + specRepo?: string; + workDir?: string; + sdkRepo?: string; + resultOutputFolder?: string; + logger: Logger; + + /* + * there are different modes to use the docker image: + * 1. local: generate codes + * 2. local: grow up + * 3. pipeline: generate codes + * */ + public initialize(inputParams: DockerCliInput) { + this.readmeMdPath = inputParams.readmeMdPath; + this.tag = inputParams.tag; + this.sdkList = inputParams.sdkList?.split(',').map((e) => e.trim()).filter((e) => e.length > 0); + this.specRepo = inputParams.specRepo; + this.workDir = inputParams.workDir; + this.sdkRepo = inputParams.sdkRepo; + this.resultOutputFolder = inputParams.resultOutputFolder; + + this.logger = initializeLogger(path.join(inputParams.resultOutputFolder, inputParams.dockerLogger), 'docker'); + + if (this.sdkList?.length === 0 && fs.existsSync(this.workDir)) { + this.logger.info('Preparing environment to do grow up development'); + this.mode = DockerRunningModel.GrowUp; + this.validateSpecRepo(); + this.validateWorkDir(); + } else if (fs.existsSync(this.workDir)) { + this.logger.info('Preparing environment to generate codes and do grow up development in local'); + this.mode = DockerRunningModel.CodeGenAndGrowUp; + this.validateSpecRepo(); + this.validateReadmeMdPath(); + this.validateSdk(); + } else { + this.logger.info('Preparing environment to generate codes in pipeline'); + this.mode = DockerRunningModel.Pipeline; + this.validateSdkRepo(); + this.validateSpecRepo(); + this.validateReadmeMdPath(); + this.validateOutputFolder(); + } + } + + private validateSpecRepo() { + if (!fs.existsSync(this.specRepo)) { + throw new Error(`Cannot find ${this.sdkRepo}, please mount it to docker container`); + } + } + + private validateReadmeMdPath() { + if (!this.readmeMdPath) { + throw new Error(`Get empty readme.md path, please input it with --readme`); + } + if (!fs.existsSync(path.join(this.specRepo, this.readmeMdPath))) { + throw new Error(`Cannot find file ${this.readmeMdPath}, please input a valid one`); + } + } + + private validateSdk() { + const supportedSdk = Object.keys(sdkToRepoMap); + const unSupportedSdk: string[] = []; + for (const sdk of this.sdkList) { + if (!supportedSdk.includes(sdk)) { + unSupportedSdk.push(sdk); + } + } + if (unSupportedSdk.length > 0) { + throw new Error(`Docker container doesn't support the following sdks: ${unSupportedSdk.join(', ')}`); + } + } + + private validateWorkDir() { + if (!fs.existsSync(this.workDir)) { + throw new Error(`Cannot find ${this.workDir}, please mount it to docker container`); + } + } + + private validateSdkRepo() { + if (!fs.existsSync(this.sdkRepo)) { + throw new Error(`Cannot find ${this.sdkRepo}, please mount it to docker container`); + } + } + + private validateOutputFolder() { + if (!fs.existsSync(this.resultOutputFolder)) { + throw new Error(`Cannot find ${this.resultOutputFolder}, please mount it to docker container`); + } + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerRunningModel.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerRunningModel.ts new file mode 100644 index 000000000..99f5dd6ef --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerRunningModel.ts @@ -0,0 +1,5 @@ +export enum DockerRunningModel { + CodeGenAndGrowUp, + GrowUp, + Pipeline +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerTaskEngineContext.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerTaskEngineContext.ts new file mode 100644 index 000000000..ea7c91991 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/DockerTaskEngineContext.ts @@ -0,0 +1,148 @@ +import { CodegenToSdkConfig, getCodegenToSdkConfig, requireJsonc, StringMap } from '@azure-tools/sdk-generation-lib'; +import { execSync } from 'child_process'; +import * as fs from 'fs'; +import { writeFileSync } from 'fs'; +import * as path from 'path'; +import { Logger } from 'winston'; + +import { disableFileMode, getHeadRef, getHeadSha, safeDirectory } from '../../../utils/git'; +import { dockerTaskEngineInput } from '../schema/dockerTaskEngineInput'; +import { DockerContext } from './DockerContext'; +import { DockerRunningModel } from './DockerRunningModel'; +import { GenerateAndBuildTask } from './tasks/GenerateAndBuildTask'; +import { InitTask } from './tasks/InitTask'; +import { MockTestTask } from './tasks/MockTestTask'; +import { SDKGenerationTaskBase } from './tasks/SDKGenerationTaskBase'; + +export class DockerTaskEngineContext { + logger: Logger; + configFilePath: string; + initOutputJsonFile: string; + generateAndBuildInputJsonFile: string; + generateAndBuildOutputJsonFile: string; + mockTestInputJsonFile: string; + mockTestOutputJsonFile: string; + initTaskLog: string; + generateAndBuildTaskLog: string; + mockTestTaskLog: string; + readmeMdPath: string; + specRepo: { + repoPath: string; + headSha: string; + headRef: string; + repoHttpsUrl: string; + }; + serviceType?: string; + tag?: string; + sdkRepo: string; + resultOutputFolder?: string; + envs?: StringMap; + packageFolders?: string[]; + mockServerHost?: string; + taskResults?: {}; + taskResultJsonPath: string; + changeOwner: boolean; + mode: DockerRunningModel; + + public initialize(dockerContext: DockerContext) { + // before execute task engine, safe spec repos and sdk repos because they may be owned by others + safeDirectory(dockerContext.specRepo); + safeDirectory(dockerContext.sdkRepo); + const dockerTaskEngineConfigProperties = dockerTaskEngineInput.getProperties(); + this.logger = dockerContext.logger; + this.configFilePath = dockerTaskEngineConfigProperties.configFilePath; + this.initOutputJsonFile = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.initOutputJsonFile); + this.generateAndBuildInputJsonFile = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.generateAndBuildInputJsonFile); + this.generateAndBuildOutputJsonFile = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.generateAndBuildOutputJsonFile); + this.mockTestInputJsonFile = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.mockTestInputJsonFile); + this.mockTestOutputJsonFile = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.mockTestOutputJsonFile); + this.initTaskLog = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.initTaskLog); + this.generateAndBuildTaskLog = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.generateAndBuildTaskLog); + this.mockTestTaskLog = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.mockTestTaskLog); + this.readmeMdPath = dockerContext.readmeMdPath; + this.specRepo = { + repoPath: dockerContext.specRepo, + headSha: dockerTaskEngineConfigProperties.headSha ?? dockerContext.mode === DockerRunningModel.Pipeline? + getHeadSha(dockerContext.specRepo) : '{commit_id}', + headRef: dockerTaskEngineConfigProperties.headRef ?? getHeadRef(dockerContext.specRepo), + repoHttpsUrl: dockerTaskEngineConfigProperties.repoHttpsUrl + }; + this.serviceType = dockerContext.readmeMdPath.includes('data-plane') && dockerTaskEngineConfigProperties.serviceType ? 'data-plane': 'resource-manager'; + this.tag = dockerContext.tag; + this.sdkRepo = dockerContext.sdkRepo; + this.resultOutputFolder = dockerContext.resultOutputFolder ?? '/tmp/output'; + this.mockServerHost = dockerTaskEngineConfigProperties.mockServerHost; + this.taskResultJsonPath = path.join(dockerContext.resultOutputFolder, dockerTaskEngineConfigProperties.taskResultJson); + this.changeOwner = dockerTaskEngineConfigProperties.changeOwner; + this.mode = dockerContext.mode; + } + + public async beforeRunTaskEngine() { + if (!!this.resultOutputFolder && !fs.existsSync(this.resultOutputFolder)) { + fs.mkdirSync(this.resultOutputFolder, { recursive: true }); + } + this.logger.info(`Start to run task engine in ${path.basename(this.sdkRepo)}`); + } + + public async afterRunTaskEngine() { + if (this.changeOwner && !!this.specRepo?.repoPath && !!fs.existsSync(this.specRepo.repoPath)) { + const userGroupId = (execSync(`stat -c "%u:%g" ${this.specRepo.repoPath}`, { encoding: 'utf8' })).trim(); + if (!!this.resultOutputFolder && fs.existsSync(this.resultOutputFolder)) { + execSync(`chown -R ${userGroupId} ${this.specRepo.repoPath}`); + } + if (!!this.sdkRepo && fs.existsSync(this.sdkRepo)) { + execSync(`chown -R ${userGroupId} ${this.sdkRepo}`, { encoding: 'utf8' }); + disableFileMode(this.sdkRepo); + } + } + if (!!this.taskResults) { + writeFileSync(this.taskResultJsonPath, JSON.stringify(this.taskResults, undefined, 2), 'utf-8'); + } + this.logger.info(`Finish running task engine in ${path.basename(this.sdkRepo)}`); + } + + public async getTaskToRun(): Promise { + const codegenToSdkConfig: CodegenToSdkConfig = getCodegenToSdkConfig(requireJsonc(path.join(this.sdkRepo, this.configFilePath))); + this.logger.info(`Get codegen_to_sdk_config.json`); + this.logger.info(JSON.stringify(codegenToSdkConfig, undefined, 2)); + const tasksToRun: SDKGenerationTaskBase[] = []; + for (const taskName of Object.keys(codegenToSdkConfig)) { + let task: SDKGenerationTaskBase; + switch (taskName) { + case 'init': + task = new InitTask(this); + break; + case 'generateAndBuild': + task = new GenerateAndBuildTask(this); + break; + case 'mockTest': + task = new MockTestTask(this); + break; + } + + if (!!task) { + tasksToRun.push(task); + if (!this.taskResults) { + this.taskResults = {}; + } + this.taskResults[taskName] = 'skipped'; + } + } + tasksToRun.sort((a, b) => a.order - b.order); + this.logger.info(`Get tasks to run: ${tasksToRun.map((task) => task.taskType).join(',')}`); + return tasksToRun; + } + + public async runTaskEngine() { + await this.beforeRunTaskEngine(); + try { + const tasksToRun: SDKGenerationTaskBase[] = await this.getTaskToRun(); + for (const task of tasksToRun) { + await task.execute(); + } + } finally { + await this.afterRunTaskEngine(); + } + } +} + diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/constants.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/constants.ts new file mode 100644 index 000000000..20775e014 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/constants.ts @@ -0,0 +1,7 @@ +export const sdkToRepoMap = { + 'js': 'azure-sdk-for-js', + 'python': 'azure-sdk-for-python', + 'go': 'azure-sdk-for-go', + 'java': 'azure-sdk-for-java', + '.net': 'azure-sdk-for-net' +}; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/BaseJob.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/BaseJob.ts new file mode 100644 index 000000000..7b96d8cd5 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/BaseJob.ts @@ -0,0 +1,8 @@ +import * as fs from 'fs'; + +export class BaseJob { + public doNotExitDockerContainer() { + // this file will be used by entrypoint.sh to determine whether exit the docker container. + fs.writeFileSync('/tmp/notExit', 'yes', 'utf-8'); + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInLocalJob.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInLocalJob.ts new file mode 100644 index 000000000..f815e5d89 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInLocalJob.ts @@ -0,0 +1,57 @@ +import { existsSync } from 'fs'; +import * as path from 'path'; + +import { cloneRepo, getChangedPackageDirectory } from '../../../../utils/git'; +import { sdkToRepoMap } from '../constants'; +import { DockerContext } from '../DockerContext'; +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; +import { BaseJob } from './BaseJob'; + +export class GenerateCodesInLocalJob extends BaseJob { + context: DockerContext; + + constructor(context: DockerContext) { + super(); + this.context = context; + } + + public async cloneRepoIfNotExist(sdkRepos: string[]) { + for (const sdkRepo of sdkRepos) { + if (!existsSync(path.join(this.context.workDir, sdkRepo))) { + await cloneRepo(sdkRepo, this.context.workDir, this.context.logger); + } + this.context.sdkRepo = path.join(this.context.workDir, sdkRepo); + } + } + + public async execute() { + const sdkRepos: string[] = this.context.sdkList.map((ele) => sdkToRepoMap[ele]); + await this.cloneRepoIfNotExist(sdkRepos); + for (const sdk of this.context.sdkList) { + this.context.sdkRepo = path.join(this.context.workDir, sdkToRepoMap[sdk]); + const dockerTaskEngineContext = new DockerTaskEngineContext(); + dockerTaskEngineContext.initialize(this.context); + await dockerTaskEngineContext.runTaskEngine(); + } + + const generatedCodesPath: Map> = new Map(); + + for (const sdk of this.context.sdkList) { + generatedCodesPath[sdk] = await getChangedPackageDirectory(path.join(this.context.workDir, sdkToRepoMap[sdk])); + } + + this.context.logger.info(`Finish generating sdk for ${this.context.sdkList.join(', ')}.`); + for (const sdk of this.context.sdkList) { + if (generatedCodesPath[sdk].size > 0) { + this.context.logger.info(`You can find changed files of ${sdk} in:`); + generatedCodesPath[sdk].forEach((ele) => { + this.context.logger.info(` - ${path.join(this.context.workDir, sdkToRepoMap[sdk], ele)}`); + }); + } else { + this.context.logger.info(`Cannot find changed files of ${sdk} because there is no git diff.`); + } + } + this.context.logger.info(`You can use vscode to connect this docker container for further development.`); + this.doNotExitDockerContainer(); + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInPipelineJob.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInPipelineJob.ts new file mode 100644 index 000000000..a6d798ce6 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GenerateCodesInPipelineJob.ts @@ -0,0 +1,18 @@ +import { DockerContext } from '../DockerContext'; +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; +import { BaseJob } from './BaseJob'; + +export class GenerateCodesInPipelineJob extends BaseJob { + context: DockerContext; + + constructor(context: DockerContext) { + super(); + this.context = context; + } + + public async execute() { + const context: DockerTaskEngineContext = new DockerTaskEngineContext(); + context.initialize(this.context); + await context.runTaskEngine(); + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GrowUpJob.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GrowUpJob.ts new file mode 100644 index 000000000..b747b1c49 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/jobs/GrowUpJob.ts @@ -0,0 +1,16 @@ +import { DockerContext } from '../DockerContext'; +import { BaseJob } from './BaseJob'; + +export class GrowUpJob extends BaseJob { + context: DockerContext; + + constructor(context: DockerContext) { + super(); + this.context = context; + } + + public async execute() { + this.context.logger.info(`Please use vscode to connect this container.`); + this.doNotExitDockerContainer(); + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/GenerateAndBuildTask.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/GenerateAndBuildTask.ts new file mode 100644 index 000000000..615a5e8d5 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/GenerateAndBuildTask.ts @@ -0,0 +1,71 @@ +import { + addFileLog, GenerateAndBuildInput, + GenerateAndBuildOptions, + getGenerateAndBuildOutput, + getTask, removeFileLog, requireJsonc, + runScript +} from '@azure-tools/sdk-generation-lib'; +import fs from 'fs'; +import path from 'path'; + +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; +import { SDKGenerationTaskBase, TaskType } from './SDKGenerationTaskBase'; + +export class GenerateAndBuildTask implements SDKGenerationTaskBase { + taskType: TaskType; + order: number; + context: DockerTaskEngineContext; + + constructor(context: DockerTaskEngineContext) { + this.taskType = 'GenerateAndBuildTask'; + this.order = 1; + this.context = context; + } + + public async execute() { + const generateAndBuildTask = getTask(path.join(this.context.sdkRepo, this.context.configFilePath), 'generateAndBuild'); + if (!generateAndBuildTask) { + throw new Error(`Generate and build task is ${generateAndBuildTask}`); + } + const generateAndBuildOptions = generateAndBuildTask as GenerateAndBuildOptions; + const runOptions = generateAndBuildOptions.generateAndBuildScript; + const readmeMdAbsolutePath = path.join(this.context.specRepo.repoPath, this.context.readmeMdPath); + const specRepoPath = this.context.specRepo.repoPath.includes('specification')? + this.context.specRepo.repoPath : path.join(this.context.specRepo.repoPath, 'specification'); + const relatedReadmeMdFileRelativePath = path.relative(specRepoPath, readmeMdAbsolutePath); + const inputContent: GenerateAndBuildInput = { + specFolder: specRepoPath, + headSha: this.context.specRepo.headSha, + headRef: this.context.specRepo.headRef, + repoHttpsUrl: this.context.specRepo.repoHttpsUrl, + relatedReadmeMdFile: relatedReadmeMdFileRelativePath, + serviceType: this.context.serviceType + }; + const inputJson = JSON.stringify(inputContent, undefined, 2); + this.context.logger.info(`Get ${path.basename(this.context.generateAndBuildInputJsonFile)}:`); + this.context.logger.info(inputJson); + fs.writeFileSync(this.context.generateAndBuildInputJsonFile, inputJson, { encoding: 'utf-8' }); + addFileLog(this.context.logger, this.context.generateAndBuildTaskLog, 'generateAndBuild'); + const executeResult = await runScript(runOptions, { + cwd: path.resolve(this.context.sdkRepo), + args: [this.context.generateAndBuildInputJsonFile, this.context.generateAndBuildOutputJsonFile], + envs: this.context.envs, + customizedLogger: this.context.logger + }); + removeFileLog(this.context.logger, 'generateAndBuild'); + this.context.taskResults['generateAndBuild'] = executeResult; + if (executeResult === 'failed') { + throw new Error(`Execute generateAndBuild script failed.`); + } + if (fs.existsSync(this.context.generateAndBuildOutputJsonFile)) { + const generateAndBuildOutputJson = getGenerateAndBuildOutput(requireJsonc(this.context.generateAndBuildOutputJsonFile)); + this.context.logger.info(`Get ${path.basename(this.context.generateAndBuildOutputJsonFile)}:`); + this.context.logger.info(JSON.stringify(generateAndBuildOutputJson, undefined, 2)); + const packageFolders: string[] = []; + for (const p of generateAndBuildOutputJson.packages) { + packageFolders.push(p.packageFolder); + } + this.context.packageFolders = packageFolders; + } + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/InitTask.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/InitTask.ts new file mode 100644 index 000000000..899e23614 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/InitTask.ts @@ -0,0 +1,55 @@ +import { + addFileLog, + getTask, + InitOptions, + initOutput, + removeFileLog, + requireJsonc, + runScript +} from '@azure-tools/sdk-generation-lib'; +import fs from 'fs'; +import path from 'path'; + +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; +import { SDKGenerationTaskBase, TaskType } from './SDKGenerationTaskBase'; + +export class InitTask implements SDKGenerationTaskBase { + taskType: TaskType; + order: number; + context: DockerTaskEngineContext; + + constructor(context: DockerTaskEngineContext) { + this.taskType = 'InitTask'; + this.order = 0; + this.context = context; + } + + public async execute() { + const initTask = getTask(path.join(this.context.sdkRepo, this.context.configFilePath), 'init'); + if (!initTask) { + throw new Error(`Init task is ${initTask}`); + } + const initOptions = initTask as InitOptions; + const runOptions = initOptions.initScript; + addFileLog(this.context.logger, this.context.initTaskLog, 'init'); + const executeResult = await runScript(runOptions, { + cwd: path.resolve(this.context.sdkRepo), + args: [this.context.initOutputJsonFile], + customizedLogger: this.context.logger + }); + removeFileLog(this.context.logger, 'init'); + this.context.taskResults['init'] = executeResult; + if (executeResult === 'failed') { + throw new Error(`Execute init script failed.`); + } + if (fs.existsSync(this.context.initOutputJsonFile)) { + const initOutputJson = initOutput(requireJsonc(this.context.initOutputJsonFile)); + this.context.logger.info(`Get ${path.basename(this.context.initOutputJsonFile)}:`); + this.context.logger.info(JSON.stringify(initOutputJson, undefined, 2)); + + if (initOutputJson?.envs) { + this.context.envs = initOutputJson.envs; + } + } + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/MockTestTask.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/MockTestTask.ts new file mode 100644 index 000000000..38265cc73 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/MockTestTask.ts @@ -0,0 +1,72 @@ +import { + addFileLog, + getTask, + getTestOutput, + MockTestInput, + MockTestOptions, removeFileLog, requireJsonc, + runScript, TaskResultStatus +} from '@azure-tools/sdk-generation-lib'; +import fs from 'fs'; +import path from 'path'; + +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; +import { SDKGenerationTaskBase, TaskType } from './SDKGenerationTaskBase'; + +export class MockTestTask implements SDKGenerationTaskBase { + context: DockerTaskEngineContext; + order: number; + taskType: TaskType; + + constructor(context: DockerTaskEngineContext) { + this.taskType = 'MockTestTask'; + this.order = 2; + this.context = context; + } + + public async execute() { + const mockTestTask = getTask(path.join(this.context.sdkRepo, this.context.configFilePath), 'mockTest'); + if (!mockTestTask) { + throw new Error(`Init task is ${mockTestTask}`); + } + const mockTestOptions = mockTestTask as MockTestOptions; + const runOptions = mockTestOptions.mockTestScript; + for (const packageFolder of this.context.packageFolders) { + this.context.logger.info(`Run MockTest for ${packageFolder}`); + + const inputContent: MockTestInput = { + packageFolder: path.join(this.context.sdkRepo, packageFolder), + mockServerHost: this.context.mockServerHost + }; + const inputJson = JSON.stringify(inputContent, undefined, 2); + const formattedPackageName = packageFolder.replace(/[^a-zA-z0-9]/g, '-'); + const mockTestInputJsonPath = this.context.packageFolders.length > 1 ? + this.context.mockTestInputJsonFile.replace('.json', `${formattedPackageName}.json`) : this.context.mockTestInputJsonFile; + const mockTestOutputJsonPath = this.context.packageFolders.length > 1 ? + this.context.mockTestOutputJsonFile.replace('.json', `${formattedPackageName}.json`) : this.context.mockTestOutputJsonFile; + const mockTestTaskLogPath = this.context.packageFolders.length > 1 ? + this.context.mockTestTaskLog.replace('task.log', `${formattedPackageName}-task.log`) : this.context.mockTestTaskLog; + fs.writeFileSync(mockTestInputJsonPath, inputJson, { encoding: 'utf-8' }); + this.context.logger.info(`Get ${path.basename(mockTestInputJsonPath)}:`); + this.context.logger.info(inputJson); + addFileLog(this.context.logger, mockTestTaskLogPath, `mockTest_${formattedPackageName}`); + const executeResult = await runScript(runOptions, { + cwd: path.resolve(this.context.sdkRepo), + args: [mockTestInputJsonPath, mockTestOutputJsonPath], + envs: this.context.envs, + customizedLogger: this.context.logger + }); + this.context.taskResults['mockTest'] = executeResult === TaskResultStatus.Success && + this.context.taskResults['mockTest'] !== TaskResultStatus.Failure ? + TaskResultStatus.Success : TaskResultStatus.Failure; + removeFileLog(this.context.logger, `mockTest_${formattedPackageName}`); + if (fs.existsSync(mockTestOutputJsonPath)) { + const mockTestOutputJson = getTestOutput(requireJsonc(mockTestOutputJsonPath)); + this.context.logger.info(`Get ${path.basename(mockTestOutputJsonPath)}:`); + this.context.logger.info(JSON.stringify(mockTestOutputJson, undefined, 2)); + } + if (this.context.taskResults['mockTest'] === TaskResultStatus.Failure) { + throw new Error('Run Mock Test Failed'); + } + } + } +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/SDKGenerationTaskBase.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/SDKGenerationTaskBase.ts new file mode 100644 index 000000000..62ba8cf5a --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/core/tasks/SDKGenerationTaskBase.ts @@ -0,0 +1,10 @@ +import { DockerTaskEngineContext } from '../DockerTaskEngineContext'; + +export type TaskType = 'InitTask' | 'GenerateAndBuildTask' | 'MockTestTask'; + +export interface SDKGenerationTaskBase { + taskType: TaskType; + context: DockerTaskEngineContext; + order: number; + execute(); +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/dockerCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/dockerCli.ts new file mode 100644 index 000000000..e802dccef --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/dockerCli.ts @@ -0,0 +1,38 @@ +#!/usr/bin/env node +import { DockerContext } from './core/DockerContext'; +import { DockerRunningModel } from './core/DockerRunningModel'; +import { GenerateCodesInLocalJob } from './core/jobs/GenerateCodesInLocalJob'; +import { GenerateCodesInPipelineJob } from './core/jobs/GenerateCodesInPipelineJob'; +import { GrowUpJob } from './core/jobs/GrowUpJob'; +import { DockerCliInput, dockerCliInput } from './schema/dockerCliInput'; + +async function main() { + const inputParams: DockerCliInput = dockerCliInput.getProperties(); + const context: DockerContext = new DockerContext(); + context.initialize(inputParams); + + let executeJob: GenerateCodesInLocalJob | GrowUpJob | GenerateCodesInPipelineJob; + + switch (context.mode) { + case DockerRunningModel.CodeGenAndGrowUp: + executeJob = new GenerateCodesInLocalJob(context); + break; + case DockerRunningModel.GrowUp: + executeJob = new GrowUpJob(context); + break; + case DockerRunningModel.Pipeline: + executeJob = new GenerateCodesInPipelineJob(context); + break; + } + + if (!!executeJob) { + await executeJob.execute(); + } +} + +main().catch((e) => { + console.error('\x1b[31m', e.toString()); + console.error('\x1b[31m', e.message); + console.error('\x1b[31m', e.stack); + process.exit(1); +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/runMockHostCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/runMockHostCli.ts new file mode 100644 index 000000000..10b6c5ba1 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/runMockHostCli.ts @@ -0,0 +1,53 @@ +#!/usr/bin/env node + +import { initializeLogger } from '@azure-tools/sdk-generation-lib'; +import { spawn } from 'child_process'; +import * as path from 'path'; +import { Logger } from 'winston'; + +import { DockerCliInput, dockerCliInput } from './schema/dockerCliInput'; +import { DockerMockHostInput, dockerMockHostInput } from './schema/mockHostCliInput'; + +export type DockerMockHostContext = { + readmeMdPath?: string; + specRepo?: string; + mockHostPath: string; + logger: Logger; +} + +export function initializeDockerMockHostContext(inputParams: DockerMockHostInput & DockerCliInput) { + const dockerMockHostConfigProperties = dockerMockHostInput.getProperties(); + const dockerMockHostContext: DockerMockHostContext = { + readmeMdPath: inputParams.readmeMdPath, + specRepo: inputParams.specRepo, + mockHostPath: dockerMockHostConfigProperties.mockHostPath, + logger: initializeLogger(path.join(inputParams.resultOutputFolder, dockerMockHostConfigProperties.mockHostLogger), 'mock-host', false) + }; + return dockerMockHostContext; +} + +export function runMockHost() { + const inputParams: DockerMockHostInput & DockerCliInput = { + ...dockerCliInput.getProperties(), + ...dockerMockHostInput.getProperties() + }; + const context = initializeDockerMockHostContext(inputParams); + if (!context.readmeMdPath) { + context.logger.log('cmdout', `Cannot get valid readme, so do not start mock server.`); + return; + } + const swaggerJsonFilePattern = context.readmeMdPath.replace(/readme[.a-z-]*.md/gi, '**/*.json'); + const child = spawn(`node`, [`node_modules/@azure-tools/mock-service-host/dist/src/main.js`], { + cwd: context.mockHostPath, + env: { + ...process.env, + 'specRetrievalMethod': 'filesystem', + 'specRetrievalLocalRelativePath': context.specRepo, + 'validationPathsPattern': swaggerJsonFilePattern + } + }); + child.stdout.on('data', (data) => context.logger.log('cmdout', data.toString())); + child.stderr.on('data', (data) => context.logger.log('cmderr', data.toString())); +} + +runMockHost(); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerCliInput.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerCliInput.ts new file mode 100644 index 000000000..c6153bf22 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerCliInput.ts @@ -0,0 +1,74 @@ +import convict from 'convict'; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +export class DockerCliInput { + readmeMdPath: string; + tag: string; + sdkList: string; + specRepo: string; + workDir: string; + sdkRepo: string; + resultOutputFolder: string; + dockerLogger: string; +} + +export const dockerCliInput = convict({ + readmeMdPath: { + default: '', + env: 'README_MD_PATH', + arg: 'readme', + format: String, + doc: 'The relative path to readme.md, which is from the root of spec repo' + }, + tag: { + default: '', + env: 'TAG', + arg: 'tag', + format: String, + doc: 'The tag used to generated codes. If not defined, default tag will be used' + }, + sdkList: { + default: '', + env: 'SDK', + arg: 'sdk', + format: String, + doc: 'which language of sdks do you want to generate? you can input multi language splitted by comma' + }, + specRepo: { + default: '/spec-repo', + env: 'SPEC_REPO', + arg: 'spec-repo', + format: String, + doc: 'the absolute path of the mounted spec repo' + }, + workDir: { + default: '/work-dir', + env: 'WORK_DIR', + arg: 'work-dir', + format: String, + doc: 'the absolute path of work directory, which contains all sdk repos' + }, + sdkRepo: { + default: '/sdk-repo', + env: 'SDK_REPO', + arg: 'sdk-repo', + format: String, + doc: 'the absolute path of sdk repo' + }, + resultOutputFolder: { + default: '/tmp/output', + env: 'RESULT_OUTPUT_FOLDER', + arg: 'result-output-folder', + format: String, + doc: 'the absolute path of output folder, which stores the result of task engine' + }, + dockerLogger: { + default: 'docker.log', + env: 'DOCKER_LOGGER', + arg: 'docker-logger', + format: String, + doc: 'the path of docker.log. it will concat with resultOutputFolder' + } +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerTaskEngineInput.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerTaskEngineInput.ts new file mode 100644 index 000000000..938491786 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/dockerTaskEngineInput.ts @@ -0,0 +1,128 @@ +import convict from 'convict'; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +export class DockerTaskEngineInput { + configFilePath: string; + initOutputJsonFile: string; + generateAndBuildInputJsonFile: string; + generateAndBuildOutputJsonFile: string; + mockTestInputJsonFile: string; + mockTestOutputJsonFile: string; + headSha: string | undefined; + headRef: string | undefined; + repoHttpsUrl: string; + serviceType: string; + mockServerHost?: string; + initTaskLog: string; + generateAndBuildTaskLog: string; + mockTestTaskLog: string; + taskResultJson: string; + changeOwner: boolean; +} + +export const dockerTaskEngineInput = convict({ + configFilePath: { + default: 'eng/codegen_to_sdk_config.json', + env: 'CONFIG_FILE_PATH', + arg: 'configFilePath', + format: String, + doc: 'The relative path to codegen_to_sdk_config.json' + }, + initOutputJsonFile: { + default: 'initOutput.json', + env: 'INIT_OUTPUT_JSON_FILE', + arg: 'initOutputJsonFile', + format: String, + doc: 'The relative path to initOut.json. It will concat with resultOutputFolder' + }, + generateAndBuildInputJsonFile: { + default: 'generateAndBuildInput.json', + env: 'GENERATE_AND_BUILD_INPUT_JSON_FILE', + arg: 'generateAndBuildInputJsonFile', + format: String, + doc: 'The relative path to generateAndBuildInput.json. It will concat with resultOutputFolder' + }, + generateAndBuildOutputJsonFile: { + default: 'generateAndBuildOutputJson.json', + env: 'GENERATE_AND_BUILD_OUTPUT_JSON_File', + arg: 'generateAndBuildOutputJsonFile', + format: String, + doc: 'The relative path to generateAndBuildOutput.json. It will concat with resultOutputFolder' + }, + mockTestInputJsonFile: { + default: 'mockTestInput.json', + env: 'MOCK_TEST_INPUT_JSON_FILE', + arg: 'mockTestInputJsonFile', + format: String, + doc: 'The relative path to mockTestInput.json. It will concat with resultOutputFolder' + }, + mockTestOutputJsonFile: { + default: 'mockTestOutput.json', + env: 'MOCK_TEST_OUTPUT_JSON_FILE', + arg: 'mockTestOutputJsonFile', + format: String, + doc: 'The relative path to mockTestOutput.json. It will concat with resultOutputFolder' + }, + headSha: { + default: undefined, + env: 'HEAD_SHA', + format: String, + doc: 'headSha of spec repo' + }, + headRef: { + default: undefined, + env: 'HEAD_REF', + format: String, + doc: 'headRef of spec repo' + }, + repoHttpsUrl: { + default: 'https://github.com/Azure/azure-rest-api-specs', + env: 'REPO_HTTP_URL', + format: String, + doc: 'The http url of spec repo' + }, + serviceType: { + default: 'resource-manager', + env: 'SERVICE_TYPE', + format: String, + doc: 'resource-manager or data-plane' + }, + mockServerHost: { + default: 'https://localhost:8443', + env: 'MOCK_SERVER_HOST', + format: String, + doc: 'The host of mocker server' + }, + initTaskLog: { + default: 'init-task.log', + env: 'INIT_TASK_LOG', + format: String, + doc: 'The relative path to init-task.log. It will concat with resultOutputFolder' + }, + generateAndBuildTaskLog: { + default: 'generateAndBuild-task.log', + env: 'GENERATE_AND_BUILD_TASK_LOG', + format: String, + doc: 'The relative path to generate-and-build-task.log. It will concat with resultOutputFolder' + }, + mockTestTaskLog: { + default: 'mockTest-task.log', + env: 'MOCK_TEST_TASK_LOG', + format: String, + doc: 'The relative path to mock-test-task.log. It will concat with resultOutputFolder' + }, + taskResultJson: { + default: 'taskResults.json', + env: 'TASK_RESULT_JSON', + format: String, + doc: 'The relative path to taskResult.json. It will concat with resultOutputFolder' + }, + changeOwner: { + default: true, + env: 'CHANGE_OWNER', + format: Boolean, + doc: 'When the commands run in docker, it is required to change the sdk owner because generated codes is owned by root' + } +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/mockHostCliInput.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/mockHostCliInput.ts new file mode 100644 index 000000000..5c98d76f1 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/dockerCli/schema/mockHostCliInput.ts @@ -0,0 +1,26 @@ +import convict from 'convict'; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +export class DockerMockHostInput { + mockHostLogger: string; + mockHostPath: string; +} + +export const dockerMockHostInput = convict({ + mockHostLogger: { + default: 'mock-host.log', + env: 'MOCK_HOST_LOGGER', + arg: 'mock-host-logger', + format: String, + doc: 'the path of mock-host.log. it will concat with resultOutputFolder' + }, + mockHostPath: { + default: '/mock-host', + env: 'MOCK_HOST_PATH', + arg: 'mock-host-path', + format: String, + doc: 'the path of mock-host' + } +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/generateResultCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/generateResultCli.ts similarity index 93% rename from tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/generateResultCli.ts rename to tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/generateResultCli.ts index 473a0346a..9656fb562 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/generateResultCli.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/generateResultCli.ts @@ -1,17 +1,18 @@ #!/usr/bin/env node -import * as fs from 'fs'; import { AzureSDKTaskName, createTaskResult, LogFilter, logger, requireJsonc, - TaskResult, - TaskResultStatus, TaskOutput, + TaskResult, + TaskResultStatus } from '@azure-tools/sdk-generation-lib'; +import * as fs from 'fs'; + +import { GenerateResultCliInput, generateResultCliInput } from '../../cliSchema/generateResultCliConfig'; -import { generateResultCliInput, GenerateResultCliInput } from './cliSchema/generateResultCliConfig'; generateResultCliInput.validate(); const config: GenerateResultCliInput = generateResultCliInput.getProperties(); @@ -60,7 +61,7 @@ async function main() { ); fs.writeFileSync(config.resultOutputPath, JSON.stringify(taskResult, null, 2), { - encoding: 'utf-8', + encoding: 'utf-8' }); console.log('Generate Success !!!'); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/getRepoNameCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/getRepoNameCli.ts similarity index 100% rename from tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/getRepoNameCli.ts rename to tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/getRepoNameCli.ts diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/prepareArtifactFilesCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/prepareArtifactFilesCli.ts similarity index 91% rename from tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/prepareArtifactFilesCli.ts rename to tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/prepareArtifactFilesCli.ts index 97e40d3f2..40a125c29 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/prepareArtifactFilesCli.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/prepareArtifactFilesCli.ts @@ -1,17 +1,17 @@ #!/usr/bin/env node -import * as fs from 'fs'; -import * as path from 'path'; - -import { prepareArtifactFilesInput, PrepareArtifactFilesInput } from './cliSchema/prepareArtifactFilesCliConfig'; import { GenerateAndBuildOutput, getGenerateAndBuildOutput, logger, requireJsonc, SDK, - TaskResultStatus, + TaskResultStatus } from '@azure-tools/sdk-generation-lib'; -import { getFileListInPackageFolder } from './utils/git'; +import * as fs from 'fs'; +import * as path from 'path'; + +import { PrepareArtifactFilesInput, prepareArtifactFilesInput } from '../../cliSchema/prepareArtifactFilesCliConfig'; +import { getFileListInPackageFolder } from '../../utils/git'; function copyFile(filePath: string, targetDir: string) { const fileDir = path.dirname(filePath); @@ -26,7 +26,7 @@ async function prepareSourceCode( ) { for (const p of generateAndBuildOutput.packages) { const result = p.result; - if (result === TaskResultStatus.failure) { + if (result === TaskResultStatus.Failure) { logger.warn(`Build ${p.packageName} failed, skipped it`); continue; } @@ -53,7 +53,7 @@ async function prepareSourceCode( async function prepareArtifacts(generateAndBuildOutput: GenerateAndBuildOutput, language: string, artifactDir: string) { for (const p of generateAndBuildOutput.packages) { const result = p.result; - if (result === TaskResultStatus.failure) { + if (result === TaskResultStatus.Failure) { logger.warn(`Build ${p.packageName} failed, skipped it`); continue; } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/publishResultCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/publishResultCli.ts similarity index 77% rename from tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/publishResultCli.ts rename to tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/publishResultCli.ts index 2b0172820..1e395fe77 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/publishResultCli.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/publishResultCli.ts @@ -1,5 +1,4 @@ #!/usr/bin/env node -import * as fs from 'fs'; import { AzureSDKTaskName, BlobBasicContext, @@ -13,24 +12,25 @@ import { QueuedEvent, requireJsonc, ResultBlobPublisher, - ResultEventhubPublisher, ResultDBPublisher, + ResultEventhubPublisher, SDKPipelineStatus, StorageType, TaskResult, - Trigger, + Trigger } from '@azure-tools/sdk-generation-lib'; +import * as fs from 'fs'; import { - resultPublisherBlobInput, ResultPublisherBlobInput, - resultPublisherDBCodeGenerationInput, + resultPublisherBlobInput, ResultPublisherDBCodeGenerationInput, - resultPublisherDBResultInput, + resultPublisherDBCodeGenerationInput, ResultPublisherDBResultInput, - resultPublisherEventHubInput, + resultPublisherDBResultInput, ResultPublisherEventHubInput, -} from './cliSchema/publishResultConfig'; + resultPublisherEventHubInput +} from '../../cliSchema/publishResultConfig'; async function publishBlob() { resultPublisherBlobInput.validate(); @@ -39,7 +39,7 @@ async function publishBlob() { pipelineBuildId: config.pipelineBuildId, sdkGenerationName: config.sdkGenerationName, azureStorageBlobSasUrl: config.azureStorageBlobSasUrl, - azureBlobContainerName: config.azureBlobContainerName, + azureBlobContainerName: config.azureBlobContainerName }; const resultBlobPublisher: ResultBlobPublisher = new ResultBlobPublisher(context); await resultBlobPublisher.uploadLogsAndResult(config.logsAndResultPath, config.taskName as AzureSDKTaskName); @@ -75,7 +75,7 @@ function initMongoConnectContext(config: ResultPublisherDBCodeGenerationInput): database: config.mongodb.database, ssl: config.mongodb.ssl, synchronize: true, - logging: true, + logging: true }; return mongoConnectContext; @@ -144,37 +144,37 @@ async function publishEventhub(pipelineStatus: SDKPipelineStatus) { const publisher: ResultEventhubPublisher = new ResultEventhubPublisher(config.eventHubConnectionString); switch (pipelineStatus) { - case 'queued': - event = { - status: 'queued', - trigger: trigger, - pipelineBuildId: config.pipelineBuildId, - } as QueuedEvent; - break; - case 'in_progress': - event = { - status: 'in_progress', - trigger: trigger, - pipelineBuildId: config.pipelineBuildId, - } as InProgressEvent; - break; - case 'completed': - if (!config.resultsPath || !config.logPath) { - throw new Error(`Invalid completed event parameter!`); - } + case 'queued': + event = { + status: 'queued', + trigger: trigger, + pipelineBuildId: config.pipelineBuildId + } as QueuedEvent; + break; + case 'in_progress': + event = { + status: 'in_progress', + trigger: trigger, + pipelineBuildId: config.pipelineBuildId + } as InProgressEvent; + break; + case 'completed': + if (!config.resultsPath || !config.logPath) { + throw new Error(`Invalid completed event parameter!`); + } - const taskResults: TaskResult[] = getTaskResults(config.resultsPath); - const taskTotalResult: TaskResult = generateTotalResult(taskResults, config.pipelineBuildId); - event = { - status: 'completed', - trigger: trigger, - pipelineBuildId: config.pipelineBuildId, - logPath: config.logPath, - result: taskTotalResult, - } as CompletedEvent; - break; - default: - throw new Error(`Unsupported status: ` + (pipelineStatus as string)); + const taskResults: TaskResult[] = getTaskResults(config.resultsPath); + const taskTotalResult: TaskResult = generateTotalResult(taskResults, config.pipelineBuildId); + event = { + status: 'completed', + trigger: trigger, + pipelineBuildId: config.pipelineBuildId, + logPath: config.logPath, + result: taskTotalResult + } as CompletedEvent; + break; + default: + throw new Error(`Unsupported status: ` + (pipelineStatus as string)); } await publisher.publishEvent(event); await publisher.close(); @@ -186,17 +186,17 @@ async function main() { const pipelineStatus = args['pipelineStatus']; switch (storageType as StorageType) { - case StorageType.Blob: - await publishBlob(); - break; - case StorageType.Db: - await publishDB(pipelineStatus); - break; - case StorageType.EventHub: - await publishEventhub(pipelineStatus); - break; - default: - throw new Error(`Unknown storageType:${storageType}!`); + case StorageType.Blob: + await publishBlob(); + break; + case StorageType.Db: + await publishDB(pipelineStatus); + break; + case StorageType.EventHub: + await publishEventhub(pipelineStatus); + break; + default: + throw new Error(`Unknown storageType:${storageType}!`); } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/uploadArtifactCli.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/uploadArtifactCli.ts similarity index 89% rename from tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/uploadArtifactCli.ts rename to tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/uploadArtifactCli.ts index fe9d98d18..d84bb061b 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/uploadArtifactCli.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cli/pipelineCli/uploadArtifactCli.ts @@ -1,15 +1,15 @@ #!/usr/bin/env node -import * as fs from 'fs'; import { ArtifactBlobUploader, ArtifactBlobUploaderContext, GenerateAndBuildOutput, getGenerateAndBuildOutput, logger, - requireJsonc, + requireJsonc } from '@azure-tools/sdk-generation-lib'; +import * as fs from 'fs'; -import { uploadBlobInput, UploadBlobInput } from './cliSchema/uploadArtifactConfig'; +import { UploadBlobInput, uploadBlobInput } from '../../cliSchema/uploadArtifactConfig'; async function main() { uploadBlobInput.validate(); @@ -22,7 +22,7 @@ async function main() { azureStorageBlobSasUrl: config.azureStorageBlobSasUrl, azureBlobContainerName: config.azureBlobContainerName, language: config.language, - pipelineBuildId: config.pipelineBuildId, + pipelineBuildId: config.pipelineBuildId }; const artifactBlobUploader: ArtifactBlobUploader = new ArtifactBlobUploader(blobContext); const generateAndBuildOutputJson: GenerateAndBuildOutput = getGenerateAndBuildOutput( diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/generateResultCliConfig.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/generateResultCliConfig.ts index d97a7e866..adc0303e6 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/generateResultCliConfig.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/generateResultCliConfig.ts @@ -17,45 +17,45 @@ export const generateResultCliInput = convict({ pipelineBuildId: { default: null, format: assertNullOrEmpty, - arg: 'buildId', + arg: 'buildId' }, logfile: { default: null, format: assertNullOrEmpty, - arg: 'logfile', + arg: 'logfile' }, logFilterStr: { default: null, nullable: true, format: String, - arg: 'logFilterStr', + arg: 'logFilterStr' }, taskName: { default: null, format: ['init', 'generateAndBuild', 'mockTest', 'liveTest'], - arg: 'taskName', + arg: 'taskName' }, exeResult: { default: null, nullable: true, format: ['success', 'failure'], - arg: 'exeResult', + arg: 'exeResult' }, taskOutputPath: { default: null, nullable: true, format: String, - arg: 'taskOutputPath', + arg: 'taskOutputPath' }, resultOutputPath: { default: null, format: assertNullOrEmpty, - arg: 'resultOutputPath', + arg: 'resultOutputPath' }, dockerResultFile: { default: null, nullable: true, format: String, - arg: 'dockerResultFile', - }, + arg: 'dockerResultFile' + } }); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/prepareArtifactFilesCliConfig.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/prepareArtifactFilesCliConfig.ts index b3ae81f2a..8c59b6023 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/prepareArtifactFilesCliConfig.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/prepareArtifactFilesCliConfig.ts @@ -12,17 +12,17 @@ export const prepareArtifactFilesInput = convict({ generateAndBuildOutputFile: { default: null, format: assertNullOrEmpty, - arg: 'generateAndBuildOutputFile', + arg: 'generateAndBuildOutputFile' }, artifactDir: { doc: 'The dir to publish artifact', default: null, format: assertNullOrEmpty, - arg: 'artifactDir', + arg: 'artifactDir' }, language: { default: null, format: ['js', 'python', 'go', 'net', 'java'], - arg: 'language', - }, + arg: 'language' + } }); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/publishResultConfig.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/publishResultConfig.ts index 60b168a4d..0fda636d7 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/publishResultConfig.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/cliSchema/publishResultConfig.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node +import { ServiceType } from '@azure-tools/sdk-generation-lib'; import convict from 'convict'; -import { ServiceType } from '@azure-tools/sdk-generation-lib'; import { assertNullOrEmpty } from '../utils/validator'; export class ResultPublisherBlobInput { @@ -17,33 +17,33 @@ export const resultPublisherBlobInput = convict({ logsAndResultPath: { default: null, format: assertNullOrEmpty, - arg: 'logsAndResultPath', + arg: 'logsAndResultPath' }, pipelineBuildId: { default: null, format: assertNullOrEmpty, - arg: 'buildId', + arg: 'buildId' }, taskName: { default: null, format: String, - arg: 'taskName', + arg: 'taskName' }, sdkGenerationName: { default: null, format: assertNullOrEmpty, - arg: 'sdkGenerationName', + arg: 'sdkGenerationName' }, azureStorageBlobSasUrl: { default: null, env: 'AZURE_STORAGE_BLOB_SAS_URL', - format: assertNullOrEmpty, + format: assertNullOrEmpty }, azureBlobContainerName: { default: 'sdk-generation', env: 'AZURE_BLOB_CONTAINER_NAME', - format: assertNullOrEmpty, - }, + format: assertNullOrEmpty + } }); export class ResultPublisherDBCodeGenerationInput { @@ -75,102 +75,102 @@ export const resultPublisherDBCodeGenerationInput = convict({ generateAndBuildOutputFile: { default: null, format: assertNullOrEmpty, - arg: 'generateAndBuildOutputFile', + arg: 'generateAndBuildOutputFile' }, pipelineBuildId: { default: null, format: assertNullOrEmpty, - arg: 'buildId', + arg: 'buildId' }, language: { default: null, format: ['js', 'python', 'go', 'net', 'java'], - arg: 'language', + arg: 'language' }, azureStorageBlobSasUrl: { default: null, env: 'AZURE_STORAGE_BLOB_SAS_URL', - format: assertNullOrEmpty, + format: assertNullOrEmpty }, azureBlobContainerName: { default: 'sdk-generation', env: 'AZURE_BLOB_CONTAINER_NAME', - format: assertNullOrEmpty, - }, + format: assertNullOrEmpty + } }); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/SdkGenerationServerClient.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/SdkGenerationServerClient.ts index 13a80d835..a81147fbc 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/SdkGenerationServerClient.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/SdkGenerationServerClient.ts @@ -1,8 +1,8 @@ -import {TaskResult} from "@azure-tools/sdk-generation-lib/dist/types/taskResult"; -import * as https from "https"; -import * as fs from "fs"; +import { TaskResult } from '@azure-tools/sdk-generation-lib/dist/types/taskResult'; +import * as fs from 'fs'; +import * as https from 'https'; -const axios = require('axios') +const axios = require('axios'); export class SdkGenerationServerClient { host: string; @@ -22,8 +22,8 @@ export class SdkGenerationServerClient { }, { httpsAgent: new https.Agent({ cert: this.cert, - key: this.key, + key: this.key }) - }) + }); } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/git.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/git.ts index 91818f6ba..1b9300293 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/git.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/src/utils/git.ts @@ -1,10 +1,58 @@ -import * as child_process from 'child_process'; +import { execSync, spawn } from 'child_process'; +import * as os from 'os'; +import { Logger } from 'winston'; export function getFileListInPackageFolder(packageFolder: string) { - const files = child_process - .execSync('git ls-files -cmo --exclude-standard', { encoding: 'utf8', cwd: packageFolder }) + const files = execSync('git ls-files -cmo --exclude-standard', { encoding: 'utf8', cwd: packageFolder }) .trim() .split('\n'); return files; } + +export function getHeadSha(specRepo: string) { + const headSha = execSync(`git rev-parse HEAD`, { encoding: 'utf8', cwd: specRepo }); + return headSha.trim(); +} + +export function getHeadRef(specRepo: string) { + const headRef = execSync(`git rev-parse --abbrev-ref HEAD`, { encoding: 'utf8', cwd: specRepo }); + return headRef.trim(); +} + +export function safeDirectory(sdkRepo: string) { + execSync(`git config --global --add safe.directory ${sdkRepo}`, { encoding: 'utf8', cwd: sdkRepo }); +} + +export function disableFileMode(sdkRepo: string) { + execSync(`git config core.fileMode false --replace-all`, { encoding: 'utf8', cwd: sdkRepo }); +} + +export async function getChangedPackageDirectory(repo: string): Promise> { + const changedPackageDirectories: Set = new Set(); + const gitLsFiles = execSync(`git ls-files -mdo --exclude-standard`, { encoding: 'utf8', cwd: repo }); + const files = gitLsFiles.split(os.EOL); + for (const filePath of files) { + if (filePath.match(/sdk\/[^\/0-9]*\/.*/)) { + const packageDirectory = /sdk\/[^\/0-9]*\/[^\/]*/.exec(filePath); + if (packageDirectory) { + changedPackageDirectories.add(packageDirectory[0]); + } + } + } + return changedPackageDirectories; +} + +export async function cloneRepo(githubRepo: string, cwd: string, logger: Logger) { + const child = spawn(`git`, [`clone`, `https://github.com/Azure/${githubRepo}.git`], { + cwd: cwd, + stdio: ['ignore', 'pipe', 'pipe'] + }); + child.stdout.on('data', (data) => logger.log('cmdout', data.toString())); + child.stderr.on('data', (data) => logger.log('cmderr', data.toString())); + await new Promise((resolve) => { + child.on('exit', (code, signal) => { + resolve({ code, signal }); + }); + }); +} diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/integration/integrationTest.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/integration/integrationTest.ts new file mode 100644 index 000000000..eb84c8115 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/integration/integrationTest.ts @@ -0,0 +1,101 @@ +import { execSync } from 'child_process'; +import commandLineArgs from 'command-line-args'; +import { existsSync, mkdirSync } from 'fs'; +import * as path from 'path'; +import * as process from 'process'; + +const repoCommitId = { + 'azure-rest-api-specs': '0baca05c851c1749e92beb0d2134cd958827dd54', + 'azure-sdk-for-js': '67946c5b0ce135f58ecfeab1443e5be52604908e', + 'azure-sdk-for-java': '307df24267304fbf3947025bef7eaf9698410de8', + 'azure-sdk-for-python': '53f66170cc47739204cedfe0a46989290c047c98', + 'azure-sdk-for-go': '241bdb849ce431e1a5e398a5649cde93149ee374', + 'azure-sdk-for-net': 'e9db0733a642d50c34101339f74fdc487599d824' +}; + +const defaultImageName = 'sdkgeneration.azurecr.io/sdk-generation:v1.0'; +const integrationBranch = 'sdkgeneration-integration-test'; + +async function prepareRepo(currentPath: string, repoName: string) { + const tmpFolder = path.join(currentPath, 'tmp'); + if (!existsSync(tmpFolder)) { + mkdirSync(tmpFolder); + } + + if (!existsSync(path.join(tmpFolder, repoName))) { + execSync(`git clone https://github.com/Azure/${repoName}.git`, { + cwd: tmpFolder, + stdio: 'inherit' + }); + } + execSync(`git restore --staged . && git restore . && git checkout . && git clean -fd`, { + cwd: path.join(tmpFolder, repoName), + stdio: 'inherit' + }); + + if (!!repoCommitId[repoName] && execSync(`git rev-parse HEAD`, { + encoding: 'utf-8', + cwd: path.join(tmpFolder, repoName) + }).trim() !== repoCommitId[repoName]) { + execSync(`git checkout ${repoCommitId[repoName]}`, { + cwd: path.join(tmpFolder, repoName), + stdio: 'inherit' + }); + } + + if (execSync(`git rev-parse --abbrev-ref HEAD`, { + encoding: 'utf-8', + cwd: path.join(tmpFolder, repoName) + }).trim() !== integrationBranch) { + execSync(`git switch -c ${integrationBranch}`, { + cwd: path.join(tmpFolder, repoName), + stdio: 'inherit' + }); + } +} + +async function runDocker(currentPath: string, sdkRepoName: string, dockerImage: string) { + const tmpFolder = path.join(currentPath, 'tmp'); + // eslint-disable-next-line max-len + execSync(`docker run -v ${path.join(tmpFolder, 'azure-rest-api-specs')}:/spec-repo -v ${path.join(tmpFolder, sdkRepoName)}:/sdk-repo ${dockerImage} --readme=specification/agrifood/resource-manager/readme.md`, { + stdio: 'inherit' + }); +} + +async function buildDockImage(rushCwd: string, dockerCwd: string) { + execSync(`rushx pack`, { + cwd: rushCwd, + stdio: 'inherit' + }); + execSync(`docker build -t ${defaultImageName} .`, { + cwd: dockerCwd, + stdio: 'inherit' + }); +} + +export async function main(options: any) { + const currentPath = path.resolve(__dirname); + if (!options['docker-image']) { + await buildDockImage(path.join(currentPath, '..', '..'), path.join(currentPath, '..', '..', '..', '..')); + options['docker-image'] = defaultImageName; + } + if (!options['sdk-repo']) { + options['sdk-repo'] = Object.keys(repoCommitId).filter((ele) => ele !== 'azure-rest-api-specs').join(','); + } + await prepareRepo(currentPath, 'azure-rest-api-specs'); + for (const sdkRepo of options['sdk-repo'].split(',')) { + await prepareRepo(currentPath, sdkRepo); + await runDocker(currentPath, sdkRepo, options['docker-image']); + } +} + +const optionDefinitions = [ + { name: 'docker-image', type: String }, + { name: 'sdk-repo', type: String } +]; +const options = commandLineArgs(optionDefinitions); + +main(options).catch((err) => { + console.log(err); + process.exit(1); +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/DockerTaskEngine.test.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/DockerTaskEngine.test.ts new file mode 100644 index 000000000..4dbb251ea --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/DockerTaskEngine.test.ts @@ -0,0 +1,84 @@ +import { initializeLogger } from '@azure-tools/sdk-generation-lib'; +import { existsSync } from 'fs'; +import * as path from 'path'; + +import { DockerContext } from '../../src/cli/dockerCli/core/DockerContext'; +import { + DockerTaskEngineContext +} from '../../src/cli/dockerCli/core/DockerTaskEngineContext'; +import { SDKGenerationTaskBase } from '../../src/cli/dockerCli/core/tasks/SDKGenerationTaskBase'; + +describe('task engine', () => { + it('should initialize a DockerTaskEngineContext by DockerContext', async () => { + const dockerContext = new DockerContext(); + const tmpFolder = path.join(path.resolve('.'), 'test', 'unit', 'tmp'); + dockerContext.initialize({ + readmeMdPath: 'specification/agrifood/resource-manager/readme.md', + tag: '', + sdkList: '', + specRepo: path.join(tmpFolder, 'spec-repo'), + workDir: '/work-dir', + sdkRepo: path.join(tmpFolder, 'sdk-repo'), + resultOutputFolder: path.join(tmpFolder, 'output'), + dockerLogger: 'docker.log' + }); + const dockerTaskEngineContext = new DockerTaskEngineContext(); + dockerTaskEngineContext.initialize(dockerContext); + expect(dockerTaskEngineContext.configFilePath).toBe('eng/codegen_to_sdk_config.json'); + expect(dockerTaskEngineContext.initOutputJsonFile).toBe(path.join(tmpFolder, 'output', 'initOutput.json')); + expect(dockerTaskEngineContext.generateAndBuildInputJsonFile).toBe(path.join(tmpFolder, 'output', 'generateAndBuildInput.json')); + expect(dockerTaskEngineContext.generateAndBuildOutputJsonFile).toBe(path.join(tmpFolder, 'output', 'generateAndBuildOutputJson.json')); + expect(dockerTaskEngineContext.mockTestInputJsonFile).toBe(path.join(tmpFolder, 'output', 'mockTestInput.json')); + expect(dockerTaskEngineContext.mockTestOutputJsonFile).toBe(path.join(tmpFolder, 'output', 'mockTestOutput.json')); + expect(dockerTaskEngineContext.initTaskLog).toBe(path.join(tmpFolder, 'output', 'init-task.log')); + expect(dockerTaskEngineContext.generateAndBuildTaskLog).toBe(path.join(tmpFolder, 'output', 'generateAndBuild-task.log')); + expect(dockerTaskEngineContext.mockTestTaskLog).toBe(path.join(tmpFolder, 'output', 'mockTest-task.log')); + expect(dockerTaskEngineContext.readmeMdPath).toBe('specification/agrifood/resource-manager/readme.md'); + }); + + it('should get task list', async () => { + const tmpFolder = path.join(path.resolve('.'), 'test', 'unit', 'tmp'); + const dockerTaskEngineContext = new DockerTaskEngineContext(); + dockerTaskEngineContext.sdkRepo = path.join(tmpFolder, 'sdk-repo'); + dockerTaskEngineContext.configFilePath = 'eng/codegen_to_sdk_config.json'; + dockerTaskEngineContext.logger = initializeLogger(path.join(tmpFolder, 'docker.log'), 'docker', true); + const tasksToRun: SDKGenerationTaskBase[] = await dockerTaskEngineContext.getTaskToRun(); + expect(tasksToRun.length).toEqual(2); + expect(tasksToRun[0].taskType).toEqual('InitTask'); + expect(tasksToRun[1].taskType).toEqual('GenerateAndBuildTask'); + }); + + it('should run tasks', async () => { + jest.setTimeout(999999); + const tmpFolder = path.join(path.resolve('.'), 'test', 'unit', 'tmp'); + const dockerTaskEngineContext = new DockerTaskEngineContext(); + + dockerTaskEngineContext.sdkRepo = path.join(tmpFolder, 'sdk-repo'); + dockerTaskEngineContext.taskResultJsonPath = path.join(tmpFolder, 'output', 'taskResults.json'); + dockerTaskEngineContext.logger = initializeLogger(path.join(tmpFolder, 'docker.log'), 'docker', true); + dockerTaskEngineContext.configFilePath = 'eng/codegen_to_sdk_config.json'; + dockerTaskEngineContext.initOutputJsonFile = path.join(tmpFolder, 'output', 'initOutput.json'); + dockerTaskEngineContext.generateAndBuildInputJsonFile = path.join(tmpFolder, 'output', 'generateAndBuildInput.json'); + dockerTaskEngineContext.generateAndBuildOutputJsonFile = path.join(tmpFolder, 'output', 'generateAndBuildOutputJson.json'); + dockerTaskEngineContext.mockTestInputJsonFile = path.join(tmpFolder, 'output', 'mockTestInput.json'); + dockerTaskEngineContext.mockTestOutputJsonFile = path.join(tmpFolder, 'output', 'mockTestOutput.json'); + dockerTaskEngineContext.initTaskLog = path.join(tmpFolder, 'output', 'init-task.log'); + dockerTaskEngineContext.generateAndBuildTaskLog = path.join(tmpFolder, 'output', 'generateAndBuild-task.log'); + dockerTaskEngineContext.mockTestTaskLog = path.join(tmpFolder, 'output', 'mockTest-task.log'); + dockerTaskEngineContext.readmeMdPath = 'specification/agrifood/resource-manager/readme.md'; + dockerTaskEngineContext.specRepo = { + repoPath: path.join(tmpFolder, 'spec-repo'), + headSha: '11111', + headRef: '11111', + repoHttpsUrl: 'https://github.com/Azure/azure-rest-api-specs' + }; + dockerTaskEngineContext.changeOwner = false; + + await dockerTaskEngineContext.runTaskEngine(); + expect(existsSync(dockerTaskEngineContext.initTaskLog)).toBe(true); + expect(existsSync(dockerTaskEngineContext.generateAndBuildInputJsonFile)).toBe(true); + expect(existsSync(dockerTaskEngineContext.generateAndBuildOutputJsonFile)).toBe(true); + expect(existsSync(dockerTaskEngineContext.generateAndBuildTaskLog)).toBe(true); + expect(existsSync(dockerTaskEngineContext.taskResultJsonPath)).toBe(true); + }); +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/utils/prepareEnvironment.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/utils/prepareEnvironment.ts new file mode 100644 index 000000000..c91074d2e --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-cli/test/unit/utils/prepareEnvironment.ts @@ -0,0 +1,57 @@ +import { execSync } from 'child_process'; +import { existsSync, mkdirSync } from 'fs'; +import * as path from 'path'; + +function mkdirTmpFolderIfNotExist(tmpFolder: string) { + if (!existsSync(tmpFolder)) { + mkdirSync(tmpFolder); + } +} + +function cloneSpecRepoIfNotExist(tmpFolder: string) { + if (!existsSync(path.join(tmpFolder, 'spec-repo'))) { + execSync(`git clone https://github.com/Azure/azure-rest-api-specs.git spec-repo`, { + cwd: tmpFolder, + stdio: 'inherit' + }); + } + execSync(`git checkout 0baca05c851c1749e92beb0d2134cd958827dd54`, { + cwd: path.join(tmpFolder, 'spec-repo'), + stdio: 'inherit' + }); +} + +function cloneSdkRepoIfNotExist(tmpFolder: string) { + if (!existsSync(path.join(tmpFolder, 'sdk-repo'))) { + execSync(`git clone https://github.com/Azure/azure-sdk-for-js.git sdk-repo`, { + cwd: tmpFolder, + stdio: 'inherit' + }); + } + execSync(`git checkout . && git clean -fd`, { + cwd: path.join(tmpFolder, 'sdk-repo'), + stdio: 'inherit' + }); + execSync(`git checkout 67946c5b0ce135f58ecfeab1443e5be52604908e`, { + cwd: path.join(tmpFolder, 'sdk-repo'), + stdio: 'inherit' + }); +} + +function mkdirResultOutputFolderIfNotExist(tmpFolder: string) { + if (!existsSync(path.join(tmpFolder, 'output'))) { + mkdirSync(path.join(tmpFolder, 'output')); + } +} + +async function main() { + const tmpFolder = path.join(path.resolve(__dirname), '..', 'tmp'); + mkdirTmpFolderIfNotExist(tmpFolder); + cloneSpecRepoIfNotExist(tmpFolder); + cloneSdkRepoIfNotExist(tmpFolder); + mkdirResultOutputFolderIfNotExist(tmpFolder); +} + +main().catch((e) => { + console.log(e); +}); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/README.md b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/README.md new file mode 100644 index 000000000..8fd871d49 --- /dev/null +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/README.md @@ -0,0 +1,37 @@ +# @azure-tools/sdk-generation-lib + +This packages includes some basic functionalities and definitions used by sdk generation pipeline. + +## Install + +```shell +npm i @azure-tools/sdk-generation-lib +``` + +# Functionalities + +| Functionalities | Description | +|------------------|------------------------------------------------------------------------------| +| runScript | Run any kind of script/command os supported. | +| createTaskResult | It parses the logs produced by tasks, and generate a summarized task result. | +| executeTask | The wrapper of `runScript` and `createTaskResult`. | +| logger | The logger instance can be used by sdk generation pipeline. | +| getTask | Get task configuration from sdk repo's task configuration. | + +# Definitions + +| Definitions | Description | +|-------------------------|--------------------------------------------------------| +| CodegenToSdkConfig | The configuration type of `codegen_to_sdk_config.json` | +| InitOptions | The configuration type of init task. | +| GenerateAndBuildOptions | The configuration type of generate and build task. | +| MockTestOptions | The configuration type of mock test task. | +| RunOptions | The configuration type of running script. | +| LogFilter | The configuration type of filtering log. | +| InitOutput | The output type of init task. | +| GenerateAndBuildInput | The input type of generate and build task. | +| GenerateAndBuildOutput | The output type of generate and build task. | +| MockTestInput | The input type of mock test task. | +| TestOutput | The output type of mock test task. | +| TaskResultStatus | The task status. | +| TaskResult | The details of a task result. | diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/package.json b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/package.json index 724b821d5..5956d1885 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/package.json +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/package.json @@ -1,54 +1,63 @@ { - "name": "@azure-tools/sdk-generation-lib", - "version": "1.0.4", - "description": "", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "rimraf dist && tsc && npm run copy", - "copy": "copyfiles -u 1 src/types/taskInputAndOuputSchemaTypes/*.json dist", - "prepack": "npm run build", - "pack": "npm pack 2>&1", - "test": "jest --forceExit --detectOpenHandles --coverage=true" - }, - "author": "Microsoft", - "license": "MIT", - "files": [ - "dist/**/*.js", - "dist/**/*.json", - "dist/**/*.js.map", - "dist/**/*.d.ts", - "dist/**/*.d.ts.map", - "dist/**/*.handlebars", - "LICENSE", - "README.md" - ], - "dependencies": { - "@azure/event-hubs": "~5.5.1", - "@azure/storage-blob": "^12.8.0", - "@azure/swagger-validation-common": "^0.1.2", - "@octokit/auth-app": "^2.4.5", - "@octokit/rest": "^18.0.3", - "ajv": "^6.12.6", - "class-validator": "^0.13.2", - "colors": "1.4.0", - "convict": "^6.2.3", - "jsonc-parser": "^3.0.0", - "hot-shots": "^8.5.2", - "memory-fs": "^0.5.0", - "mongodb": "^3.6.10", - "node-yaml": "^3.2.0", - "typeorm": "^0.2.37", - "winston": "^3.7.2" - }, - "devDependencies": { - "@types/node": "^16.11.7", - "copyfiles": "^2.4.1", - "rimraf": "^3.0.2", - "jest": "~26.6.3", - "ts-jest": "~26.5.4", - "@types/jest": "^25.2.1", - "typescript": "~4.6.3", - "ts-node": "~10.7.0" - } + "name": "@azure-tools/sdk-generation-lib", + "version": "1.0.4", + "description": "", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "rimraf dist && tsc && npm run copy", + "copy": "copyfiles -u 1 src/types/taskInputAndOuputSchemaTypes/*.json dist", + "prepack": "npm run build", + "pack": "npm pack 2>&1", + "test": "jest --forceExit --detectOpenHandles --coverage=true", + "lint": "eslint . -c ../../.eslintrc.json --ignore-path ../../.eslintignore --ext .ts", + "lint:fix": "eslint . -c ../../.eslintrc.json --ignore-path ../../.eslintignore --ext .ts --fix" + }, + "author": "Microsoft", + "license": "MIT", + "files": [ + "dist/**/*.js", + "dist/**/*.json", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "dist/**/*.handlebars", + "LICENSE", + "README.md" + ], + "dependencies": { + "@azure/event-hubs": "~5.5.1", + "@azure/storage-blob": "^12.8.0", + "@azure/swagger-validation-common": "^0.1.2", + "@octokit/auth-app": "^2.4.5", + "@octokit/rest": "^18.0.3", + "ajv": "^6.12.6", + "class-validator": "^0.13.2", + "colors": "1.4.0", + "convict": "^6.2.3", + "jsonc-parser": "^3.0.0", + "hot-shots": "^8.5.2", + "memory-fs": "^0.5.0", + "mongodb": "^3.6.10", + "node-yaml": "^3.2.0", + "typeorm": "^0.2.37", + "winston": "^3.7.2" + }, + "devDependencies": { + "@types/node": "^16.11.7", + "copyfiles": "^2.4.1", + "rimraf": "^3.0.2", + "jest": "~26.6.3", + "ts-jest": "~26.5.4", + "@types/jest": "^25.2.1", + "typescript": "~4.6.3", + "ts-node": "~10.7.0","eslint": "^8.16.0", + "@typescript-eslint/eslint-plugin": "^5.25.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "@typescript-eslint/parser": "^5.25.0", + "eslint-plugin-simple-import-sort": "^7.0.0" + } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ArtifactUploader.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ArtifactUploader.ts index 15f035840..026fb292f 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ArtifactUploader.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ArtifactUploader.ts @@ -1,15 +1,15 @@ -import * as child_process from 'child_process'; +import * as childProcess from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; -import { AzureBlobClient } from '../utils/blob/AzureBlobClient'; -import { GenerateAndBuildOutput } from '../types/taskInputAndOuputSchemaTypes/GenerateAndBuildOutput'; -import { logger } from '../utils/logger'; import { SDK } from '../types/commonType'; +import { GenerateAndBuildOutput } from '../types/taskInputAndOuputSchemaTypes/GenerateAndBuildOutput'; import { TaskResultStatus } from '../types/taskResult'; +import { AzureBlobClient } from '../utils/blob/AzureBlobClient'; +import { logger } from '../utils/logger'; function getFileListInPackageFolder(packageFolder: string) { - const files = child_process + const files = childProcess .execSync('git ls-files -cmo --exclude-standard', { encoding: 'utf8', cwd: packageFolder }) .trim() .split('\n'); @@ -57,7 +57,7 @@ export class ArtifactBlobUploader { public async uploadSourceCode(generateAndBuildOutputJson: GenerateAndBuildOutput) { for (const p of generateAndBuildOutputJson.packages) { const result = p.result; - if (result === TaskResultStatus.failure) { + if (result === TaskResultStatus.Failure) { logger.warn(`Build ${p.packageName} failed, skipped it`); continue; } @@ -80,7 +80,7 @@ export class ArtifactBlobUploader { public async uploadArtifacts(generateAndBuildOutputJson: GenerateAndBuildOutput) { for (const p of generateAndBuildOutputJson.packages) { const result = p.result; - if (result === TaskResultStatus.failure) { + if (result === TaskResultStatus.Failure) { logger.warn(`Build ${p.packageName} failed, skipped it`); continue; } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ResultPublisher.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ResultPublisher.ts index 6e6f6c817..c4403cb0f 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ResultPublisher.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/ResultPublisher.ts @@ -1,17 +1,17 @@ import * as fs from 'fs'; - import { Connection, createConnection } from 'typeorm'; -import { AzureBlobClient } from '../utils/blob/AzureBlobClient'; -import { AzureSDKTaskName, SDKPipelineStatus } from '../types/commonType'; + import { CodeGeneration } from '../types/codeGeneration'; -import { CodeGenerationDao } from '../utils/db/codeGenerationDao'; -import { CodeGenerationDaoImpl } from '../utils/db/codeGenerationDaoImpl'; -import { EventHubProducer } from '../utils/eventhub/EventHubProducer'; -import { logger } from '../utils/logger'; +import { AzureSDKTaskName } from '../types/commonType'; import { PipelineRunEvent } from '../types/events'; import { TaskResult, TaskResultEntity } from '../types/taskResult'; +import { AzureBlobClient } from '../utils/blob/AzureBlobClient'; +import { CodeGenerationDao } from '../utils/db/codeGenerationDao'; +import { CodeGenerationDaoImpl } from '../utils/db/codeGenerationDaoImpl'; import { TaskResultDao } from '../utils/db/taskResultDao'; import { TaskResultDaoImpl } from '../utils/db/taskResultDaoImpl'; +import { EventHubProducer } from '../utils/eventhub/EventHubProducer'; +import { logger } from '../utils/logger'; export type MongoConnectContext = { name: string; @@ -50,7 +50,7 @@ export class ResultDBPublisher { ssl: this.context.ssl, synchronize: this.context.synchronize, logging: this.context.logging, - entities: [TaskResultEntity, CodeGeneration], + entities: [TaskResultEntity, CodeGeneration] }); } @@ -101,9 +101,9 @@ export class ResultBlobPublisher { const logsAndResultPathArray = JSON.parse(logsAndResultPath); for (const file of logsAndResultPathArray) { if (fs.existsSync(file)) { - let blobName: string = file.includes('.json') - ? `${this.pipelineBuildId}/logs/${this.sdkGenerationName}-${taskName}-result.json` - : `${this.pipelineBuildId}/logs/${this.sdkGenerationName}-${taskName}.log`; + const blobName: string = file.includes('.json') ? + `${this.pipelineBuildId}/logs/${this.sdkGenerationName}-${taskName}-result.json` : + `${this.pipelineBuildId}/logs/${this.sdkGenerationName}-${taskName}.log`; await this.azureBlobClient.publishBlob(file, blobName); logger.info(`Publish ${file} Success !!!`); } else { diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/executeTask.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/executeTask.ts index 1f4ca608d..e7a53b3cf 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/executeTask.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/executeTask.ts @@ -1,3 +1,6 @@ +import * as fs from 'fs'; + +import { AzureSDKTaskName } from '../types/commonType'; import { getTaskBasicConfig, TaskBasicConfig } from '../types/taskBasicConfig'; import { RunOptions } from '../types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig'; import { GenerateAndBuildInput } from '../types/taskInputAndOuputSchemaTypes/GenerateAndBuildInput'; @@ -6,12 +9,10 @@ import { InitOutput } from '../types/taskInputAndOuputSchemaTypes/InitOutput'; import { LiveTestInput } from '../types/taskInputAndOuputSchemaTypes/LiveTestInput'; import { MockTestInput } from '../types/taskInputAndOuputSchemaTypes/MockTestInput'; import { TestOutput } from '../types/taskInputAndOuputSchemaTypes/TestOutput'; -import { TaskResultStatus, TaskResult } from '../types/taskResult'; +import { TaskResult } from '../types/taskResult'; import { requireJsonc } from '../utils/requireJsonc'; -import { runScript } from './runScript'; -import * as fs from 'fs'; import { createTaskResult } from './generateResult'; -import { AzureSDKTaskName } from '../types/commonType'; +import { runScript } from './runScript'; export async function executeTask( taskName: AzureSDKTaskName, @@ -30,14 +31,10 @@ export async function executeTask( args.push(inputJsonPath); } args.push(outputJsonPath); - const result = await runScript(runScriptOptions, { + const execResult = await runScript(runScriptOptions, { cwd: cwd, - args: args, + args: args }); - let execResult: TaskResultStatus = TaskResultStatus.success; - if (result === 'failed') { - execResult = TaskResultStatus.failure; - } if (fs.existsSync(outputJsonPath)) { const outputJson = requireJsonc(outputJsonPath); return { @@ -49,7 +46,7 @@ export async function executeTask( runScriptOptions.logFilter, outputJson ), - output: outputJson, + output: outputJson }; } else { return { @@ -61,7 +58,7 @@ export async function executeTask( runScriptOptions.logFilter, undefined ), - output: undefined, + output: undefined }; } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/generateResult.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/generateResult.ts index c0714da92..087b8f36f 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/generateResult.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/generateResult.ts @@ -1,18 +1,19 @@ +import * as fs from 'fs'; + import { AzureSDKTaskName } from '../types/commonType'; import { LogFilter } from '../types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig'; import { TestOutput } from '../types/taskInputAndOuputSchemaTypes/TestOutput'; import { - TaskResultCommon, MessageRecord, RawMessageRecord, TaskOutput, TaskResult, + TaskResultCommon, TaskResultStatus, - TestTaskResult, + TestTaskResult } from '../types/taskResult'; import { logger } from '../utils/logger'; import { isLineMatch } from './runScript'; -import * as fs from 'fs'; const logSeparatorLength = 26; // length of '20xx-xx-xx xx:xx:xx cmdout' const timestampLength = 19; // length of '20xx-xx-xx xx:xx:xx' @@ -62,7 +63,7 @@ export function parseGenerateLog( level: 'Error', message: line, time: new Date(line.substring(0, timestampLength)), - type: 'Raw', + type: 'Raw' }; messages.push(message); } else if (isLineMatch(line.toLowerCase(), logWarningFilter)) { @@ -71,7 +72,7 @@ export function parseGenerateLog( level: 'Warning', message: line, time: new Date(line.substring(0, timestampLength)), - type: 'Raw', + type: 'Raw' }; messages.push(message); } @@ -85,7 +86,7 @@ export function parseGenerateLog( pipelineBuildId: pipelineBuildId, errorCount: errorNum, warningCount: warnNum, - messages: messages, + messages: messages }; return result; @@ -100,13 +101,13 @@ export function createTaskResult( taskOutput: TaskOutput ): TaskResult { let commonResult: TaskResultCommon = undefined; - if (taskExeResult === TaskResultStatus.success) { + if (taskExeResult === TaskResultStatus.Success) { commonResult = { name: taskname, pipelineBuildId: pipelineBuildId, result: taskExeResult, errorCount: 0, - warningCount: 0, + warningCount: 0 }; } else { commonResult = parseGenerateLog(pipelineBuildId, taskname, logfile, logFilter); @@ -121,7 +122,7 @@ export function createTaskResult( apiCoverage: 0, codeCoverage: 0, result: taskExeResult, - ...commonResult, + ...commonResult }; } const testOutput: TestOutput = taskOutput as TestOutput; @@ -132,7 +133,7 @@ export function createTaskResult( apiCoverage: testOutput.apiCoverage, codeCoverage: testOutput.codeCoverage, result: taskExeResult, - ...commonResult, + ...commonResult }; return testTaskResult; } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/getTask.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/getTask.ts index a53c9f4a5..f220c99f7 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/getTask.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/getTask.ts @@ -4,7 +4,7 @@ import { getCodegenToSdkConfig, InitOptions, LiveTestOptions, - MockTestOptions, + MockTestOptions } from '../types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig'; import { requireJsonc } from '../utils/requireJsonc'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/runScript.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/runScript.ts index c611f0a0b..712a7215f 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/runScript.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/lib/runScript.ts @@ -1,10 +1,14 @@ -import { RunOptions } from '../types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig'; -import * as path from 'path'; import { spawn } from 'child_process'; -import { logger } from '../utils/logger'; -import { Readable } from 'stream'; -import { scriptRunningState } from '../types/scriptRunningState'; import * as fs from 'fs'; +import * as path from 'path'; +import { Readable } from 'stream'; +import { Logger } from 'winston'; + +import { StringMap, TaskResultStatus } from '../types'; +import { RunOptions } from '../types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig'; +import { logger as globalLogger } from '../utils/logger'; + +let logger = globalLogger; export const isLineMatch = (line: string, filter: RegExp | undefined) => { if (filter === undefined) { @@ -14,12 +18,16 @@ export const isLineMatch = (line: string, filter: RegExp | undefined) => { return filter.exec(line) !== null; }; -const listenOnStream = (prefix: string, stream: Readable, logType: 'cmdout' | 'cmderr') => { +const listenOnStream = ( + prefix: string, + stream: Readable, + logType: 'cmdout' | 'cmderr' +) => { const addLine = (line: string) => { if (line.length === 0) { return; } - logger.log(logType, `${prefix} ${line}`, { show: true }); + logger.log(logType, `${prefix} ${line}`); }; stream.on('data', (data) => { @@ -27,25 +35,29 @@ const listenOnStream = (prefix: string, stream: Readable, logType: 'cmdout' | 'c }); }; -export async function runScript( - runOptions: RunOptions, - options: { - cwd: string; - args?: string[]; +export async function runScript(runOptions: RunOptions, options: { + cwd: string; + args?: string[]; + envs?: StringMap; + customizedLogger?: Logger; +}): Promise { + if (!!options?.customizedLogger) { + logger = options.customizedLogger; } -): Promise { - let executeResult: scriptRunningState; + + let executeResult: TaskResultStatus; const scriptCmd = runOptions.script; const scriptPath = runOptions.path.trim(); - const env = { PWD: path.resolve(options.cwd), ...process.env }; + const env = { ...process.env, PWD: path.resolve(options.cwd), ...options.envs }; + for (const e of runOptions.envs) { env[e] = process.env[e]; } let cmdRet: { code: number | null; signal: NodeJS.Signals | null } = { code: null, - signal: null, + signal: null }; - logger.log('cmdout', 'task script path:' + path.join(options.cwd, scriptPath)); + logger.log('cmdout', 'task script path:' + path.join(options.cwd, scriptPath) ); if (fs.existsSync(path.join(options.cwd, scriptPath))) { logger.log('cmdout', 'chmod'); fs.chmodSync(path.join(options.cwd, scriptPath), '777'); @@ -53,7 +65,7 @@ export async function runScript( try { let command: string = ''; - let args: string[] = []; + let args:string[] = []; const scriptPaths: string[] = scriptPath.split(' '); if (scriptCmd !== undefined && scriptCmd.length > 0) { command = scriptCmd; @@ -67,7 +79,7 @@ export async function runScript( cwd: options.cwd, shell: false, stdio: ['ignore', 'pipe', 'pipe'], - env, + env }); const prefix = `[${runOptions.logPrefix ?? path.basename(scriptPath)}]`; listenOnStream(prefix, child.stdout, 'cmdout'); @@ -79,31 +91,19 @@ export async function runScript( }); }); if (cmdRet.code === 0) { - executeResult = 'succeeded'; + executeResult = TaskResultStatus.Success; } else { - executeResult = 'failed'; + executeResult = TaskResultStatus.Failure; } } catch (e) { cmdRet.code = -1; logger.error(`${e.message}\n${e.stack}`); - executeResult = 'failed'; + executeResult = TaskResultStatus.Failure; } - let storeLog = false; - if ((cmdRet.code !== 0 || cmdRet.signal !== null) && runOptions.exitWithNonZeroCode !== undefined) { - if (runOptions.exitWithNonZeroCode.storeLog) { - storeLog = true; - } - if (runOptions.exitWithNonZeroCode.result === 'error') { - executeResult = 'failed'; - } else if (runOptions.exitWithNonZeroCode.result === 'warning') { - executeResult = 'warning'; - } + if (cmdRet.code !== 0 || cmdRet.signal !== null) { + executeResult = TaskResultStatus.Failure; const message = `Script return with result [${executeResult}] code [${cmdRet.code}] signal [${cmdRet.signal}] cwd [${options.cwd}]: ${scriptPath}`; - if (runOptions.exitWithNonZeroCode.result === 'error') { - logger.error(message, { show: storeLog }); - } else if (runOptions.exitWithNonZeroCode.result === 'warning') { - logger.warn(message, { show: storeLog }); - } + logger.log('cmderr', message); } return executeResult; } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/codeGeneration.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/codeGeneration.ts index 5f46d776c..cfa511bcc 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/codeGeneration.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/codeGeneration.ts @@ -13,49 +13,49 @@ export class CodeGeneration { } } @ObjectIdColumn() - id: number; + id: number; @Index({ unique: true }) @Column() @IsNotEmpty() - name: string; + name: string; @Column() @IsNotEmpty() - service: string; + service: string; @Column() @IsNotEmpty() - serviceType: string; + serviceType: string; @Column() - resourcesToGenerate: string; + resourcesToGenerate: string; @Column() - tag: string; + tag: string; @Column() @IsNotEmpty() - sdk: string; + sdk: string; @Column() @IsNotEmpty() - swaggerRepo: string; + swaggerRepo: string; @Column() @IsNotEmpty() - sdkRepo: string; + sdkRepo: string; @Column() @IsNotEmpty() - codegenRepo: string; + codegenRepo: string; @Column() @IsNotEmpty() - type: string; + type: string; @Column() - ignoreFailure: string; + ignoreFailure: string; @Column() - stages: string; + stages: string; @Column({ default: '' }) - lastPipelineBuildID: string; + lastPipelineBuildID: string; @Column() - swaggerPR: string; + swaggerPR: string; @Column() - codePR: string; + codePR: string; @Column() @IsNotEmpty() - status: string; + status: string; @Column({ default: '' }) - owner: string; + owner: string; } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/index.ts index 2fd866b3c..b689fc1ae 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/index.ts @@ -1,4 +1,3 @@ -export * from './scriptRunningState'; export * from './taskBasicConfig'; export * from './taskResult'; export * from './taskInputAndOuputSchemaTypes'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/scriptRunningState.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/scriptRunningState.ts deleted file mode 100644 index cc8f9e0f3..000000000 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/scriptRunningState.ts +++ /dev/null @@ -1,24 +0,0 @@ -const scriptRunningStateStrings = { - /** - * The process of running script has not yet begun. - */ - pending: `Pending`, - /** - * TThe process of running script is in-progress. - */ - inProgress: `In-Progress`, - /** - * TThe process of running script has failed. - */ - failed: `Failed`, - /** - * TThe process of running script has succeeded. - */ - succeeded: `Succeeded`, - /** - * TThe process of running script has warnings. - */ - warning: `Warning` -}; - -export type scriptRunningState = keyof typeof scriptRunningStateStrings; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskBasicConfig.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskBasicConfig.ts index 984058235..37abd3c59 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskBasicConfig.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskBasicConfig.ts @@ -19,62 +19,62 @@ export const taskBasicConfig = { sdkRepo: { default: '', env: 'SDK_REPO', - format: String, + format: String }, configPath: { default: 'eng/codegen_to_sdk_config.json', env: 'CONFIG_PATH', - format: String, + format: String }, pipelineId: { default: '', env: 'PIPELINE_ID', - format: String, + format: String }, queuedAt: { default: '', env: 'QUEUE_AT', - format: String, + format: String }, pipeLog: { default: '/tmp/sdk-generation/pipe.log', env: 'PIPE_LOG', - format: String, + format: String }, pipeFullLog: { default: '/tmp/sdk-generation/pipe.full.log', env: 'PIPE_FULL_LOG', - format: String, + format: String }, mockServerLog: { default: '', env: 'MOCK_SERVER_LOG', - format: String, + format: String }, sdkGenerationName: { default: '', env: 'SDK_GENERATION_NAME', - format: String, + format: String }, buildId: { default: '', env: 'BUILD_ID', - format: String, + format: String }, taskName: { default: '', env: 'TASK_NAME', - format: String, + format: String }, azureStorageBlobSasUrl: { default: '', env: 'AZURE_STORAGE_BLOB_SAS_URL', - format: String, + format: String }, azureBlobContainerName: { default: 'sdks', env: 'AZURE_BLOB_CONTAINER_NAME', - format: String, - }, + format: String + } }; export const getTaskBasicConfig = convict(taskBasicConfig); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig.ts index 6dfbf73af..dc55845b6 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfig.ts @@ -1,6 +1,7 @@ +import * as path from 'path'; + import { requireJsonc } from '../../utils/requireJsonc'; import { getTypeTransformer } from '../../utils/validator'; -import * as path from 'path'; export const codegenToSdkConfigSchema = requireJsonc(path.join(__dirname, 'CodegenToSdkConfigSchema.json')); @@ -10,10 +11,6 @@ export type RunOptions = { envs?: string[]; logPrefix?: string; logFilter?: LogFilter; - exitWithNonZeroCode?: { - storeLog: boolean; - result: 'error' | 'warning' | 'ignore'; - }; }; export type LogFilter = { diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfigSchema.json b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfigSchema.json index 5b2ec847a..04159ae72 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfigSchema.json +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/CodegenToSdkConfigSchema.json @@ -73,10 +73,9 @@ "type": "string" }, "envs": { - // Not Implemented // Extra environment variable to be passed to the script (except initScript). // By default the following envs will be passed: - // PATH, SHELL, PWD (current directory) + // PWD (current directory) "type": "array", "items": { "type": "string" @@ -90,26 +89,6 @@ "logFilter": { // filter for error msg and warning msg. "$ref": "#/definitions/LogFilter" - }, - "exitWithNonZeroCode": { - "properties": { - // How should SDK Automation handle non-zero exitCode. - "storeLog": { - // Should we store this error. - "type": "boolean", - "default": true - }, - "result": { - // If script has non-error exitCode how should we mark the script's result. - "type": "string", - "enum": ["error", "warning", "ignore"], - "default": "error" - } - }, - "storeAllLog": { - "show": true, - "result": "error" - } } }, "required": ["path"] diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/TestOutputSchema.json b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/TestOutputSchema.json index 478efa89a..7dd2a753b 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/TestOutputSchema.json +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskInputAndOuputSchemaTypes/TestOutputSchema.json @@ -17,6 +17,5 @@ "codeCoverage": { "type": "number" } - }, - "required": ["total", "success", "fail", "apiCoverage", "codeCoverage"] + } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskResult.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskResult.ts index ab8ef7b2d..728babe21 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskResult.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/types/taskResult.ts @@ -1,25 +1,26 @@ +import * as fs from 'fs'; +import { Column, Entity, ObjectIdColumn } from 'typeorm'; + +import { getTaskBasicConfig, TaskBasicConfig } from './taskBasicConfig'; import { GenerateAndBuildOutput } from './taskInputAndOuputSchemaTypes/GenerateAndBuildOutput'; import { InitOutput } from './taskInputAndOuputSchemaTypes/InitOutput'; import { TestOutput } from './taskInputAndOuputSchemaTypes/TestOutput'; -import { getTaskBasicConfig, TaskBasicConfig } from './taskBasicConfig'; -import * as fs from 'fs'; -import { Column, Entity, ObjectIdColumn } from 'typeorm'; @Entity('sdkGenerationResults') export class TaskResultEntity { @ObjectIdColumn() - id: string; + id: string; @Column() - key: string; + key: string; @Column() - pipelineBuildId: string; + pipelineBuildId: string; @Column() - taskResult: TaskResult; + taskResult: TaskResult; } export enum TaskResultStatus { - success = 'succeeded', - failure = 'failed', + Success = 'succeeded', + Failure = 'failed', } export type Extra = { @@ -101,9 +102,9 @@ export function setTaskResult(config: TaskBasicConfig, taskName: string) { taskResult = { name: taskName, pipelineBuildId: '', - result: TaskResultStatus.success, + result: TaskResultStatus.Success, errorCount: 0, - warningCount: 0, + warningCount: 0 }; } @@ -119,18 +120,18 @@ export function generateTotalResult(taskResults: TaskResult[], pipelineBuildId: const totalResult: TaskResult = { name: 'total', pipelineBuildId: pipelineBuildId, - result: TaskResultStatus.success, + result: TaskResultStatus.Success, errorCount: 0, - messages: [], + messages: [] }; if (taskResults.length === 0) { - totalResult.result = TaskResultStatus.failure; + totalResult.result = TaskResultStatus.Failure; return totalResult; } for (const taskResult of taskResults) { - if (taskResult.result !== TaskResultStatus.success) { + if (taskResult.result !== TaskResultStatus.Success) { totalResult.result = taskResult.result; } totalResult.errorCount += taskResult.errorCount; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/AzureBlobClient.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/AzureBlobClient.ts index 456062e4c..e93c44ca1 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/AzureBlobClient.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/AzureBlobClient.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License in the project root for license information. -import { BlobServiceClient } from "@azure/storage-blob"; +import { BlobServiceClient } from '@azure/storage-blob'; -import { logger } from "../logger"; +import { logger } from '../logger'; export class AzureBlobClient { private blobServiceClient: BlobServiceClient; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/index.ts index 0cdab65d2..f07a4980d 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/blob/index.ts @@ -1 +1 @@ -export * from "./AzureBlobClient"; +export * from './AzureBlobClient'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/codeGenerationDaoImpl.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/codeGenerationDaoImpl.ts index b02bf8748..5d6d9957f 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/codeGenerationDaoImpl.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/codeGenerationDaoImpl.ts @@ -1,7 +1,7 @@ import { Connection, MongoRepository } from 'typeorm'; -import { CodeGenerationDao } from './codeGenerationDao'; import { CodeGeneration } from '../../types/codeGeneration'; +import { CodeGenerationDao } from './codeGenerationDao'; export class CodeGenerationDaoImpl implements CodeGenerationDao { private repo: MongoRepository; @@ -40,7 +40,7 @@ export class CodeGenerationDaoImpl implements CodeGenerationDao { await this.repo.delete(codegen); } - /*Get all code generations of an special onboard type. */ + /* Get all code generations of an special onboard type. */ public async listCodeGenerations(filters: any = undefined, filterCompleted = false): Promise { let finalFilters: any; if (!filters) { @@ -48,7 +48,7 @@ export class CodeGenerationDaoImpl implements CodeGenerationDao { } if (filterCompleted) { finalFilters = { - where: { $and: [{ status: { $ne: 'completed' } }, { status: { $ne: 'pipelineCompleted' } }, filters] }, + where: { $and: [{ status: { $ne: 'completed' } }, { status: { $ne: 'pipelineCompleted' } }, filters] } }; } else { finalFilters = filters; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/index.ts index f9e118fb4..88075e7a1 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/index.ts @@ -1,4 +1,4 @@ -export * from "./codeGenerationDao"; -export * from "./codeGenerationDaoImpl"; -export * from "./taskResultDao"; -export * from "./taskResultDaoImpl"; \ No newline at end of file +export * from './codeGenerationDao'; +export * from './codeGenerationDaoImpl'; +export * from './taskResultDao'; +export * from './taskResultDaoImpl'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/taskResultDaoImpl.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/taskResultDaoImpl.ts index 7673e20b6..c070c15d6 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/taskResultDaoImpl.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/db/taskResultDaoImpl.ts @@ -1,7 +1,8 @@ -import { TaskResultDao } from './taskResultDao'; -import { TaskResult, TaskResultEntity } from '../../types/taskResult'; import { Connection, MongoRepository } from 'typeorm'; +import { TaskResult, TaskResultEntity } from '../../types/taskResult'; +import { TaskResultDao } from './taskResultDao'; + export class TaskResultDaoImpl implements TaskResultDao { private repo: MongoRepository; @@ -11,7 +12,7 @@ export class TaskResultDaoImpl implements TaskResultDao { public async getFromBuild(pipelineBuildId: string): Promise { const taskResults: TaskResultEntity[] = await this.repo.find({ - pipelineBuildId: pipelineBuildId, + pipelineBuildId: pipelineBuildId }); const results: TaskResult[] = []; for (const taskResult of taskResults) { @@ -27,7 +28,7 @@ export class TaskResultDaoImpl implements TaskResultDao { { key: key, pipelineBuildId: pipelineBuildId, - taskResult: taskResult, + taskResult: taskResult }, { upsert: true } ); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/EventHubProducer.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/EventHubProducer.ts index 4d3e75e94..1774e70e4 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/EventHubProducer.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/EventHubProducer.ts @@ -2,11 +2,11 @@ // Licensed under the MIT License. See License in the project root for license information. import { CreateBatchOptions, - EventHubProducerClient, EventDataBatch, -} from "@azure/event-hubs"; + EventHubProducerClient +} from '@azure/event-hubs'; -import { logger } from "../logger"; +import { logger } from '../logger'; export class EventHubProducer { private producer: EventHubProducerClient; @@ -23,7 +23,7 @@ export class EventHubProducer { return await this.producer.createBatch(batchOptions); } - private async *getBatchIterator(events: string[], partitionKey?: string) { + private async* getBatchIterator(events: string[], partitionKey?: string) { let toAddIndex = 0; if (toAddIndex >= events.length) { return; @@ -56,19 +56,19 @@ export class EventHubProducer { let next = await batchIterator.next(); while (!next.done) { if (next.value !== undefined) { - let batch: EventDataBatch = next.value as EventDataBatch; + const batch: EventDataBatch = next.value as EventDataBatch; await this.producer.sendBatch(batch); } next = await batchIterator.next(); } - logger.info("Send events done"); + logger.info('Send events done'); } public async close() { try { await this.producer.close(); } catch (err) { - logger.error("Error when closing client: ", err); + logger.error('Error when closing client: ', err); } // swallow the error } } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/index.ts index 01b94d339..42ad36246 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/eventhub/index.ts @@ -1 +1 @@ -export * from "./EventHubProducer"; +export * from './EventHubProducer'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/index.ts index 48426686f..52beb0e55 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/index.ts @@ -1,7 +1,7 @@ -export * from "./logger"; -export * from "./requireJsonc"; -export * from "./validator"; -export * from "./blob"; -export * from "./db"; -export * from "./eventhub"; -export * from "./metric"; \ No newline at end of file +export * from './logger'; +export * from './requireJsonc'; +export * from './validator'; +export * from './blob'; +export * from './db'; +export * from './eventhub'; +export * from './metric'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/logger.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/logger.ts index 4f62b5caa..0152dbff0 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/logger.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/logger.ts @@ -1,86 +1,83 @@ -import * as winston from 'winston'; -import { getTaskBasicConfig, TaskBasicConfig } from '../types/taskBasicConfig'; +import { createLogger, format, Logger, transports } from 'winston'; +import { FileTransportInstance } from 'winston/lib/winston/transports'; -function getLogger() { - const config: TaskBasicConfig = getTaskBasicConfig.getProperties(); - const sdkAutoLogLevels = { - levels: { - error: 0, - warn: 1, - section: 5, // Log as azure devops section - command: 6, // Running a command - cmdout: 7, // Command stdout - cmderr: 8, // Command stdout - info: 15, - endsection: 20, - debug: 50, - }, - colors: { - error: 'red', - warn: 'yellow', - info: 'green', - cmdout: 'green underline', - cmderr: 'yellow underline', - section: 'magenta bold', - endsection: 'magenta bold', - command: 'cyan bold', - debug: 'blue', - }, - }; +import { getTaskBasicConfig } from '../types'; - const logger = winston.createLogger({ - levels: sdkAutoLogLevels.levels, +const loggerLevels = { + levels: { + error: 0, + warn: 1, + cmdout: 2, + cmderr: 3, + info: 4, + debug: 5 + }, + colors: { + error: 'red', + warn: 'yellow', + cmdout: 'green underline', + cmderr: 'yellow underline', + info: 'green', + debug: 'blue' + } +}; + +type WinstonInfo = { + level: keyof typeof loggerLevels.levels; + message: string; + timestamp: string; +}; + +const fileTransportInstances: { + [key: string]: FileTransportInstance +} = {}; + +export function addFileLog(logger: Logger, logPath: string, taskName: string) { + const fileTransportInstance = new transports.File({ + level: 'info', + filename: logPath, + options: { flags: 'w' }, + format: format.combine( + format.timestamp({ format: 'YYYY-MM-DD hh:mm:ss' }), + format.printf((info: WinstonInfo) => { + const msg = `${info.timestamp} ${info.level} \t${info.message}`; + return msg; + }) + ) + }); + fileTransportInstances[taskName] = fileTransportInstance; + logger.add(fileTransportInstance); +} + +export function removeFileLog(logger: Logger, taskName: string) { + if (!fileTransportInstances[taskName]) { + throw new Error(`Try to remove non-existed logger transport: ${taskName}`); + } + logger.remove(fileTransportInstances[taskName]); +} + +export function initializeLogger(logPath: string, taskName: string, addConsoleLog: boolean = true): Logger { + const logger = createLogger({ + levels: loggerLevels.levels }); - type WinstonInfo = { - level: keyof typeof sdkAutoLogLevels.levels; - message: string; - timestamp: string; - storeLog?: boolean; - }; + addFileLog(logger, logPath, taskName); - logger.add( - new winston.transports.File({ + if (addConsoleLog) { + logger.add(new transports.Console({ level: 'info', - filename: config.pipeFullLog, - options: { flags: 'w' }, - format: winston.format.combine( - winston.format.timestamp({ format: 'YYYY-MM-DD hh:mm:ss' }), - winston.format.printf((info: WinstonInfo) => { + format: format.combine( + format.colorize({ colors: loggerLevels.colors }), + format.timestamp({ format: 'YYYY-MM-DD hh:mm:ss' }), + format.printf((info: WinstonInfo) => { const msg = `${info.timestamp} ${info.level} \t${info.message}`; return msg; }) - ), - }) - ); - - logger.add( - new winston.transports.Console({ - level: 'endsection', - format: winston.format.combine( - winston.format.colorize({ colors: sdkAutoLogLevels.colors }), - winston.format.timestamp({ format: 'YYYY-MM-DD hh:mm:ss' }), - winston.format.printf((info: WinstonInfo) => { - const { level } = info; - let msg = `${info.timestamp} ${info.level} \t${info.message}`; - switch (level) { - case 'error': - case 'debug': - case 'command': - msg = `##[${level}] ${msg}`; - case 'warn': - msg = `##[warning] ${msg}`; - case 'section': - msg = `##[group] ${info.message}`; - case 'endsection': - msg = `##[endgroup] ${info.message}`; - } - return msg; - }) - ), - }) - ); + ) + })); + } return logger; } -export const logger: winston.Logger = getLogger(); +// export a default logger, which can be used by pipeline commands +export const logger = initializeLogger(getTaskBasicConfig?.getProperties()?.pipeFullLog, 'pipeline'); diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/MonitorClient.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/MonitorClient.ts index 1c86e8a78..4e2b3ddfe 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/MonitorClient.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/MonitorClient.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License in the project root for license information. -import * as statsd from "hot-shots"; +import * as statsd from 'hot-shots'; export enum Metrics { - Liveness = "liveness", - ApiCalls = "apiCalls", - InternalServerError = "InternalServerError", - BadRequest = "BadRequest", - NotFound = "NotFound", - Success = "success", + Liveness = 'liveness', + ApiCalls = 'apiCalls', + InternalServerError = 'InternalServerError', + BadRequest = 'BadRequest', + NotFound = 'NotFound', + Success = 'success', } export class MonitorClient { @@ -17,7 +17,7 @@ export class MonitorClient { this.stats = new statsd.StatsD({ host: host, port: port, - mock: mock, + mock: mock }); } @@ -45,7 +45,7 @@ export class MonitorClient { const stat = JSON.stringify({ Namespace: serviceName, Metric: metric, - Dims: dims, + Dims: dims }); this.stats.gauge(stat, value); } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/index.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/index.ts index 0f8a90c21..ba52427e6 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/index.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/metric/index.ts @@ -1 +1 @@ -export * from "./MonitorClient"; +export * from './MonitorClient'; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/requireJsonc.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/requireJsonc.ts index 63184bcb3..f885a38ee 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/requireJsonc.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/requireJsonc.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import { parse } from 'jsonc-parser'; export const requireJsonc = (path: string) => { - const contentStr = fs.readFileSync(path).toString(); - const content = parse(contentStr); - return content; + const contentStr = fs.readFileSync(path).toString(); + const content = parse(contentStr); + return content; }; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/validator.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/validator.ts index 439d49258..4d8644d54 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/validator.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/src/utils/validator.ts @@ -1,25 +1,25 @@ -import {ValidateFunction} from "ajv"; +import { ValidateFunction } from 'ajv'; -const Ajv = require("ajv") +const ajvInstance = require('ajv'); -const ajv = new Ajv({ - coerceTypes: true, - messages: true, - verbose: true, - useDefaults: true +const ajv = new ajvInstance({ + coerceTypes: true, + messages: true, + verbose: true, + useDefaults: true }); export const getTypeTransformer = (schema: object, name: string) => { - let validator: ValidateFunction | undefined; - return (obj: unknown) => { - if (validator === undefined) { - validator = ajv.compile(schema); - } - if (!validator(obj)) { - const error = validator.errors![0]; - throw new Error(`Invalid ${name}: ${error.dataPath} ${error.message}`); - } + let validator: ValidateFunction | undefined; + return (obj: unknown) => { + if (validator === undefined) { + validator = ajv.compile(schema); + } + if (!validator(obj)) { + const error = validator.errors![0]; + throw new Error(`Invalid ${name}: ${error.dataPath} ${error.message}`); + } - return obj as T; - }; + return obj as T; + }; }; diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/codeGenerationDao.test.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/codeGenerationDao.test.ts index dbce24a5e..7b9889010 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/codeGenerationDao.test.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/codeGenerationDao.test.ts @@ -1,8 +1,8 @@ import { Connection, createConnection } from 'typeorm'; +import { CodeGeneration } from '../../src/types/codeGeneration'; import { CodeGenerationDao } from '../../src/utils/db/codeGenerationDao'; import { CodeGenerationDaoImpl } from '../../src/utils/db/codeGenerationDaoImpl'; -import { CodeGeneration } from '../../src/types/codeGeneration'; let mongoDbConnection: Connection; @@ -17,7 +17,7 @@ async function initDaoTest() { database: 'admin', synchronize: true, logging: true, - entities: [CodeGeneration], + entities: [CodeGeneration] }); } diff --git a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/generateResult.test.ts b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/generateResult.test.ts index edafe0552..a4c425e52 100644 --- a/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/generateResult.test.ts +++ b/tools/sdk-generation-pipeline/packages/sdk-generation-lib/test/unit/generateResult.test.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; +import { createTaskResult, parseGenerateLog, spliteLog } from '../../src/lib/generateResult'; import { AzureSDKTaskName } from '../../src/types/commonType'; -import { spliteLog, parseGenerateLog, createTaskResult } from '../../src/lib/generateResult'; -import { TaskResultCommon, TaskResult, TestTaskResult } from '../../src/types/taskResult'; +import { TaskResult, TaskResultCommon, TestTaskResult } from '../../src/types/taskResult'; test('spliteLog', async () => { // Standard use case: single line @@ -30,7 +30,7 @@ test('parseGenerateLog', async () => { fs.unlinkSync(parseGenerateLogTestFile); } fs.writeFileSync(parseGenerateLogTestFile, correctStr, { - encoding: 'utf-8', + encoding: 'utf-8' }); const correctResult: TaskResultCommon = parseGenerateLog('testId', 'init', parseGenerateLogTestFile, undefined); expect(correctResult.name).toBe('init'); @@ -53,7 +53,7 @@ test('createTaskResult', async () => { fs.unlinkSync(createTaskResultTestFile); } fs.writeFileSync(createTaskResultTestFile, correctStr, { - encoding: 'utf-8', + encoding: 'utf-8' }); const correctResult: TaskResult = createTaskResult( diff --git a/tools/sdk-generation-pipeline/scripts/change-owner.sh b/tools/sdk-generation-pipeline/scripts/change-owner.sh new file mode 100644 index 000000000..32f5a2f9c --- /dev/null +++ b/tools/sdk-generation-pipeline/scripts/change-owner.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +SPEC_REPO=/spec-repo +WORK_DIR=/work-dir +SDK_REPO=/sdk-repo + +if [ -d "${SPEC_REPO}" ]; then + while true + do + if [ -f "/tmp/notExit" ]; then + USER_GROUP_ID=`stat -c "%u:%g" ${SPEC_REPO}` + if [ -d "${WORK_DIR}" ]; then + chown -R ${USER_GROUP_ID} ${WORK_DIR} + fi + if [ -d "${SDK_REPO}" ]; then + chown -R ${USER_GROUP_ID} ${SDK_REPO} + fi + fi + sleep 5s + done +else + echo "Error: '${SPEC_REPO}' NOT found." + exit 1 +fi + diff --git a/tools/sdk-generation-pipeline/scripts/entrypoint.sh b/tools/sdk-generation-pipeline/scripts/entrypoint.sh new file mode 100755 index 000000000..28c672ec5 --- /dev/null +++ b/tools/sdk-generation-pipeline/scripts/entrypoint.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e +dockerd > /dev/null 2>&1 & +sh /change-owner.sh & +run-mock-host "$@" & +docker-cli "$@" +if [ -f "/tmp/notExit" ]; then + bash +fi \ No newline at end of file diff --git a/tools/sdk-generation-pipeline/scripts/install-vscode-server.sh b/tools/sdk-generation-pipeline/scripts/install-vscode-server.sh new file mode 100644 index 000000000..8ffab6d6b --- /dev/null +++ b/tools/sdk-generation-pipeline/scripts/install-vscode-server.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +commit_sha="da15b6fd3ef856477bf6f4fb29ba1b7af717770d" +archive="vscode-server-linux-x64.tar.gz" + +# Download VS Code Server tarball to tmp directory. +curl -L "https://update.code.visualstudio.com/commit:${commit_sha}/server-linux-x64/stable" -o "/tmp/${archive}" + +mkdir -vp ~/.vscode-server/bin/"${commit_sha}" + +tar --no-same-owner -xzv --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}" + +sh /root/.vscode-server/bin/${commit_sha}/bin/code-server --install-extension vscjava.vscode-java-pack +sh /root/.vscode-server/bin/${commit_sha}/bin/code-server --install-extension ms-dotnettools.csharp +sh /root/.vscode-server/bin/${commit_sha}/bin/code-server --install-extension ms-python.python diff --git a/tools/sdk-generation-pipeline/scripts/rerun-tasks b/tools/sdk-generation-pipeline/scripts/rerun-tasks new file mode 100755 index 000000000..436239473 --- /dev/null +++ b/tools/sdk-generation-pipeline/scripts/rerun-tasks @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +docker-cli "$@" \ No newline at end of file