diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 780f0677a8..3ab7fc97d1 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -99,21 +99,26 @@
/packages/fx-core/scripts/delete-unused-strings.js @jayzhang
/packages/fx-core/scripts/find-unused-strings.js @jayzhang
/packages/fx-core/scripts/generate-appdef.ps1 @nliu-ms
+/packages/fx-core/src/common/azureUtil.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/constants.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/correlator.ts @chagong @jayzhang @LongOddCode
-/packages/fx-core/src/common/featureFlags.ts @jayzhang @xzf0587
+/packages/fx-core/src/common/featureFlags.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/globalState.ts @tecton @jayzhang @LongOddCode
+/packages/fx-core/src/common/globalVars.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/jsonUtils.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/localizeUtils.ts @jayzhang @HuihuiWu-Microsoft @chagong
/packages/fx-core/src/common/permissionInterface.ts @SLdragon @KennethBWSong
/packages/fx-core/src/common/projectSettingsHelper.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/projectSettingsHelperV3.ts @jayzhang @xzf0587 @LongOddCode
+/packages/fx-core/src/common/requestUtils.ts @jayzhang @hund030
/packages/fx-core/src/common/samples.ts @HuihuiWu-Microsoft @wenytang-ms @jayzhang @tecton
+/packages/fx-core/src/common/stringUtils.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/telemetry.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/templates-config.json @hund030 @eriolchan @huimiu
/packages/fx-core/src/common/tools.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/utils.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/src/common/versionMetadata.ts @xzf0587 @blackchoey
+/packages/fx-core/src/common/wrappedAxiosClient.ts @nliu-ms @anchenyi
/packages/fx-core/src/component @jayzhang @xzf0587 @hund030 @LongOddCode
/packages/fx-core/src/component/configManager @jayzhang @wenytang-ms @kuojianlu @Siglud
/packages/fx-core/src/component/debugHandler @swatDong @XiaofuHuang @kuojianlu @kimizhu
@@ -166,9 +171,13 @@
/packages/fx-core/test/component @jayzhang @xzf0587 @hund030 @LongOddCode
/packages/fx-core/tests/common/featureFlags.test.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/tests/common/globalState.test.ts @tecton @jayzhang @LongOddCode
+/packages/fx-core/tests/common/globalVars.ts @jayzhang @xzf0587 @LongOddCode
+/packages/fx-core/tests/common/projectTypeChecker.test.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/tests/common/samples.test.ts @HuihuiWu-Microsoft @wenytang-ms @jayzhang @tecton
+/packages/fx-core/tests/common/stringUtils.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/tests/common/tools.test.ts @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/tests/common/utils.test.ts @jayzhang @xzf0587 @LongOddCode
+/packages/fx-core/tests/common/wrappedAxiosClient.ts @nliu-ms @anchenyi
/packages/fx-core/tests/component/configManager @jayzhang @wenytang-ms @kuojianlu @Siglud
/packages/fx-core/tests/component/coordinator @jayzhang @xzf0587 @LongOddCode
/packages/fx-core/tests/component/deps-checker @qinezh @a1exwang @kimizhu @swatDong @XiaofuHuang
@@ -259,11 +268,24 @@
/packages/vscode-extension/README.md @therealjohn @sffamily
/packages/vscode-extension/WHATISNEW.md @therealjohn @sffamily
/packages/vscode-extension/package.nls.json @timngmsft @sffamily @therealjohn @supkasar
+/packages/vscode-extension/src/chat @tecton @Alive-Fish @lijie-lee @1openwindow
/packages/vscode-extension/src/commonlib @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
+/packages/vscode-extension/src/controls @tecton @yiqing-zhao
/packages/vscode-extension/src/debug @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
/packages/vscode-extension/src/debug/officeTaskHandler.ts @swatDong @jayzhang @tecton
/packages/vscode-extension/src/debug/taskTerminal/officeDevTerminal.ts @tecton @swatDong
+/packages/vscode-extension/src/handlers @tecton @jayzhang @yiqing-zhao
+/packages/vscode-extension/src/handlers/accounts @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
+/packages/vscode-extension/src/handlers/aadManifestHandlers.ts @blackchoey @wenytang-ms @KennethBWSong
+/packages/vscode-extension/src/handlers/collaboratorHandlers.ts @KennethBWSong @SLdragon
+/packages/vscode-extension/src/handlers/copilotChatHandlers.ts @yuqizhou77
+/packages/vscode-extension/src/handlers/manifestHandlers.ts @nliu-ms @yuqizhou77 @anchenyi
/packages/vscode-extension/src/migration @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
+/packages/vscode-extension/src/officeChat @1openwindow @MSFT-yiz
+/packages/vscode-extension/src/qm @jayzhang
+/packages/vscode-extension/src/telemetry @chagong @tecton @yiqing-zhao
+/packages/vscode-extension/src/treeview @tecton @yiqing-zhao
+/packages/vscode-extension/test @tecton @yiqing-zhao @HuihuiWu-Microsoft
/packages/vscode-extension/test/localdebug @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
/packages/vscode-extension/test/migration @kimizhu @swatDong @kuojianlu @a1exwang @qinezh @XiaofuHuang @xiaolang124 @dooriya
diff --git a/.github/actions/setup-project/action.yml b/.github/actions/setup-project/action.yml
index 635eb84654..376c7e6f2a 100644
--- a/.github/actions/setup-project/action.yml
+++ b/.github/actions/setup-project/action.yml
@@ -13,9 +13,7 @@ runs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: Setup project
if: ${{ inputs.setup == 'true' }}
diff --git a/.github/detect/excludes.txt b/.github/detect/excludes.txt
deleted file mode 100644
index c823eb698c..0000000000
--- a/.github/detect/excludes.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-.github/detect/regexes.json
-*.jpg
-*.png
-*.gif
-*.svg
-*.ico
-*.woff
-*.ttf
-*.otf
-*.eot
-*.sppkg
-.git/**
-*.woff
-*.ttf
-*.otf
-*.eot
-*.bicep
-**/package.json
-**/package-lock.json
-.azure-pipelines/apiscan.yml
-packages/cli/tests/unit/commonlib/sharepointLogin.tests.ts
-packages/cli/tests/unit/commonlib/appStudioLogin.tests.ts
-packages/cli/tests/e2e/multienv/TestRemoteHappyPath.tests.ts
-templates/bot/js/default/adaptiveCards/learn.json
-templates/bot/ts/default/adaptiveCards/learn.json
-docs/cicd/README.md
-docs/cicd_insider/README.md
-docs/cicd/azdo/*.yml
-.github/scripts/download-simpleauth.sh
-packages/fx-core/tests/component/local/localCertificateManager.test.ts
-packages/sdk/test/unit/node/appCredential.spec.ts
-packages/sdk/test/unit/node/core/onBehalfOfUserCredential.spec.ts
-packages/fx-core/tests/component/driver/teamsApp/success.zip
-packages/fx-core/tests/component/driver/teamsApp/fail.zip
-packages/cli/tests/e2e/manifest/appPackage.dev.zip
-packages/fx-core/templates/plugins/resource/cicd/azdo/*.yml
-packages/fx-core/templates/plugins/resource/cicd_v2/azdo/*.yml
-packages/vscode-extension/src/debug/teamsfxDebugProvider.ts
-packages/fx-core/tests/core/samples_v3.zip
-packages/fx-core/tests/core/samples_v2.zip
-.azure-pipelines/CredScanSuppressions.json
-.azure-pipelines/vs-sdk-build.yml
-.azure-pipelines/componentDetect.yml
\ No newline at end of file
diff --git a/.github/detect/regexes.json b/.github/detect/regexes.json
deleted file mode 100644
index 7e5e23bad2..0000000000
--- a/.github/detect/regexes.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "Slack Token": "(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})",
- "Generic Private Key POST Encapsulation Boundary": " PRIVATE KEY-----",
- "Generic Private Key Block POST Encapsulation Boundary": " PRIVATE KEY BLOCK-----",
- "Private key": "-----BEGIN PRIVATE KEY-----",
- "RSA private key": "-----BEGIN RSA PRIVATE KEY-----",
- "SSH (DSA) private key": "-----BEGIN DSA PRIVATE KEY-----",
- "SSH (EC) private key": "-----BEGIN EC PRIVATE KEY-----",
- "PGP private key block": "-----BEGIN PGP PRIVATE KEY BLOCK-----",
- "Amazon AWS Access Key ID": "AKIA[0-9A-Z]{16}",
- "Amazon MWS Auth Token": "amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
- "AWS API Key": "AKIA[0-9A-Z]{16}",
- "Bitly Key": "R_[0-9a-f]{32}",
- "Facebook Access Token": "EAACEdEose0cBA[0-9A-Za-z]+",
- "Facebook OAuth": "[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].*['|\"][0-9a-f]{32}['|\"]",
- "GitHub": "[g|G][i|I][t|T][h|H][u|U][b|B].*['|\"][0-9a-zA-Z]{35,40}['|\"]",
- "Generic API Key": "[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]",
- "Generic Secret": "[s|S][e|E][c|C][r|R][e|E][t|T].*['|\"][0-9a-zA-Z]{32,45}['|\"]",
- "Google API Key": "AIza[0-9A-Za-z\\-_]{35}",
- "Google Cloud Platform API Key": "AIza[0-9A-Za-z\\-_]{35}",
- "Google Cloud Platform OAuth": "[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com",
- "Google Drive API Key": "AIza[0-9A-Za-z\\-_]{35}",
- "Google Drive OAuth": "[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com",
- "Google (GCP) Service-account": "\"type\": \"service_account\"",
- "Google Gmail API Key": "AIza[0-9A-Za-z\\-_]{35}",
- "Google Gmail OAuth": "[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com",
- "Google OAuth Access Token": "ya29\\.[0-9A-Za-z\\-_]+",
- "Google YouTube API Key": "AIza[0-9A-Za-z\\-_]{35}",
- "Google YouTube OAuth": "[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com",
- "Heroku API Key": "[h|H][e|E][r|R][o|O][k|K][u|U].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}",
- "LinkedIn API Key": "[l|L][i|I][n|N][k|K][e|E][d|D][i|I][n|N].*['|\"][0-9a-zA-Z]{16}['|\"]",
- "MailChimp API Key": "[0-9a-f]{32}-us[0-9]{1,2}",
- "Mailgun API Key": "key-[0-9a-zA-Z]{32}",
- "Password in URL": "[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]",
- "PayPal Braintree Access Token": "access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}",
- "Picatic API Key": "sk_live_[0-9a-z]{32}",
- "Slack Webhook": "https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}",
- "Stripe API Key": "sk_live_[0-9a-zA-Z]{24}",
- "Stripe Restricted API Key": "rk_live_[0-9a-zA-Z]{24}",
- "Square Access Token": "sq0atp-[0-9A-Za-z\\-_]{22}",
- "Square OAuth Secret": "sq0csp-[0-9A-Za-z\\-_]{43}",
- "Twilio API Key": "SK[0-9a-fA-F]{32}",
- "Twitter Access Token": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*[1-9][0-9]+-[0-9a-zA-Z]{40}",
- "Twitter OAuth": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*['|\"][0-9a-zA-Z]{35,44}['|\"]",
- "Github OAuth": " [A-Za-z0-9_]{255}",
- "Common 32bit": "[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}",
- "Secret Pattern": "regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!#^~@$%*^&'\"])[a-zA-Z0-9!#^~@$%*^&'\"]{8,}$"
-}
\ No newline at end of file
diff --git a/.github/detect/sensitive-detect.py b/.github/detect/sensitive-detect.py
deleted file mode 100644
index 05b0384678..0000000000
--- a/.github/detect/sensitive-detect.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-# -*- coding utf-8 -*-
-
-import sys
-import os
-import re
-import json
-import fnmatch
-
-exclude_key_words = "http"
-
-def read_pattern(r):
- if r.startswith("regex:"):
- return re.compile(r[6:])
- converted = re.escape(r)
- converted = re.sub(r"((\\*\r)?\\*\n|(\\+r)?\\+n)+", r"( |\\t|(\\r|\\n|\\\\+[rn])[-+]?)*", converted)
- return re.compile(converted)
-
-def read_regexes(file):
- regexes = {}
- try:
- with open(file, "r") as regexesFile:
- rules = json.loads(regexesFile.read())
- for rule in rules:
- regexes[rule] = read_pattern(rules[rule])
- except (IOError, ValueError) as e:
- raise("Error Reading rules file")
- return regexes
-
-def read_files(filePath):
- try:
- with open(filePath, "r") as fileContent:
- contents = fileContent.read()
- except (IOError, ValueError) as e:
- raise("Error Reading rules file", filePath)
- return contents.splitlines()
-
-def read_content(contentFile, rootDir):
- contentFileDir = os.path.join(rootDir, contentFile)
- try:
- with open(contentFileDir, "r") as content:
- return content.read()
- except (IOError, ValueError) as e:
- print("============ read file fail: ", contentFileDir)
- raise Exception("Error Reading rules file")
-
-def find_string(patterns, content, diffFile):
- for pattern in patterns:
- res = patterns[pattern].findall(content)
- if res:
- print("diffFile:", diffFile)
- for res_item in res:
- print("Sensitive Content: ", res_item)
- raise Exception("Found sensitive words")
-
-def read_diffFiles(rootDir):
- includeFilePath = os.path.join(rootDir, "diffFiles.txt")
- diffFiles = read_files(includeFilePath)
- excludeFiles = filter_diffFiles(rootDir)
- targetDiffFiles = diffFiles.copy()
- for item in diffFiles:
- for exFile in excludeFiles:
- if fnmatch.fnmatch(item, exFile):
- targetDiffFiles.remove(item)
- break
- return targetDiffFiles
-
-def read_allRepoFile(rootDir):
- result = [os.path.join(dp, f) for dp, dn, filenames in os.walk(rootDir) for f in filenames]
- pathPerfix = rootDir + '/'
- new_list = [str(i).replace( pathPerfix, '') for i in result]
- targetDiffFiles = new_list.copy()
- excludeFiles = filter_diffFiles(rootDir)
- for item in new_list:
- for exFile in excludeFiles:
- if fnmatch.fnmatch(item, exFile):
- targetDiffFiles.remove(item)
- break
- return targetDiffFiles
-
-def filter_diffFiles(rootDir):
- excludeFilePath = os.path.join(rootDir, ".github", "detect", "excludes.txt")
- excludeFiles = read_files(excludeFilePath)
- return excludeFiles
-
-def find_string_in_content(pattern, diffFile):
- try:
- for i, line in enumerate(open(diffFile)):
- if exclude_key_words in line:
- continue
- new_line=line.replace('"',' ')
- new_line=new_line.replace(',',' ')
- x = new_line.split()
- match = list(filter(pattern.match, x))
- if match:
- print("Sensitive Content: ", line, " in file: ", diffFile)
- raise Exception("Sensitive content detected! please take action to this file: ", diffFile)
- except (IOError, ValueError) as e:
- print("============ read file fail: ", diffFile)
- raise Exception("Error Reading rules file")
-
-def main():
- currentDir = os.path.dirname(os.path.realpath(__file__))
- regexesFilePath = os.path.join(currentDir, "regexes.json")
- patterns = read_regexes(regexesFilePath)
- rootDir = os.path.join(currentDir, "..", "..")
- scanType = sys.argv[1]
- targetDiffFiles = []
- if scanType == 'diff':
- targetDiffFiles = read_diffFiles(rootDir)
- else:
- targetDiffFiles = read_allRepoFile(rootDir)
- for diffFile in targetDiffFiles:
- for pattern in patterns:
- find_string_in_content(patterns[pattern], diffFile)
-
-main()
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
index ea14c2b1df..40e6ee7bca 100644
--- a/.github/workflows/cd.yml
+++ b/.github/workflows/cd.yml
@@ -74,9 +74,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: Install wine64
run: |
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 1d3d44f145..32447e2fda 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -26,7 +26,7 @@ jobs:
run: |
links=`git grep -hEo "https://aka[a-zA-Z0-9./?=_%:-]*[a-zA-Z0-9]" | sort -nr | uniq`
- white_list=""
+ white_list="https://aka.ms/teamsfx-plugin-api;https://aka.ms/dotnet;"
while IFS= read -r link;
do
@@ -157,7 +157,7 @@ jobs:
done < $file/akas.data
done
- body="Dashboard App: Click Here to Open Dashboard App
"
+ body="Dashboard App: Click Here to Open Dashboard App "
total=$((valid+invalid))
subject="TeamsFx AKA Link Report ($valid/$total Passed)"
if [ $invalid -gt 0 ]; then
diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
index 4d148df655..8a79ce8ae5 100644
--- a/.github/workflows/e2e-test.yml
+++ b/.github/workflows/e2e-test.yml
@@ -204,9 +204,7 @@ jobs:
python3 --version
pip3 --version
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: Setup project
run: |
@@ -479,7 +477,7 @@ jobs:
done <<< $cases
- body="Dashboard App: Click Here to Open Dashboard App PATH CASE TARGET TYPE STATUS AUTHOR DURATION $failed_lists $skipped_lists $passed_lists
"
+ body="Dashboard App: Click Here to Open Dashboard App PATH CASE TARGET TYPE STATUS AUTHOR DURATION $failed_lists $skipped_lists $passed_lists
"
total=$((passed+failed+skipped))
@@ -512,9 +510,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: mv files
working-directory: packages/tests
diff --git a/.github/workflows/env-checker-ci-pr.yml b/.github/workflows/env-checker-ci-pr.yml
index c6f9c10a38..259caceee4 100644
--- a/.github/workflows/env-checker-ci-pr.yml
+++ b/.github/workflows/env-checker-ci-pr.yml
@@ -54,9 +54,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
# https://github.com/marketplace/actions/retry-step
- name: Setup project with Retry
diff --git a/.github/workflows/env-checker-ci-schedule.yml b/.github/workflows/env-checker-ci-schedule.yml
index 6bb26cb50f..f47ccae889 100644
--- a/.github/workflows/env-checker-ci-schedule.yml
+++ b/.github/workflows/env-checker-ci-schedule.yml
@@ -38,9 +38,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
# https://github.com/marketplace/actions/retry-step
- name: Setup project with Retry
@@ -106,9 +104,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
# https://github.com/marketplace/actions/retry-step
- name: Setup project with Retry
@@ -187,9 +183,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
# https://github.com/marketplace/actions/retry-step
- name: Setup project with Retry
diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml
index b2759095a8..71020011db 100644
--- a/.github/workflows/lint-pr.yml
+++ b/.github/workflows/lint-pr.yml
@@ -137,45 +137,39 @@ jobs:
fi
check-sensitive-content:
- if: ${{ github.event_name == 'pull_request' }}
+ if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }}
runs-on: ubuntu-latest
steps:
- - name: Checkout branch
- uses: actions/checkout@v3
+ - shell: bash
+ if: ${{ github.event_name == 'pull_request'}}
+ run: |
+ if [ "${{ github.event_name }}" == "push" ]; then
+ echo "depth=$(($(jq length <<< '${{ toJson(github.event.commits) }}') + 1))" >> $GITHUB_ENV
+ echo "branch=${{ github.ref_name }}" >> $GITHUB_ENV
+ fi
+ if [ "${{ github.event_name }}" == "pull_request" ]; then
+ echo "depth=$((${{ github.event.pull_request.commits }} + 1))" >> $GITHUB_ENV
+ echo "branch=${{ github.event.pull_request.head.ref }}" >> $GITHUB_ENV
+ fi
+ - uses: actions/checkout@v4
+ if: ${{ github.event_name == 'pull_request'}}
with:
- fetch-depth: 0
- ref: ${{ github.event.pull_request.head.ref }}
+ ref: ${{env.branch}}
repository: ${{github.event.pull_request.head.repo.full_name}}
+ fetch-depth: ${{env.depth}}
+ - uses: trufflesecurity/trufflehog@main
+ if: ${{ github.event_name == 'pull_request'}}
+ with:
+ extra_args: --only-verified
- - name: prettier check files in PR on Fork
- if: ${{ github.event.pull_request.head.repo.full_name != 'OfficeDev/TeamsFx' }}
- run: |
- git remote add upstream https://github.com/OfficeDev/TeamsFx.git
- git fetch upstream ${{ github.event.pull_request.base.ref }}
- git diff --diff-filter=MARC upstream/${{ github.event.pull_request.base.ref }}...HEAD --name-only >> diffFiles.txt
-
- - name: prettier check files in PR on local
- if: ${{ github.event.pull_request.head.repo.full_name == 'OfficeDev/TeamsFx' }}
- run: |
- git diff --diff-filter=MARC origin/${{ github.event.pull_request.base.ref }}...HEAD --name-only >> diffFiles.txt
-
- - name: check content
- run: |
- touch diffFiles.txt
- python .github/detect/sensitive-detect.py diff
-
- schedule-check-sensitive-content:
- if: ${{ github.event_name == 'schedule' && (github.ref == 'refs/heads/dev'|| github.ref == 'refs/heads/main' || github.ref == 'refs/heads/ga') }}
- runs-on: ubuntu-latest
- steps:
- - name: checkout branch
- uses: actions/checkout@v3
+ - if: ${{ github.event_name == 'schedule' }}
+ uses: actions/checkout@v4
+ - if: ${{ github.event_name == 'schedule' }}
+ uses: trufflesecurity/trufflehog@main
with:
- token: ${{ secrets.CD_PAT }}
- ref: ${{ github.ref }}
- - name: check content
- run: |
- python .github/detect/sensitive-detect.py repo
+ base: ""
+ head: ${{ github.ref_name }}
+ extra_args: --only-verified
attension-on-version:
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' && github.event.action != 'edited' }}
diff --git a/.github/workflows/rerun.yml b/.github/workflows/rerun.yml
index 0d9bd177b5..99cd9d86c2 100644
--- a/.github/workflows/rerun.yml
+++ b/.github/workflows/rerun.yml
@@ -114,9 +114,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: Setup project
working-directory: ./
diff --git a/.github/workflows/templates-ci.yml b/.github/workflows/templates-ci.yml
index 7febeb02c1..8ce6ff2718 100644
--- a/.github/workflows/templates-ci.yml
+++ b/.github/workflows/templates-ci.yml
@@ -31,9 +31,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: Setup project
run: |
diff --git a/.github/workflows/ui-test.yml b/.github/workflows/ui-test.yml
index 3d30f48784..37f48ec5e4 100644
--- a/.github/workflows/ui-test.yml
+++ b/.github/workflows/ui-test.yml
@@ -31,8 +31,8 @@ on:
type: string
node-version:
- default: "[16]"
- description: "node version, e.g. [16]"
+ default: "[18]"
+ description: "node version, e.g. [18]"
required: false
type: string
@@ -108,9 +108,7 @@ jobs:
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: create pvt file (random platform/node)
if: ${{ github.event.schedule == '0 18 * * *' }} || ${{ github.event.inputs.test-case }} == ''
@@ -539,9 +537,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18
- - uses: pnpm/action-setup@v2
- with:
- version: 8
+ - uses: pnpm/action-setup@v4
- name: setup project
run: |
pnpm --filter=@microsoft/teamsfx-test install
@@ -682,8 +678,7 @@ jobs:
fi
done <<< $cases
-
- body="Dashboard App: Click Here to Open Dashboard App Release: ${{ needs.setup.outputs.ttk-package }}. CASE OS NODE STATUS AUTHOR DURATION $lists
"
+ body="Dashboard App: Click Here to Open Dashboard App Release: ${{ needs.setup.outputs.ttk-package }}. CASE OS NODE STATUS AUTHOR DURATION $lists
"
total=$((passed+failed))
diff --git a/packages/api/src/qm/ui.ts b/packages/api/src/qm/ui.ts
index 82462b7d28..1b10f2e680 100644
--- a/packages/api/src/qm/ui.ts
+++ b/packages/api/src/qm/ui.ts
@@ -405,6 +405,11 @@ export interface UserInteraction {
selectFileOrInput?(
config: SingleFileOrInputConfig
): Promise, FxError>>;
+
+ /**
+ * Supports in VSC only for now. Show diagnostic message in editor.
+ */
+ showDiagnosticInfo?(diagnostics: IDiagnosticInfo[]): void;
}
export interface IProgressHandler {
@@ -429,3 +434,70 @@ export interface IProgressHandler {
*/
end: (success: boolean, hideAfterFinish?: boolean) => Promise;
}
+
+export enum DiagnosticSeverity {
+ /**
+ * Something not allowed by the rules of a language or other means.
+ */
+ Error = 0,
+
+ /**
+ * Something suspicious but allowed.
+ */
+ Warning = 1,
+
+ /**
+ * Something to inform about but not a problem.
+ */
+ Information = 2,
+
+ /**
+ * Something to hint to a better way of doing it, like proposing
+ * a refactoring.
+ */
+ Hint = 3,
+}
+
+export interface IDiagnosticInfo {
+ /**
+ * Path of file where diagnostic shows.
+ */
+ filePath: string;
+ /**
+ * Line number where diagnostic info starts.
+ */
+ startLine: number;
+ /**
+ * Index of the beginning character where diagnostic info shows
+ */
+ startIndex: number;
+ /**
+ * Line number where diagnostic info ends.
+ */
+ endLine: number;
+ /**
+ * Index of the end character where diagnostic info ends.
+ */
+ endIndex: number;
+ /**
+ * Message.
+ */
+ message: string;
+ /**
+ * Severity.
+ */
+ severity: DiagnosticSeverity;
+ /**
+ * A code or identifier for this diagnostic.
+ */
+ code?: {
+ /**
+ * Value.
+ */
+ value: string;
+ /**
+ * Link to open with more information about the diagnostic error.
+ */
+ link: string;
+ };
+}
diff --git a/packages/cli/.vscode/launch.json b/packages/cli/.vscode/launch.json
index 4338fe3e8e..89f80b57f4 100644
--- a/packages/cli/.vscode/launch.json
+++ b/packages/cli/.vscode/launch.json
@@ -113,6 +113,25 @@
"${workspaceFolder}/../api/build/**/*.js"
],
"console": "integratedTerminal"
+ },
+ {
+ "type": "pwa-node",
+ "request": "launch",
+ "name": "Launch uninstall command",
+ "skipFiles": ["/**"],
+ "program": "${workspaceFolder}/cli.js",
+ "args": ["uninstall"],
+ "outFiles": [
+ "${workspaceFolder}/lib/**/*.js",
+ "${workspaceFolder}/../fx-core/build/**/*.js",
+ "${workspaceFolder}/../api/build/**/*.js"
+ ],
+ "resolveSourceMapLocations": [
+ "${workspaceFolder}/lib/**/*.js",
+ "${workspaceFolder}/../fx-core/build/**/*.js",
+ "${workspaceFolder}/../api/build/**/*.js"
+ ],
+ "console": "integratedTerminal"
}
]
}
diff --git a/packages/cli/src/cmds/preview/launch.ts b/packages/cli/src/cmds/preview/launch.ts
index 084b7faf29..475a61f30a 100644
--- a/packages/cli/src/cmds/preview/launch.ts
+++ b/packages/cli/src/cmds/preview/launch.ts
@@ -103,7 +103,7 @@ async function _openTeamsDesktopClient(
const desktopDebugHelpMessage = [
{
- content: `Before proceeding, make sure your Teams desktop login matches your current Microsoft 365 account${username} used in Teams Toolkit.`,
+ content: `Before proceeding, make sure your Teams desktop login matches your current Microsoft 365 account${username} used in Teams Toolkit. Please visit https://aka.ms/teamsfx-debug-in-desktop-client to get more info.`,
color: Colors.WHITE,
},
];
diff --git a/packages/cli/src/commands/engine.ts b/packages/cli/src/commands/engine.ts
index 1780c15c8e..a048e46655 100644
--- a/packages/cli/src/commands/engine.ts
+++ b/packages/cli/src/commands/engine.ts
@@ -503,7 +503,7 @@ class CLIEngine {
context.optionValues.platform = Platform.CLI;
// set projectPath
const projectFolderOption = context.command.options?.find(
- (o) => o.questionName === "projectPath"
+ (o) => o.questionName === "projectPath" && o.required
);
if (projectFolderOption) {
// resolve projectPath
diff --git a/packages/cli/src/commands/models/addPlugin.ts b/packages/cli/src/commands/models/addPlugin.ts
index 9d760a434a..fcf6b41fe4 100644
--- a/packages/cli/src/commands/models/addPlugin.ts
+++ b/packages/cli/src/commands/models/addPlugin.ts
@@ -8,8 +8,8 @@ import { TelemetryEvent } from "../../telemetry/cliTelemetryEvents";
import { ProjectFolderOption } from "../common";
export const addPluginCommand: CLICommand = {
- name: "copilot-plugin",
- description: commands["add.copilot-plugin"].description,
+ name: "plugin",
+ description: commands["add.plugin"].description,
options: [...AddPluginOptions, ProjectFolderOption],
telemetry: {
event: TelemetryEvent.AddCopilotPlugin,
diff --git a/packages/cli/src/commands/models/m365Unacquire.ts b/packages/cli/src/commands/models/m365Unacquire.ts
index 9aef78fc3d..0c1753a4d5 100644
--- a/packages/cli/src/commands/models/m365Unacquire.ts
+++ b/packages/cli/src/commands/models/m365Unacquire.ts
@@ -1,12 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CLICommand, err, ok } from "@microsoft/teamsfx-api";
-import { PackageService } from "@microsoft/teamsfx-core";
+import { UninstallInputs, QuestionNames } from "@microsoft/teamsfx-core";
import { logger } from "../../commonlib/logger";
import { MissingRequiredOptionError } from "../../error";
import { commands } from "../../resource";
import { TelemetryEvent } from "../../telemetry/cliTelemetryEvents";
import { m365utils, sideloadingServiceEndpoint } from "./m365Sideloading";
+import { getFxCore } from "../../activate";
export const m365UnacquireCommand: CLICommand = {
name: "uninstall",
@@ -14,44 +15,67 @@ export const m365UnacquireCommand: CLICommand = {
description: commands.uninstall.description,
options: [
{
- name: "title-id",
+ name: QuestionNames.UninstallMode,
+ description: commands.uninstall.options["mode"],
+ type: "string",
+ },
+ {
+ name: QuestionNames.TitleId,
description: commands.uninstall.options["title-id"],
type: "string",
},
{
- name: "manifest-id",
+ name: QuestionNames.ManifestId,
description: commands.uninstall.options["manifest-id"],
type: "string",
},
+ {
+ name: QuestionNames.Env,
+ description: commands.uninstall.options["env"],
+ type: "string",
+ },
+ {
+ name: "folder",
+ questionName: QuestionNames.ProjectPath,
+ description: commands.uninstall.options["folder"],
+ type: "string",
+ },
+ {
+ name: QuestionNames.UninstallOptions,
+ description: commands.uninstall.options["options"],
+ type: "array",
+ },
],
examples: [
{
- command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall --title-id U_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
- description: "Remove the acquired M365 App by Title ID",
+ command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall -i false --mode title-id --title-id U_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
+ description: "Remove the acquired Microsoft 365 Application using Title ID",
+ },
+ {
+ command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall -i false --mode manifest-id --manifest-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --options 'm365-app,app-registration,bot-framework-registration'`,
+ description: "Remove the acquired Microsoft 365 Application using Manifest ID",
+ },
+ {
+ command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall -i false --mode env --env xxx --options 'm365-app,app-registration,bot-framework-registration' --folder ./myapp`,
+ description:
+ "Remove the acquired Microsoft 365 Application using environment in Teams Toolkit generated project",
},
{
- command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall --manifest-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
- description: "Remove the acquired M365 App by Manifest ID",
+ command: `${process.env.TEAMSFX_CLI_BIN_NAME} uninstall`,
+ description: "Uninstall in interactive mode",
},
],
telemetry: {
event: TelemetryEvent.M365Unacquire,
},
- defaultInteractiveOption: false,
+ defaultInteractiveOption: true,
handler: async (ctx) => {
- const packageService = new PackageService(sideloadingServiceEndpoint, logger);
- let titleId = ctx.optionValues["title-id"] as string;
- const manifestId = ctx.optionValues["manifest-id"] as string;
- if (titleId === undefined && manifestId === undefined) {
- return err(
- new MissingRequiredOptionError(ctx.command.fullName, `--title-id or --manifest-id`)
- );
- }
- const tokenAndUpn = await m365utils.getTokenAndUpn();
- if (titleId === undefined) {
- titleId = await packageService.retrieveTitleId(tokenAndUpn[0], manifestId);
+ const inputs = ctx.optionValues as UninstallInputs;
+ const core = getFxCore();
+ const res = await core.uninstall(inputs);
+ if (res.isErr()) {
+ return err(res.error);
}
- await packageService.unacquire(tokenAndUpn[0], titleId);
return ok(undefined);
},
};
diff --git a/packages/cli/src/commonlib/azureLoginCI.ts b/packages/cli/src/commonlib/azureLoginCI.ts
index 98ca43b735..6adb2414b6 100644
--- a/packages/cli/src/commonlib/azureLoginCI.ts
+++ b/packages/cli/src/commonlib/azureLoginCI.ts
@@ -85,13 +85,22 @@ export class AzureAccountManager extends login implements AzureAccountProvider {
async getIdentityCredentialAsync(): Promise {
await this.load();
if (AzureAccountManager.tokenCredential == undefined) {
- const identityCredential = new identity.ClientSecretCredential(
- AzureAccountManager.tenantId,
- AzureAccountManager.clientId,
- AzureAccountManager.secret
- );
- const credentialChain = new identity.ChainedTokenCredential(identityCredential);
- AzureAccountManager.tokenCredential = credentialChain;
+ if (await fs.pathExists(AzureAccountManager.secret)) {
+ const certCredential = new identity.ClientCertificateCredential(
+ AzureAccountManager.tenantId,
+ AzureAccountManager.clientId,
+ AzureAccountManager.secret
+ );
+ AzureAccountManager.tokenCredential = certCredential;
+ } else {
+ const identityCredential = new identity.ClientSecretCredential(
+ AzureAccountManager.tenantId,
+ AzureAccountManager.clientId,
+ AzureAccountManager.secret
+ );
+ const credentialChain = new identity.ChainedTokenCredential(identityCredential);
+ AzureAccountManager.tokenCredential = credentialChain;
+ }
}
return new Promise((resolve) => {
diff --git a/packages/cli/src/commonlib/m365Login.ts b/packages/cli/src/commonlib/m365Login.ts
index 0e54bedd12..5c07d0c4bc 100644
--- a/packages/cli/src/commonlib/m365Login.ts
+++ b/packages/cli/src/commonlib/m365Login.ts
@@ -146,6 +146,41 @@ export class M365Login extends BasicLogin implements M365TokenProvider {
}
}
-const m365Login = !ui.interactive ? M365TokenProviderUserPassword : M365Login.getInstance();
+/**
+ * this class is a wrapper for M365TokenProvider that will use M365Login if interactive is true, otherwise use M365TokenProviderUserPassword
+ */
+class MM365TokenProviderWrapper implements M365TokenProvider {
+ getProvider(): M365TokenProvider {
+ const m365Login = !ui.interactive ? M365TokenProviderUserPassword : M365Login.getInstance();
+ return m365Login;
+ }
+ getAccessToken(tokenRequest: TokenRequest): Promise> {
+ return this.getProvider().getAccessToken(tokenRequest);
+ }
+ getJsonObject(tokenRequest: TokenRequest): Promise, FxError>> {
+ return this.getProvider().getJsonObject(tokenRequest);
+ }
+ getStatus(tokenRequest: TokenRequest): Promise> {
+ return this.getProvider().getStatus(tokenRequest);
+ }
+ setStatusChangeMap(
+ name: string,
+ tokenRequest: TokenRequest,
+ statusChange: (
+ status: string,
+ token?: string,
+ accountInfo?: Record
+ ) => Promise,
+ immediateCall?: boolean
+ ): Promise> {
+ return this.getProvider().setStatusChangeMap(name, tokenRequest, statusChange, immediateCall);
+ }
+ removeStatusChangeMap(name: string): Promise> {
+ return this.getProvider().removeStatusChangeMap(name);
+ }
+ async signout(): Promise {
+ return await (this.getProvider() as any).signout();
+ }
+}
-export default m365Login;
+export default new MM365TokenProviderWrapper();
diff --git a/packages/cli/src/commonlib/m365LoginUserPassword.ts b/packages/cli/src/commonlib/m365LoginUserPassword.ts
index 77e5022e11..43ff01cf13 100644
--- a/packages/cli/src/commonlib/m365LoginUserPassword.ts
+++ b/packages/cli/src/commonlib/m365LoginUserPassword.ts
@@ -133,7 +133,7 @@ export class M365ProviderUserPassword extends BasicLogin implements M365TokenPro
}
signout(): boolean {
- throw new Error("Method not implemented.");
+ return true;
}
}
diff --git a/packages/cli/src/resource/commands.json b/packages/cli/src/resource/commands.json
index 842f0e3df5..e95d65f6e1 100644
--- a/packages/cli/src/resource/commands.json
+++ b/packages/cli/src/resource/commands.json
@@ -49,7 +49,7 @@
"add.spfx-web-part": {
"description": "Auto-hosted SPFx web part tightly integrated with Microsoft Teams."
},
- "add.copilot-plugin": {
+ "add.plugin": {
"description": "A plugin to extend Copilot using your APIs."
},
"create": {
@@ -144,10 +144,14 @@
"description": "Run the publish stage in teamsapp.yml."
},
"uninstall": {
- "description": "Remove an acquired M365 App.",
+ "description": "Clean up resources associated with Manifest ID, Title ID, or an environment in Teams Toolkit generated project. Resources include app registration in Teams Developer Portal, bot registration in Bot Framework Portal, and uploaded custom apps in Microsoft 365 apps.",
"options": {
- "title-id": "Title ID of the acquired M365 App.",
- "manifest-id": "Manifest ID of the acquired M365 App."
+ "mode": "Choose a way to clean up resources.",
+ "title-id": "Title ID of the App.",
+ "manifest-id": "Manifest ID of the App.",
+ "env": "The specific environment in the project created by Teams Toolkit.",
+ "folder": "Project path to uninstall, only used in env mode.",
+ "options": "Selected resourecs to uninstall. example: --options m365-app,app-registration,bot-framework-registration"
}
},
"update": {
diff --git a/packages/cli/tests/unit/commands.tests.ts b/packages/cli/tests/unit/commands.tests.ts
index dba14f3015..87a407af6a 100644
--- a/packages/cli/tests/unit/commands.tests.ts
+++ b/packages/cli/tests/unit/commands.tests.ts
@@ -1,4 +1,4 @@
-import { CLIContext, err, ok } from "@microsoft/teamsfx-api";
+import { CLIContext, SystemError, err, ok } from "@microsoft/teamsfx-api";
import {
CollaborationStateResult,
FeatureFlags,
@@ -237,7 +237,7 @@ describe("CLI commands", () => {
it("success", async () => {
sandbox.stub(FxCore.prototype, "addPlugin").resolves(ok(undefined));
const ctx: CLIContext = {
- command: { ...addPluginCommand, fullName: "add copilot-plugin" },
+ command: { ...addPluginCommand, fullName: "add plugin" },
optionValues: {},
globalOptionValues: {},
argumentValues: [],
@@ -775,8 +775,8 @@ describe("CLI commands", () => {
beforeEach(() => {
sandbox.stub(logger, "warning");
});
- it("MissingRequiredOptionError", async () => {
- sandbox.stub(m365utils, "getTokenAndUpn").resolves(["token", "upn"]);
+ it("success", async () => {
+ sandbox.stub(FxCore.prototype, "uninstall").resolves(ok(undefined));
const ctx: CLIContext = {
command: { ...m365UnacquireCommand, fullName: "teamsfx" },
optionValues: {},
@@ -785,34 +785,19 @@ describe("CLI commands", () => {
telemetryProperties: {},
};
const res = await m365UnacquireCommand.handler!(ctx);
- assert.isTrue(res.isErr());
- });
- it("success retrieveTitleId", async () => {
- sandbox.stub(m365utils, "getTokenAndUpn").resolves(["token", "upn"]);
- sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("id");
- sandbox.stub(PackageService.prototype, "unacquire").resolves();
- const ctx: CLIContext = {
- command: { ...m365UnacquireCommand, fullName: "teamsfx" },
- optionValues: { "manifest-id": "aaa" },
- globalOptionValues: {},
- argumentValues: [],
- telemetryProperties: {},
- };
- const res = await m365UnacquireCommand.handler!(ctx);
assert.isTrue(res.isOk());
});
- it("success", async () => {
- sandbox.stub(m365utils, "getTokenAndUpn").resolves(["token", "upn"]);
- sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ it("failed", async () => {
+ sandbox.stub(FxCore.prototype, "uninstall").resolves(err(new SystemError("", "", "")));
const ctx: CLIContext = {
command: { ...m365UnacquireCommand, fullName: "teamsfx" },
- optionValues: { "title-id": "aaa" },
+ optionValues: {},
globalOptionValues: {},
argumentValues: [],
telemetryProperties: {},
};
const res = await m365UnacquireCommand.handler!(ctx);
- assert.isTrue(res.isOk());
+ assert.isTrue(res.isErr());
});
});
@@ -1148,7 +1133,7 @@ describe("CLI read-only commands", () => {
};
const res = await listTemplatesCommand.handler!(ctx);
assert.isTrue(res.isOk());
- assert.isFalse(!!messages.find((msg) => msg.includes("copilot-plugin-existing-api")));
+ assert.isFalse(!!messages.find((msg) => msg.includes("api-plugin-existing-api")));
});
it("table with description", async () => {
const ctx: CLIContext = {
@@ -1186,7 +1171,7 @@ describe("CLI read-only commands", () => {
};
const res = await listTemplatesCommand.handler!(ctx);
assert.isTrue(res.isOk());
- assert.isTrue(!!messages.find((msg) => msg.includes("copilot-plugin-existing-api")));
+ assert.isTrue(!!messages.find((msg) => msg.includes("api-plugin-existing-api")));
});
});
describe("listSamplesCommand", async () => {
diff --git a/packages/eslint-plugin-teamsfx/config/shared.js b/packages/eslint-plugin-teamsfx/config/shared.js
index 118c61ec2e..2e447b1bd1 100644
--- a/packages/eslint-plugin-teamsfx/config/shared.js
+++ b/packages/eslint-plugin-teamsfx/config/shared.js
@@ -34,7 +34,7 @@ module.exports = {
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-empty-function": 0,
"import/no-cycle": [
- "warn",
+ "error",
{
maxDepth: Infinity,
ignoreExternal: true,
diff --git a/packages/fx-core/resource/package.nls.json b/packages/fx-core/resource/package.nls.json
index c89be2b7aa..faadd8e8c9 100644
--- a/packages/fx-core/resource/package.nls.json
+++ b/packages/fx-core/resource/package.nls.json
@@ -255,9 +255,9 @@
"core.TabSPFxOption.detailNew": "Build UI with SharePoint Framework",
"core.TabNonSso.label": "Basic Tab",
"core.TabNonSso.detail": "A simple implementation of a web app that's ready to customize",
- "core.copilotPlugin.api.noAuth": "None auth",
- "core.copilotPlugin.api.apiKeyAuth": "API key auth(Bearer token auth)",
- "core.copilotPlugin.api.oauth": "OAuth(Auth code flow)",
+ "core.copilotPlugin.api.noAuth": "No authentication",
+ "core.copilotPlugin.api.apiKeyAuth": "API Key authentication(Bearer token authentication)",
+ "core.copilotPlugin.api.oauth": "OAuth(Authorization code flow)",
"core.copilotPlugin.validate.apiSpec.summary": "Teams Toolkit has checked your OpenAPI description document:\n\nSummary:\n%s.\n%s\n%s",
"core.copilotPlugin.validate.summary.validate.failed": "%s failed",
"core.copilotPlugin.validate.summary.validate.warning": "%s warning",
@@ -294,11 +294,11 @@
"core.createProjectQuestion.projectType.tab.detail": "Embed your own web content in Teams, Outlook, and the Microsoft 365 app",
"core.createProjectQuestion.projectType.tab.title": "App Features Using a Tab",
"core.createProjectQuestion.projectType.copilotPlugin.detail": "Create a plugin to extend Microsoft Copilot for Microsoft 365 using your APIs",
- "core.createProjectQuestion.projectType.copilotPlugin.label": "Copilot Plugin",
- "core.createProjectQuestion.projectType.copilotPlugin.title": "Copilot Plugin",
+ "core.createProjectQuestion.projectType.copilotPlugin.label": "API Plugin",
+ "core.createProjectQuestion.projectType.copilotPlugin.title": "API Plugin",
"core.createProjectQuestion.projectType.copilotPlugin.placeholder": "Select an option",
"core.createProjectQuestion.projectType.customCopilot.detail": "Build intelligent chatbot in Microsoft Teams easily using Teams AI Library",
- "core.createProjectQuestion.projectType.customCopilot.label": "Custom Copilot",
+ "core.createProjectQuestion.projectType.customCopilot.label": "Custom Engine Copilot",
"core.createProjectQuestion.projectType.customCopilot.title": "App Features Using Teams AI Library",
"core.createProjectQuestion.projectType.customCopilot.placeholder": "Select an option",
"core.createProjectQuestion.projectType.copilotHelp.label": "Don't know how to start? Use Github Copilot Chat",
@@ -341,7 +341,7 @@
"core.createProjectQuestion.capability.declarativeCopilotBasic.title": "Basic Declarative Copilot",
"core.createProjectQuestion.capability.declarativeCopilotBasic.detail": "A declarative Copilot skeleton you can author without any plugin",
"core.createProjectQuestion.capability.declarativeCopilotWithPlugin.title": "Declarative Copilot with a plugin using Azure Functions",
- "core.createProjectQuestion.capability.declarativeCopilotWithPlugin.detail": "A declarative Copilot containing a Copilot plugin with a new API from Azure Functions",
+ "core.createProjectQuestion.capability.declarativeCopilotWithPlugin.detail": "A declarative Copilot containing an API plugin with a new API from Azure Functions",
"core.createProjectQuestion.declarativeCopilotType.title": "Choose Declarative Copilot Type",
"core.createProjectQuestion.llmService.title": "Service for Large Language Model (LLM)",
"core.createProjectQuestion.llmService.placeholder": "Select a service to access LLMs",
@@ -379,40 +379,6 @@
"core.createProjectQuestion.apiSpec.multipleValidationErrors.message": "Incompatible OpenAPI description document. Check output panel for details.",
"core.createProjectQuestion.apiSpec.multipleValidationErrors.vscode.message": "Incompatible OpenAPI description document. Check [output panel](command:fx-extension.showOutputChannel) for details.",
"core.createProjectQuestion.meArchitecture.title": "Architecture of Search Based Message Extension",
- "core.createProjectQuestion.officeXMLAddin.bar.title": "Office Add-in",
- "core.createProjectQuestion.officeXMLAddin.bar.detail": "Creating Project.",
- "core.createProjectQuestion.officeXMLAddin.mainEntry.title": "Office Add-in",
- "core.createProjectQuestion.officeXMLAddin.mainEntry.detail": "Create integration with Outlook, Word, Excel, or PowerPoint",
- "core.createProjectQuestion.officeXMLAddin.create.title": "Select to Create an Outlook, Word, Excel, or PowerPoint Add-in",
- "core.createProjectQuestion.officeXMLAddin.word.title": "Word Add-in",
- "core.createProjectQuestion.officeXMLAddin.word.detail": "Create an add-in that can run in Word across multiple platforms",
- "core.createProjectQuestion.officeXMLAddin.word.sso.title": "Add-in with Single Sign On",
- "core.createProjectQuestion.officeXMLAddin.word.sso.detail": "Create a Word add-in with Single Sign On capabilities",
- "core.createProjectQuestion.officeXMLAddin.word.react.title": "Add-in with React Framework",
- "core.createProjectQuestion.officeXMLAddin.word.react.detail": "Create a Word add-in with React framework",
- "core.createProjectQuestion.officeXMLAddin.word.create.title": "Create a Word Add-in",
- "core.createProjectQuestion.officeXMLAddin.excel.title": "Excel Add-in",
- "core.createProjectQuestion.officeXMLAddin.excel.detail": "Extend Excel functionality and access Excel data on multiple platforms",
- "core.createProjectQuestion.officeXMLAddin.excel.sso.title": "Add-in with Single Sign On",
- "core.createProjectQuestion.officeXMLAddin.excel.sso.detail": "Create an Excel add-in with Single Sign On capabilities",
- "core.createProjectQuestion.officeXMLAddin.excel.react.title": "Add-in with React Framework",
- "core.createProjectQuestion.officeXMLAddin.excel.react.detail": "Create an Excel add-in with React framework",
- "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.title": "Excel Custom Functions Using Shared Runtime",
- "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.detail": "Create an Excel add-in leveraging Custom Functions using a Shared Runtime",
- "core.createProjectQuestion.officeXMLAddin.excel.cf.js.title": "Excel Custom Functions Using JavaScript-only Runtime",
- "core.createProjectQuestion.officeXMLAddin.excel.cf.js.detail": "Create an Excel add-in leveraging Custom Functions using a JavaScript-only Runtime",
- "core.createProjectQuestion.officeXMLAddin.excel.create.title": "Create Excel Add-in",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.title": "PowerPoint Add-in",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.detail": "Build engaging solutions for presentations across platform",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.title": "Add-in with Single Sign On",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.detail": "PowerPoint add-in with Single Sign On capabilities",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.react.title": "Add-in with React Framework",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.react.detail": "Create a PowerPoint add-in with React framework",
- "core.createProjectQuestion.officeXMLAddin.powerpoint.create.title": "Create a PowerPoint Add-in",
- "core.createProjectQuestion.officeXMLAddin.taskpane.title": "Add-in with Basic Task Pane",
- "core.createProjectQuestion.officeXMLAddin.taskpane.detail": "Customize the Ribbon with a button and create a dashboard in the Task Pane",
- "core.createProjectQuestion.officeXMLAddin.manifestOnly.title": "Add-in Project With only Manifest File",
- "core.createProjectQuestion.officeXMLAddin.manifestOnly.detail": "Create an add-in project that includes only the manifest file",
"core.aiAssistantBotOption.label": "AI Agent Bot",
"core.aiAssistantBotOption.detail": "A custom AI Agent bot in Teams using Teams AI library and OpenAI Assistants API",
"core.aiBotOption.label": "AI Chat Bot",
@@ -563,6 +529,33 @@
"core.copilot.addAPI.success": "%s have(has) been successfully added to %s",
"core.copilot.addAPI.InjectAPIKeyActionFailed": "Inject API key action to teamsapp.yaml file unsuccessful, make sure the file contains teamsApp/create action in provision section.",
"core.copilot.addAPI.InjectOAuthActionFailed": "Inject OAuth action to teamsapp.yaml file unsuccessful, make sure the file contains teamsApp/create action in provision section.",
+ "core.uninstall.botNotFound": "Cannot find bot using the manifest ID %s",
+ "core.uninstall.confirm.tdp": "App registration of manifest ID: %s will be removed. Please confirm.",
+ "core.uninstall.confirm.m365App": "Microsoft 365 Application of Title ID: %s will be uninstalled. Please confirm.",
+ "core.uninstall.confirm.bot": "Bot framework registration of bot ID: %s will be removed. Please confirm.",
+ "core.uninstall.confirm.cancel.tdp": "Removal of app registration is canceled.",
+ "core.uninstall.confirm.cancel.m365App": "Uninstallation of Microsoft 365 Application is canceled.",
+ "core.uninstall.confirm.cancel.bot": "Removal of Bot framework registration is canceled.",
+ "core.uninstall.success.tdp": "App registration of manifest ID: %s successfully removed.",
+ "core.uninstall.success.m365App": "Microsoft 365 Application of Title ID: %s successfully uninstalled.",
+ "core.uninstall.success.delayWarning": "The uninstallation of the Microsoft 365 Application may be delayed.",
+ "core.uninstall.success.bot": "Bot framework registration of bot ID: %s successfully removed.",
+ "core.uninstall.failed.titleId": "Unable to find the Title ID. This app is probably not installed.",
+ "core.uninstallQuestion.manifestId": "Manifest ID",
+ "core.uninstallQuestion.env": "Environment",
+ "core.uninstallQuestion.titleId": "Title ID",
+ "core.uninstallQuestion.chooseMode": "Choose a way to clean up resources",
+ "core.uninstallQuestion.manifestIdMode": "Manifest ID",
+ "core.uninstallQuestion.manifestIdMode.detail": "Clean up resources associated with Manifest ID. This includes app registration in Teams Developer Portal, bot registration in Bot Framework Portal, and custom apps uploaded to Microsoft 365. You can find the Manifest ID in the environment file (default environment key: Teams_App_ID) in the project created by Teams Toolkit.",
+ "core.uninstallQuestion.envMode": "Environment in Teams Toolkit Created Project",
+ "core.uninstallQuestion.envMode.detail": "Clean up resources associated with a specific environment in the Teams Toolkit created project. Resources include app registration in Teams Developer Portal, bot registration in Bot Framework Portal, and custom apps uploaded in Microsoft 365 apps.",
+ "core.uninstallQuestion.titleIdMode": "Title ID",
+ "core.uninstallQuestion.titleIdMode.detail": "Uninstall the uploaded custom app associated with Title ID. The Title ID can be found in the environment file in the Teams Toolkit created project.",
+ "core.uninstallQuestion.chooseOption": "Choose resources to uninstall",
+ "core.uninstallQuestion.m365Option": "Microsoft 365 Application",
+ "core.uninstallQuestion.tdpOption": "App registration",
+ "core.uninstallQuestion.botOption": "Bot framework registration",
+ "core.uninstallQuestion.projectPath": "Project path",
"ui.select.LoadingOptionsPlaceholder": "Loading options ...",
"ui.select.LoadingDefaultPlaceholder": "Loading default value ...",
"error.aad.manifest.NameIsMissing": "name is missing\n",
@@ -578,28 +571,28 @@
"error.aad.manifest.OptionalClaimsIsMissing": "optionalClaims is missing\n",
"error.aad.manifest.OptionalClaimsMissingIdtypClaim": "optionalClaims access token doesn't contain idtyp claim\n",
"error.aad.manifest.AADManifestIssues": "Microsoft Entra manifest has following issues that may potentially break the Teams App:\n",
- "error.aad.manifest.DeleteOrUpdatePermissionFailed": "Unable to update or delete an existing permission when it's enabled. One possible reason is that the ACCESS_AS_USER_PERMISSION_ID environment variable is changed for selected environment. Ensure your permission id(s) are identical with the actual Microsoft Entra application and try again.\n",
+ "error.aad.manifest.DeleteOrUpdatePermissionFailed": "Unable to update or delete an enabled permission. It may be because the ACCESS_AS_USER_PERMISSION_ID environment variable is changed for selected environment. Make sure your permission id(s) match the actual Microsoft Entra application and try again.\n",
"error.aad.manifest.HostNameNotOnVerifiedDomain": "Unable to set identifierUri because the value is not on verified domain: %s",
"error.aad.manifest.UnknownResourceAppId": "Unknown resourceAppId %s",
"error.aad.manifest.UnknownResourceAccessType": "Unknown resourceAccess: %s",
- "error.aad.manifest.UnknownResourceAccessId": "Unknown resourceAccess id: %s, if you're using permission as resourceAccess id, please try to use permission id instead.",
+ "error.aad.manifest.UnknownResourceAccessId": "Unknown resourceAccess id: %s, try to use permission id instead of resourceAccess id.",
"core.addSsoFiles.emptyProjectPath": "Project path is empty",
"core.addSsoFiles.FailedToCreateAuthFiles": "Unable to create files for add sso. Detail error: %s.",
- "core.getUserEmailQuestion.validation3": "Email address is not valid",
+ "core.getUserEmailQuestion.validation3": "Email address is invalid",
"plugins.bot.ErrorSuggestions": "Suggestions: %s",
"plugins.bot.InvalidValue": "%s is invalid with value: %s",
- "plugins.bot.SomethingIsMissing": "%s is missing.",
+ "plugins.bot.SomethingIsMissing": "%s is not available.",
"plugins.bot.FailedToProvision": "Unable to provision %s.",
"plugins.bot.FailedToUpdateConfigs": "Unable to update configs for %s",
"plugins.bot.BotRegistrationNotFoundWith": "Bot registration was not found with botId %s. Click 'Get Help' button to get more info about how to check bot registrations.",
"plugins.bot.BotResourceExists": "Bot resource already existed on %s, skip creating Bot resource.",
"plugins.bot.FailRetrieveAzureCredentials": "Unable to retrieve Azure credentials.",
- "plugins.bot.ProvisionBotRegistration": "Provisioning bot registration.",
- "plugins.bot.ProvisionBotRegistrationSuccess": "Successfully provisioned bot registration.",
- "plugins.bot.CheckLogAndFix": "Please check log in Output panel and try to fix this issue.",
+ "plugins.bot.ProvisionBotRegistration": "Bot registration provisioning in progress...",
+ "plugins.bot.ProvisionBotRegistrationSuccess": "Bot registration provisioned successfully.",
+ "plugins.bot.CheckLogAndFix": "Please check log-in Output panel and try to fix this issue.",
"plugins.bot.AppStudioBotRegistration": "Developer Portal bot registration",
- "plugins.function.getTemplateFromLocal": "Unable to get newest template from github, trying to use the local template.",
- "error.depChecker.DefaultErrorMessage": "Install the required dependencies manually.",
+ "plugins.function.getTemplateFromLocal": "Unable to get latest template from github, trying to use the local template.",
+ "error.depChecker.DefaultErrorMessage": "Install required dependencies manually.",
"depChecker.learnMoreButtonText": "Get more info",
"depChecker.needInstallNpm": "You must have NPM installed to debug your local functions.",
"depChecker.failToValidateFuncCoreTool": "Unable to validate Azure Functions Core Tools after installation.",
@@ -662,7 +655,7 @@
"driver.botAadApp.error.unexpectedEmptyBotPassword": "Bot password is empty. Add it in env file or clear bot id to have bot id/password pair regenerated. action: %s.",
"driver.arm.description.deploy": "Deploy the given ARM templates to Azure.",
"driver.arm.deploy.progressBar.message": "Deploying the ARM templates to Azure...",
- "debug.warningMessage": "To debug applications in Teams, your localhost server must be on HTTPS.\nFor Teams to trust the self-signed SSL certificate used by the toolkit, a self-signed certificate must be added to your certificate store.\n You may skip this step, but you'll have to manually trust the secure connection in a new browser window when debugging your apps in Teams.\nFor more information \"https://aka.ms/teamsfx-ca-certificate\".",
+ "debug.warningMessage": "To debug applications in Teams, your localhost server need to be on HTTPS.\nFor Teams to trust the self-signed SSL certificate used by the toolkit, add a self-signed certificate to your certificate store.\n You may skip this step, but you'll have to manually trust the secure connection in a new browser window when debugging your apps in Teams.\nFor more information \"https://aka.ms/teamsfx-ca-certificate\".",
"debug.warningMessage2": " You may be asked for your account credentials when installing the certificate.",
"debug.install": "Install",
"driver.spfx.deploy.description": "deploys the SPFx package to SharePoint app catalog.",
@@ -671,12 +664,12 @@
"driver.spfx.deploy.deployPackage": "Deploy SPFx package to your tenant app catalog.",
"driver.spfx.deploy.skipCreateAppCatalog": "Skip to create SharePoint app catalog.",
"driver.spfx.deploy.uploadPackage": "Upload SPFx package to your tenant app catalog.",
- "driver.spfx.info.tenantAppCatalogCreated": "SharePoint tenant app catalog %s created, wait for a few minutes to be active.",
- "driver.spfx.warn.noTenantAppCatalogFound": "No tenant app catalog found, retry: %s",
- "driver.spfx.error.failedToGetAppCatalog": "Cannot get app catalog site url after creation. You may need wait a few minutes and retry.",
+ "driver.spfx.info.tenantAppCatalogCreated": "SharePoint tenant app catalog %s is created. Please wait a few minutes for it to be active.",
+ "driver.spfx.warn.noTenantAppCatalogFound": "No tenant app catalog found, try again: %s",
+ "driver.spfx.error.failedToGetAppCatalog": "Unable to get app catalog site url after creation. Wait a few minutes and try again.",
"driver.spfx.error.noValidAppCatelog": "There is no valid app catalog in your tenant. You can update the property 'createAppCatalogIfNotExist' in %s to true if you want Teams Toolkit to create it for you or you can create it by yourself.",
"driver.spfx.add.description": "add additional web part to SPFx project",
- "driver.spfx.add.successNotice": "Web part %s was successfully added to project.",
+ "driver.spfx.add.successNotice": "Web part %s was successfully added to the project.",
"driver.spfx.add.progress.title": "Scaffolding web part",
"driver.spfx.add.progress.scaffoldWebpart": "Generate SPFx web part using Yeoman CLI",
"driver.prerequisite.error.funcInstallationError": "Unable to check and install Azure Functions Core Tools.",
@@ -687,26 +680,26 @@
"driver.prerequisite.summary.devCert.trusted.succuss": "Development certificate for localhost is installed.",
"driver.prerequisite.summary.devCert.notTrusted.succuss": "Development certificate for localhost is generated.",
"driver.prerequisite.summary.devCert.skipped": "Skip trusting development certificate for localhost.",
- "driver.prerequisite.summary.func.installedWithPath": "Azure Functions Core Tools is installed at %s.",
- "driver.prerequisite.summary.func.installed": "Azure Functions Core Tools is installed.",
+ "driver.prerequisite.summary.func.installedWithPath": "Azure Functions Core Tools are installed at %s.",
+ "driver.prerequisite.summary.func.installed": "Azure Functions Core Tools are installed.",
"driver.prerequisite.summary.dotnet.installedWithPath": ".NET Core SDK is installed at %s.",
"driver.prerequisite.summary.dotnet.installed": ".NET Core SDK is installed.",
"driver.prerequisite.summary.testTool.installedWithPath": "Teams App Test Tool is installed at %s.",
"driver.prerequisite.summary.testTool.installed": "Teams App Test Tool is installed.",
- "driver.file.createOrUpdateEnvironmentFile.description": "Create or update variables to environment file.",
- "driver.file.createOrUpdateEnvironmentFile.summary": "The variables have been generated successfully to %s.",
+ "driver.file.createOrUpdateEnvironmentFile.description": "Create or update variables to env file.",
+ "driver.file.createOrUpdateEnvironmentFile.summary": "Variables have been generated successfully to %s.",
"driver.file.createOrUpdateJsonFile.description": "Create or update JSON file.",
- "driver.file.createOrUpdateJsonFile.summary": "The json file has been generated successfully to %s.",
+ "driver.file.createOrUpdateJsonFile.summary": "Json file has been successfully generated to %s.",
"driver.file.progressBar.appsettings": "Generating json file...",
"driver.file.progressBar.env": "Generating environment variables...",
- "driver.deploy.error.restartWebAppError": "Unable to restart web app.\nPlease try to restart the web app manually if the app doesn't work properly.",
- "driver.deploy.notice.deployAcceleration": "Deploying to Azure App Service takes a long time. Consider referring to this document to optimize your deployment:",
+ "driver.deploy.error.restartWebAppError": "Unable to restart web app.\nPlease try to restart it manually.",
+ "driver.deploy.notice.deployAcceleration": "Deploying to Azure App Service takes a long time. Refer this document to optimize your deployment:",
"driver.deploy.notice.deployDryRunComplete": "Deployment preparations are completed. You can find the package in `%s`",
- "driver.deploy.azureAppServiceDeployDetailSummary": "Successfully deployed `%s` to Azure App Service.",
- "driver.deploy.azureFunctionsDeployDetailSummary": "Successfully deployed `%s` to Azure Functions.",
- "driver.deploy.azureStorageDeployDetailSummary": "Successfully deployed `%s` to Azure Storage.",
- "driver.deploy.enableStaticWebsiteSummary": "Azure Storage enable static website successfully.",
- "driver.deploy.getSWADeploymentTokenSummary": "Successfully get the deployment token for Azure Static Web Apps.",
+ "driver.deploy.azureAppServiceDeployDetailSummary": "`%s` deployed to Azure App Service.",
+ "driver.deploy.azureFunctionsDeployDetailSummary": "`%s` deployed to Azure Functions.",
+ "driver.deploy.azureStorageDeployDetailSummary": "`%s` deployed to Azure Storage.",
+ "driver.deploy.enableStaticWebsiteSummary": "Azure Storage enable static website.",
+ "driver.deploy.getSWADeploymentTokenSummary": "Get the deployment token for Azure Static Web Apps.",
"driver.deploy.deployToAzureAppServiceDescription": "deploy the project to the Azure App Service.",
"driver.deploy.deployToAzureFunctionsDescription": "deploy the project to the Azure Functions.",
"driver.deploy.deployToAzureStorageDescription": "deploy the project to the Azure Storage.",
@@ -717,20 +710,20 @@
"driver.script.dotnetDescription": "running dotnet command.",
"driver.script.npmDescription": "running npm command.",
"driver.script.npxDescription": "running npx command.",
- "driver.script.runCommandSummary": "Successful execution of the `%s` command at `%s`.",
- "driver.m365.acquire.description": "acquire an Microsoft 365 title with the app package",
+ "driver.script.runCommandSummary": "`%s` command executed at `%s`.",
+ "driver.m365.acquire.description": "acquire Microsoft 365 title with the app package",
"driver.m365.acquire.progress.message": "Acquiring Microsoft 365 title with the app package...",
- "driver.m365.acquire.summary": "The Microsoft 365 title has been acquired successfully (%s).",
+ "driver.m365.acquire.summary": "Microsoft 365 title acquired successfully (%s).",
"driver.teamsApp.description.copyAppPackageToSPFxDriver": "copies the generated Teams app package to SPFx solution.",
- "driver.teamsApp.description.createDriver": "create a Teams app.",
- "driver.teamsApp.description.updateDriver": "update a Teams app.",
- "driver.teamsApp.description.publishDriver": "publish a Teams app to tenant app catalog.",
- "driver.teamsApp.description.validateDriver": "validate a Teams app.",
- "driver.teamsApp.description.createAppPackageDriver": "build a Teams app package.",
+ "driver.teamsApp.description.createDriver": "create Teams app.",
+ "driver.teamsApp.description.updateDriver": "update Teams app.",
+ "driver.teamsApp.description.publishDriver": "publish Teams app to tenant app catalog.",
+ "driver.teamsApp.description.validateDriver": "validate Teams app.",
+ "driver.teamsApp.description.createAppPackageDriver": "build Teams app package.",
"driver.teamsApp.progressBar.copyAppPackageToSPFxStepMessage": "Copying Teams app package to SPFx solution...",
"driver.teamsApp.progressBar.createTeamsAppStepMessage": "Creating Teams app...",
"driver.teamsApp.progressBar.updateTeamsAppStepMessage": "Updating Teams app...",
- "driver.teamsApp.progressBar.publishTeamsAppStep1": "Checking if the Teams app has already been submitted to tenant App Catalog",
+ "driver.teamsApp.progressBar.publishTeamsAppStep1": "Checking if the Teams app is already submitted to tenant App Catalog",
"driver.teamsApp.progressBar.publishTeamsAppStep2.1": "Update published Teams app",
"driver.teamsApp.progressBar.publishTeamsAppStep2.2": "Publishing Teams app...",
"driver.teamsApp.progressBar.validateWithTestCases": "Submitting validation request...",
@@ -747,7 +740,7 @@
"driver.teamsApp.summary.validateManifest": "Teams Toolkit has checked manifest(s) with the corresponding schema:\n\nSummary:\n%s.",
"driver.teamsApp.summary.validateTeamsManifest.checkPath": "You can check and update your Teams manifest at %s.",
"driver.teamsApp.summary.validateDeclarativeCopilotManifest.checkPath": "You can check and update your Declarative Copilot manifest at %s.",
- "driver.teamsApp.summary.validatePluginManifest.checkPath": "You can check and update your Copilot Plugin manifest at %s.",
+ "driver.teamsApp.summary.validatePluginManifest.checkPath": "You can check and update your API Plugin manifest at %s.",
"driver.teamsApp.summary.validate.succeed": "%s passed",
"driver.teamsApp.summary.validate.failed": "%s failed",
"driver.teamsApp.summary.validate.warning": "%s warning",
@@ -779,56 +772,57 @@
"error.yaml.InvalidActionInputError": "The '%s' action cannot be completed as the following parameter(s): %s, are either missing or have an invalid value in the provided yaml file: %s. Ensure that the required parameters are provided and have valid values and try again.",
"error.common.InstallSoftwareError": "Unable to install %s. You can install it manually and restart Visual Studio Code if you are using the Toolkit in Visual Studio Code.",
"error.common.VersionError": "Unable to find a version satisfying the version range %s.",
- "error.common.MissingEnvironmentVariablesError": "The program cannot proceed as the following environment variables are missing: '%s', which are required for file: %s. Make sure the required variables are set either by editing the .env file '%s' with the correct names and values , or by setting the system environment variables with the correct names and values. If you are developing with a new project created with Teams Toolkit, running provision or debug will register correct values for these environment variables.",
- "error.common.InvalidProjectError": "This command only works for project created by Teams Toolkit.",
+ "error.common.MissingEnvironmentVariablesError": "Missing environment variables '%s' for file: %s. Please edit the .env file '%s' or '%s', or adjust system environment variables. For new Teams Toolkit projects, make sure you've run provision or debug to set these variables correctly.",
+ "error.common.InvalidProjectError": "This command only works for project created by Teams Toolkit. 'teamsapp.yml' or 'teamsapp.local.yml' not found",
+ "error.common.InvalidProjectError.display": "This command only works for project created by Teams Toolkit. Yaml file not found: %s",
"error.common.FileNotFoundError": "The file or directory is not found: '%s'. Check if it exists and you have permission to access it.",
"error.common.JSONSyntaxError": "JSON syntax error: %s. Check the JSON syntax to ensure it is properly formatted.",
"error.common.ReadFileError": "Unable to read file for reason: %s",
"error.common.UnhandledError": "An unexpected error has occurred while performing the %s task. %s",
"error.common.WriteFileError": "Unable to write file for reason: %s",
- "error.common.FilePermissionError": "File operation is not permitted, ensure that you have the necessary permissions: %s",
+ "error.common.FilePermissionError": "File operation is not permitted, make sure you have the necessary permissions: %s",
"error.common.MissingRequiredInputError": "Missing required input: %s",
- "error.common.InputValidationError": "Input '%s' validation failed: %s",
+ "error.common.InputValidationError": "Input '%s' validation unsuccessful: %s",
"error.common.NoEnvFilesError": "Unable to find .env files.",
"error.common.MissingRequiredFileError": "Missing %srequired file `%s`",
- "error.common.HttpClientError": "A http client error happened while performing the %s task. The error response is: %s",
- "error.common.HttpServerError": "A http server error happened while performing the %s task. Please try again later. The error response is: %s",
+ "error.common.HttpClientError": "A http client error occurred while performing the %s task. The error response is: %s",
+ "error.common.HttpServerError": "A http server error occurred while performing the %s task. Try again later. The error response is: %s",
"error.common.AccessGithubError": "Access GitHub (%s) Error: %s",
"error.common.ConcurrentError": "Previous task is still running. Wait until your previous task is finished and try again.",
"error.common.NetworkError": "Network error: %s",
"error.common.NetworkError.EAI_AGAIN": "DNS cannot resolve domain %s.",
- "error.upgrade.NoNeedUpgrade": "This project is already the latest, no need to upgrade.",
- "error.collaboration.InvalidManifestError": "Unable to process your manifest file ('%s') due to the absence of the 'id' key. To identify your application correctly, please make sure that the 'id' key is present in the manifest file.",
+ "error.upgrade.NoNeedUpgrade": "This is the latest project, upgrade not required.",
+ "error.collaboration.InvalidManifestError": "Unable to process your manifest file ('%s') due to absence of the 'id' key. To identify your app correctly, make sure the 'id' key is present in the manifest file.",
"error.collaboration.FailedToLoadManifest": "Unable to load manifest file. Reason: %s.",
- "error.azure.InvalidAzureCredentialError": "Unable to obtain your Azure credentials. Ensure that your Azure account is properly authenticated and try again.",
- "error.azure.InvalidAzureSubscriptionError": "The Azure subscription '%s' is not available in your current account. Ensure that you have signed in with the correct Azure account and that you have the necessary permissions to access the subscription.",
- "error.azure.ResourceGroupConflictError": "Resource group '%s' already exists in subscription '%s'. Consider choosing a different name or using the existing resource group for your task.",
+ "error.azure.InvalidAzureCredentialError": "Unable to obtain your Azure credentials. Make sure your Azure account is properly authenticated and try again.",
+ "error.azure.InvalidAzureSubscriptionError": "Azure subscription '%s' is not available in your current account. Make sure you've signed in with the correct Azure account and have necessary permissions to access the subscription.",
+ "error.azure.ResourceGroupConflictError": "Resource group '%s' already exists in subscription '%s'. Choose a different name or use the existing resource group for your task.",
"error.azure.SelectSubscriptionError": "Unable to select subscription in current account.",
- "error.azure.ResourceGroupNotExistError": "The resource group '%s' cannot be found in subscription '%s'.",
+ "error.azure.ResourceGroupNotExistError": "Unable to find the resource group '%s' in subscription '%s'.",
"error.azure.CreateResourceGroupError": "Unable to create resource group '%s' in subscription '%s'due to error: %s. \nIf the error message specifies the reason, fix the error and try again.",
"error.azure.CheckResourceGroupExistenceError": "Unable to check existence of resource group '%s' in subscription '%s'due to error: %s. \nIf the error message specifies the reason, fix the error and try again.",
"error.azure.ListResourceGroupsError": "Unable to get resource groups in subscription '%s'due to error: %s. \nIf the error message specifies the reason, fix the error and try again.",
"error.azure.GetResourceGroupError": "Unable to get information of resource group '%s' in subscription '%s'due to error: %s. \nIf the error message specifies the reason, fix the error and try again.",
"error.azure.ListResourceGroupLocationsError": "Unable to get available resource group locations for subscription '%s'.",
- "error.m365.M365TokenJSONNotFoundError": "Unable to obtain JSON object for Microsoft 365 token. Ensure that your account is authorized to access the tenant and that the token JSON object is valid.",
- "error.m365.M365TenantIdNotFoundInTokenError": "Unable to obtain Microsoft 365 tenant ID in token JSON object. Ensure that your account is authorized to access the tenant and that the token JSON object is valid.",
- "error.m365.M365TenantIdNotMatchError": "Authentication failed. You are currently signed in to Microsoft 365 tenant '%s', which is different from the one specified in the .env file (TEAMS_APP_TENANT_ID='%s'). To resolve this issue and switch to your current signed-in tenant, please remove the values of '%s' from the .env file and try again.",
+ "error.m365.M365TokenJSONNotFoundError": "Unable to obtain JSON object for Microsoft 365 token. Make sure your account is authorized to access the tenant and the token JSON object is valid.",
+ "error.m365.M365TenantIdNotFoundInTokenError": "Unable to obtain Microsoft 365 tenant ID in token JSON object. Make sure your account is authorized to access the tenant and the token JSON object is valid.",
+ "error.m365.M365TenantIdNotMatchError": "Authentication unsuccessful. You're currently signed in to Microsoft 365 tenant '%s', which is different from the one specified in the .env file (TEAMS_APP_TENANT_ID='%s'). To resolve this issue and switch to your current signed-in tenant, remove the values of '%s' from the .env file and try again.",
"error.arm.CompileBicepError": "Unable to compile Bicep files located in path '%s' to JSON ARM templates. The error message returned was: %s. Check the Bicep files for any syntax or configuration errors and try again.",
"error.arm.DownloadBicepCliError": "Unable to download Bicep cli from '%s'. The error message was: %s. Fix the error and try again. Or remove the bicepCliVersion config in the config file teamsapp.yml and Teams Toolkit will use bicep CLI in PATH",
- "error.arm.DeployArmError.Notification": "The ARM templates for deployment name: '%s' could not be deployed in resource group '%s'. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details.",
- "error.arm.DeployArmError": "The ARM templates for deployment name: '%s' could not be deployed in resource group '%s' for reason: %s",
- "error.arm.GetArmDeploymentError": "The ARM templates for deployment name: '%s' could not be deployed in resource group '%s' for reason: %s. \nUnable to get detailed error message due to: %s. \nRefer to the resource group %s in portal for deployment error.",
- "error.arm.ConvertArmOutputError": "Unable to convert ARM deployment result to action output, there is a duplicated key '%s' in ARM deployment result.",
- "error.deploy.DeployEmptyFolderError": "Unable to locate any files in the distribution folder: '%s'. Please ensure that the folder is not empty and that all necessary files have been included.",
- "error.deploy.CheckDeploymentStatusTimeoutError": "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, please review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred.",
- "error.deploy.ZipFileError": "Failed to zip the artifact folder. The folder size exceeds the maximum limit of 2GB. Please reduce the size of the folder and try again.",
- "error.deploy.ZipFileTargetInUse": "Failed to clear the distribution zip file in %s. The file may be currently in use. Please close any applications using the file and try again.",
+ "error.arm.DeployArmError.Notification": "The ARM templates for deployment name: '%s' couldn't be deployed in resource group '%s'. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details.",
+ "error.arm.DeployArmError": "The ARM templates for deployment name: '%s' couldn't be deployed in resource group '%s' for reason: %s",
+ "error.arm.GetArmDeploymentError": "The ARM templates for deployment name: '%s' couldn't be deployed in resource group '%s' for reason: %s. \nUnable to get detailed error message due to: %s. \nRefer to the resource group %s in portal for deployment error.",
+ "error.arm.ConvertArmOutputError": "Unable to convert ARM deployment result into action output. There is a duplicated key '%s' in ARM deployment result.",
+ "error.deploy.DeployEmptyFolderError": "Unable to locate any files in the distribution folder: '%s'. Make sure the folder includes all necessary files.",
+ "error.deploy.CheckDeploymentStatusTimeoutError": "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred.",
+ "error.deploy.ZipFileError": "Unable to zip the artifact folder as its size exceeds the maximum limit of 2GB. Reduce the folder size and try again.",
+ "error.deploy.ZipFileTargetInUse": "Unable to clear the distribution zip file in %s as it may be currently in use. Close any apps using the file and try again.",
"error.deploy.GetPublishingCredentialsError.Notification": "Unable to obtain publishing credentials of app '%s' in resource group '%s'. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details.",
- "error.deploy.GetPublishingCredentialsError": "Unable to obtain publishing credentials of app '%s' in resource group '%s' for reason:\n %s.\n Suggestions:\n 1. Verify that the app name and resource group name are spelled correctly and are valid. \n 2. Verify that your Azure account has the necessary permissions to access the API. You may need to elevate your role or request additional permissions from an administrator. \n 3. If the error message includes a specific reason, such as an authentication failure or a network issue, investigate that issue specifically to resolve the error and try again. \n 4. You can test the API in this page: '%s'",
+ "error.deploy.GetPublishingCredentialsError": "Unable to obtain publishing credentials of app '%s' in resource group '%s' for reason:\n %s.\n Suggestions:\n 1. Make sure the app name and resource group name are spelled correctly and are valid. \n 2. Make sure your Azure account has necessary permissions to access the API. You may need to elevate your role or request additional permissions from an administrator. \n 3. If the error message includes a specific reason, such as an authentication failure or a network issue, investigate that issue specifically to resolve the error and try again. \n 4. You can test the API in this page: '%s'",
"error.deploy.DeployZipPackageError.Notification": "Unable to deploy zip package to endpoint: '%s'. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details and try again.",
- "error.deploy.DeployZipPackageError": "Unable to deploy zip package to endpoint '%s' in Azure due to error: %s. \nSuggestions:\n 1. Verify that your Azure account has the necessary permissions to access the API. \n 2. Verify that the endpoint is properly configured in Azure and that the required resources have been provisioned. \n 3. Ensure that the zip package is valid and free of errors. \n 4. If the error message specifies the reason, such as an authentication failure or a network issue, fix the error and try again. \n 5. If the error still persists, you can attempt to deploy the package manually following the guidelines in this link: '%s'",
- "error.deploy.CheckDeploymentStatusError": "Unable to check deployment status for location: '%s' due to error: %s. If the issue persists, please review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred.",
- "error.deploy.DeployRemoteStartError": "The package has been successfully deployed to Azure for location: '%s', but the application is not able to start due to error: %s.\n If the reason is not clearly specified, here are some suggestions to troubleshoot:\n 1. Check the application logs: Look for any error messages or stack traces in the application logs to identify the root cause of the problem.\n 2. Check the Azure configuration: Ensure that the Azure configuration is correct, including connection strings and application settings.\n 3. Check the application code: Review the code to see if there are any syntax or logic errors that could be causing the issue.\n 4. Check the dependencies: Verify that all dependencies required by the application are correctly installed and updated.\n 5. Restart the application: Try restarting the application in Azure to see if that resolves the issue.\n 6. Check the resource allocation: Make sure that the resource allocation for the Azure instance is appropriate for the application and its workload.\n 7. Seek help from Azure support: If the issue persists, reach out to Azure support for further assistance.",
+ "error.deploy.DeployZipPackageError": "Unable to deploy zip package to endpoint '%s' in Azure due to error: %s. \nSuggestions:\n 1. Make sure your Azure account has necessary permissions to access the API. \n 2. Make sure the endpoint is properly configured in Azure and the required resources have been provisioned. \n 3. Make sure the zip package is valid and free of errors. \n 4. If the error message specifies the reason, such as an authentication failure or a network issue, fix the error and try again. \n 5. If the error still persists, deploy the package manually following the guidelines in this link: '%s'",
+ "error.deploy.CheckDeploymentStatusError": "Unable to check deployment status for location: '%s' due to error: %s. If the issue persists, review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred.",
+ "error.deploy.DeployRemoteStartError": "The package deployed to Azure for location: '%s', but the app is not able to start due to error: %s.\n If the reason is not clearly specified, here are some suggestions to troubleshoot:\n 1. Check the app logs: Look for any error messages or stack traces in the app logs to identify the root cause of the problem.\n 2. Check the Azure configuration: Make sure the Azure configuration is correct, including connection strings and application settings.\n 3. Check the application code: Review the code to see if there are any syntax or logic errors that could be causing the issue.\n 4. Check the dependencies: Make sure all dependencies required by the app are correctly installed and updated.\n 5. Restart the application: Try restarting the application in Azure to see if that resolves the issue.\n 6. Check the resource allocation: Make sure the resource allocation for the Azure instance is appropriate for the app and its workload.\n 7. Get help from Azure support: If the issue persists, reach out to Azure support for further assistance.",
"error.script.ScriptTimeoutError": "Script execution timeout. Adjust 'timeout' parameter in yaml or improve your script's efficiency.",
"error.script.ScriptExecutionError": "Unable to execute script action.",
"error.deploy.AzureStorageClearBlobsError.Notification": "Unable to clear blob files in Azure Storage Account '%s'. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details.",
@@ -841,8 +835,8 @@
"error.deploy.AzureStorageGetContainerPropertiesError": "Unable to get properties of container '%s' in Azure Storage Account '%s' due to error: %s. The error responses from Azure are:\n %s. \nIf the error message specifies the reason, fix the error and try again.",
"error.deploy.AzureStorageSetContainerPropertiesError.Notification": "Unable to set properties of container '%s' in Azure Storage Account '%s' due to error: %s. Refer to the [Output panel](command:fx-extension.showOutputChannel) for more details.",
"error.deploy.AzureStorageSetContainerPropertiesError": "Unable to set properties of container '%s' in Azure Storage Account '%s' due to error: %s. The error responses from Azure are:\n %s. \nIf the error message specifies the reason, fix the error and try again.",
- "error.core.failedToLoadManifestId": "Unable to load manifest id from path: %s. You must run provision first.",
- "error.core.appIdNotExist": "Cannot find app id: %s. Either your current M365 account does not have permission, or the app has alredy been deleted.",
+ "error.core.failedToLoadManifestId": "Unable to load manifest id from path: %s. Run provision first.",
+ "error.core.appIdNotExist": "Unable to find app id: %s. Either your current M365 account doesn't have permission, or the app has been deleted.",
"driver.apiKey.description.create": "Create an API key on Developer Portal for authentication in Open API spec.",
"driver.aadApp.apiKey.title.create": "Creating API key...",
"driver.apiKey.description.update": "Update an API key on Developer Portal for authentication in Open API spec.",
@@ -853,11 +847,11 @@
"driver.apiKey.info.update": "API key updated successfully! The following parameters have been updated:\n%s",
"driver.apiKey.log.startExecuteDriver": "Executing action %s",
"driver.apiKey.log.skipCreateApiKey": "Environment variable %s exists. Skip creating API key.",
- "driver.apiKey.log.apiKeyNotFound": "Environment variable %s exists but failed to retrieve API key from Developer Portal. Check manually if API key exists.",
- "driver.apiKey.error.nameTooLong": "The name for API key is too long. The maximum length is 128.",
+ "driver.apiKey.log.apiKeyNotFound": "Environment variable %s exists but unable to retrieve API key from Developer Portal. Check manually if API key exists.",
+ "driver.apiKey.error.nameTooLong": "The name for API key is too long. The maximum character length is 128.",
"driver.apiKey.error.clientSecretInvalid": "Client secret is invalid. The length of client secret should be in this range: >=10 and <=128",
- "driver.apiKey.error.domainInvalid": "Domain is invalid. Domain for API key should follow: 1. Max %d domain per API key. 2. Use comma to separate domains",
- "driver.apiKey.error.failedToGetDomain": "Failed to get domain from API specification. Please make sure your API specification is valid.",
+ "driver.apiKey.error.domainInvalid": "Domain is invalid. Domain for API key should follow: 1. Max %d domain(s) per API key. 2. Use comma to separate domains",
+ "driver.apiKey.error.failedToGetDomain": "Unable to get domain from API specification. Make sure your API specification is valid.",
"driver.apiKey.log.successCreateApiKey": "Created API key with id %s",
"driver.apiKey.log.failedExecuteDriver": "Unable to execute action %s. Error message: %s",
"driver.oauth.description.create": "Create an OAuth registration on Developer Portal for authentication in Open API spec.",
diff --git a/packages/fx-core/src/client/teamsDevPortalClient.ts b/packages/fx-core/src/client/teamsDevPortalClient.ts
index 80afd319a7..a92be95b8e 100644
--- a/packages/fx-core/src/client/teamsDevPortalClient.ts
+++ b/packages/fx-core/src/client/teamsDevPortalClient.ts
@@ -274,7 +274,15 @@ export class TeamsDevPortalClient {
}
throw new Error(`Cannot get the app definition with app ID ${teamsAppId}`);
}
-
+ @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })])
+ async getBotId(token: string, teamsAppId: string): Promise {
+ const app = await this.getApp(token, teamsAppId);
+ if (app?.bots?.length && app.bots.length > 0) {
+ return app.bots[0].botId;
+ }
+ TOOLS.logProvider?.error(`botId not found. Input: ${teamsAppId}`);
+ return undefined;
+ }
@hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })])
async getAppPackage(token: string, teamsAppId: string): Promise {
TOOLS.logProvider?.info("Downloading app package for app " + teamsAppId);
diff --git a/packages/fx-core/src/common/constants.ts b/packages/fx-core/src/common/constants.ts
index 6374f16ab7..bd1f1d54ac 100644
--- a/packages/fx-core/src/common/constants.ts
+++ b/packages/fx-core/src/common/constants.ts
@@ -37,22 +37,6 @@ export class OutlookClientId {
static readonly Web2 = "bc59ab01-8403-45c6-8796-ac3ef710b3e3";
static readonly Mobile = "27922004-5251-4030-b22d-91ecd9a37ea4";
}
-export class FeatureFlagName {
- static readonly CLIDotNet = "TEAMSFX_CLI_DOTNET";
- static readonly OfficeAddin = "TEAMSFX_OFFICE_ADDIN";
- static readonly CopilotPlugin = "DEVELOP_COPILOT_PLUGIN";
- static readonly SampleConfigBranch = "TEAMSFX_SAMPLE_CONFIG_BRANCH";
- static readonly TestTool = "TEAMSFX_TEST_TOOL";
- static readonly METestTool = "TEAMSFX_ME_TEST_TOOL";
- static readonly TeamsFxRebranding = "TEAMSFX_REBRANDING";
- static readonly TdpTemplateCliTest = "TEAMSFX_TDP_TEMPLATE_CLI_TEST";
- static readonly AsyncAppValidation = "TEAMSFX_ASYNC_APP_VALIDATION";
- static readonly NewProjectType = "TEAMSFX_NEW_PROJECT_TYPE";
- static readonly ChatParticipant = "TEAMSFX_CHAT_PARTICIPANT";
- static readonly NewGenerator = "TEAMSFX_NEW_GENERATOR";
- static readonly SMEOAuth = "SME_OAUTH";
- static readonly CustomizeGpt = "TEAMSFX_DECLARATIVE_COPILOT";
-}
export function getAllowedAppMaps(): Record {
return {
diff --git a/packages/fx-core/src/common/featureFlags.ts b/packages/fx-core/src/common/featureFlags.ts
index 07fb0dde6f..1b28f49e4e 100644
--- a/packages/fx-core/src/common/featureFlags.ts
+++ b/packages/fx-core/src/common/featureFlags.ts
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { FeatureFlagName } from "./constants";
// Determine whether feature flag is enabled based on environment variable setting
export function isFeatureFlagEnabled(featureFlagName: string, defaultValue = false): boolean {
@@ -11,61 +10,24 @@ export function isFeatureFlagEnabled(featureFlagName: string, defaultValue = fal
return flag === "1" || flag.toLowerCase() === "true"; // can enable feature flag by set environment variable value to "1" or "true"
}
}
-
-///////////////////////////////////////////////////////////////////////////////
-// Notes for Office Addin Feature flags:
-// Case 1: TEAMSFX_OFFICE_ADDIN = false, TEAMSFX_OFFICE_XML_ADDIN = false
-// 1.1 project-type option: `outlook-addin-type`
-// 1.2 addin-host: not show but use `outlook` internally
-// 1.3 capabilities options: [`json-taskpane`, `outlook-addin-import`]
-// 1.4 programming-language options: [`typescript`] (skip in UI)
-// 1.5 office-addin-framework-type: not show question but use `default_old` internally
-// 1.6 generator class: OfficeAddinGenerator
-// 1.7 template link: config.json.json-taskpane.default_old.typescript
-// Case 2: TEAMSFX_OFFICE_ADDIN = false AND TEAMSFX_OFFICE_XML_ADDIN = true
-// 2.1 project-type option: `office-xml-addin-type`
-// 2.2 addin-host options: [`outlook`, `word`, `excel`, `powerpoint`]
-// 2.3 capabilities options:
-// if (addin-host == `outlook`) then [`json-taskpane`, `outlook-addin-import`]
-// else if (addin-host == `word`) then [`word-taskpane`, `word-xxx`, ...]
-// else if (addin-host == `excel`) then [`excel-taskpane`, `excel-xxx`, ...]
-// else if (addin-host === `powerpoint`) then [`powerpoint-taskpane`, `powerpoint-xxx`, ...]
-// 2.4 programming-language options:
-// if (addin-host == `outlook`) then [`typescript`] (skip in UI)
-// else two options: [`typescript`, `javascript`]
-// 2.5 office-addin-framework-type options:
-// if (word excel and powerpoint) use `default` internally
-// else if (outlook) use `default_old` internally
-// 2.6 generator class:
-// if (addin-host == `outlook`) then OfficeAddinGenerator
-// else OfficeXMLAddinGenerator
-// 2.7 template link:
-// if (addin-host == `outlook`) config.json.json-taskpane.default.[programming-language]
-// else config[addin-host].[capabilities].default.[programming-language]
-// Case 3: TEAMSFX_OFFICE_ADDIN = true AND TEAMSFX_OFFICE_XML_ADDIN = true
-// 3.1 project-type option: `office-addin-type`
-// 3.2 addin-host: not show but will use `wxpo` internally
-// 3.3 capabilities options: [`json-taskpane`, `office-addin-import`, `office-content-addin`]
-// 3.4 programming-language options: [`typescript`, `javascript`]
-// 3.5 office-addin-framework-type options: [`default`, `react`]
-// if (capabilities == `json-taskpane`) then [`default`, `react`]
-// else if (capabilities == `office-addin-import`) then [`default`] (skip in UI)
-// else if (capabilities == `office-content-addin`) then [`default`] (skip in UI)
-// 3.6 generator class: OfficeAddinGenerator
-// 3.7 template link: config.json.[capabilities].[office-addin-framework-type].[programming-language]
-// case 4: TEAMSFX_OFFICE_ADDIN = true AND TEAMSFX_OFFICE_XML_ADDIN = fasle
-// 4.1 project-type option: `office-addin-type`
-// 4.2 addin-host: not show but will use `wxpo` internally
-// 4.3 capabilities options: [`json-taskpane`, `office-addin-import`]
-// 4.4 programming-language options: [`typescript`, `javascript`]
-// 4.5 office-addin-framework-type options: [`default`, `react`]
-// if (capabilities == `json-taskpane`) then [`default`, `react`]
-// else if (capabilities == `office-addin-import`) then [`default`] (skip in UI)
-// else if (capabilities == `office-content-addin`) then [`default`] (skip in UI)
-// 4.6 generator class: OfficeAddinGenerator
-// 4.7 template link: config.json.[capabilities].[office-addin-framework-type].[programming-language]
-///////////////////////////////////////////////////////////////////////////////////////////////////////
-
+export class FeatureFlagName {
+ static readonly CLIDotNet = "TEAMSFX_CLI_DOTNET";
+ static readonly OfficeAddin = "TEAMSFX_OFFICE_ADDIN";
+ static readonly CopilotPlugin = "DEVELOP_COPILOT_PLUGIN";
+ static readonly SampleConfigBranch = "TEAMSFX_SAMPLE_CONFIG_BRANCH";
+ static readonly TestTool = "TEAMSFX_TEST_TOOL";
+ static readonly METestTool = "TEAMSFX_ME_TEST_TOOL";
+ static readonly TeamsFxRebranding = "TEAMSFX_REBRANDING";
+ static readonly TdpTemplateCliTest = "TEAMSFX_TDP_TEMPLATE_CLI_TEST";
+ static readonly AsyncAppValidation = "TEAMSFX_ASYNC_APP_VALIDATION";
+ static readonly NewProjectType = "TEAMSFX_NEW_PROJECT_TYPE";
+ static readonly ChatParticipant = "TEAMSFX_CHAT_PARTICIPANT";
+ static readonly SMEOAuth = "SME_OAUTH";
+ static readonly CustomizeGpt = "TEAMSFX_DECLARATIVE_COPILOT";
+ static readonly ShowDiagnostics = "TEAMSFX_SHOW_DIAGNOSTICS";
+ static readonly TelemetryTest = "TEAMSFX_TELEMETRY_TEST";
+ static readonly DevTunnelTest = "TEAMSFX_DEV_TUNNEL_TEST";
+}
export interface FeatureFlag {
name: string;
defaultValue: string;
@@ -77,7 +39,6 @@ export class FeatureFlags {
static readonly CopilotPlugin = { name: FeatureFlagName.CopilotPlugin, defaultValue: "false" };
static readonly TestTool = { name: FeatureFlagName.TestTool, defaultValue: "true" };
static readonly METestTool = { name: FeatureFlagName.METestTool, defaultValue: "true" };
- static readonly NewGenerator = { name: FeatureFlagName.NewGenerator, defaultValue: "true" };
static readonly OfficeAddin = { name: FeatureFlagName.OfficeAddin, defaultValue: "false" };
static readonly TdpTemplateCliTest = {
name: FeatureFlagName.TdpTemplateCliTest,
@@ -94,6 +55,18 @@ export class FeatureFlags {
};
static readonly SMEOAuth = { name: FeatureFlagName.SMEOAuth, defaultValue: "false" };
static readonly CustomizeGpt = { name: FeatureFlagName.CustomizeGpt, defaultValue: "false" };
+ static readonly ShowDiagnostics = {
+ name: FeatureFlagName.ShowDiagnostics,
+ defaultValue: "false",
+ };
+ static readonly TelemetryTest = {
+ name: FeatureFlagName.TelemetryTest,
+ defaultValue: "false",
+ };
+ static readonly DevTunnelTest = {
+ name: FeatureFlagName.DevTunnelTest,
+ defaultValue: "false",
+ };
}
export class FeatureFlagManager {
@@ -103,12 +76,20 @@ export class FeatureFlagManager {
featureFlag.defaultValue === "true" || featureFlag.defaultValue === "1"
);
}
+ setBooleanValue(featureFlag: FeatureFlag, value: boolean): void {
+ process.env[featureFlag.name] = value ? "true" : "false";
+ }
getStringValue(featureFlag: FeatureFlag): string {
return process.env[featureFlag.name] || featureFlag.defaultValue;
}
list(): FeatureFlag[] {
return Object.values(FeatureFlags);
}
+ listEnabled(): string[] {
+ return this.list()
+ .filter((f) => isFeatureFlagEnabled(f.name))
+ .map((f) => f.name);
+ }
}
export const featureFlagManager = new FeatureFlagManager();
diff --git a/packages/fx-core/src/common/samples.ts b/packages/fx-core/src/common/samples.ts
index c80620552b..8ffc16aa70 100644
--- a/packages/fx-core/src/common/samples.ts
+++ b/packages/fx-core/src/common/samples.ts
@@ -5,7 +5,7 @@ import axios from "axios";
import { hooks } from "@feathersjs/hooks";
import { ErrorContextMW } from "./globalVars";
import { AccessGithubError } from "../error/common";
-import { FeatureFlagName } from "./constants";
+import { FeatureFlagName } from "./featureFlags";
import { sendRequestWithTimeout } from "./requestUtils";
const packageJson = require("../../package.json");
diff --git a/packages/fx-core/src/common/telemetry.ts b/packages/fx-core/src/common/telemetry.ts
index 67e3fd03f9..aede020419 100644
--- a/packages/fx-core/src/common/telemetry.ts
+++ b/packages/fx-core/src/common/telemetry.ts
@@ -83,6 +83,9 @@ export enum TelemetryProperty {
HasAzureOpenAIEndpoint = "has-azure-openai-endpoint",
HasAzureOpenAIDeploymentName = "has-azure-openai-deployment-name",
HasOpenAIKey = "has-openai-key",
+
+ TDPTraceId = "tdp-trace-id",
+ MOSTraceId = "mos-trace-id",
}
export const TelemetryConstants = {
@@ -156,6 +159,7 @@ export enum TelemetryEvent {
ProjectType = "project-type",
DependencyApi = "dependency-api",
AppStudioApi = "app-studio-api",
+ MOSApi = "ttk-mos-api",
}
export enum ProjectTypeProps {
diff --git a/packages/fx-core/src/common/tools.ts b/packages/fx-core/src/common/tools.ts
index 6a431beec7..36f539a66d 100644
--- a/packages/fx-core/src/common/tools.ts
+++ b/packages/fx-core/src/common/tools.ts
@@ -44,14 +44,22 @@ export async function getSPFxToken(
// this function will be deleted after VS has added get dev tunnel and list dev tunnels API
const TunnelManagementUserAgent = { name: "Teams-Toolkit" };
-export async function listDevTunnels(token: string): Promise> {
+export async function listDevTunnels(
+ token: string,
+ isGitHub = false
+): Promise> {
try {
const tunnelManagementClientImpl = new TunnelManagementHttpClient(
TunnelManagementUserAgent,
ManagementApiVersions.Version20230927preview,
() => {
- const res = `Bearer ${token}`;
- return Promise.resolve(res);
+ if (isGitHub === true) {
+ const res = `github client_id=a200baed193bb2088a6e ${token}`;
+ return Promise.resolve(res);
+ } else {
+ const res = `Bearer ${token}`;
+ return Promise.resolve(res);
+ }
}
);
diff --git a/packages/fx-core/src/common/wrappedAxiosClient.ts b/packages/fx-core/src/common/wrappedAxiosClient.ts
index 2f584923d3..17840dc838 100644
--- a/packages/fx-core/src/common/wrappedAxiosClient.ts
+++ b/packages/fx-core/src/common/wrappedAxiosClient.ts
@@ -47,14 +47,7 @@ export class WrappedAxiosClient {
params: this.generateParameters(request.params),
...this.generateExtraProperties(fullPath, request.data),
};
-
- let eventName: string;
- if (this.isTDPApi(fullPath)) {
- eventName = TelemetryEvent.AppStudioApi;
- } else {
- eventName = TelemetryEvent.DependencyApi;
- }
-
+ const eventName = this.getEventName(fullPath);
TOOLS?.telemetryReporter?.sendTelemetryEvent(`${eventName}-start`, properties);
return request;
}
@@ -80,12 +73,7 @@ export class WrappedAxiosClient {
...this.generateExtraProperties(fullPath, response.data),
};
- let eventName: string;
- if (this.isTDPApi(fullPath)) {
- eventName = TelemetryEvent.AppStudioApi;
- } else {
- eventName = TelemetryEvent.DependencyApi;
- }
+ const eventName = this.getEventName(fullPath);
TOOLS?.telemetryReporter?.sendTelemetryEvent(eventName, properties);
return response;
}
@@ -122,8 +110,8 @@ export class WrappedAxiosClient {
...this.generateExtraProperties(fullPath, requestData),
};
- let eventName: string;
- if (this.isTDPApi(fullPath)) {
+ const eventName = this.getEventName(fullPath);
+ if (eventName === TelemetryEvent.AppStudioApi) {
const correlationId = error.response?.headers[Constants.CORRELATION_ID] ?? "undefined";
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
const extraData = error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : "";
@@ -137,9 +125,16 @@ export class WrappedAxiosClient {
TelemetryProperty.ErrorCode
] = `${TDPApiFailedError.source}.${TDPApiFailedError.name}`;
properties[TelemetryProperty.ErrorMessage] = TDPApiFailedError.message;
- eventName = TelemetryEvent.AppStudioApi;
- } else {
- eventName = TelemetryEvent.DependencyApi;
+ properties[TelemetryProperty.TDPTraceId] = correlationId;
+ } else if (eventName === TelemetryEvent.MOSApi) {
+ const tracingId = (error.response?.headers?.traceresponse ?? "undefined") as string;
+ const originalMessage = error.message;
+ const innerError = (error.response?.data as any).error || { code: "", message: "" };
+ const finalMessage = `${originalMessage} (tracingId: ${tracingId}) ${
+ innerError.code as string
+ }: ${innerError.message as string} `;
+ properties[TelemetryProperty.ErrorMessage] = finalMessage;
+ properties[TelemetryProperty.MOSTraceId] = tracingId;
}
TOOLS?.telemetryReporter?.sendTelemetryErrorEvent(eventName, properties);
@@ -295,6 +290,18 @@ export class WrappedAxiosClient {
return matches != null && matches.length > 0;
}
+ private static getEventName(
+ baseUrl: string
+ ): TelemetryEvent.MOSApi | TelemetryEvent.AppStudioApi | TelemetryEvent.DependencyApi {
+ if (this.isTDPApi(baseUrl)) {
+ return TelemetryEvent.AppStudioApi;
+ } else if (baseUrl.includes("titles.prod.mos.microsoft.com")) {
+ return TelemetryEvent.MOSApi;
+ } else {
+ return TelemetryEvent.DependencyApi;
+ }
+ }
+
/**
* Flattern query parameters to string, e.g. {a: 1, b: 2} => a:1;b:2
* @param params
diff --git a/packages/fx-core/src/component/coordinator/index.ts b/packages/fx-core/src/component/coordinator/index.ts
index 548b28b009..792fc78fef 100644
--- a/packages/fx-core/src/component/coordinator/index.ts
+++ b/packages/fx-core/src/component/coordinator/index.ts
@@ -24,7 +24,6 @@ import * as path from "path";
import * as uuid from "uuid";
import * as xml2js from "xml2js";
import { AppStudioScopes, getResourceGroupInPortal } from "../../common/constants";
-import { FeatureFlags, featureFlagManager } from "../../common/featureFlags";
import { ErrorContextMW, globalVars } from "../../common/globalVars";
import { getLocalizedString } from "../../common/localizeUtils";
import { convertToAlphanumericOnly } from "../../common/stringUtils";
@@ -41,10 +40,6 @@ import {
import { LifeCycleUndefinedError } from "../../error/yml";
import {
AppNamePattern,
- CapabilityOptions,
- CustomCopilotRagOptions,
- MeArchitectureOptions,
- OfficeAddinHostOptions,
ProjectTypeOptions,
QuestionNames,
ScratchOptions,
@@ -57,14 +52,8 @@ import { developerPortalScaffoldUtils } from "../developerPortalScaffoldUtils";
import { DriverContext } from "../driver/interface/commonArgs";
import { updateTeamsAppV3ForPublish } from "../driver/teamsApp/appStudio";
import { Constants } from "../driver/teamsApp/constants";
-import { CopilotPluginGenerator } from "../generator/copilotPlugin/generator";
import { Generator } from "../generator/generator";
import { Generators } from "../generator/generatorProvider";
-import { OfficeAddinGenerator } from "../generator/officeAddin/generator";
-import { OfficeXMLAddinGenerator } from "../generator/officeXMLAddin/generator";
-import { SPFxGenerator } from "../generator/spfx/spfxGenerator";
-import { Feature2TemplateName } from "../generator/templates/templateNames";
-import { convertToLangKey } from "../generator/utils";
import { ActionContext, ActionExecutionMW } from "../middleware/actionExecutionMW";
import { provisionUtils } from "../provisionUtils";
import { ResourceGroupInfo, resourceGroupHelper } from "../utils/ResourceGroupHelper";
@@ -150,8 +139,6 @@ class Coordinator {
globalVars.isVS = language === "csharp";
const capability = inputs.capabilities as string;
const projectType = inputs[QuestionNames.ProjectType];
- const meArchitecture = inputs[QuestionNames.MeArchitectureType] as string;
- const apiMEAuthType = inputs[QuestionNames.ApiAuth] as string;
delete inputs.folder;
merge(actionContext?.telemetryProps, {
@@ -174,161 +161,21 @@ class Coordinator {
});
}
- if (featureFlagManager.getBooleanValue(FeatureFlags.NewGenerator)) {
- // refactored generator
- const generator = Generators.find((g) => g.activate(context, inputs));
- if (!generator) {
- return err(new MissingRequiredInputError(QuestionNames.Capabilities, "coordinator"));
- }
- const res = await generator.run(context, inputs, projectPath);
- if (res.isErr()) return err(res.error);
- else {
- warnings = res.value.warnings;
- }
- } else {
- // legacy logic
- if (capability === CapabilityOptions.SPFxTab().id) {
- const res = await SPFxGenerator.generate(context, inputs, projectPath);
- if (res.isErr()) return err(res.error);
- } else if (ProjectTypeOptions.officeAddinAllIds().includes(projectType)) {
- const addinHost = inputs[QuestionNames.OfficeAddinHost];
- if (
- projectType === ProjectTypeOptions.officeXMLAddin().id &&
- addinHost &&
- addinHost !== OfficeAddinHostOptions.outlook().id
- ) {
- const res = await OfficeXMLAddinGenerator.generate(context, inputs, projectPath);
- if (res.isErr()) return err(res.error);
- } else {
- const res = await OfficeAddinGenerator.generate(context, inputs, projectPath);
- if (res.isErr()) return err(res.error);
- }
- } else if (capability === CapabilityOptions.copilotPluginApiSpec().id) {
- const res = await CopilotPluginGenerator.generatePluginFromApiSpec(
- context,
- inputs,
- projectPath
- );
- if (res.isErr()) {
- return err(res.error);
- } else {
- warnings = res.value.warnings;
- }
- } else if (meArchitecture === MeArchitectureOptions.apiSpec().id) {
- const res = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- projectPath
- );
- if (res.isErr()) {
- return err(res.error);
- } else {
- warnings = res.value.warnings;
- }
- } else {
- if (
- capability === CapabilityOptions.m365SsoLaunchPage().id ||
- capability === CapabilityOptions.m365SearchMe().id
- ) {
- inputs.isM365 = true;
- }
- const trigger = inputs[QuestionNames.BotTrigger] as string;
- let feature = `${capability}:${trigger}`;
-
- if (
- language === "csharp" &&
- capability === CapabilityOptions.notificationBot().id &&
- inputs.isIsolated === true
- ) {
- feature += "-isolated";
- }
-
- if (meArchitecture) {
- feature = `${feature}:${meArchitecture}`;
- }
- if (
- inputs.targetFramework &&
- inputs.targetFramework !== "net6.0" &&
- inputs.targetFramework !== "net7.0" &&
- (capability === CapabilityOptions.nonSsoTab().id ||
- capability === CapabilityOptions.tab().id)
- ) {
- feature = `${capability}:ssr`;
- }
-
- if (
- capability === CapabilityOptions.m365SearchMe().id &&
- meArchitecture === MeArchitectureOptions.newApi().id
- ) {
- feature = `${feature}:${apiMEAuthType}`;
- }
-
- if (capability === CapabilityOptions.copilotPluginNewApi().id) {
- feature = `${feature}:${apiMEAuthType}`;
- }
-
- if (capability === CapabilityOptions.customCopilotRag().id) {
- feature = `${feature}:${inputs[QuestionNames.CustomCopilotRag] as string}`;
- } else if (capability === CapabilityOptions.customCopilotAssistant().id) {
- feature = `${feature}:${inputs[QuestionNames.CustomCopilotAssistant] as string}`;
- }
-
- const templateName = Feature2TemplateName[feature];
-
- if (templateName) {
- const langKey = convertToLangKey(language);
- const safeProjectNameFromVS =
- language === "csharp" ? inputs[QuestionNames.SafeProjectName] : undefined;
- const llmService: string | undefined = inputs[QuestionNames.LLMService];
- const openAIKey: string | undefined = inputs[QuestionNames.OpenAIKey];
- const azureOpenAIKey: string | undefined = inputs[QuestionNames.AzureOpenAIKey];
- const azureOpenAIEndpoint: string | undefined =
- inputs[QuestionNames.AzureOpenAIEndpoint];
- const azureOpenAIDeploymentName: string | undefined =
- inputs[QuestionNames.AzureOpenAIDeploymentName];
- context.templateVariables = Generator.getDefaultVariables(
- appName,
- safeProjectNameFromVS,
- inputs.targetFramework,
- inputs.placeProjectFileInSolutionDir === "true",
- undefined,
- {
- llmService,
- openAIKey,
- azureOpenAIKey,
- azureOpenAIEndpoint,
- azureOpenAIDeploymentName,
- }
- );
- const res = await Generator.generateTemplate(
- context,
- projectPath,
- templateName,
- langKey
- );
- if (res.isErr()) return err(res.error);
- if (inputs[QuestionNames.CustomCopilotRag] === CustomCopilotRagOptions.customApi().id) {
- const res = await CopilotPluginGenerator.generateForCustomCopilotRagCustomApi(
- context,
- inputs,
- projectPath
- );
- if (res.isErr()) {
- return err(res.error);
- } else {
- warnings = res.value.warnings;
- }
- }
- } else {
- return err(new MissingRequiredInputError(QuestionNames.Capabilities, "coordinator"));
- }
- }
+ // refactored generator
+ const generator = Generators.find((g) => g.activate(context, inputs));
+ if (!generator) {
+ return err(new MissingRequiredInputError(QuestionNames.Capabilities, "coordinator"));
+ }
+ const res = await generator.run(context, inputs, projectPath);
+ if (res.isErr()) return err(res.error);
+ else {
+ warnings = res.value.warnings;
}
}
// generate unique projectId in teamsapp.yaml (optional)
const ymlPath = path.join(projectPath, MetadataV3.configFile);
- if (fs.pathExistsSync(ymlPath)) {
+ if (await fs.pathExists(ymlPath)) {
const ensureRes = await this.ensureTrackingId(projectPath, inputs.projectId);
if (ensureRes.isErr()) return err(ensureRes.error);
inputs.projectId = ensureRes.value;
diff --git a/packages/fx-core/src/component/generator/copilotPlugin/generator.ts b/packages/fx-core/src/component/generator/apiSpec/generator.ts
similarity index 96%
rename from packages/fx-core/src/component/generator/copilotPlugin/generator.ts
rename to packages/fx-core/src/component/generator/apiSpec/generator.ts
index a3eb618cf4..dd5cbf625e 100644
--- a/packages/fx-core/src/component/generator/copilotPlugin/generator.ts
+++ b/packages/fx-core/src/component/generator/apiSpec/generator.ts
@@ -91,11 +91,11 @@ function normalizePath(path: string): string {
return "./" + path.replace(/\\/g, "/");
}
-export interface CopilotPluginGeneratorResult {
+export interface OpenAPISpecGeneratorResult {
warnings?: Warning[];
}
-export class CopilotPluginGenerator {
+export class OpenAPISpecGenerator {
@hooks([
ActionExecutionMW({
enableTelemetry: true,
@@ -104,12 +104,12 @@ export class CopilotPluginGenerator {
errorSource: fromApiSpecComponentName,
}),
])
- public static async generateMeFromApiSpec(
+ public static async generateMe(
context: Context,
inputs: Inputs,
destinationPath: string,
actionContext?: ActionContext
- ): Promise> {
+ ): Promise> {
const templateName = fromApiSpecTemplateName;
const componentName = fromApiSpecComponentName;
@@ -134,12 +134,12 @@ export class CopilotPluginGenerator {
errorSource: pluginFromApiSpecComponentName,
}),
])
- public static async generatePluginFromApiSpec(
+ public static async generateCopilotPlugin(
context: Context,
inputs: Inputs,
destinationPath: string,
actionContext?: ActionContext
- ): Promise> {
+ ): Promise> {
const templateName = apiPluginFromApiSpecTemplateName;
const componentName = fromApiSpecComponentName;
@@ -164,11 +164,11 @@ export class CopilotPluginGenerator {
errorSource: fromOpenAIPlugincomponentName,
}),
])
- public static async generateForCustomCopilotRagCustomApi(
+ public static async generateCustomCopilot(
context: Context,
inputs: Inputs,
destinationPath: string
- ): Promise> {
+ ): Promise> {
return await this.generate(
context,
inputs,
@@ -187,7 +187,7 @@ export class CopilotPluginGenerator {
componentName: string,
isPlugin: boolean,
authData?: AuthInfo
- ): Promise> {
+ ): Promise> {
try {
const appName = inputs[QuestionNames.AppName];
const language = inputs[QuestionNames.ProgrammingLanguage];
@@ -250,7 +250,7 @@ export class CopilotPluginGenerator {
[telemetryProperties.authType]: authData?.authType ?? "None",
});
- const newGenerator = new CopilotGenerator();
+ const newGenerator = new SpecGenerator();
const getTemplateInfosState: any = {};
inputs.getTemplateInfosState = getTemplateInfosState;
getTemplateInfosState.isYaml = isYaml;
@@ -272,8 +272,8 @@ export class CopilotPluginGenerator {
}
}
-export class CopilotGenerator extends DefaultTemplateGenerator {
- componentName = "copilot-generator";
+export class SpecGenerator extends DefaultTemplateGenerator {
+ componentName = "spec-generator";
// isYaml = false;
// templateName = "";
// url = "";
diff --git a/packages/fx-core/src/component/generator/copilotPlugin/helper.ts b/packages/fx-core/src/component/generator/apiSpec/helper.ts
similarity index 98%
rename from packages/fx-core/src/component/generator/copilotPlugin/helper.ts
rename to packages/fx-core/src/component/generator/apiSpec/helper.ts
index c927d2b1eb..60156ac1f8 100644
--- a/packages/fx-core/src/component/generator/copilotPlugin/helper.ts
+++ b/packages/fx-core/src/component/generator/apiSpec/helper.ts
@@ -52,7 +52,7 @@ import {
CustomCopilotRagOptions,
ProgrammingLanguage,
QuestionNames,
- copilotPluginApiSpecOptionId,
+ apiPluginApiSpecOptionId,
} from "../../../question/constants";
import { SummaryConstant } from "../../configManager/constant";
import { manifestUtils } from "../../driver/teamsApp/utils/ManifestUtils";
@@ -61,6 +61,7 @@ import { pluginManifestUtils } from "../../driver/teamsApp/utils/PluginManifestU
const enum telemetryProperties {
validationStatus = "validation-status",
validationErrors = "validation-errors",
+ specNotValidDetails = "spec-not-valid-details",
validationWarnings = "validation-warnings",
validApisCount = "valid-apis-count",
allApisCount = "all-apis-count",
@@ -123,7 +124,9 @@ export async function listOperations(
shouldLogWarning = true,
existingCorrelationId?: string
): Promise> {
- const isPlugin = inputs[QuestionNames.Capabilities] === copilotPluginApiSpecOptionId;
+ const isPlugin =
+ inputs[QuestionNames.Capabilities] === apiPluginApiSpecOptionId ||
+ !!inputs[QuestionNames.PluginAvailability];
const isCustomApi =
inputs[QuestionNames.CustomCopilotRag] === CustomCopilotRagOptions.customApi().id;
@@ -361,6 +364,12 @@ export function logValidationResults(
.map((warn: WarningResult) => formatTelemetryValidationProperty(warn))
.join(";"),
};
+
+ const specNotValidError = errors.find((error) => error.type === ErrorType.SpecNotValid);
+ if (specNotValidError) {
+ properties[telemetryProperties.specNotValidDetails] = specNotValidError.content;
+ }
+
if (existingCorrelationId) {
properties["correlation-id"] = existingCorrelationId;
}
@@ -676,7 +685,7 @@ function mapInvalidReasonToMessage(reason: ErrorType): string {
}
function formatValidationErrorContent(error: ApiSpecErrorResult, inputs: Inputs): string {
- const isPlugin = inputs[QuestionNames.Capabilities] === copilotPluginApiSpecOptionId;
+ const isPlugin = inputs[QuestionNames.Capabilities] === apiPluginApiSpecOptionId;
try {
switch (error.type) {
case ErrorType.SpecNotValid: {
diff --git a/packages/fx-core/src/component/generator/generatorProvider.ts b/packages/fx-core/src/component/generator/generatorProvider.ts
index 49eae6aa19..0dd082349f 100644
--- a/packages/fx-core/src/component/generator/generatorProvider.ts
+++ b/packages/fx-core/src/component/generator/generatorProvider.ts
@@ -1,8 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { CopilotGenerator } from "./copilotPlugin/generator";
+import { SpecGenerator } from "./apiSpec/generator";
import { OfficeAddinGeneratorNew } from "./officeAddin/generator";
-import { OfficeXmlAddinGeneratorNew } from "./officeXMLAddin/generator";
import { SPFxGeneratorImport, SPFxGeneratorNew } from "./spfx/spfxGenerator";
import { SsrTabGenerator } from "./templates/ssrTabGenerator";
import { DefaultTemplateGenerator } from "./templates/templateGenerator";
@@ -10,10 +9,9 @@ import { DefaultTemplateGenerator } from "./templates/templateGenerator";
// When multiple generators are activated, only the top one will be executed.
export const Generators = [
new OfficeAddinGeneratorNew(),
- new OfficeXmlAddinGeneratorNew(),
new SsrTabGenerator(),
new DefaultTemplateGenerator(),
new SPFxGeneratorNew(),
new SPFxGeneratorImport(),
- new CopilotGenerator(),
+ new SpecGenerator(),
];
diff --git a/packages/fx-core/src/component/generator/officeAddin/generator.ts b/packages/fx-core/src/component/generator/officeAddin/generator.ts
index 5b7ea3e028..476d72db42 100644
--- a/packages/fx-core/src/component/generator/officeAddin/generator.ts
+++ b/packages/fx-core/src/component/generator/officeAddin/generator.ts
@@ -18,6 +18,7 @@ import {
ok,
} from "@microsoft/teamsfx-api";
import * as childProcess from "child_process";
+import fse from "fs-extra";
import { toLower } from "lodash";
import { OfficeAddinManifest } from "office-addin-manifest";
import { convertProject } from "office-addin-project";
@@ -27,7 +28,6 @@ import { getLocalizedString } from "../../../common/localizeUtils";
import { assembleError } from "../../../error";
import {
CapabilityOptions,
- OfficeAddinHostOptions,
ProgrammingLanguage,
ProjectTypeOptions,
QuestionNames,
@@ -108,11 +108,7 @@ export class OfficeAddinGenerator {
const capability = inputs[QuestionNames.Capabilities];
const inputHost = inputs[QuestionNames.OfficeAddinHost];
let host: string = inputHost;
- if (
- projectType === ProjectTypeOptions.outlookAddin().id ||
- (projectType === ProjectTypeOptions.officeXMLAddin().id &&
- inputHost === OfficeAddinHostOptions.outlook().id)
- ) {
+ if (projectType === ProjectTypeOptions.outlookAddin().id) {
host = "outlook";
} else if (projectType === ProjectTypeOptions.officeAddin().id) {
if (capability === "json-taskpane") {
@@ -133,10 +129,7 @@ export class OfficeAddinGenerator {
if (!fromFolder) {
// from template
const framework = getOfficeAddinFramework(inputs);
- const templateConfig = getOfficeAddinTemplateConfig(
- projectType,
- inputs[QuestionNames.OfficeAddinHost]
- );
+ const templateConfig = getOfficeAddinTemplateConfig();
const projectLink = templateConfig[capability].framework[framework][language];
// Copy project template files from project repository
@@ -264,6 +257,39 @@ export class OfficeAddinGeneratorNew extends DefaultTemplateGenerator {
): Promise> {
const res = await OfficeAddinGenerator.doScaffolding(context, inputs, destinationPath);
if (res.isErr()) return err(res.error);
+ await this.fixIconPath(destinationPath);
return ok({});
}
+
+ /**
+ * this is a work around for MOS API bug that will return invalid package if the icon path is not root folder of appPackage
+ * so this function will move the two icon files to root folder of appPackage and update the manifest.json
+ */
+ async fixIconPath(projectPath: string): Promise {
+ const outlineOldPath = join(projectPath, "appPackage", "assets", "outline.png");
+ const colorOldPath = join(projectPath, "appPackage", "assets", "color.png");
+ const outlineNewPath = join(projectPath, "appPackage", "outline.png");
+ const colorNewPath = join(projectPath, "appPackage", "color.png");
+ const manifestPath = join(projectPath, "appPackage", "manifest.json");
+ if (!(await fse.pathExists(manifestPath))) return;
+ const manifest = await fse.readJson(manifestPath);
+ let change = false;
+ if (manifest.icons.outline === "assets/outline.png") {
+ if ((await fse.pathExists(outlineOldPath)) && !(await fse.pathExists(outlineNewPath))) {
+ await fse.move(outlineOldPath, outlineNewPath);
+ manifest.icons.outline = "outline.png";
+ change = true;
+ }
+ }
+ if (manifest.icons.color === "assets/color.png") {
+ if ((await fse.pathExists(colorOldPath)) && !(await fse.pathExists(colorNewPath))) {
+ await fse.move(colorOldPath, colorNewPath);
+ manifest.icons.color = "color.png";
+ change = true;
+ }
+ }
+ if (change) {
+ await fse.writeJson(manifestPath, manifest, { spaces: 4 });
+ }
+ }
}
diff --git a/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts b/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts
deleted file mode 100644
index d98aee7837..0000000000
--- a/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-/**
- * @author zyun@microsoft.com
- */
-
-import { hooks } from "@feathersjs/hooks/lib";
-import { Context, FxError, GeneratorResult, Inputs, Result, err, ok } from "@microsoft/teamsfx-api";
-import * as childProcess from "child_process";
-import _, { merge } from "lodash";
-import { OfficeAddinManifest } from "office-addin-manifest";
-import { join } from "path";
-import { promisify } from "util";
-import { getLocalizedString } from "../../../common/localizeUtils";
-import { assembleError } from "../../../error";
-import {
- OfficeAddinHostOptions,
- ProgrammingLanguage,
- ProjectTypeOptions,
- QuestionNames,
-} from "../../../question/constants";
-import { getOfficeAddinTemplateConfig } from "../../../question/create";
-import { ActionContext, ActionExecutionMW } from "../../middleware/actionExecutionMW";
-import { Generator } from "../generator";
-import { HelperMethods } from "../officeAddin/helperMethods";
-import { DefaultTemplateGenerator } from "../templates/templateGenerator";
-import { TemplateInfo } from "../templates/templateInfo";
-import { convertToLangKey } from "../utils";
-
-const COMPONENT_NAME = "office-xml-addin";
-const TELEMETRY_EVENT = "generate";
-const TEMPLATE_BASE = "office-xml-addin";
-const TEMPLATE_COMMON_NAME = "office-xml-addin-common";
-const TEMPLATE_COMMON_LANG = "common";
-
-const enum OfficeXMLAddinTelemetryProperties {
- host = "office-xml-addin-host",
- project = "office-xml-addin-project",
- lang = "office-xml-addin-lang",
-}
-
-/**
- * project-type=office-xml-addin-type addin-host!==outlook
- */
-export class OfficeXMLAddinGenerator {
- @hooks([
- ActionExecutionMW({
- enableTelemetry: true,
- telemetryComponentName: COMPONENT_NAME,
- telemetryEventName: TELEMETRY_EVENT,
- errorSource: COMPONENT_NAME,
- }),
- ])
- static async generate(
- context: Context,
- inputs: Inputs,
- destinationPath: string,
- actionContext?: ActionContext
- ): Promise> {
- const host = inputs[QuestionNames.OfficeAddinHost] as string;
- const capability = inputs[QuestionNames.Capabilities];
- const lang = _.toLower(inputs[QuestionNames.ProgrammingLanguage]) as
- | "javascript"
- | "typescript";
- const langKey = convertToLangKey(lang);
- const appName = inputs[QuestionNames.AppName] as string;
- const projectType = inputs[QuestionNames.ProjectType];
- const templateConfig = getOfficeAddinTemplateConfig(projectType, host);
- const templateName = templateConfig[capability].localTemplate;
- const projectLink = templateConfig[capability].framework["default"][lang];
- const workingDir = process.cwd();
- const progressBar = context.userInteraction.createProgressBar(
- getLocalizedString("core.createProjectQuestion.officeXMLAddin.bar.title"),
- 1
- );
-
- merge(actionContext?.telemetryProps, {
- [OfficeXMLAddinTelemetryProperties.host]: host,
- [OfficeXMLAddinTelemetryProperties.project]: capability,
- [OfficeXMLAddinTelemetryProperties.lang]: lang,
- });
-
- try {
- process.chdir(destinationPath);
- await progressBar.start();
- await progressBar.next(
- getLocalizedString("core.createProjectQuestion.officeXMLAddin.bar.detail")
- );
-
- if (!!projectLink) {
- // [Condition]: Project have remote repo (not manifest-only proj)
-
- // -> Step: Download the project from GitHub
- const fetchRes = await HelperMethods.fetchAndUnzip(
- "office-xml-addin-generator",
- projectLink,
- destinationPath
- );
- if (fetchRes.isErr()) {
- return err(fetchRes.error);
- }
- // -> Step: Convert to single Host
- await OfficeXMLAddinGenerator.childProcessExec(
- `npm run convert-to-single-host --if-present -- ${_.toLower(host)}`
- );
- } else {
- // [Condition]: Manifest Only
-
- // -> Step: Copy proj files for manifest-only project
- const getManifestOnlyProjectTemplateRes = await Generator.generateTemplate(
- context,
- destinationPath,
- `${TEMPLATE_BASE}-manifest-only`,
- langKey
- );
- if (getManifestOnlyProjectTemplateRes.isErr())
- throw err(getManifestOnlyProjectTemplateRes.error);
- }
-
- // -> Common Step: Copy the README (or with manifest for manifest-only proj)
- const getReadmeTemplateRes = await Generator.generateTemplate(
- context,
- destinationPath,
- `${TEMPLATE_BASE}-${templateName}`,
- langKey
- );
- if (getReadmeTemplateRes.isErr()) throw err(getReadmeTemplateRes.error);
-
- // -> Common Step: Modify the Manifest
- await OfficeAddinManifest.modifyManifestFile(
- `${join(destinationPath, "manifest.xml")}`,
- "random",
- `${appName}`
- );
-
- // -> Common Step: Generate OfficeXMLAddin specific `teamsapp.yml`
- const generateOfficeYMLRes = await Generator.generateTemplate(
- context,
- destinationPath,
- TEMPLATE_COMMON_NAME,
- TEMPLATE_COMMON_LANG
- );
- if (generateOfficeYMLRes.isErr()) throw err(generateOfficeYMLRes.error);
-
- process.chdir(workingDir);
- await progressBar.end(true, true);
- return ok(undefined);
- } catch (e) {
- process.chdir(workingDir);
- await progressBar.end(false, true);
- return err(assembleError(e as Error));
- }
- }
-
- public static async childProcessExec(cmdLine: string): Promise<{
- stdout: string;
- stderr: string;
- }> {
- return promisify(childProcess.exec)(cmdLine);
- }
-}
-
-export class OfficeXmlAddinGeneratorNew extends DefaultTemplateGenerator {
- componentName = "office-xml-addin-generator";
-
- public activate(context: Context, inputs: Inputs): boolean {
- const projectType = inputs[QuestionNames.ProjectType];
- const addinHost = inputs[QuestionNames.OfficeAddinHost];
- return (
- projectType === ProjectTypeOptions.officeXMLAddin().id &&
- addinHost &&
- addinHost !== OfficeAddinHostOptions.outlook().id
- );
- }
-
- public async getTemplateInfos(
- context: Context,
- inputs: Inputs,
- destinationPath: string,
- actionContext?: ActionContext
- ): Promise> {
- const host = inputs[QuestionNames.OfficeAddinHost] as string;
- const capability = inputs[QuestionNames.Capabilities];
- const lang = _.toLower(inputs[QuestionNames.ProgrammingLanguage]) as
- | "javascript"
- | "typescript";
- const projectType = inputs[QuestionNames.ProjectType];
- const templateConfig = getOfficeAddinTemplateConfig(projectType, host);
- const templateName = templateConfig[capability].localTemplate;
- const projectLink = templateConfig[capability].framework["default"][lang];
- merge(actionContext?.telemetryProps, {
- [OfficeXMLAddinTelemetryProperties.host]: host,
- [OfficeXMLAddinTelemetryProperties.project]: capability,
- [OfficeXMLAddinTelemetryProperties.lang]: lang,
- });
-
- process.chdir(destinationPath);
- const templates: TemplateInfo[] = [];
- if (!!projectLink) {
- // [Condition]: Project have remote repo (not manifest-only proj)
-
- // -> Step: Download the project from GitHub
- const fetchRes = await HelperMethods.fetchAndUnzip(
- this.componentName,
- projectLink,
- destinationPath
- );
- if (fetchRes.isErr()) {
- return err(fetchRes.error);
- }
- // -> Step: Convert to single Host
- await OfficeXMLAddinGenerator.childProcessExec(
- `npm run convert-to-single-host --if-present -- ${_.toLower(host)}`
- );
- } else {
- templates.push({
- templateName: `${TEMPLATE_BASE}-manifest-only`,
- language: lang as ProgrammingLanguage,
- });
- }
- // -> Common Step: Copy the README (or with manifest for manifest-only proj)
- templates.push({
- templateName: `${TEMPLATE_BASE}-${templateName}`,
- language: lang as ProgrammingLanguage,
- });
- templates.push({
- templateName: TEMPLATE_COMMON_NAME,
- language: ProgrammingLanguage.None,
- });
- return ok(templates);
- }
-
- public async post(
- context: Context,
- inputs: Inputs,
- destinationPath: string,
- actionContext?: ActionContext
- ): Promise> {
- const appName = inputs[QuestionNames.AppName] as string;
- // -> Common Step: Modify the Manifest
- await OfficeAddinManifest.modifyManifestFile(
- `${join(destinationPath, "manifest.xml")}`,
- "random",
- `${appName}`
- );
- return ok({});
- }
-}
diff --git a/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts b/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts
index e0fce984aa..da4e3fe808 100644
--- a/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts
+++ b/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts
@@ -24,42 +24,6 @@ export interface IOfficeAddinProjectConfig {
[property: string]: IOfficeAddinHostConfig;
}
-const CommonProjectConfig = {
- taskpane: {
- title: "core.createProjectQuestion.officeXMLAddin.taskpane.title",
- detail: "core.createProjectQuestion.officeXMLAddin.taskpane.detail",
- framework: {
- default: {
- typescript: "https://aka.ms/ccdevx-fx-taskpane-ts",
- javascript: "https://aka.ms/ccdevx-fx-taskpane-js",
- },
- },
- },
- sso: {
- framework: {
- default: {
- typescript: "https://aka.ms/ccdevx-fx-sso-ts",
- javascript: "https://aka.ms/ccdevx-fx-sso-js",
- },
- },
- },
- react: {
- framework: {
- default: {
- typescript: "https://aka.ms/ccdevx-fx-react-ts",
- javascript: "https://aka.ms/ccdevx-fx-react-js",
- },
- },
- },
- manifest: {
- title: "core.createProjectQuestion.officeXMLAddin.manifestOnly.title",
- detail: "core.createProjectQuestion.officeXMLAddin.manifestOnly.detail",
- framework: {
- default: {},
- },
- },
-};
-
export const OfficeAddinProjectConfig: IOfficeAddinProjectConfig = {
json: {
"json-taskpane": {
@@ -94,92 +58,4 @@ export const OfficeAddinProjectConfig: IOfficeAddinProjectConfig = {
manifestPath: "manifest.json",
},
},
- word: {
- "word-taskpane": {
- localTemplate: "word-taskpane",
- ...CommonProjectConfig.taskpane,
- },
- "word-sso": {
- title: "core.createProjectQuestion.officeXMLAddin.word.sso.title",
- detail: "core.createProjectQuestion.officeXMLAddin.word.sso.detail",
- localTemplate: "word-sso",
- ...CommonProjectConfig.sso,
- },
- "word-react": {
- title: "core.createProjectQuestion.officeXMLAddin.word.react.title",
- detail: "core.createProjectQuestion.officeXMLAddin.word.react.detail",
- localTemplate: "word-react",
- ...CommonProjectConfig.react,
- },
- "word-manifest": {
- localTemplate: "word-manifest-only",
- ...CommonProjectConfig.manifest,
- },
- },
- excel: {
- "excel-taskpane": {
- localTemplate: "excel-taskpane",
- ...CommonProjectConfig.taskpane,
- },
- "excel-sso": {
- title: "core.createProjectQuestion.officeXMLAddin.excel.sso.title",
- detail: "core.createProjectQuestion.officeXMLAddin.excel.sso.detail",
- localTemplate: "excel-sso",
- ...CommonProjectConfig.sso,
- },
- "excel-react": {
- title: "core.createProjectQuestion.officeXMLAddin.excel.react.title",
- detail: "core.createProjectQuestion.officeXMLAddin.excel.react.detail",
- localTemplate: "excel-react",
- ...CommonProjectConfig.react,
- },
- "excel-custom-functions-shared": {
- title: "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.title",
- detail: "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.detail",
- localTemplate: "excel-cf",
- framework: {
- default: {
- typescript: "https://aka.ms/ccdevx-fx-cf-shared-ts",
- javascript: "https://aka.ms/ccdevx-fx-cf-shared-js",
- },
- },
- },
- "excel-custom-functions-js": {
- title: "core.createProjectQuestion.officeXMLAddin.excel.cf.js.title",
- detail: "core.createProjectQuestion.officeXMLAddin.excel.cf.js.detail",
- localTemplate: "excel-cf",
- framework: {
- default: {
- typescript: "https://aka.ms/ccdevx-fx-cf-js-ts",
- javascript: "https://aka.ms/ccdevx-fx-cf-js-js",
- },
- },
- },
- "excel-manifest": {
- localTemplate: "excel-manifest-only",
- ...CommonProjectConfig.manifest,
- },
- },
- powerpoint: {
- "powerpoint-taskpane": {
- localTemplate: "powerpoint-taskpane",
- ...CommonProjectConfig.taskpane,
- },
- "powerpoint-sso": {
- localTemplate: "powerpoint-sso",
- title: "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.title",
- detail: "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.detail",
- ...CommonProjectConfig.sso,
- },
- "powerpoint-react": {
- localTemplate: "powerpoint-react",
- title: "core.createProjectQuestion.officeXMLAddin.powerpoint.react.title",
- detail: "core.createProjectQuestion.officeXMLAddin.powerpoint.react.detail",
- ...CommonProjectConfig.react,
- },
- "powerpoint-manifest": {
- localTemplate: "powerpoint-manifest-only",
- ...CommonProjectConfig.manifest,
- },
- },
};
diff --git a/packages/fx-core/src/component/generator/spfx/spfxGenerator.ts b/packages/fx-core/src/component/generator/spfx/spfxGenerator.ts
index 8b3489d97d..f767df2d40 100644
--- a/packages/fx-core/src/component/generator/spfx/spfxGenerator.ts
+++ b/packages/fx-core/src/component/generator/spfx/spfxGenerator.ts
@@ -649,23 +649,24 @@ export class SPFxGenerator {
return undefined;
}
- const webpartName = webparts[0].split(path.sep).pop();
- const webpartManifestPath = path.join(
- webpartsDir,
- webparts[0],
- `${webpartName as string}WebPart.manifest.json`
+ const webpartManifest = (await fs.readdir(path.join(webpartsDir, webparts[0]))).find((file) =>
+ file.endsWith("WebPart.manifest.json")
);
- if (!(await fs.pathExists(webpartManifestPath))) {
+ if (webpartManifest === undefined) {
throw new FileNotFoundError(
Constants.PLUGIN_NAME,
- webpartManifestPath,
+ path.join(
+ webpartsDir,
+ webparts[0],
+ `${webparts[0].split(path.sep).pop() as string}WebPart.manifest.json`
+ ),
Constants.IMPORT_HELP_LINK
);
}
const matchHashComment = new RegExp(/(\/\/ .*)/, "gi");
const manifest = JSON.parse(
- (await fs.readFile(webpartManifestPath, "utf8"))
+ (await fs.readFile(path.join(webpartsDir, webparts[0], webpartManifest), "utf8"))
.toString()
.replace(matchHashComment, "")
.trim()
diff --git a/packages/fx-core/src/component/generator/templates/templateNames.ts b/packages/fx-core/src/component/generator/templates/templateNames.ts
index 44a8b6eb2e..29ccbf8f44 100644
--- a/packages/fx-core/src/component/generator/templates/templateNames.ts
+++ b/packages/fx-core/src/component/generator/templates/templateNames.ts
@@ -373,4 +373,12 @@ export const inputsToTemplateName: Map<{ [key: string]: any }, TemplateNames> =
},
TemplateNames.ApiPluginFromScratchOAuth,
],
+ [
+ { [QuestionNames.Capabilities]: CapabilityOptions.customizeGptBasic().id },
+ TemplateNames.BasicGpt,
+ ],
+ [
+ { [QuestionNames.Capabilities]: CapabilityOptions.customizeGptWithPlugin().id },
+ TemplateNames.GptWithPluginFromScratch,
+ ],
]);
diff --git a/packages/fx-core/src/core/FxCore.ts b/packages/fx-core/src/core/FxCore.ts
index c29bd7f469..067c53a285 100644
--- a/packages/fx-core/src/core/FxCore.ts
+++ b/packages/fx-core/src/core/FxCore.ts
@@ -38,7 +38,7 @@ import * as path from "path";
import "reflect-metadata";
import { Container } from "typedi";
import { pathToFileURL } from "url";
-import { VSCodeExtensionCommand } from "../common/constants";
+import { VSCodeExtensionCommand, AppStudioScopes } from "../common/constants";
import {
ErrorContextMW,
TOOLS,
@@ -105,7 +105,7 @@ import {
specParserGenerateResultAllSuccessTelemetryProperty,
specParserGenerateResultTelemetryEvent,
specParserGenerateResultWarningsTelemetryProperty,
-} from "../component/generator/copilotPlugin/helper";
+} from "../component/generator/apiSpec/helper";
import { LaunchHelper } from "../component/m365/launchHelper";
import { EnvLoaderMW, EnvWriterMW } from "../component/middleware/envMW";
import { QuestionMW } from "../component/middleware/questionMW";
@@ -121,6 +121,7 @@ import {
MissingRequiredInputError,
MultipleAuthError,
MultipleServerError,
+ UnhandledError,
UserCancelError,
assembleError,
} from "../error/common";
@@ -135,7 +136,7 @@ import {
SPFxVersionOptionIds,
ScratchOptions,
TeamsAppValidationOptions,
- copilotPluginApiSpecOptionId,
+ apiPluginApiSpecOptionId,
} from "../question/constants";
import { createProjectCliHelpNode } from "../question/create";
import { ValidateTeamsAppInputs } from "../question/inputs/ValidateTeamsAppInputs";
@@ -155,6 +156,10 @@ import {
} from "./middleware/utils/v3MigrationUtils";
import { CoreTelemetryComponentName, CoreTelemetryEvent, CoreTelemetryProperty } from "./telemetry";
import { CoreHookContext, PreProvisionResForVS, VersionCheckRes } from "./types";
+import { UninstallInputs } from "../question";
+import { PackageService } from "../component/m365/packageService";
+import { MosServiceEndpoint, MosServiceScope } from "../component/m365/serviceConstant";
+import { teamsDevPortalClient } from "../client/teamsDevPortalClient";
export class FxCore {
constructor(tools: Tools) {
@@ -293,6 +298,329 @@ export class FxCore {
} catch (e) {}
}
}
+
+ /**
+ * none lifecycle command, uninstall provisioned resources
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstall", reset: true }),
+ ErrorHandlerMW,
+ ProjectMigratorMWV3,
+ QuestionMW("uninstall"),
+ ])
+ async uninstall(inputs: UninstallInputs): Promise> {
+ switch (inputs[QuestionNames.UninstallMode as string]) {
+ case QuestionNames.UninstallModeManifestId:
+ return await this.uninstallByManifestId(inputs);
+ case QuestionNames.UninstallModeEnv:
+ return await this.uninstallByEnv(inputs);
+ case QuestionNames.UninstallModeTitleId:
+ return await this.uninstallByTitleId(inputs);
+ default:
+ return err(new UnhandledError(new Error("Uninstall mode not supported"), "FxCore"));
+ }
+ }
+
+ /**
+ * uninstall provisioned resources by manifest ID
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallByManifestId", reset: true }),
+ ErrorHandlerMW,
+ ])
+ async uninstallByManifestId(inputs: UninstallInputs): Promise> {
+ const manifestId = inputs[QuestionNames.ManifestId as string] as string;
+ if (!manifestId) {
+ return err(new MissingRequiredInputError("manifest-id", "FxCore"));
+ }
+ const uninstallOptions = inputs[QuestionNames.UninstallOptions as string];
+ const m356AppOption = uninstallOptions?.includes(QuestionNames.UninstallOptionM365);
+ const tdpOption = uninstallOptions?.includes(QuestionNames.UninstallOptionTDP);
+ const botOption = uninstallOptions?.includes(QuestionNames.UninstallOptionBot);
+
+ if (m356AppOption) {
+ const res = await this.uninstallM365App(undefined, manifestId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ }
+ if (botOption) {
+ const res = await this.uninstallBotFrameworRegistration(undefined, manifestId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ }
+ // App registraion should be the last to remove, because we might need to query some metadata from TDP.
+ if (tdpOption) {
+ const res = await this.uninstallAppRegistration(manifestId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ }
+
+ return ok(undefined);
+ }
+
+ /**
+ * uninstall provisioned resources by a given environment
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallByEnv", reset: true }),
+ ErrorHandlerMW,
+ EnvLoaderMW(true, true),
+ ConcurrentLockerMW,
+ ContextInjectorMW,
+ EnvWriterMW,
+ ])
+ async uninstallByEnv(
+ inputs: UninstallInputs,
+ ctx?: CoreHookContext
+ ): Promise> {
+ if (!inputs.env) {
+ return err(new MissingRequiredInputError("env", "FxCore"));
+ }
+ const teamsappYamlPath = pathUtils.getYmlFilePath(inputs.projectPath!, inputs.env);
+ const yamlProjectModel = await metadataUtil.parse(teamsappYamlPath, inputs.env);
+ if (yamlProjectModel.isErr()) {
+ return err(yamlProjectModel.error);
+ }
+ const projectModel = yamlProjectModel.value;
+
+ let teamsAppId;
+ let botId;
+ let m365TitleId;
+ let teamsAppIdKeyName = "";
+ let botIdKeyName = "";
+ let m365TitleIdKeyName = "";
+ for (const action of projectModel.provision?.driverDefs ?? []) {
+ if (action.uses === "teamsApp/create") {
+ teamsAppIdKeyName = action.writeToEnvironmentFile?.teamsAppId || "TEAMS_APP_ID";
+ teamsAppId = process.env[teamsAppIdKeyName];
+ } else if (action.uses === "botFramework/create") {
+ botIdKeyName = action.writeToEnvironmentFile?.botId || "BOT_ID";
+ botId = process.env[botIdKeyName];
+ } else if (action.uses === "teamsApp/extendToM365") {
+ m365TitleIdKeyName = action.writeToEnvironmentFile?.titleId || "M365_TITLE_ID";
+ m365TitleId = process.env[m365TitleIdKeyName];
+ }
+ }
+
+ const uninstallOptions = inputs[QuestionNames.UninstallOptions as string];
+ const m356AppOption = uninstallOptions?.includes(QuestionNames.UninstallOptionM365);
+ const tdpOption = uninstallOptions?.includes(QuestionNames.UninstallOptionTDP);
+ const botOption = uninstallOptions?.includes(QuestionNames.UninstallOptionBot);
+
+ if ((teamsAppId || m365TitleId) && m356AppOption) {
+ const res = await this.uninstallM365App(m365TitleId, teamsAppId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ this.resetEnvVar(teamsAppIdKeyName, ctx);
+ this.resetEnvVar(m365TitleIdKeyName, ctx);
+ }
+ if (botId && botOption) {
+ const res = await this.uninstallBotFrameworRegistration(botId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ this.resetEnvVar(botIdKeyName, ctx);
+ }
+ // App registraion should be the last to remove, because we might need to query some metadata from TDP.
+ if (teamsAppId && tdpOption) {
+ const res = await this.uninstallAppRegistration(teamsAppId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ this.resetEnvVar(teamsAppIdKeyName, ctx);
+ }
+ return ok(undefined);
+ }
+ resetEnvVar(key: string, ctx?: CoreHookContext, skipIfNotExist = true, resetValue = ""): void {
+ if (!ctx) {
+ return;
+ }
+ if (!ctx.envVars) {
+ ctx.envVars = {};
+ }
+ if (skipIfNotExist && !ctx.envVars[key]) {
+ return;
+ }
+ ctx.envVars[key] = resetValue;
+ return;
+ }
+ /**
+ * uninstall provisioned resources by title ID. Titlle mode only uninstalls M365 app.
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallByTitleId", reset: true }),
+ ErrorHandlerMW,
+ ])
+ async uninstallByTitleId(inputs: UninstallInputs): Promise> {
+ const titleId = inputs[QuestionNames.TitleId as string] as string;
+ if (!titleId) {
+ return err(new MissingRequiredInputError("title-id", "FxCore"));
+ }
+ const res = await this.uninstallM365App(titleId);
+ if (res.isErr()) {
+ return err(res.error);
+ }
+ return ok(undefined);
+ }
+
+ /**
+ * uninstall sideloaded appps in M365
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallM365App", reset: true }),
+ ErrorHandlerMW,
+ ])
+ async uninstallM365App(
+ titleId?: string,
+ manifestId?: string
+ ): Promise> {
+ if (titleId === undefined && manifestId === undefined) {
+ return err(new MissingRequiredInputError("title id or manifest id", "FxCore"));
+ }
+ const sideloadingServiceEndpoint =
+ process.env.SIDELOADING_SERVICE_ENDPOINT ?? MosServiceEndpoint;
+ const sideloadingServiceScope = process.env.SIDELOADING_SERVICE_SCOPE ?? MosServiceScope;
+ const sideloadingTokenRes = await TOOLS.tokenProvider.m365TokenProvider.getAccessToken({
+ scopes: [sideloadingServiceScope],
+ });
+ if (sideloadingTokenRes.isErr()) {
+ return err(sideloadingTokenRes.error);
+ }
+ const packageService = new PackageService(sideloadingServiceEndpoint, TOOLS.logProvider);
+ if (titleId === undefined) {
+ try {
+ titleId = await packageService.retrieveTitleId(sideloadingTokenRes.value, manifestId ?? "");
+ } catch (err: any) {
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.failed.titleId"),
+ false
+ );
+ throw assembleError(err);
+ }
+ }
+ const confirmRes = await TOOLS.ui.confirm?.({
+ name: "uninstallM365App",
+ title: getLocalizedString("core.uninstall.confirm.m365App", titleId),
+ default: true,
+ });
+ if (confirmRes?.isOk() && confirmRes.value.result === true) {
+ await packageService.unacquire(sideloadingTokenRes.value, titleId);
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.success.m365App", titleId),
+ false
+ );
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.success.delayWarning"),
+ false
+ );
+ } else {
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.confirm.cancel.m365App"),
+ false
+ );
+ return err(new UserCancelError("Uninstall M365 App"));
+ }
+ return ok(undefined);
+ }
+
+ /**
+ * uninstall sideloaded apps in Teams Developer Portal
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallAppRegistration", reset: true }),
+ ErrorHandlerMW,
+ ])
+ async uninstallAppRegistration(manifestId: string): Promise> {
+ const appStudioTokenRes = await TOOLS.tokenProvider.m365TokenProvider.getAccessToken({
+ scopes: AppStudioScopes,
+ });
+ if (appStudioTokenRes.isErr()) {
+ return err(appStudioTokenRes.error);
+ }
+ const confirmRes = await TOOLS.ui.confirm?.({
+ name: "uninstallAppRegistration",
+ title: getLocalizedString("core.uninstall.confirm.tdp", manifestId),
+ default: true,
+ });
+ if (confirmRes?.isOk() && confirmRes.value.result === true) {
+ const token = appStudioTokenRes.value;
+ await teamsDevPortalClient.deleteApp(token, manifestId);
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.success.tdp", manifestId),
+ false
+ );
+ return ok(undefined);
+ } else {
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.confirm.cancel.tdp"),
+ false
+ );
+ return err(new UserCancelError("Uninstall App Registration"));
+ }
+ }
+
+ /**
+ * uninstall bots created in dev.botframework.com
+ */
+ @hooks([
+ ErrorContextMW({ component: "FxCore", stage: "uninstallBotFrameworRegistration", reset: true }),
+ ErrorHandlerMW,
+ ])
+ async uninstallBotFrameworRegistration(
+ botId?: string,
+ manifestId?: string
+ ): Promise> {
+ if (!botId && !manifestId) {
+ return err(new MissingRequiredInputError("bot id or manifest id", "FxCore"));
+ }
+ const appStudioTokenRes = await TOOLS.tokenProvider.m365TokenProvider.getAccessToken({
+ scopes: AppStudioScopes,
+ });
+ if (appStudioTokenRes.isErr()) {
+ return err(appStudioTokenRes.error);
+ }
+ const token = appStudioTokenRes.value;
+ if (!botId) {
+ const botIdRes = await teamsDevPortalClient.getBotId(token, manifestId!);
+ if (!botIdRes) {
+ const msg = getLocalizedString("core.uninstall.botNotFound", manifestId!);
+ return err(new UserError("FxCore", "Uninstall", msg, msg));
+ }
+ botId = botIdRes;
+ }
+ const confirmRes = await TOOLS.ui.confirm?.({
+ name: "uninstallBotFrameworRegistration",
+ title: getLocalizedString("core.uninstall.confirm.bot", botId),
+ default: true,
+ });
+ if (confirmRes?.isOk() && confirmRes.value.result === true) {
+ await teamsDevPortalClient.deleteBot(token, botId);
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.success.bot", botId),
+ false
+ );
+ } else {
+ await TOOLS.ui.showMessage(
+ "info",
+ getLocalizedString("core.uninstall.confirm.cancel.bot"),
+ false
+ );
+ return err(new UserCancelError("Uninstall Bot Framework Registration"));
+ }
+ return ok(undefined);
+ }
+
/**
* lifecycle commands: deploy
*/
@@ -1060,11 +1388,11 @@ export class FxCore {
} else if (version.source === VersionSource.projectSettings) {
const isValid = await checkActiveResourcePlugins(projectPath);
if (!isValid) {
- return err(new InvalidProjectError());
+ return err(new InvalidProjectError(projectPath));
}
}
if (version.source === VersionSource.unknown) {
- return err(new InvalidProjectError());
+ return err(new InvalidProjectError(projectPath));
}
return this.innerMigrationV3(inputs);
}
@@ -1084,14 +1412,14 @@ export class FxCore {
if (isValidProjectV3(projectPath) || isValidProjectV2(projectPath)) {
const versionInfo = await getProjectVersionFromPath(projectPath);
if (!versionInfo.version) {
- return err(new InvalidProjectError());
+ return err(new InvalidProjectError(projectPath));
}
const trackingId = await getTrackingIdFromPath(projectPath);
const isSupport = getVersionState(versionInfo);
// if the project is upgradeable, check whether the project is valid and invalid project should not show upgrade option.
if (isSupport === VersionState.upgradeable) {
if (!(await checkActiveResourcePlugins(projectPath))) {
- return err(new InvalidProjectError());
+ return err(new InvalidProjectError(projectPath));
}
}
return ok({
@@ -1101,7 +1429,7 @@ export class FxCore {
versionSource: VersionSource[versionInfo.source],
});
} else {
- return err(new InvalidProjectError());
+ return err(new InvalidProjectError(projectPath));
}
}
@@ -1245,7 +1573,7 @@ export class FxCore {
const newOperations = inputs[QuestionNames.ApiOperation] as string[];
const url = inputs[QuestionNames.ApiSpecLocation];
const manifestPath = inputs[QuestionNames.ManifestPath];
- const isPlugin = inputs[QuestionNames.Capabilities] === copilotPluginApiSpecOptionId;
+ const isPlugin = inputs[QuestionNames.Capabilities] === apiPluginApiSpecOptionId;
const context = createContext();
// Get API spec file path from manifest
diff --git a/packages/fx-core/src/core/middleware/concurrentLocker.ts b/packages/fx-core/src/core/middleware/concurrentLocker.ts
index a11a514545..c9acfb3f67 100644
--- a/packages/fx-core/src/core/middleware/concurrentLocker.ts
+++ b/packages/fx-core/src/core/middleware/concurrentLocker.ts
@@ -51,7 +51,7 @@ export const ConcurrentLockerMW: Middleware = async (ctx: HookContext, next: Nex
} else if (isValidProjectV2(inputs.projectPath)) {
configFolder = path.join(inputs.projectPath, `.${ConfigFolderName}`);
} else {
- ctx.result = err(new InvalidProjectError());
+ ctx.result = err(new InvalidProjectError(inputs.projectPath));
return;
}
diff --git a/packages/fx-core/src/error/common.ts b/packages/fx-core/src/error/common.ts
index 30af3efc60..a1185e3d23 100644
--- a/packages/fx-core/src/error/common.ts
+++ b/packages/fx-core/src/error/common.ts
@@ -12,6 +12,8 @@ import { camelCase } from "lodash";
import { getDefaultString, getLocalizedString } from "../common/localizeUtils";
import { globalVars } from "../common/globalVars";
import { ErrorCategory } from "./types";
+import path from "path";
+import { MetadataV3 } from "../common/versionMetadata";
export class FileNotFoundError extends UserError {
constructor(source: string, filePath: string, helpLink?: string) {
@@ -32,12 +34,25 @@ export class MissingEnvironmentVariablesError extends UserError {
constructor(source: string, variableNames: string, filePath?: string, helpLink?: string) {
const templateFilePath = filePath || globalVars.ymlFilePath || "";
const envFilePath = globalVars.envFilePath || "";
+ const secretEnvFilePath = globalVars.envFilePath ? `${globalVars.envFilePath}.user` : "";
const key = "error.common.MissingEnvironmentVariablesError";
const errorOptions: UserErrorOptions = {
source: camelCase(source),
name: "MissingEnvironmentVariablesError",
- message: getDefaultString(key, variableNames, templateFilePath, envFilePath),
- displayMessage: getLocalizedString(key, variableNames, templateFilePath, envFilePath),
+ message: getDefaultString(
+ key,
+ variableNames,
+ templateFilePath,
+ envFilePath,
+ secretEnvFilePath
+ ),
+ displayMessage: getLocalizedString(
+ key,
+ variableNames,
+ templateFilePath,
+ envFilePath,
+ secretEnvFilePath
+ ),
helpLink: helpLink || "https://aka.ms/teamsfx-v5.0-guide#environments",
categories: [ErrorCategory.Internal],
};
@@ -66,10 +81,15 @@ export class InvalidActionInputError extends UserError {
}
export class InvalidProjectError extends UserError {
- constructor() {
+ constructor(projectPath: string) {
+ const ymlFilePath = path.join(projectPath, MetadataV3.configFile);
+ const localYmlPath = path.join(projectPath, MetadataV3.localConfigFile);
super({
message: getDefaultString("error.common.InvalidProjectError"),
- displayMessage: getLocalizedString("error.common.InvalidProjectError"),
+ displayMessage: getLocalizedString(
+ "error.common.InvalidProjectError.display",
+ `'${ymlFilePath}' or '${localYmlPath}'`
+ ),
source: "coordinator",
categories: [ErrorCategory.Internal],
});
diff --git a/packages/fx-core/src/index.ts b/packages/fx-core/src/index.ts
index 3eb5f4e21b..7c0006f810 100644
--- a/packages/fx-core/src/index.ts
+++ b/packages/fx-core/src/index.ts
@@ -25,7 +25,12 @@ export {
getAllowedAppMaps,
} from "./common/constants";
export { Correlator } from "./common/correlator";
-export { FeatureFlags, featureFlagManager, isFeatureFlagEnabled } from "./common/featureFlags";
+export {
+ FeatureFlags,
+ featureFlagManager,
+ isFeatureFlagEnabled,
+ FeatureFlagName,
+} from "./common/featureFlags";
export { globalStateGet, globalStateUpdate } from "./common/globalState";
export { getDefaultString, getLocalizedString } from "./common/localizeUtils";
export * from "./common/permissionInterface";
@@ -72,7 +77,7 @@ export { getPermissionMap } from "./component/driver/aad/permissions/index";
export { AppDefinition } from "./component/driver/teamsApp/interfaces/appdefinitions/appDefinition";
export { manifestUtils } from "./component/driver/teamsApp/utils/ManifestUtils";
export { pluginManifestUtils } from "./component/driver/teamsApp/utils/PluginManifestUtils";
-export { generateScaffoldingSummary } from "./component/generator/copilotPlugin/helper";
+export { generateScaffoldingSummary } from "./component/generator/apiSpec/helper";
export { HelperMethods } from "./component/generator/officeAddin/helperMethods";
export { DefaultTemplateGenerator } from "./component/generator/templates/templateGenerator";
export { getSampleFileInfo, runWithLimitedConcurrency } from "./component/generator/utils";
@@ -98,3 +103,5 @@ export * from "./error/index";
export * from "./question/constants";
export * from "./question/inputs";
export * from "./question/options";
+export * from "./component/middleware/actionExecutionMW";
+export { TemplateInfo } from "./component/generator/templates/templateInfo";
diff --git a/packages/fx-core/src/question/constants.ts b/packages/fx-core/src/question/constants.ts
index 1c229bf475..f9c9bdbf05 100644
--- a/packages/fx-core/src/question/constants.ts
+++ b/packages/fx-core/src/question/constants.ts
@@ -77,9 +77,19 @@ export enum QuestionNames {
M365Host = "m365-host",
ManifestPath = "manifest-path",
-
+ ManifestId = "manifest-id",
+ TitleId = "title-id",
UserEmail = "email",
+ UninstallMode = "mode",
+ UninstallModeManifestId = "manifest-id",
+ UninstallModeEnv = "env",
+ UninstallModeTitleId = "title-id",
+ UninstallOptions = "options",
+ UninstallOptionM365 = "m365-app",
+ UninstallOptionTDP = "app-registration",
+ UninstallOptionBot = "bot-framework-registration",
+
collaborationAppType = "collaborationType",
DestinationApiSpecFilePath = "destination-api-spec-location",
PluginAvailability = "plugin-availability",
@@ -97,13 +107,14 @@ export enum ProgrammingLanguage {
TS = "typescript",
CSharp = "csharp",
PY = "python",
+ Common = "common",
None = "none",
}
-export const copilotPluginApiSpecOptionId = "copilot-plugin-existing-api";
-export const copilotPluginExistingApiOptionIds = [copilotPluginApiSpecOptionId];
-export const copilotPluginNewApiOptionId = "copilot-plugin-new-api";
-export const copilotPluginOptionIds = [copilotPluginNewApiOptionId, copilotPluginApiSpecOptionId];
+export const apiPluginApiSpecOptionId = "api-plugin-existing-api";
+export const apiPluginExistingApiOptionIds = [apiPluginApiSpecOptionId];
+export const apiPluginNewApiOptionId = "api-plugin-new-api";
+export const apiPluginOptionIds = [apiPluginNewApiOptionId, apiPluginApiSpecOptionId];
export const capabilitiesHavePythonOption = [
"custom-copilot-basic",
"custom-copilot-rag-azureAISearch",
@@ -215,17 +226,6 @@ export class ProjectTypeOptions {
};
}
- static officeXMLAddin(platform?: Platform): OptionItem {
- return {
- id: "office-xml-addin-type",
- label: `${platform === Platform.VSCode ? "$(teamsfx-m365) " : ""}${getLocalizedString(
- "core.createProjectQuestion.officeXMLAddin.mainEntry.title"
- )}`,
- detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.mainEntry.detail"),
- groupName: ProjectTypeOptions.getCreateGroupName(),
- };
- }
-
static officeAddin(platform?: Platform): OptionItem {
return {
id: "office-addin-type",
@@ -240,14 +240,13 @@ export class ProjectTypeOptions {
static officeAddinAllIds(platform?: Platform): string[] {
return [
ProjectTypeOptions.officeAddin(platform).id,
- ProjectTypeOptions.officeXMLAddin(platform).id,
ProjectTypeOptions.outlookAddin(platform).id,
];
}
static copilotPlugin(platform?: Platform): OptionItem {
return {
- id: "copilot-plugin-type",
+ id: "api-plugin-type",
label: `${
platform === Platform.VSCode ? "$(teamsfx-copilot-plugin) " : ""
}${getLocalizedString("core.createProjectQuestion.projectType.copilotPlugin.label")}`,
@@ -567,9 +566,6 @@ export class CapabilityOptions {
const items: OptionItem[] = [];
const isOutlookAddin = projectType === ProjectTypeOptions.outlookAddin().id;
const isOfficeAddin = projectType === ProjectTypeOptions.officeAddin().id;
- const isOfficeXMLAddinForOutlook =
- projectType === ProjectTypeOptions.officeXMLAddin().id &&
- host === OfficeAddinHostOptions.outlook().id;
const pushToItems = (option: any) => {
const capabilityValue = OfficeAddinProjectConfig.json[option];
@@ -580,11 +576,11 @@ export class CapabilityOptions {
});
};
- if (isOutlookAddin || isOfficeAddin || isOfficeXMLAddinForOutlook) {
+ if (isOutlookAddin || isOfficeAddin) {
pushToItems("json-taskpane");
- if (isOutlookAddin || isOfficeXMLAddinForOutlook) {
+ if (isOutlookAddin) {
items.push(CapabilityOptions.outlookAddinImport());
- } else if (isOfficeAddin) {
+ } else {
items.push(CapabilityOptions.officeContentAddin());
items.push(CapabilityOptions.officeAddinImport());
}
@@ -717,7 +713,7 @@ export class CapabilityOptions {
// copilot plugin
static copilotPluginNewApi(): OptionItem {
return {
- id: copilotPluginNewApiOptionId,
+ id: apiPluginNewApiOptionId,
label: getLocalizedString(
"core.createProjectQuestion.capability.copilotPluginNewApiOption.label"
),
@@ -729,7 +725,7 @@ export class CapabilityOptions {
static copilotPluginApiSpec(): OptionItem {
return {
- id: copilotPluginApiSpecOptionId,
+ id: apiPluginApiSpecOptionId,
label: getLocalizedString(
"core.createProjectQuestion.capability.copilotPluginApiSpecOption.label"
),
@@ -819,53 +815,6 @@ export class CapabilityOptions {
}
}
-export class OfficeAddinHostOptions {
- static all(platform?: Platform): OptionItem[] {
- return [
- OfficeAddinHostOptions.outlook(platform),
- OfficeAddinHostOptions.word(),
- OfficeAddinHostOptions.excel(),
- OfficeAddinHostOptions.powerpoint(),
- ];
- }
- static outlook(platform?: Platform): OptionItem {
- return {
- id: "outlook",
- label: `${platform === Platform.VSCode ? "$(mail) " : ""}${getLocalizedString(
- "core.createProjectQuestion.projectType.outlookAddin.label"
- )}`,
- detail: getLocalizedString("core.createProjectQuestion.projectType.outlookAddin.detail"),
- data: "Outlook",
- };
- }
- static word(): OptionItem {
- return {
- id: "word",
- label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.word.title"),
- detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.word.detail"),
- data: "Word",
- };
- }
-
- static excel(): OptionItem {
- return {
- id: "excel",
- label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.title"),
- detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.detail"),
- data: "Excel",
- };
- }
-
- static powerpoint(): OptionItem {
- return {
- id: "powerpoint",
- label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.powerpoint.title"),
- detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.powerpoint.detail"),
- data: "PowerPoint",
- };
- }
-}
-
export class ApiAuthOptions {
static none(): OptionItem {
return {
@@ -876,7 +825,7 @@ export class ApiAuthOptions {
static apiKey(): OptionItem {
return {
id: "api-key",
- label: "API Key",
+ label: "API Key (Bearer Token Auth)",
};
}
@@ -1233,13 +1182,13 @@ export class PluginAvailabilityOptions {
}
static copilotPlugin(): OptionItem {
return {
- id: "copilot-plugin",
+ id: "api-plugin",
label: getLocalizedString("core.pluginAvailability.copilotForM365"),
};
}
static copilotPluginAndAction(): OptionItem {
return {
- id: "copilot-plugin-and-action",
+ id: "api-plugin-and-action",
label: getLocalizedString("core.pluginAvailability.declarativeCopilotAndM365"),
};
}
diff --git a/packages/fx-core/src/question/create.ts b/packages/fx-core/src/question/create.ts
index bc0343d69b..b402e05521 100644
--- a/packages/fx-core/src/question/create.ts
+++ b/packages/fx-core/src/question/create.ts
@@ -39,7 +39,7 @@ import {
needTabAndBotCode,
needTabCode,
} from "../component/driver/teamsApp/utils/utils";
-import { listOperations } from "../component/generator/copilotPlugin/helper";
+import { listOperations } from "../component/generator/apiSpec/helper";
import {
IOfficeAddinHostConfig,
OfficeAddinProjectConfig,
@@ -57,7 +57,6 @@ import {
CustomCopilotRagOptions,
MeArchitectureOptions,
NotificationTriggerOptions,
- OfficeAddinHostOptions,
ProgrammingLanguage,
ProjectTypeOptions,
QuestionNames,
@@ -72,7 +71,6 @@ export function projectTypeQuestion(): SingleSelectQuestion {
ProjectTypeOptions.bot(Platform.CLI),
ProjectTypeOptions.tab(Platform.CLI),
ProjectTypeOptions.me(Platform.CLI),
- ProjectTypeOptions.officeXMLAddin(Platform.CLI),
ProjectTypeOptions.officeAddin(Platform.CLI),
ProjectTypeOptions.outlookAddin(Platform.CLI),
];
@@ -109,15 +107,10 @@ export function projectTypeQuestion(): SingleSelectQuestion {
return [projectType];
}
} else {
- if (inputs.agent === "office") {
- //only for @office agent, officeXMLAddin are supported
- staticOptions.push(ProjectTypeOptions.officeXMLAddin(inputs.platform));
+ if (featureFlagManager.getBooleanValue(FeatureFlags.OfficeAddin)) {
+ staticOptions.push(ProjectTypeOptions.officeAddin(inputs.platform));
} else {
- if (featureFlagManager.getBooleanValue(FeatureFlags.OfficeAddin)) {
- staticOptions.push(ProjectTypeOptions.officeAddin(inputs.platform));
- } else {
- staticOptions.push(ProjectTypeOptions.outlookAddin(inputs.platform));
- }
+ staticOptions.push(ProjectTypeOptions.outlookAddin(inputs.platform));
}
}
@@ -185,28 +178,9 @@ export function capabilityQuestion(): SingleSelectQuestion {
"core.createProjectQuestion.projectType.messageExtension.title"
);
case ProjectTypeOptions.outlookAddin().id:
+ return getLocalizedString("core.createProjectQuestion.projectType.outlookAddin.title");
case ProjectTypeOptions.officeAddin().id:
- case ProjectTypeOptions.officeXMLAddin().id: {
- switch (inputs[QuestionNames.OfficeAddinHost]) {
- case OfficeAddinHostOptions.outlook().id:
- return getLocalizedString(
- "core.createProjectQuestion.projectType.outlookAddin.title"
- );
- case OfficeAddinHostOptions.word().id:
- return getLocalizedString(
- "core.createProjectQuestion.officeXMLAddin.word.create.title"
- );
- case OfficeAddinHostOptions.excel().id:
- return getLocalizedString(
- "core.createProjectQuestion.officeXMLAddin.excel.create.title"
- );
- case OfficeAddinHostOptions.powerpoint().id:
- return getLocalizedString(
- "core.createProjectQuestion.officeXMLAddin.powerpoint.create.title"
- );
- }
return getLocalizedString("core.createProjectQuestion.projectType.officeAddin.title");
- }
case ProjectTypeOptions.copilotPlugin().id:
return getLocalizedString("core.createProjectQuestion.projectType.copilotPlugin.title");
case ProjectTypeOptions.customCopilot().id:
@@ -500,15 +474,6 @@ export function SPFxImportFolderQuestion(hasDefaultFunc = false): FolderQuestion
};
}
-export function officeAddinHostingQuestion(): SingleSelectQuestion {
- return {
- name: QuestionNames.OfficeAddinHost,
- title: getLocalizedString("core.createProjectQuestion.officeXMLAddin.create.title"),
- type: "singleSelect",
- staticOptions: OfficeAddinHostOptions.all(),
- };
-}
-
export function officeAddinFrameworkQuestion(): SingleSelectQuestion {
return {
type: "singleSelect",
@@ -531,12 +496,7 @@ export function officeAddinFrameworkQuestion(): SingleSelectQuestion {
export function getAddinFrameworkOptions(inputs: Inputs): OptionItem[] {
const projectType = inputs[QuestionNames.ProjectType];
const capabilities = inputs[QuestionNames.Capabilities];
- const host = inputs[QuestionNames.OfficeAddinHost];
- if (
- projectType === ProjectTypeOptions.outlookAddin().id ||
- (projectType === ProjectTypeOptions.officeXMLAddin().id &&
- host === OfficeAddinHostOptions.outlook().id)
- ) {
+ if (projectType === ProjectTypeOptions.outlookAddin().id) {
return [{ id: "default", label: "Default" }];
} else if (
(projectType === ProjectTypeOptions.officeAddin().id &&
@@ -564,29 +524,17 @@ export function getOfficeAddinFramework(inputs: Inputs): string {
inputs[QuestionNames.OfficeAddinFramework]
) {
return inputs[QuestionNames.OfficeAddinFramework];
- } else if (
- (projectType === ProjectTypeOptions.officeXMLAddin().id &&
- inputs[QuestionNames.OfficeAddinHost] === OfficeAddinHostOptions.outlook().id) ||
- projectType === ProjectTypeOptions.outlookAddin().id
- ) {
+ } else if (projectType === ProjectTypeOptions.outlookAddin().id) {
return "default_old";
} else {
return "default";
}
}
-export function getOfficeAddinTemplateConfig(
- projectType: string,
- addinHost?: string
-): IOfficeAddinHostConfig {
- if (
- projectType === ProjectTypeOptions.officeXMLAddin().id &&
- addinHost &&
- addinHost !== OfficeAddinHostOptions.outlook().id
- ) {
- return OfficeAddinProjectConfig[addinHost];
- }
+
+export function getOfficeAddinTemplateConfig(): IOfficeAddinHostConfig {
return OfficeAddinProjectConfig["json"];
}
+
export function getLanguageOptions(inputs: Inputs): OptionItem[] {
const runtime = getRuntime(inputs);
// dotnet runtime only supports C#
@@ -594,7 +542,6 @@ export function getLanguageOptions(inputs: Inputs): OptionItem[] {
return [{ id: ProgrammingLanguage.CSharp, label: "C#" }];
}
const capabilities = inputs[QuestionNames.Capabilities] as string;
- const host = inputs[QuestionNames.OfficeAddinHost] as string;
// office addin supports language defined in officeAddinJsonData
const projectType = inputs[QuestionNames.ProjectType];
@@ -602,19 +549,14 @@ export function getLanguageOptions(inputs: Inputs): OptionItem[] {
if (capabilities.endsWith("-manifest")) {
return [{ id: ProgrammingLanguage.JS, label: "JavaScript" }];
}
- if (
- projectType === ProjectTypeOptions.outlookAddin().id ||
- (projectType === ProjectTypeOptions.officeXMLAddin().id &&
- host === OfficeAddinHostOptions.outlook().id)
- ) {
+ if (projectType === ProjectTypeOptions.outlookAddin().id) {
return [{ id: ProgrammingLanguage.TS, label: "TypeScript" }];
}
- const officeXMLAddinLangConfig = getOfficeAddinTemplateConfig(projectType, host)[capabilities]
- .framework["default"];
+ const officeAddinLangConfig = getOfficeAddinTemplateConfig()[capabilities].framework["default"];
const officeXMLAddinLangOptions = [];
- if (!!officeXMLAddinLangConfig.typescript)
+ if (!!officeAddinLangConfig.typescript)
officeXMLAddinLangOptions.push({ id: ProgrammingLanguage.TS, label: "TypeScript" });
- if (!!officeXMLAddinLangConfig.javascript)
+ if (!!officeAddinLangConfig.javascript)
officeXMLAddinLangOptions.push({ id: ProgrammingLanguage.JS, label: "JavaScript" });
return officeXMLAddinLangOptions;
}
@@ -1528,11 +1470,6 @@ export function createProjectQuestionNode(): IQTreeNode {
data: projectTypeQuestion(),
cliOptionDisabled: "self",
},
- {
- condition: (inputs: Inputs) =>
- inputs[QuestionNames.ProjectType] === ProjectTypeOptions.officeXMLAddin().id,
- data: officeAddinHostingQuestion(),
- },
capabilitySubTree(),
{
condition: (inputs: Inputs) =>
diff --git a/packages/fx-core/src/question/generator.ts b/packages/fx-core/src/question/generator.ts
index aa89e9719f..52dab57560 100644
--- a/packages/fx-core/src/question/generator.ts
+++ b/packages/fx-core/src/question/generator.ts
@@ -454,6 +454,9 @@ async function batchGenerate() {
await generateCliOptions(questionNodes.addPlugin(), "AddPlugin");
await generateInputs(questionNodes.addPlugin(), "AddPlugin");
+
+ await generateCliOptions(questionNodes.uninstall(), "Uninstall");
+ await generateInputs(questionNodes.uninstall(), "Uninstall");
}
void batchGenerate();
diff --git a/packages/fx-core/src/question/index.ts b/packages/fx-core/src/question/index.ts
index 0d31eb62bb..7765861f18 100644
--- a/packages/fx-core/src/question/index.ts
+++ b/packages/fx-core/src/question/index.ts
@@ -19,6 +19,7 @@ import {
oauthQuestion,
previewWithTeamsAppManifestQuestionNode,
selectTeamsAppManifestQuestionNode,
+ uninstallQuestionNode,
validateTeamsAppQuestionNode,
} from "./other";
export * from "./constants";
@@ -72,6 +73,9 @@ export class QuestionNodes {
addPlugin(): IQTreeNode {
return addPluginQuestionNode();
}
+ uninstall(): IQTreeNode {
+ return uninstallQuestionNode();
+ }
}
export const questionNodes = new QuestionNodes();
diff --git a/packages/fx-core/src/question/inputs/AddPluginInputs.ts b/packages/fx-core/src/question/inputs/AddPluginInputs.ts
index 2454b4376f..3512a56fdd 100644
--- a/packages/fx-core/src/question/inputs/AddPluginInputs.ts
+++ b/packages/fx-core/src/question/inputs/AddPluginInputs.ts
@@ -14,7 +14,7 @@ export interface AddPluginInputs extends Inputs {
/** @description Select Teams manifest.json File */
"manifest-path"?: string;
/** @description Select Plugin Availability */
- "plugin-availability"?: "copilot-plugin" | "action" | "copilot-plugin-and-action";
+ "plugin-availability"?: "api-plugin" | "action" | "api-plugin-and-action";
/** @description OpenAPI Description Document */
"openapi-spec-location"?: string;
/** @description Select Operation(s) Copilot Can Interact with */
diff --git a/packages/fx-core/src/question/inputs/CreateProjectInputs.ts b/packages/fx-core/src/question/inputs/CreateProjectInputs.ts
index 8f8430a72b..daf9884830 100644
--- a/packages/fx-core/src/question/inputs/CreateProjectInputs.ts
+++ b/packages/fx-core/src/question/inputs/CreateProjectInputs.ts
@@ -14,15 +14,7 @@ export interface CreateProjectInputs extends Inputs {
/** @description Teams Toolkit: select runtime for your app */
runtime?: "node" | "dotnet";
/** @description New Project */
- "project-type"?:
- | "bot-type"
- | "tab-type"
- | "me-type"
- | "office-xml-addin-type"
- | "office-addin-type"
- | "outlook-addin-type";
- /** @description Select to Create an Outlook, Word, Excel, or PowerPoint Add-in */
- "addin-host"?: "outlook" | "word" | "excel" | "powerpoint";
+ "project-type"?: "bot-type" | "tab-type" | "me-type" | "office-addin-type" | "outlook-addin-type";
/** @description Capabilities */
capabilities?:
| "empty"
@@ -38,8 +30,8 @@ export interface CreateProjectInputs extends Inputs {
| "collect-form-message-extension"
| "search-message-extension"
| "link-unfurling"
- | "copilot-plugin-new-api"
- | "copilot-plugin-existing-api"
+ | "api-plugin-new-api"
+ | "api-plugin-existing-api"
| "custom-copilot-basic"
| "custom-copilot-rag"
| "custom-copilot-agent"
@@ -49,21 +41,7 @@ export interface CreateProjectInputs extends Inputs {
| "basic-declarative-copilot"
| "declarative-copilot-with-plugin-from-scratch"
| "json-taskpane"
- | "office-content-addin"
- | "word-taskpane"
- | "word-sso"
- | "word-react"
- | "word-manifest"
- | "excel-taskpane"
- | "excel-sso"
- | "excel-react"
- | "excel-custom-functions-shared"
- | "excel-custom-functions-js"
- | "excel-manifest"
- | "powerpoint-taskpane"
- | "powerpoint-sso"
- | "powerpoint-react"
- | "powerpoint-manifest";
+ | "office-content-addin";
/** @description Select triggers */
"bot-host-type-trigger"?:
| "http-restify"
diff --git a/packages/fx-core/src/question/inputs/UninstallInputs.ts b/packages/fx-core/src/question/inputs/UninstallInputs.ts
new file mode 100644
index 0000000000..f2e92fb2d3
--- /dev/null
+++ b/packages/fx-core/src/question/inputs/UninstallInputs.ts
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/****************************************************************************************
+ * NOTICE: AUTO-GENERATED *
+ ****************************************************************************************
+ * This file is automatically generated by script "./src/question/generator.ts". *
+ * Please don't manually change its contents, as any modifications will be overwritten! *
+ ***************************************************************************************/
+
+import { Inputs } from "@microsoft/teamsfx-api";
+
+export interface UninstallInputs extends Inputs {
+ /** @description Choose a way to clean up resources */
+ mode?: "manifest-id" | "env" | "title-id";
+ /** @description Manifest ID */
+ "manifest-id"?: string;
+ /** @description Environment */
+ env?: string;
+ /** @description Project path */
+ projectPath?: string;
+ /** @description Choose resources to uninstall */
+ options?: "m365-app" | "app-registration" | "bot-framework-registration"[];
+ /** @description Title ID */
+ "title-id"?: string;
+}
diff --git a/packages/fx-core/src/question/inputs/index.ts b/packages/fx-core/src/question/inputs/index.ts
index f62876795d..767423e260 100644
--- a/packages/fx-core/src/question/inputs/index.ts
+++ b/packages/fx-core/src/question/inputs/index.ts
@@ -11,3 +11,4 @@ export * from "./PermissionGrantInputs";
export * from "./PermissionListInputs";
export * from "./DeployAadManifestInputs";
export * from "./AddPluginInputs";
+export * from "./UninstallInputs";
diff --git a/packages/fx-core/src/question/options/AddPluginOptions.ts b/packages/fx-core/src/question/options/AddPluginOptions.ts
index 72c24e8922..d8125f1b29 100644
--- a/packages/fx-core/src/question/options/AddPluginOptions.ts
+++ b/packages/fx-core/src/question/options/AddPluginOptions.ts
@@ -26,7 +26,7 @@ export const AddPluginOptions: CLICommandOption[] = [
type: "string",
description: "Select plugin availability.",
required: true,
- choices: ["copilot-plugin", "action", "copilot-plugin-and-action"],
+ choices: ["api-plugin", "action", "api-plugin-and-action"],
},
{
name: "openapi-spec-location",
diff --git a/packages/fx-core/src/question/options/CreateProjectOptions.ts b/packages/fx-core/src/question/options/CreateProjectOptions.ts
index 4f55d9ab47..d70a94d12a 100644
--- a/packages/fx-core/src/question/options/CreateProjectOptions.ts
+++ b/packages/fx-core/src/question/options/CreateProjectOptions.ts
@@ -19,12 +19,6 @@ export const CreateProjectOptions: CLICommandOption[] = [
hidden: true,
choices: ["node", "dotnet"],
},
- {
- name: "addin-host",
- type: "string",
- description: "Select to Create an Outlook, Word, Excel, or PowerPoint Add-in",
- choices: ["outlook", "word", "excel", "powerpoint"],
- },
{
name: "capability",
questionName: "capabilities",
@@ -46,8 +40,8 @@ export const CreateProjectOptions: CLICommandOption[] = [
"collect-form-message-extension",
"search-message-extension",
"link-unfurling",
- "copilot-plugin-new-api",
- "copilot-plugin-existing-api",
+ "api-plugin-new-api",
+ "api-plugin-existing-api",
"custom-copilot-basic",
"custom-copilot-rag",
"custom-copilot-agent",
@@ -58,20 +52,6 @@ export const CreateProjectOptions: CLICommandOption[] = [
"declarative-copilot-with-plugin-from-scratch",
"json-taskpane",
"office-content-addin",
- "word-taskpane",
- "word-sso",
- "word-react",
- "word-manifest",
- "excel-taskpane",
- "excel-sso",
- "excel-react",
- "excel-custom-functions-shared",
- "excel-custom-functions-js",
- "excel-manifest",
- "powerpoint-taskpane",
- "powerpoint-sso",
- "powerpoint-react",
- "powerpoint-manifest",
],
choiceListCommand: "teamsapp list templates",
},
diff --git a/packages/fx-core/src/question/options/UninstallOptions.ts b/packages/fx-core/src/question/options/UninstallOptions.ts
new file mode 100644
index 0000000000..5b5c0fc167
--- /dev/null
+++ b/packages/fx-core/src/question/options/UninstallOptions.ts
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/****************************************************************************************
+ * NOTICE: AUTO-GENERATED *
+ ****************************************************************************************
+ * This file is automatically generated by script "./src/question/generator.ts". *
+ * Please don't manually change its contents, as any modifications will be overwritten! *
+ ***************************************************************************************/
+
+import { CLICommandOption, CLICommandArgument } from "@microsoft/teamsfx-api";
+
+export const UninstallOptions: CLICommandOption[] = [
+ {
+ name: "mode",
+ type: "string",
+ description: "Choose a way to clean up resources",
+ required: true,
+ default: "manifest-id",
+ choices: ["manifest-id", "env", "title-id"],
+ },
+ {
+ name: "manifest-id",
+ type: "string",
+ description: "Manifest ID",
+ },
+ {
+ name: "env",
+ type: "string",
+ description: "Environment",
+ },
+ {
+ name: "projectPath",
+ type: "string",
+ description: "Project Path for uninstall",
+ default: "./",
+ },
+ {
+ name: "options",
+ type: "array",
+ description: "Choose resources to uninstall",
+ choices: ["m365-app", "app-registration", "bot-framework-registration"],
+ },
+ {
+ name: "title-id",
+ type: "string",
+ description: "Title ID",
+ },
+];
+export const UninstallArguments: CLICommandArgument[] = [];
diff --git a/packages/fx-core/src/question/options/index.ts b/packages/fx-core/src/question/options/index.ts
index 227db9cf16..07ebb6e24c 100644
--- a/packages/fx-core/src/question/options/index.ts
+++ b/packages/fx-core/src/question/options/index.ts
@@ -11,3 +11,4 @@ export * from "./PermissionGrantOptions";
export * from "./PermissionListOptions";
export * from "./DeployAadManifestOptions";
export * from "./AddPluginOptions";
+export * from "./UninstallOptions";
diff --git a/packages/fx-core/src/question/other.ts b/packages/fx-core/src/question/other.ts
index a8802efbe5..15ee3ce0fa 100644
--- a/packages/fx-core/src/question/other.ts
+++ b/packages/fx-core/src/question/other.ts
@@ -14,6 +14,7 @@ import {
SingleFileQuestion,
SingleSelectQuestion,
TextInputQuestion,
+ FolderQuestion,
} from "@microsoft/teamsfx-api";
import fs from "fs-extra";
import * as path from "path";
@@ -42,6 +43,7 @@ import {
apiOperationQuestion,
apiSpecLocationQuestion,
} from "./create";
+import { UninstallInputs } from "./inputs";
export function listCollaboratorQuestionNode(): IQTreeNode {
const selectTeamsAppNode = selectTeamsAppManifestQuestionNode();
@@ -874,6 +876,129 @@ export function oauthQuestion(): IQTreeNode {
};
}
+export function uninstallQuestionNode(): IQTreeNode {
+ return {
+ data: {
+ type: "group",
+ },
+ children: [
+ {
+ data: uninstallModeQuestion(),
+ condition: () => {
+ return true;
+ },
+ children: [
+ {
+ data: {
+ type: "text",
+ name: QuestionNames.ManifestId,
+ title: getLocalizedString("core.uninstallQuestion.manifestId"),
+ },
+ condition: (input: UninstallInputs) => {
+ return input[QuestionNames.UninstallMode] === QuestionNames.UninstallModeManifestId;
+ },
+ },
+ {
+ data: {
+ type: "text",
+ name: QuestionNames.Env,
+ title: getLocalizedString("core.uninstallQuestion.env"),
+ },
+ condition: (input: UninstallInputs) => {
+ return input[QuestionNames.UninstallMode] === QuestionNames.UninstallModeEnv;
+ },
+ children: [
+ {
+ data: uninstallProjectPathQuestion(),
+ condition: () => {
+ return true;
+ },
+ },
+ ],
+ },
+ {
+ data: uninstallOptionQuestion(),
+ condition: (input: UninstallInputs) => {
+ return (
+ input[QuestionNames.UninstallMode] === QuestionNames.UninstallModeManifestId ||
+ input[QuestionNames.UninstallMode] === QuestionNames.UninstallModeEnv
+ );
+ },
+ },
+ {
+ data: {
+ type: "text",
+ name: QuestionNames.TitleId,
+ title: getLocalizedString("core.uninstallQuestion.titleId"),
+ },
+ condition: (input: UninstallInputs) => {
+ return input[QuestionNames.UninstallMode] === QuestionNames.UninstallModeTitleId;
+ },
+ },
+ ],
+ },
+ ],
+ };
+}
+
+function uninstallModeQuestion(): SingleSelectQuestion {
+ return {
+ name: QuestionNames.UninstallMode,
+ title: getLocalizedString("core.uninstallQuestion.chooseMode"),
+ type: "singleSelect",
+ staticOptions: [
+ {
+ id: QuestionNames.UninstallModeManifestId,
+ label: getLocalizedString("core.uninstallQuestion.manifestIdMode"),
+ detail: getLocalizedString("core.uninstallQuestion.manifestIdMode.detail"),
+ },
+ {
+ id: QuestionNames.UninstallModeEnv,
+ label: getLocalizedString("core.uninstallQuestion.envMode"),
+ detail: getLocalizedString("core.uninstallQuestion.envMode.detail"),
+ },
+ {
+ id: QuestionNames.UninstallModeTitleId,
+ label: getLocalizedString("core.uninstallQuestion.titleIdMode"),
+ detail: getLocalizedString("core.uninstallQuestion.titleIdMode.detail"),
+ },
+ ],
+ default: QuestionNames.UninstallModeManifestId,
+ };
+}
+
+function uninstallOptionQuestion(): MultiSelectQuestion {
+ return {
+ name: QuestionNames.UninstallOptions,
+ title: getLocalizedString("core.uninstallQuestion.chooseOption"),
+ type: "multiSelect",
+ staticOptions: [
+ {
+ id: QuestionNames.UninstallOptionM365,
+ label: getLocalizedString("core.uninstallQuestion.m365Option"),
+ },
+ {
+ id: QuestionNames.UninstallOptionTDP,
+ label: getLocalizedString("core.uninstallQuestion.tdpOption"),
+ },
+ {
+ id: QuestionNames.UninstallOptionBot,
+ label: getLocalizedString("core.uninstallQuestion.botOption"),
+ },
+ ],
+ };
+}
+function uninstallProjectPathQuestion(): FolderQuestion {
+ return {
+ type: "folder",
+ name: QuestionNames.ProjectPath,
+ title: getLocalizedString("core.uninstallQuestion.projectPath"),
+ cliDescription: "Project Path for uninstall",
+ placeholder: "./",
+ default: "./",
+ };
+}
+
function oauthClientIdQuestion(): TextInputQuestion {
return {
type: "text",
diff --git a/packages/fx-core/tests/client/tdpClient.test.ts b/packages/fx-core/tests/client/tdpClient.test.ts
index a94edc4d6c..e75217b24a 100644
--- a/packages/fx-core/tests/client/tdpClient.test.ts
+++ b/packages/fx-core/tests/client/tdpClient.test.ts
@@ -1940,4 +1940,53 @@ describe("TeamsDevPortalClient Test", () => {
chai.assert.isUndefined(res);
});
});
+ describe("getBotId", () => {
+ afterEach(() => {
+ sandbox.restore();
+ });
+ it("happy", async () => {
+ sandbox.stub(teamsDevPortalClient, "getApp").resolves({
+ bots: [
+ {
+ botId: "mocked-bot-id",
+ needsChannelSelector: false,
+ isNotificationOnly: false,
+ supportsFiles: false,
+ supportsCalling: false,
+ supportsVideo: false,
+ scopes: [],
+ teamCommands: [],
+ personalCommands: [],
+ groupChatCommands: [],
+ },
+ ],
+ });
+ try {
+ const res = await teamsDevPortalClient.getBotId("token", "anything");
+ chai.assert.equal(res, "mocked-bot-id");
+ } catch (e) {
+ chai.assert.fail(Messages.ShouldNotReachHere);
+ }
+ });
+ it("empty bots", async () => {
+ sandbox.stub(teamsDevPortalClient, "getApp").resolves({
+ bots: [],
+ });
+ try {
+ const res = await teamsDevPortalClient.getBotId("token", "anything");
+ chai.assert.isUndefined(res);
+ } catch (e) {
+ chai.assert.fail(Messages.ShouldNotReachHere);
+ }
+ });
+ it("no bots", async () => {
+ sandbox.stub(teamsDevPortalClient, "getApp").resolves({});
+ try {
+ const res = await teamsDevPortalClient.getBotId("token", "anything");
+ chai.assert.isUndefined(res);
+ } catch (e) {
+ chai.assert.fail(Messages.ShouldNotReachHere);
+ }
+ });
+ });
});
diff --git a/packages/fx-core/tests/common/error/deployError.test.ts b/packages/fx-core/tests/common/error/deployError.test.ts
index faeabd0533..ce700d2606 100644
--- a/packages/fx-core/tests/common/error/deployError.test.ts
+++ b/packages/fx-core/tests/common/error/deployError.test.ts
@@ -20,10 +20,10 @@ describe("DeployEmptyFolderError", () => {
expect(error).to.be.instanceOf(UserError);
expect(error.source).to.equal("azureDeploy");
expect(error.message).to.equal(
- `Unable to locate any files in the distribution folder: '${folderPath}'. Please ensure that the folder is not empty and that all necessary files have been included.`
+ `Unable to locate any files in the distribution folder: '${folderPath}'. Make sure the folder includes all necessary files.`
);
expect(error.displayMessage).to.equal(
- `Unable to locate any files in the distribution folder: '${folderPath}'. Please ensure that the folder is not empty and that all necessary files have been included.`
+ `Unable to locate any files in the distribution folder: '${folderPath}'. Make sure the folder includes all necessary files.`
);
});
});
@@ -34,10 +34,10 @@ describe("CheckDeploymentStatusTimeoutError", () => {
expect(error).to.be.instanceOf(UserError);
expect(error.source).to.equal("azureDeploy");
expect(error.message).to.equal(
- "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, please review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred."
+ "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred."
);
expect(error.displayMessage).to.equal(
- "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, please review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred."
+ "Unable to check deployment status because the process timed out. Check your internet connection and try again. If the issue persists, review the deployment logs (Deployment -> Deployment center -> Logs) in Azure portal to identify any issues that may have occurred."
);
});
});
@@ -101,7 +101,7 @@ describe("CacheFileInUse", () => {
expect(error).to.be.instanceOf(UserError);
expect(error.source).to.equal("azureDeploy");
expect(error.message).to.equal(
- `Failed to clear the distribution zip file in ${path}. The file may be currently in use. Please close any applications using the file and try again.`
+ `Unable to clear the distribution zip file in ${path} as it may be currently in use. Close any apps using the file and try again.`
);
});
});
diff --git a/packages/fx-core/tests/common/featureFlags.test.ts b/packages/fx-core/tests/common/featureFlags.test.ts
index fac28b90fb..9a4bfe4572 100644
--- a/packages/fx-core/tests/common/featureFlags.test.ts
+++ b/packages/fx-core/tests/common/featureFlags.test.ts
@@ -22,6 +22,12 @@ describe("FeatureFlagManager", () => {
const stringRes = featureFlagManager.getStringValue(FeatureFlags.CLIDotNet);
chai.assert.equal(stringRes, "true");
});
+ it("setBooleanValue", async () => {
+ mockedEnvRestore = mockedEnv({ TEAMSFX_CLI_DOTNET: "false" });
+ featureFlagManager.setBooleanValue(FeatureFlags.CLIDotNet, true);
+ const booleanRes = featureFlagManager.getBooleanValue(FeatureFlags.CLIDotNet);
+ chai.assert.isTrue(booleanRes);
+ });
it("getBooleanValue, getStringValue is false", async () => {
mockedEnvRestore = mockedEnv({ TEAMSFX_CLI_DOTNET: "false" });
const booleanRes = featureFlagManager.getBooleanValue(FeatureFlags.CLIDotNet);
@@ -33,4 +39,9 @@ describe("FeatureFlagManager", () => {
const list = featureFlagManager.list();
chai.assert.deepEqual(list, Object.values(FeatureFlags));
});
+ it("listEnabled", async () => {
+ mockedEnvRestore = mockedEnv({ TEAMSFX_CLI_DOTNET: "true", SME_OAUTH: "true" });
+ const list = featureFlagManager.listEnabled();
+ chai.assert.deepEqual(list, ["TEAMSFX_CLI_DOTNET", "SME_OAUTH"]);
+ });
});
diff --git a/packages/fx-core/tests/common/tools.test.ts b/packages/fx-core/tests/common/tools.test.ts
index a59e1474c5..d8a9559c39 100644
--- a/packages/fx-core/tests/common/tools.test.ts
+++ b/packages/fx-core/tests/common/tools.test.ts
@@ -326,6 +326,20 @@ projectId: 00000000-0000-0000-0000-000000000000`;
});
});
+ describe("listDevTunnels using github token", () => {
+ const sandbox = sinon.createSandbox();
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it("should return an error when the API call fails", async () => {
+ const token = "test-token";
+
+ const result = await listDevTunnels(token, true);
+ chai.assert.isTrue(result.isErr());
+ });
+ });
+
describe("isUserCancelError()", () => {
it("should return true if error is UserCancelError", () => {
const error = new Error();
diff --git a/packages/fx-core/tests/common/wrappedAxiosClient.test.ts b/packages/fx-core/tests/common/wrappedAxiosClient.test.ts
index 85fd4fa1d7..563d9092be 100644
--- a/packages/fx-core/tests/common/wrappedAxiosClient.test.ts
+++ b/packages/fx-core/tests/common/wrappedAxiosClient.test.ts
@@ -242,6 +242,27 @@ describe("Wrapped Axios Client Test", () => {
chai.expect(telemetryChecker.calledOnce).to.be.true;
});
+ it("MOS API error response", async () => {
+ const mockedError = {
+ request: {
+ method: "GET",
+ host: "https://titles.prod.mos.microsoft.com",
+ path: "/users/packages",
+ },
+ config: {},
+ response: {
+ status: 400,
+ data: {
+ code: "BadRequest",
+ message: "Invalid request",
+ },
+ },
+ } as any;
+ const telemetryChecker = sinon.spy(mockTools.telemetryReporter, "sendTelemetryErrorEvent");
+ WrappedAxiosClient.onRejected(mockedError);
+ chai.expect(telemetryChecker.calledOnce).to.be.true;
+ });
+
it("Create bot API start telemetry", async () => {
const mockedRequest = {
method: "POST",
diff --git a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts
index 5ea3f141c2..c51bcd422c 100644
--- a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts
+++ b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts
@@ -6,21 +6,15 @@ import fs from "fs-extra";
import { glob } from "glob";
import * as sinon from "sinon";
import { createContext, setTools } from "../../../src/common/globalVars";
-import { MetadataV3 } from "../../../src/common/versionMetadata";
import { coordinator } from "../../../src/component/coordinator";
import { developerPortalScaffoldUtils } from "../../../src/component/developerPortalScaffoldUtils";
import { AppDefinition } from "../../../src/component/driver/teamsApp/interfaces/appdefinitions/appDefinition";
-import { CopilotPluginGenerator } from "../../../src/component/generator/copilotPlugin/generator";
+import { SpecGenerator } from "../../../src/component/generator/apiSpec/generator";
import { Generator } from "../../../src/component/generator/generator";
-import {
- OfficeAddinGenerator,
- OfficeAddinGeneratorNew,
-} from "../../../src/component/generator/officeAddin/generator";
-import { OfficeXMLAddinGenerator } from "../../../src/component/generator/officeXMLAddin/generator";
-import { SPFxGenerator } from "../../../src/component/generator/spfx/spfxGenerator";
+import { OfficeAddinGeneratorNew } from "../../../src/component/generator/officeAddin/generator";
+import { SPFxGeneratorNew } from "../../../src/component/generator/spfx/spfxGenerator";
import { DefaultTemplateGenerator } from "../../../src/component/generator/templates/templateGenerator";
import { TemplateNames } from "../../../src/component/generator/templates/templateNames";
-import { settingsUtil } from "../../../src/component/utils/settingsUtil";
import { FxCore } from "../../../src/core/FxCore";
import { InputValidationError, MissingRequiredInputError } from "../../../src/error/common";
import { CreateSampleProjectInputs } from "../../../src/question";
@@ -30,7 +24,6 @@ import {
CustomCopilotAssistantOptions,
CustomCopilotRagOptions,
MeArchitectureOptions,
- OfficeAddinHostOptions,
ProjectTypeOptions,
QuestionNames,
ScratchOptions,
@@ -38,37 +31,26 @@ import {
import { validationUtils } from "../../../src/ui/validationUtils";
import { MockTools, randomAppName } from "../../core/utils";
import { MockedUserInteraction } from "../../plugins/solution/util";
-import mockedEnv, { RestoreFn } from "mocked-env";
-
-const V3Version = MetadataV3.projectVersion;
-[false].forEach((newGeneratorFlag) => {
- describe(`coordinator create with new generator enabled = ${newGeneratorFlag}`, () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- let generator: sinon.SinonStub;
- setTools(tools);
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: `${newGeneratorFlag}` });
- generator = newGeneratorFlag
- ? sandbox
- .stub(DefaultTemplateGenerator.prototype, "scaffolding")
- .resolves(ok(undefined))
- : sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- });
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
+describe("coordinator create", () => {
+ const sandbox = sinon.createSandbox();
+ const tools = new MockTools();
+ let generator: sinon.SinonStub;
+ setTools(tools);
+ beforeEach(() => {
+ sandbox.stub(fs, "ensureDir").resolves();
+ generator = sandbox
+ .stub(DefaultTemplateGenerator.prototype, "scaffolding")
+ .resolves(ok(undefined));
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+ describe("createSampleProject", () => {
it("create project from sample", async () => {
sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(fs, "pathExists").resolves(false);
const inputs: CreateSampleProjectInputs = {
platform: Platform.CLI,
folder: ".",
@@ -78,13 +60,9 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createSampleProject(inputs);
assert.isTrue(res.isOk());
});
-
it("create project from sample: todo-list-SPFx", async () => {
sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(fs, "pathExists").resolves(false);
sandbox.stub(glob, "glob").resolves();
sandbox.stub(fs, "readFile").resolves("test" as any);
sandbox.stub(fs, "writeFile").resolves("");
@@ -97,13 +75,9 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createSampleProject(inputs);
assert.isTrue(res.isOk());
});
-
it("fail to create project from sample", async () => {
sandbox.stub(Generator, "generateSample").resolves(err(new UserError({})));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(fs, "pathExists").resolves(false);
const inputs: CreateSampleProjectInputs = {
platform: Platform.CLI,
folder: ".",
@@ -116,10 +90,13 @@ const V3Version = MetadataV3.projectVersion;
it("create project from sample rename folder", async () => {
sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
- sandbox.stub(fs, "pathExists").onFirstCall().resolves(true).onSecondCall().resolves(false);
+ .stub(fs, "pathExists")
+ .onFirstCall()
+ .resolves(true)
+ .onSecondCall()
+ .resolves(false)
+ .onThirdCall()
+ .resolves(false);
sandbox
.stub(fs, "readdir")
.onFirstCall()
@@ -138,40 +115,12 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.value.projectPath.endsWith("_1"));
}
});
- it("create project from scratch", async () => {
- sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ it("MissingRequiredInputError missing sample id", async () => {
const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Capabilities]: CapabilityOptions.basicBot().id,
- [QuestionNames.ProgrammingLanguage]: "javascript",
- };
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isOk());
- });
- it("create project from scratch MissingRequiredInputError missing folder", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- ignoreLockByUT: true,
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof MissingRequiredInputError);
- }
- });
- it("create project from scratch MissingRequiredInputError missing App name", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
+ platform: Platform.CLI,
ignoreLockByUT: true,
folder: ".",
+ [QuestionNames.Scratch]: ScratchOptions.no().id,
};
const context = createContext();
const res = await coordinator.create(context, inputs);
@@ -180,27 +129,12 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.error instanceof MissingRequiredInputError);
}
});
- it("create project from scratch MissingRequiredInputError invalid App name", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- ignoreLockByUT: true,
- folder: ".",
- "app-name": "__#$%___",
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof InputValidationError);
- }
- });
- it("create project for new office Addin MissingRequiredInputError missing App name", async () => {
+ });
+
+ describe("create from scratch", async () => {
+ it("MissingRequiredInputError missing folder", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
- ignoreLockByUT: true,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
};
const context = createContext();
const res = await coordinator.create(context, inputs);
@@ -209,29 +143,11 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.error instanceof MissingRequiredInputError);
}
});
- it("create project for new office Addin MissingRequiredInputError invalid App name", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- ignoreLockByUT: true,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- "app-name": "__#$%___",
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof InputValidationError);
- }
- });
- it("create project for new office XML Addin MissingRequiredInputError missing App name", async () => {
+ it("MissingRequiredInputError missing App name", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
ignoreLockByUT: true,
folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
};
const context = createContext();
const res = await coordinator.create(context, inputs);
@@ -240,44 +156,11 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.error instanceof MissingRequiredInputError);
}
});
- it("create project for new office XML Addin InputValidationError invalid App name", async () => {
+ it("MissingRequiredInputError invalid App name", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
ignoreLockByUT: true,
folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.AppName]: "__#$%___",
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof InputValidationError);
- }
- });
- it("create project for new office JSON Addin MissingRequiredInputError missing App name", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- ignoreLockByUT: true,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof MissingRequiredInputError);
- }
- });
- it("create project for new office JSON Addin MissingRequiredInputError invalid App name", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- ignoreLockByUT: true,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
"app-name": "__#$%___",
};
const context = createContext();
@@ -287,26 +170,8 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.error instanceof InputValidationError);
}
});
- it("create project from sample MissingRequiredInputError missing sample id", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- ignoreLockByUT: true,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.no().id,
- };
- const context = createContext();
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr());
- if (res.isErr()) {
- assert.isTrue(res.error instanceof MissingRequiredInputError);
- }
- });
it("fail to create SPFx project", async () => {
- sandbox.stub(SPFxGenerator, "generate").resolves(err(new UserError({})));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(SPFxGeneratorNew.prototype, "run").resolves(err(new UserError({})));
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -317,17 +182,15 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.SPFxFramework]: "none",
[QuestionNames.SPFxWebpartName]: "test",
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isErr());
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isErr());
});
- it("create SPFx project", async () => {
- sandbox.stub(SPFxGenerator, "generate").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ it("ensureTrackingId fails", async () => {
+ sandbox.stub(fs, "pathExists").resolves(true);
+ sandbox.stub(SPFxGeneratorNew.prototype, "run").resolves(ok({}));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(err(new UserError({})));
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -338,75 +201,31 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.SPFxFramework]: "none",
[QuestionNames.SPFxWebpartName]: "test",
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isOk());
- });
-
- it("create project from VS", async () => {
- sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
- const inputs: Inputs = {
- platform: Platform.VS,
- folder: ".",
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Capabilities]: CapabilityOptions.tab().id,
- [QuestionNames.ProgrammingLanguage]: "csharp",
- [QuestionNames.SafeProjectName]: "safeprojectname",
- };
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isOk());
- });
-
- it("create notification bot project from VS", async () => {
- sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
- const inputs: Inputs = {
- platform: Platform.VS,
- folder: ".",
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Capabilities]: CapabilityOptions.notificationBot().id,
- [QuestionNames.BotTrigger]: "http-functions",
- [QuestionNames.ProgrammingLanguage]: "csharp",
- [QuestionNames.SafeProjectName]: "safeprojectname",
- isIsolated: true,
- };
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isOk());
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isErr());
});
-
- it("create m365 project from scratch", async () => {
- sandbox.stub(Generator, "generateSample").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ it("success", async () => {
+ sandbox.stub(SPFxGeneratorNew.prototype, "run").resolves(ok({}));
+ sandbox.stub(fs, "pathExists").resolves(true);
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
[QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Capabilities]: CapabilityOptions.m365SsoLaunchPage().id,
+ [QuestionNames.Capabilities]: CapabilityOptions.SPFxTab().id,
[QuestionNames.ProgrammingLanguage]: "typescript",
+ [QuestionNames.SPFxSolution]: "new",
+ [QuestionNames.SPFxFramework]: "none",
+ [QuestionNames.SPFxWebpartName]: "test",
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isOk());
- assert.isTrue(inputs.isM365);
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isOk());
});
it("create project for app with tab features from Developer Portal", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox.stub(developerPortalScaffoldUtils, "updateFilesForTdp").resolves(ok(undefined));
const appDefinition: AppDefinition = {
teamsAppId: "mock-id",
@@ -422,7 +241,6 @@ const V3Version = MetadataV3.projectVersion;
},
],
};
-
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -434,20 +252,13 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.ReplaceWebsiteUrl]: ["tab1"],
[QuestionNames.ReplaceContentUrl]: [],
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
-
- assert.isTrue(res2.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.Tab)
- : assert.equal(generator.args[0][2], TemplateNames.Tab);
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isOk());
+ assert.equal(generator.args[0][1].templateName, TemplateNames.Tab);
});
-
it("create project for app with bot feature from Developer Portal with updating files failed", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox
.stub(developerPortalScaffoldUtils, "updateFilesForTdp")
.resolves(err(new UserError("coordinator", "error", "msg", "msg")));
@@ -480,23 +291,16 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.ReplaceBotIds]: ["bot"],
teamsAppFromTdp: appDefinition,
};
- const fxCore = new FxCore(tools);
- const res = await fxCore.createProject(inputs);
-
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
assert.isTrue(res.isErr());
if (res.isErr()) {
assert.equal(res.error.name, "error");
}
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.DefaultBot)
- : assert.equal(generator.args[0][2], TemplateNames.DefaultBot);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.DefaultBot);
});
-
it("create project for app with tab and bot features from Developer Portal", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox.stub(developerPortalScaffoldUtils, "updateFilesForTdp").resolves(ok(undefined));
const appDefinition: AppDefinition = {
teamsAppId: "mock-id",
@@ -539,24 +343,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.ReplaceContentUrl]: [],
[QuestionNames.ReplaceBotIds]: ["bot"],
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
-
- if (res2.isErr()) {
- console.log(res2.error);
- }
- assert.isTrue(res2.isOk());
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isOk());
assert.isTrue(generator.calledOnce);
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.TabAndDefaultBot)
- : assert.equal(generator.args[0][2], TemplateNames.TabAndDefaultBot);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.TabAndDefaultBot);
});
-
it("create project for app with tab and message extension features from Developer Portal", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox.stub(developerPortalScaffoldUtils, "updateFilesForTdp").resolves(ok(undefined));
const appDefinition: AppDefinition = {
teamsAppId: "mock-id",
@@ -580,7 +374,6 @@ const V3Version = MetadataV3.projectVersion;
},
],
};
-
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -593,24 +386,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.ReplaceContentUrl]: [],
[QuestionNames.ReplaceBotIds]: ["messageExtension"],
};
- const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
-
- if (res2.isErr()) {
- console.log(res2.error);
- }
- assert.isTrue(res2.isOk());
+ const context = createContext();
+ const res = await coordinator.create(context, inputs);
+ assert.isTrue(res.isOk());
assert.isTrue(generator.calledOnce);
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.TabAndDefaultBot)
- : assert.equal(generator.args[0][2], TemplateNames.TabAndDefaultBot);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.TabAndDefaultBot);
});
-
it("create project for app with no features from Developer Portal - failed expecting inputs", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox.stub(developerPortalScaffoldUtils, "updateFilesForTdp").resolves(ok(undefined));
const appDefinition: AppDefinition = {
teamsAppId: "mock-id",
@@ -626,15 +409,12 @@ const V3Version = MetadataV3.projectVersion;
teamsAppFromTdp: appDefinition,
};
const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
- assert.isTrue(res2.isErr());
+ const res = await fxCore.createProject(inputs);
+ assert.isTrue(res.isErr());
});
it("create project for app from Developer Portal - not overwrite already set project type and capability", async () => {
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
+ sandbox.stub(coordinator, "ensureTrackingId").resolves(ok("mock-id"));
sandbox.stub(developerPortalScaffoldUtils, "updateFilesForTdp").resolves(ok(undefined));
const appDefinition: AppDefinition = {
teamsAppId: "mock-id",
@@ -653,18 +433,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.Capabilities]: CapabilityOptions.nonSsoTab().id,
};
const fxCore = new FxCore(tools);
- const res2 = await fxCore.createProject(inputs);
-
- assert.isTrue(res2.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.Tab)
- : assert.equal(generator.args[0][2], TemplateNames.Tab);
+ const res = await fxCore.createProject(inputs);
+ assert.isTrue(res.isOk());
+ assert.equal(generator.args[0][1].templateName, TemplateNames.Tab);
});
it("create API ME (no auth) from new api sucessfully", async () => {
const v3ctx = createContext();
v3ctx.userInteraction = new MockedUserInteraction();
-
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -677,9 +453,7 @@ const V3Version = MetadataV3.projectVersion;
};
const res = await coordinator.create(v3ctx, inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.CopilotPluginFromScratch)
- : assert.equal(generator.args[0][2], TemplateNames.CopilotPluginFromScratch);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.CopilotPluginFromScratch);
});
it("create API ME (key auth) from new api sucessfully", async () => {
@@ -698,22 +472,15 @@ const V3Version = MetadataV3.projectVersion;
};
const res = await coordinator.create(v3ctx, inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(
- generator.args[0][1].templateName,
- TemplateNames.CopilotPluginFromScratchApiKey
- )
- : assert.equal(generator.args[0][2], TemplateNames.CopilotPluginFromScratchApiKey);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.CopilotPluginFromScratchApiKey);
});
- it("create API ME from existing api sucessfully", async () => {
+ it("create API ME from existing api successfully", async () => {
const v3ctx = createContext();
v3ctx.userInteraction = new MockedUserInteraction();
-
sandbox
- .stub(CopilotPluginGenerator, "generateMeFromApiSpec")
+ .stub(SpecGenerator.prototype, "run")
.resolves(ok({ warnings: [{ type: "", content: "", data: {} } as any] }));
-
const inputs: Inputs = {
platform: Platform.VSCode,
folder: ".",
@@ -742,9 +509,7 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.Tab)
- : assert.equal(generator.args[0][2], TemplateNames.Tab);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.Tab);
});
it("create sso tab earlier than .Net8", async () => {
@@ -762,9 +527,7 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.SsoTab)
- : assert.equal(generator.args[0][2], TemplateNames.SsoTab);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.SsoTab);
});
it("create non-sso tab from .NET 8", async () => {
@@ -782,9 +545,7 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.TabSSR)
- : assert.equal(generator.args[0][2], TemplateNames.TabSSR);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.TabSSR);
});
it("create sso tab from .NET 8", async () => {
@@ -802,9 +563,7 @@ const V3Version = MetadataV3.projectVersion;
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.SsoTabSSR)
- : assert.equal(generator.args[0][2], TemplateNames.SsoTabSSR);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.SsoTabSSR);
});
it("create custom copilot rag custom api success", async () => {
@@ -822,16 +581,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.LLMService]: "llm-service-openAI",
[QuestionNames.OpenAIKey]: "mockedopenaikey",
};
- sandbox.stub(CopilotPluginGenerator, "generateForCustomCopilotRagCustomApi").resolves(ok({}));
+ sandbox.stub(SpecGenerator.prototype, "post").resolves(ok({}));
sandbox.stub(validationUtils, "validateInputs").resolves(undefined);
const fxCore = new FxCore(tools);
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotRagCustomApi)
- : assert.equal(generator.args[0][2], TemplateNames.CustomCopilotRagCustomApi);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotRagCustomApi);
});
it("create custom copilot rag custom api with azure open ai success", async () => {
@@ -851,16 +608,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.AzureOpenAIEndpoint]: "mockedAzureOpenAIEndpoint",
[QuestionNames.AzureOpenAIDeploymentName]: "mockedAzureOpenAIDeploymentName",
};
- sandbox.stub(CopilotPluginGenerator, "generateForCustomCopilotRagCustomApi").resolves(ok({}));
+ sandbox.stub(SpecGenerator.prototype, "post").resolves(ok({}));
sandbox.stub(validationUtils, "validateInputs").resolves(undefined);
const fxCore = new FxCore(tools);
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotRagCustomApi)
- : assert.equal(generator.args[0][2], TemplateNames.CustomCopilotRagCustomApi);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotRagCustomApi);
});
it("create custom agent api with azure open ai success", async () => {
@@ -879,16 +634,14 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.AzureOpenAIEndpoint]: "mockedAzureOpenAIEndpoint",
[QuestionNames.AzureOpenAIDeploymentName]: "mockedAzureOpenAIDeploymentName",
};
- sandbox.stub(CopilotPluginGenerator, "generateForCustomCopilotRagCustomApi").resolves(ok({}));
+ sandbox.stub(SpecGenerator.prototype, "post").resolves(ok({}));
sandbox.stub(validationUtils, "validateInputs").resolves(undefined);
const fxCore = new FxCore(tools);
const res = await fxCore.createProject(inputs);
assert.isTrue(res.isOk());
- newGeneratorFlag
- ? assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotAssistantNew)
- : assert.equal(generator.args[0][2], TemplateNames.CustomCopilotAssistantNew);
+ assert.equal(generator.args[0][1].templateName, TemplateNames.CustomCopilotAssistantNew);
});
it("create custom copilot rag custom api failed", async () => {
@@ -907,7 +660,7 @@ const V3Version = MetadataV3.projectVersion;
[QuestionNames.OpenAIKey]: "mockedopenaikey",
};
sandbox
- .stub(CopilotPluginGenerator, "generateForCustomCopilotRagCustomApi")
+ .stub(SpecGenerator.prototype, "run")
.resolves(err(new SystemError("test", "test", "test")));
sandbox.stub(validationUtils, "validateInputs").resolves(undefined);
@@ -917,7 +670,7 @@ const V3Version = MetadataV3.projectVersion;
assert.isTrue(res.isErr() && res.error.name === "test");
});
- it("create API Plugin with none auth (feature flag enabled)", async () => {
+ it("create API Plugin with No authentication (feature flag enabled)", async () => {
const v3ctx = createContext();
v3ctx.userInteraction = new MockedUserInteraction();
@@ -970,352 +723,60 @@ const V3Version = MetadataV3.projectVersion;
const res = await coordinator.create(v3ctx, inputs);
assert.isTrue(res.isOk());
});
- });
-});
-
-describe("Office Addin", async () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- tools.ui = new MockedUserInteraction();
- setTools(tools);
-
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "false" });
- });
-
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
-
- it("should scaffold taskpane successfully", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
-
- sandbox.stub(OfficeAddinGenerator, "generate").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isOk());
- });
-
- it("should return error if app name is invalid", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: "__invalid__",
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- };
-
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error instanceof InputValidationError);
- });
-
- it("should return error if app name is undefined", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: undefined,
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- };
-
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error instanceof MissingRequiredInputError);
- });
-
- it("should return error if OfficeAddinGenerator returns error", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
-
- const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage");
- sandbox.stub(OfficeAddinGenerator, "generate").resolves(err(mockedError));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error.name === "mockedError");
- });
-});
-
-describe("Office XML Addin", async () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- tools.ui = new MockedUserInteraction();
- setTools(tools);
-
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "false" });
- });
-
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
-
- it("should scaffold project successfully", async () => {
- const context = createContext();
- context.userInteraction = new MockedUserInteraction();
-
- sandbox.stub(OfficeXMLAddinGenerator, "generate").resolves(ok(undefined));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isOk());
- });
-
- it("should return error if app name is invalid", async () => {
- const context = createContext();
- context.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: "__invalid__",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- };
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr() && res.error instanceof InputValidationError);
- });
-
- it("should return error if app name is undefined", async () => {
- const context = createContext();
- context.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: undefined,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- };
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr() && res.error instanceof MissingRequiredInputError);
- });
-
- it("should return error if OfficeXMLAddinGenerator returns error", async () => {
- const context = createContext();
- context.userInteraction = new MockedUserInteraction();
-
- const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage");
- sandbox.stub(OfficeXMLAddinGenerator, "generate").resolves(err(mockedError));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- };
- const res = await coordinator.create(context, inputs);
- assert.isTrue(res.isErr() && res.error.name === "mockedError");
- });
-});
-
-describe("Office Addin", async () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- tools.ui = new MockedUserInteraction();
- setTools(tools);
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "false" });
- });
-
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
-
- it("should scaffold taskpane successfully", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
-
- sandbox.stub(OfficeAddinGenerator, "generate").resolves(ok(undefined));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isOk());
- });
-
- it("should return error if app name is invalid", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: "__invalid__",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id,
- };
-
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error instanceof InputValidationError);
- });
-
- it("should return error if app name is undefined", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.AppName]: undefined,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id,
- };
-
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error instanceof MissingRequiredInputError);
- });
-
- it("should return error if OfficeAddinGenerator returns error", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
-
- const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage");
- sandbox.stub(OfficeAddinGenerator, "generate").resolves(err(mockedError));
- sandbox
- .stub(settingsUtil, "readSettings")
- .resolves(ok({ trackingId: "mockId", version: V3Version }));
- sandbox.stub(settingsUtil, "writeSettings").resolves(ok(""));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr() && res.error.name === "mockedError");
- });
-});
-
-describe("Copilot plugin", async () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- tools.ui = new MockedUserInteraction();
- setTools(tools);
-
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "false" });
- });
-
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
-
- it("should scaffold from API spec successfully", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
-
- sandbox
- .stub(CopilotPluginGenerator, "generatePluginFromApiSpec")
- .resolves(ok({ warnings: [{ type: "", content: "", data: {} } as any] }));
-
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.copilotPlugin().id,
- [QuestionNames.Capabilities]: CapabilityOptions.copilotPluginApiSpec().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isOk());
- });
+ it("should scaffold taskpane successfully", async () => {
+ const v3ctx = createContext();
+ v3ctx.userInteraction = new MockedUserInteraction();
+ sandbox.stub(fs, "pathExists").resolves(false);
+ sandbox.stub(OfficeAddinGeneratorNew.prototype, "run").resolves(ok({}));
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ folder: ".",
+ [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
+ [QuestionNames.AppName]: randomAppName(),
+ [QuestionNames.Scratch]: ScratchOptions.yes().id,
+ };
+ const res = await coordinator.create(v3ctx, inputs);
+ assert.isTrue(res.isOk());
+ });
- it("scaffold from API spec error", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
+ it("should scaffold from API spec successfully", async () => {
+ const v3ctx = createContext();
+ v3ctx.userInteraction = new MockedUserInteraction();
- sandbox
- .stub(CopilotPluginGenerator, "generatePluginFromApiSpec")
- .resolves(err(new SystemError("mockedSource", "mockedError", "mockedMessage", "")));
+ sandbox
+ .stub(SpecGenerator.prototype, "run")
+ .resolves(ok({ warnings: [{ type: "", content: "", data: {} } as any] }));
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.copilotPlugin().id,
- [QuestionNames.Capabilities]: CapabilityOptions.copilotPluginApiSpec().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isErr());
- });
-});
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ folder: ".",
+ [QuestionNames.ProjectType]: ProjectTypeOptions.copilotPlugin().id,
+ [QuestionNames.Capabilities]: CapabilityOptions.copilotPluginApiSpec().id,
+ [QuestionNames.AppName]: randomAppName(),
+ [QuestionNames.Scratch]: ScratchOptions.yes().id,
+ };
+ const res = await coordinator.create(v3ctx, inputs);
+ assert.isTrue(res.isOk());
+ });
-describe(`coordinator create with new generator enabled = true`, () => {
- let mockedEnvRestore: RestoreFn = () => {};
- const sandbox = sinon.createSandbox();
- const tools = new MockTools();
- setTools(tools);
- beforeEach(() => {
- sandbox.stub(fs, "ensureDir").resolves();
- mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "true" });
- });
- afterEach(() => {
- sandbox.restore();
- mockedEnvRestore();
- });
+ it("scaffold from API spec error", async () => {
+ const v3ctx = createContext();
+ v3ctx.userInteraction = new MockedUserInteraction();
- it("should scaffold by OfficeAddinGeneratorNew successfully", async () => {
- const v3ctx = createContext();
- v3ctx.userInteraction = new MockedUserInteraction();
- sandbox.stub(OfficeAddinGeneratorNew.prototype, "run").resolves(ok({}));
- const inputs: Inputs = {
- platform: Platform.VSCode,
- folder: ".",
- [QuestionNames.ProjectType]: ProjectTypeOptions.outlookAddin().id,
- [QuestionNames.AppName]: randomAppName(),
- [QuestionNames.Scratch]: ScratchOptions.yes().id,
- };
- const res = await coordinator.create(v3ctx, inputs);
- assert.isTrue(res.isOk());
+ sandbox
+ .stub(SpecGenerator.prototype, "run")
+ .resolves(err(new SystemError("mockedSource", "mockedError", "mockedMessage", "")));
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ folder: ".",
+ [QuestionNames.ProjectType]: ProjectTypeOptions.copilotPlugin().id,
+ [QuestionNames.Capabilities]: CapabilityOptions.copilotPluginApiSpec().id,
+ [QuestionNames.AppName]: randomAppName(),
+ [QuestionNames.Scratch]: ScratchOptions.yes().id,
+ };
+ const res = await coordinator.create(v3ctx, inputs);
+ assert.isTrue(res.isErr());
+ });
});
});
diff --git a/packages/fx-core/tests/component/driver/aad/aadAppClient.test.ts b/packages/fx-core/tests/component/driver/aad/aadAppClient.test.ts
index 0dc5567465..9cde0568c3 100644
--- a/packages/fx-core/tests/component/driver/aad/aadAppClient.test.ts
+++ b/packages/fx-core/tests/component/driver/aad/aadAppClient.test.ts
@@ -492,7 +492,7 @@ describe("AadAppClient", async () => {
expect(err.source).equals("AadAppClient");
expect(err.name).equals("DeleteOrUpdatePermissionFailed");
expect(err.message).equals(
- "Unable to update or delete an existing permission when it's enabled. One possible reason is that the ACCESS_AS_USER_PERMISSION_ID environment variable is changed for selected environment. Ensure your permission id(s) are identical with the actual Microsoft Entra application and try again.\n"
+ "Unable to update or delete an enabled permission. It may be because the ACCESS_AS_USER_PERMISSION_ID environment variable is changed for selected environment. Make sure your permission id(s) match the actual Microsoft Entra application and try again.\n"
);
}
);
diff --git a/packages/fx-core/tests/component/driver/aad/aadManifestHelper.test.ts b/packages/fx-core/tests/component/driver/aad/aadManifestHelper.test.ts
index 5f87ea368c..239754fea9 100644
--- a/packages/fx-core/tests/component/driver/aad/aadManifestHelper.test.ts
+++ b/packages/fx-core/tests/component/driver/aad/aadManifestHelper.test.ts
@@ -242,7 +242,7 @@ describe("Microsoft Entra manifest helper Test", () => {
AadManifestHelper.processRequiredResourceAccessInManifest(manifest);
})
.to.throw(
- "Unknown resourceAccess id: User.Read, if you're using permission as resourceAccess id, please try to use permission id instead."
+ "Unknown resourceAccess id: User.Read, try to use permission id instead of resourceAccess id."
);
manifest = {
@@ -264,7 +264,7 @@ describe("Microsoft Entra manifest helper Test", () => {
AadManifestHelper.processRequiredResourceAccessInManifest(manifest);
})
.to.throw(
- "Unknown resourceAccess id: Sites.Read.All, if you're using permission as resourceAccess id, please try to use permission id instead."
+ "Unknown resourceAccess id: Sites.Read.All, try to use permission id instead of resourceAccess id."
);
});
diff --git a/packages/fx-core/tests/component/driver/aad/create.test.ts b/packages/fx-core/tests/component/driver/aad/create.test.ts
index a3a7340352..382b90019a 100644
--- a/packages/fx-core/tests/component/driver/aad/create.test.ts
+++ b/packages/fx-core/tests/component/driver/aad/create.test.ts
@@ -405,7 +405,7 @@ describe("aadAppCreate", async () => {
.is.instanceOf(HttpClientError)
.and.has.property("message")
.and.equals(
- 'A http client error happened while performing the aadApp/create task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
+ 'A http client error occurred while performing the aadApp/create task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
);
});
@@ -434,7 +434,7 @@ describe("aadAppCreate", async () => {
.is.instanceOf(HttpServerError)
.and.has.property("message")
.and.equals(
- 'A http server error happened while performing the aadApp/create task. Please try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
+ 'A http server error occurred while performing the aadApp/create task. Try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
);
});
@@ -597,6 +597,9 @@ describe("aadAppCreate", async () => {
expect(endTelemetry.properties.success).to.equal("no");
expect(endTelemetry.properties["error-code"]).to.equal("aadAppCreate.HttpClientError");
expect(endTelemetry.properties["error-type"]).to.equal("user");
+ // expect(endTelemetry.properties["error-message"]).to.equal(
+ // 'A http client error occurred while performing the aadApp/create task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
+ // );
});
it("should send telemetries with error stack", async () => {
diff --git a/packages/fx-core/tests/component/driver/aad/update.test.ts b/packages/fx-core/tests/component/driver/aad/update.test.ts
index 89fb11547a..0ef0153a0c 100644
--- a/packages/fx-core/tests/component/driver/aad/update.test.ts
+++ b/packages/fx-core/tests/component/driver/aad/update.test.ts
@@ -441,7 +441,7 @@ describe("aadAppUpdate", async () => {
.is.instanceOf(HttpClientError)
.and.property("message")
.equals(
- 'A http client error happened while performing the aadApp/update task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
+ 'A http client error occurred while performing the aadApp/update task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
);
});
@@ -475,7 +475,7 @@ describe("aadAppUpdate", async () => {
.is.instanceOf(HttpServerError)
.and.property("message")
.equals(
- 'A http server error happened while performing the aadApp/update task. Please try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
+ 'A http server error occurred while performing the aadApp/update task. Try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
);
});
@@ -619,6 +619,9 @@ describe("aadAppUpdate", async () => {
expect(endTelemetry.properties.success).to.equal("no");
expect(endTelemetry.properties["error-code"]).to.equal("aadAppUpdate.HttpServerError");
expect(endTelemetry.properties["error-type"]).to.equal("system");
+ // expect(endTelemetry.properties["error-message"]).to.equal(
+ // 'A http server error occurred while performing the aadApp/update task. Try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
+ // );
});
it("should throw error when missing required environment variable in manifest", async () => {
diff --git a/packages/fx-core/tests/component/driver/botAadApp/create.test.ts b/packages/fx-core/tests/component/driver/botAadApp/create.test.ts
index bc90f36d73..0c87c9d1a8 100644
--- a/packages/fx-core/tests/component/driver/botAadApp/create.test.ts
+++ b/packages/fx-core/tests/component/driver/botAadApp/create.test.ts
@@ -173,7 +173,7 @@ describe("botAadAppCreate", async () => {
).to.be.rejected.then((error) => {
expect(error instanceof HttpClientError).to.be.true;
expect(error.message).contains(
- 'A http client error happened while performing the botAadApp/create task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
+ 'A http client error occurred while performing the botAadApp/create task. The error response is: {"error":{"code":"Request_BadRequest","message":"Invalid value specified for property \'displayName\' of resource \'Application\'."}}'
);
});
});
@@ -201,7 +201,7 @@ describe("botAadAppCreate", async () => {
).to.be.rejected.then((error) => {
expect(error instanceof HttpServerError).to.be.true;
expect(error.message).equals(
- 'A http server error happened while performing the botAadApp/create task. Please try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
+ 'A http server error occurred while performing the botAadApp/create task. Try again later. The error response is: {"error":{"code":"InternalServerError","message":"Internal server error"}}'
);
});
});
diff --git a/packages/fx-core/tests/component/driver/teamsApp/createAppPackage.test.ts b/packages/fx-core/tests/component/driver/teamsApp/createAppPackage.test.ts
index f16e9a1904..d65e175577 100644
--- a/packages/fx-core/tests/component/driver/teamsApp/createAppPackage.test.ts
+++ b/packages/fx-core/tests/component/driver/teamsApp/createAppPackage.test.ts
@@ -14,7 +14,7 @@ import {
MockedUserInteraction,
} from "../../../plugins/solution/util";
import { FileNotFoundError, JSONSyntaxError } from "../../../../src/error/common";
-import { FeatureFlagName } from "../../../../src/common/constants";
+import { FeatureFlagName } from "../../../../src/common/featureFlags";
import { manifestUtils } from "../../../../src/component/driver/teamsApp/utils/ManifestUtils";
import { ok, Platform, PluginManifestSchema, TeamsAppManifest } from "@microsoft/teamsfx-api";
import AdmZip from "adm-zip";
diff --git a/packages/fx-core/tests/component/generator/copilotGenerator.test.ts b/packages/fx-core/tests/component/generator/copilotGenerator.test.ts
index b063b55bfb..d6b90b0be6 100644
--- a/packages/fx-core/tests/component/generator/copilotGenerator.test.ts
+++ b/packages/fx-core/tests/component/generator/copilotGenerator.test.ts
@@ -37,16 +37,16 @@ import { getLocalizedString } from "../../../src/common/localizeUtils";
import { manifestUtils } from "../../../src/component/driver/teamsApp/utils/ManifestUtils";
import { PluginManifestUtils } from "../../../src/component/driver/teamsApp/utils/PluginManifestUtils";
import {
- CopilotGenerator,
- CopilotPluginGenerator,
-} from "../../../src/component/generator/copilotPlugin/generator";
-import * as CopilotPluginHelper from "../../../src/component/generator/copilotPlugin/helper";
+ SpecGenerator,
+ OpenAPISpecGenerator,
+} from "../../../src/component/generator/apiSpec/generator";
+import * as CopilotPluginHelper from "../../../src/component/generator/apiSpec/helper";
import {
formatValidationErrors,
generateScaffoldingSummary,
isYamlSpecFile,
listPluginExistingOperations,
-} from "../../../src/component/generator/copilotPlugin/helper";
+} from "../../../src/component/generator/apiSpec/helper";
import { Generator } from "../../../src/component/generator/generator";
import {
CapabilityOptions,
@@ -54,7 +54,7 @@ import {
MeArchitectureOptions,
ProgrammingLanguage,
QuestionNames,
- copilotPluginApiSpecOptionId,
+ apiPluginApiSpecOptionId,
} from "../../../src/question";
import { MockTools } from "../../core/utils";
@@ -83,7 +83,7 @@ const teamsManifest: TeamsAppManifest = {
accentColor: "#FFFFFF",
};
-describe("copilotPluginGenerator", function () {
+describe("OpenAPISpecGenerator", function () {
const tools = new MockTools();
setTools(tools);
const sandbox = sinon.createSandbox();
@@ -133,16 +133,11 @@ describe("copilotPluginGenerator", function () {
const getDefaultVariables = sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath",
- {
- telemetryProps: {
- "project-id": "test",
- },
- }
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath", {
+ telemetryProps: {
+ "project-id": "test",
+ },
+ });
assert.isTrue(result.isOk());
assert.isTrue(getDefaultVariables.calledOnce);
@@ -151,7 +146,7 @@ describe("copilotPluginGenerator", function () {
assert.equal(downloadTemplate.args[0][2], "copilot-plugin-existing-api");
});
- it("success with api key auth", async function () {
+ it("success with API Key authentication", async function () {
const inputs: Inputs = {
platform: Platform.VSCode,
projectPath: "path",
@@ -176,11 +171,7 @@ describe("copilotPluginGenerator", function () {
.resolves({ allSuccess: true, warnings: [] });
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isOk());
assert.equal(downloadTemplate.args[0][2], "copilot-plugin-existing-api");
@@ -210,11 +201,7 @@ describe("copilotPluginGenerator", function () {
const getDefaultVariables = sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generatePluginFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateCopilotPlugin(context, inputs, "projectPath");
assert.isTrue(result.isOk());
assert.isTrue(getDefaultVariables.calledOnce);
@@ -261,11 +248,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isOk());
if (result.isOk()) {
@@ -304,11 +287,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isOk());
if (result.isOk()) {
@@ -340,11 +319,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isOk());
});
@@ -363,11 +338,7 @@ describe("copilotPluginGenerator", function () {
.stub(Generator, "generateTemplate")
.resolves(err(new SystemError("source", "name", "", "")));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isErr());
});
@@ -391,11 +362,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isErr());
if (result.isErr()) {
@@ -424,11 +391,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isErr());
if (result.isErr()) {
@@ -446,11 +409,7 @@ describe("copilotPluginGenerator", function () {
const context = createContext();
sandbox.stub(Generator, "generateTemplate").throws(new Error("test"));
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isErr());
});
@@ -476,11 +435,7 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
- const result = await CopilotPluginGenerator.generateMeFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateMe(context, inputs, "projectPath");
assert.isTrue(result.isErr());
if (result.isErr()) {
@@ -488,7 +443,7 @@ describe("copilotPluginGenerator", function () {
}
});
- it("generateForCustomCopilotRagCustomApi: success", async () => {
+ it("generateCustomCopilot: success", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
projectPath: "path",
@@ -528,11 +483,7 @@ describe("copilotPluginGenerator", function () {
const getDefaultVariables = sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generateForCustomCopilotRagCustomApi(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateCustomCopilot(context, inputs, "projectPath");
assert.isTrue(result.isOk());
assert.isTrue(getDefaultVariables.calledOnce);
@@ -540,7 +491,7 @@ describe("copilotPluginGenerator", function () {
assert.isTrue(generateBasedOnSpec.calledOnce);
});
- it("generateForCustomCopilotRagCustomApi: error", async () => {
+ it("generateCustomCopilot: error", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
projectPath: "path",
@@ -580,13 +531,9 @@ describe("copilotPluginGenerator", function () {
const getDefaultVariables = sandbox.stub(Generator, "getDefaultVariables").resolves(undefined);
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
sandbox
- .stub(CopilotGenerator.prototype, "getTemplateName")
+ .stub(SpecGenerator.prototype, "getTemplateName")
.returns("custom-copilot-rag-custom-api");
- const result = await CopilotPluginGenerator.generateForCustomCopilotRagCustomApi(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateCustomCopilot(context, inputs, "projectPath");
assert.isTrue(result.isErr() && result.error.message === "test");
});
@@ -621,17 +568,13 @@ describe("copilotPluginGenerator", function () {
sandbox.stub(fs, "ensureDir").resolves();
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(teamsManifest));
sandbox.stub(CopilotPluginHelper, "isYamlSpecFile").resolves(false);
- sandbox.stub(CopilotGenerator.prototype, "getTemplateName").returns("api-plugin-existing-api");
+ sandbox.stub(SpecGenerator.prototype, "getTemplateName").returns("api-plugin-existing-api");
const generateBasedOnSpec = sandbox
.stub(SpecParser.prototype, "generateForCopilot")
.resolves({ allSuccess: true, warnings: [] });
const downloadTemplate = sandbox.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await CopilotPluginGenerator.generatePluginFromApiSpec(
- context,
- inputs,
- "projectPath"
- );
+ const result = await OpenAPISpecGenerator.generateCopilotPlugin(context, inputs, "projectPath");
assert.isTrue(result.isOk());
assert.equal(downloadTemplate.args[0][2], "api-plugin-existing-api");
assert.isTrue(downloadTemplate.calledOnce);
@@ -1057,7 +1000,7 @@ describe("formatValidationErrors", () => {
const res = formatValidationErrors(errors, {
platform: Platform.VSCode,
- [QuestionNames.Capabilities]: copilotPluginApiSpecOptionId,
+ [QuestionNames.Capabilities]: apiPluginApiSpecOptionId,
});
const errorMessage1 = [
@@ -1716,10 +1659,10 @@ describe("listOperations", async () => {
});
});
-describe("CopilotGenerator", async () => {
+describe("SpecGenerator", async () => {
describe("activate", async () => {
it("should activate and get correct template name", async () => {
- const generator = new CopilotGenerator();
+ const generator = new SpecGenerator();
const context = createContext();
const inputs: Inputs = {
platform: Platform.CLI,
@@ -1750,7 +1693,7 @@ describe("CopilotGenerator", async () => {
describe("getTempalteInfos", async () => {
it("happy path", async () => {
- const generator = new CopilotGenerator();
+ const generator = new SpecGenerator();
const context = createContext();
const inputs: Inputs = {
platform: Platform.CLI,
diff --git a/packages/fx-core/tests/component/generator/generator.test.ts b/packages/fx-core/tests/component/generator/generator.test.ts
index 516cd06262..a776310214 100644
--- a/packages/fx-core/tests/component/generator/generator.test.ts
+++ b/packages/fx-core/tests/component/generator/generator.test.ts
@@ -126,22 +126,6 @@ describe("Generator utils", () => {
assert.isTrue(url?.includes("0.0.0-rc"));
});
- it("set useLocalTemplate flag to true", async () => {
- mockedEnvRestore = mockedEnv({
- TEAMSFX_TEMPLATE_PRERELEASE: "",
- });
- sandbox.replace(templateConfig, "useLocalTemplate", true);
- const tagList = "1.0.0\n 2.0.0\n 2.1.0\n 3.0.0";
- sandbox.stub(axios, "get").resolves({ data: tagList, status: 200 } as AxiosResponse);
- try {
- await generatorUtils.getTemplateLatestVersion();
- } catch (e) {
- assert.exists(e);
- return;
- }
- assert.fail("Should not reach here.");
- });
-
it("return correct version", async () => {
mockedEnvRestore = mockedEnv({
TEAMSFX_TEMPLATE_PRERELEASE: "",
@@ -1055,6 +1039,9 @@ describe("render template", () => {
sandbox.replace(templateConfig, "useLocalTemplate", false);
sandbox.replace(templateConfig, "localVersion", "9.9.9");
+ sandbox.replace(templateConfig, "version", "~3.0.0");
+ const tagList = "1.0.0\n 2.0.0\n 2.1.0\n 3.0.0";
+ sandbox.stub(axios, "get").resolves({ data: tagList, status: 200 } as AxiosResponse);
sandbox.stub(folderUtils, "getTemplatesFolder").returns(tmpDir);
sandbox
.stub(generatorUtils, "getTemplateZipUrlByVersion")
diff --git a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts
index 3762a612bc..0ebaa85580 100644
--- a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts
+++ b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts
@@ -40,7 +40,6 @@ import { HelperMethods } from "../../../src/component/generator/officeAddin/help
import { UserCancelError } from "../../../src/error";
import {
CapabilityOptions,
- OfficeAddinHostOptions,
ProgrammingLanguage,
ProjectTypeOptions,
QuestionNames,
@@ -194,26 +193,6 @@ describe("OfficeAddinGenerator for Outlook Addin", function () {
chai.expect(result.isOk()).to.eq(true);
});
- it("should scaffold taskpane successfully on happy path if project-type is officeXMLAddin and host is outlook", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- "app-name": "outlook-addin-test",
- };
- inputs[QuestionNames.ProjectType] = ProjectTypeOptions.officeXMLAddin().id;
- inputs[QuestionNames.OfficeAddinHost] = OfficeAddinHostOptions.outlook().id;
- inputs[QuestionNames.Capabilities] = "json-taskpane";
- inputs[QuestionNames.OfficeAddinFolder] = undefined;
- inputs[QuestionNames.ProgrammingLanguage] = "typescript";
-
- sinon.stub(OfficeAddinGenerator, "childProcessExec").resolves();
- sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined));
- sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({});
- const result = await OfficeAddinGenerator.doScaffolding(context, inputs, testFolder);
-
- chai.expect(result.isOk()).to.eq(true);
- });
-
it("should scaffold taskpane failed, throw error", async () => {
const inputs: Inputs = {
platform: Platform.CLI,
@@ -1051,6 +1030,7 @@ describe("OfficeAddinGeneratorNew", () => {
projectPath: "./",
};
sandbox.stub(OfficeAddinGenerator, "doScaffolding").resolves(ok(undefined));
+ sandbox.stub(generator, "fixIconPath").resolves();
const res = await generator.post(context, inputs, "./");
chai.assert.isTrue(res.isOk());
});
@@ -1065,4 +1045,85 @@ describe("OfficeAddinGeneratorNew", () => {
chai.assert.isTrue(res.isErr());
});
});
+ describe("fixIconPath()", () => {
+ const sandbox = sinon.createSandbox();
+ afterEach(() => {
+ sandbox.restore();
+ });
+ it("manifest not found", async () => {
+ sandbox.stub(fse, "pathExists").resolves(false);
+ const move = sandbox.stub(fse, "move").resolves();
+ await generator.fixIconPath("./");
+ chai.assert.isTrue(move.notCalled);
+ });
+ it("happy", async () => {
+ sandbox.stub(fse, "pathExists").callsFake(async (path) => {
+ if (path.endsWith("manifest.json")) {
+ return true;
+ } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
+ return true;
+ } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
+ return true;
+ } else if (path.endsWith("color.png")) {
+ return false;
+ } else if (path.endsWith("outline.png")) {
+ return false;
+ }
+ });
+ sandbox
+ .stub(fse, "readJson")
+ .resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
+ const move = sandbox.stub(fse, "move").resolves();
+ const writeJson = sandbox.stub(fse, "writeJson").resolves();
+ await generator.fixIconPath("./");
+ chai.assert.isTrue(move.calledTwice);
+ chai.assert.isTrue(writeJson.calledOnce);
+ });
+ it("no need to move", async () => {
+ sandbox.stub(fse, "pathExists").callsFake(async (path) => {
+ if (path.endsWith("manifest.json")) {
+ return true;
+ } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
+ return true;
+ } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
+ return true;
+ } else if (path.endsWith("color.png")) {
+ return false;
+ } else if (path.endsWith("outline.png")) {
+ return false;
+ }
+ });
+ sandbox
+ .stub(fse, "readJson")
+ .resolves({ icons: { outline: "outline.png", color: "color.png" } });
+ const move = sandbox.stub(fse, "move").resolves();
+ const writeJson = sandbox.stub(fse, "writeJson").resolves();
+ await generator.fixIconPath("./");
+ chai.assert.isTrue(move.notCalled);
+ chai.assert.isTrue(writeJson.notCalled);
+ });
+ it("no need to move", async () => {
+ sandbox.stub(fse, "pathExists").callsFake(async (path) => {
+ if (path.endsWith("manifest.json")) {
+ return true;
+ } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
+ return false;
+ } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
+ return false;
+ } else if (path.endsWith("color.png")) {
+ return false;
+ } else if (path.endsWith("outline.png")) {
+ return false;
+ }
+ });
+ sandbox
+ .stub(fse, "readJson")
+ .resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
+ const move = sandbox.stub(fse, "move").resolves();
+ const writeJson = sandbox.stub(fse, "writeJson").resolves();
+ await generator.fixIconPath("./");
+ chai.assert.isTrue(move.notCalled);
+ chai.assert.isTrue(writeJson.notCalled);
+ });
+ });
});
diff --git a/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts
deleted file mode 100644
index 73551d0fef..0000000000
--- a/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-/**
- * @author zyun@microsoft.com
- */
-
-import { Context, Inputs, Platform, SystemError, err, ok } from "@microsoft/teamsfx-api";
-import * as chai from "chai";
-import * as childProcess from "child_process";
-import fs from "fs";
-import fse from "fs-extra";
-import "mocha";
-import mockedEnv, { RestoreFn } from "mocked-env";
-import { OfficeAddinManifest } from "office-addin-manifest";
-import * as path from "path";
-import * as sinon from "sinon";
-import * as uuid from "uuid";
-import { createContext, setTools } from "../../../src/common/globalVars";
-import { cpUtils } from "../../../src/component/deps-checker/";
-import { Generator } from "../../../src/component/generator/generator";
-import { HelperMethods } from "../../../src/component/generator/officeAddin/helperMethods";
-import {
- OfficeXMLAddinGenerator,
- OfficeXmlAddinGeneratorNew,
-} from "../../../src/component/generator/officeXMLAddin/generator";
-import {
- OfficeAddinHostOptions,
- ProgrammingLanguage,
- ProjectTypeOptions,
- QuestionNames,
- getOfficeAddinTemplateConfig,
-} from "../../../src/question";
-import { MockTools } from "../../core/utils";
-
-describe("OfficeXMLAddinGenerator", function () {
- const testFolder = path.resolve("./tmp");
- let context: Context;
- let mockedEnvRestore: RestoreFn;
- const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage");
-
- beforeEach(async () => {
- mockedEnvRestore = mockedEnv({ clear: true });
- const gtools = new MockTools();
- setTools(gtools);
- context = createContext();
-
- await fse.ensureDir(testFolder);
- sinon.stub(fs, "stat").resolves();
- sinon.stub(cpUtils, "executeCommand").resolves("succeed");
- const manifestId = uuid.v4();
- sinon.stub(fs, "readFile").resolves(new Buffer(`{"id": "${manifestId}"}`));
- sinon.stub(fs, "writeFile").resolves();
- sinon.stub(fs, "rename").resolves();
- sinon.stub(fs, "copyFile").resolves();
- sinon.stub(fse, "remove").resolves();
- sinon.stub(fse, "readJson").resolves({});
- sinon.stub(fse, "ensureFile").resolves();
- sinon.stub(fse, "writeJSON").resolves();
- });
-
- afterEach(async () => {
- sinon.restore();
- mockedEnvRestore();
- if (await fse.pathExists(testFolder)) {
- await fse.rm(testFolder, { recursive: true });
- }
- });
-
- it("should run childProcessExec command success", async function () {
- sinon.stub(childProcess, "exec").yields(`echo 'test'`, "test");
- chai.assert(await OfficeXMLAddinGenerator.childProcessExec(`echo 'test'`), "test");
- });
-
- it("should throw error once command fail", async function () {
- try {
- await OfficeXMLAddinGenerator.childProcessExec("exit -1");
- } catch (err) {
- chai.assert(err.message, "Command failed: exit -1");
- }
- });
-
- it("should success when generate normal project on happy path", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: "word-taskpane",
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "typescript",
- };
-
- sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined));
- sinon.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves();
- sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({});
- sinon.stub(Generator, "generateTemplate").resolves(ok(undefined));
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.expect(result.isOk()).to.eq(true);
- });
-
- it("should success when generate manifest-only project on happy path", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: "word-manifest",
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "javascript",
- };
-
- sinon.stub(Generator, "generateTemplate").resolves(ok(undefined));
- sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({});
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.expect(result.isOk()).to.eq(true);
- });
-
- it("should failed when generate manifest-only project on happy path when download failed", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: ["react"],
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "typescript",
- };
-
- sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined));
- sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({});
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.assert.isTrue(result.isErr());
- });
-
- it("should failed when get manifest-only failed", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: ["word-manifest"],
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "javascript",
- };
-
- sinon.stub(Generator, "generateTemplate").onCall(0).resolves(err(mockedError));
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.assert.isTrue(result.isErr());
- });
-
- it("should failed when get readme failed", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: ["word-manifest"],
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "javascript",
- };
-
- const generatorStub = sinon.stub(Generator, "generateTemplate");
- generatorStub.onCall(0).resolves(ok(undefined));
- generatorStub.onCall(1).resolves(err(mockedError));
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.assert.isTrue(result.isErr());
- });
-
- it("should failed when gen yml failed", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: testFolder,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: ["word-manifest"],
- [QuestionNames.AppName]: "office-addin-test",
- [QuestionNames.OfficeAddinFolder]: undefined,
- [QuestionNames.ProgrammingLanguage]: "javascript",
- };
-
- const generatorStub = sinon.stub(Generator, "generateTemplate");
- generatorStub.onCall(0).resolves(ok(undefined));
- generatorStub.onCall(1).resolves(ok(undefined));
- generatorStub.onCall(2).resolves(err(mockedError));
- sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({});
- const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder);
-
- chai.assert.isTrue(result.isErr());
- });
-});
-
-describe("getOfficeAddinTemplateConfig", () => {
- it("should return empty repo info if manifest-only project", () => {
- const config = getOfficeAddinTemplateConfig(ProjectTypeOptions.officeXMLAddin().id, "excel");
- chai.assert.equal(config["excel-manifest"].framework?.default?.typescript, undefined);
- chai.assert.equal(
- config["excel-react"].framework?.default?.typescript,
- "https://aka.ms/ccdevx-fx-react-ts"
- );
- });
-});
-
-describe("OfficeXmlAddinGeneratorNew", () => {
- const gtools = new MockTools();
- setTools(gtools);
- const generator = new OfficeXmlAddinGeneratorNew();
- const context = createContext();
- describe("active()", () => {
- it(`should return true`, async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: "./",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- };
- const res = generator.activate(context, inputs);
- chai.assert.isTrue(res);
- });
-
- it(`should return false`, async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: "./",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.outlook().id,
- };
- const res = generator.activate(context, inputs);
- chai.assert.isFalse(res);
- });
- });
-
- describe("getTemplateInfos()", () => {
- const sandbox = sinon.createSandbox();
- afterEach(() => {
- sandbox.restore();
- });
- it("happy path for word-taskpane", async () => {
- sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined));
- sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves();
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: "./",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS,
- [QuestionNames.Capabilities]: "word-taskpane",
- };
- const res = await generator.getTemplateInfos(context, inputs, "./");
- chai.assert.isTrue(res.isOk());
- if (res.isOk()) {
- chai.assert.equal(res.value.length, 2);
- }
- });
- it("happy path for word-manifest", async () => {
- sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined));
- sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves();
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: "./",
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS,
- [QuestionNames.Capabilities]: "word-manifest",
- };
- const res = await generator.getTemplateInfos(context, inputs, "./");
- chai.assert.isTrue(res.isOk());
- if (res.isOk()) {
- chai.assert.equal(res.value.length, 3);
- }
- });
- });
-
- describe("post()", () => {
- const sandbox = sinon.createSandbox();
- afterEach(() => {
- sandbox.restore();
- });
- it("happy", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- projectPath: "./",
- };
- sandbox.stub(OfficeAddinManifest, "modifyManifestFile").resolves();
- const res = await generator.post(context, inputs, "./");
- chai.assert.isTrue(res.isOk());
- });
- });
-});
diff --git a/packages/fx-core/tests/component/generator/spfxGenerator.test.ts b/packages/fx-core/tests/component/generator/spfxGenerator.test.ts
index 3f8ae437ef..fa2e9d2730 100644
--- a/packages/fx-core/tests/component/generator/spfxGenerator.test.ts
+++ b/packages/fx-core/tests/component/generator/spfxGenerator.test.ts
@@ -435,6 +435,40 @@ describe("SPFxGenerator", function () {
}
});
+ it("No valid web part manifest when import SPFx solution", async () => {
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ projectPath: testFolder,
+ "app-name": "spfxTestApp",
+ "spfx-solution": "import",
+ "spfx-folder": "c:\\test",
+ };
+
+ sinon.stub(fs, "pathExists").resolves(true);
+ sinon.stub(fs, "readdir").callsFake((directory: any) => {
+ if (directory === path.join("c:\\test", "teams")) {
+ return ["1_color.png", "1_outline.png"] as any;
+ } else if (directory === path.join("c:\\test", "src", "webparts")) {
+ return ["helloworld", "second"] as any;
+ } else {
+ return [];
+ }
+ });
+ sinon.stub(fs, "statSync").returns({
+ isDirectory: () => {
+ return true;
+ },
+ } as any);
+ sinon.stub(fs, "copy").resolves();
+
+ const result = await SPFxGenerator.generate(context, inputs, testFolder);
+
+ chai.expect(result.isErr()).to.eq(true);
+ if (result.isErr()) {
+ chai.expect(result.error.name).to.eq("FileNotFoundError");
+ }
+ });
+
it("Copy existing SPFx solution failed when import SPFx solution", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
@@ -469,8 +503,10 @@ describe("SPFxGenerator", function () {
sinon.stub(fs, "readdir").callsFake((directory: any) => {
if (directory === path.join("c:\\test", "teams")) {
return ["1_color.png", "1_outline.png"] as any;
- } else {
+ } else if (directory === path.join("c:\\test", "src", "webparts")) {
return ["helloworld", "second"] as any;
+ } else {
+ return ["HelloWorldWebPart.manifest.json"] as any;
}
});
sinon.stub(fs, "statSync").returns({
@@ -502,7 +538,15 @@ describe("SPFxGenerator", function () {
};
sinon.stub(fs, "pathExists").resolves(true);
- sinon.stub(fs, "readdir").resolves(["helloworld", "second"] as any);
+ sinon.stub(fs, "readdir").callsFake((directory: any) => {
+ if (directory === path.join("c:\\test", "teams")) {
+ return ["1_color.png", "1_outline.png"] as any;
+ } else if (directory === path.join("c:\\test", "src", "webparts")) {
+ return ["helloworld", "second"] as any;
+ } else {
+ return ["HelloWorldWebPart.manifest.json"] as any;
+ }
+ });
sinon.stub(fs, "statSync").returns({
isDirectory: () => {
return true;
@@ -532,8 +576,10 @@ describe("SPFxGenerator", function () {
sinon.stub(fs, "readdir").callsFake((directory: any) => {
if (directory === path.join("c:\\test", "teams")) {
return ["1_color.png", "1_outline.png"] as any;
- } else {
+ } else if (directory === path.join("c:\\test", "src", "webparts")) {
return ["helloworld", "second"] as any;
+ } else {
+ return ["HelloWorldWebPart.manifest.json"] as any;
}
});
sinon.stub(fs, "statSync").returns({
diff --git a/packages/fx-core/tests/core/FxCore.test.ts b/packages/fx-core/tests/core/FxCore.test.ts
index 0a34e13a36..c65bd16877 100644
--- a/packages/fx-core/tests/core/FxCore.test.ts
+++ b/packages/fx-core/tests/core/FxCore.test.ts
@@ -13,6 +13,7 @@ import {
DeclarativeCopilotManifestSchema,
FxError,
IQTreeNode,
+ InputResult,
Inputs,
LogProvider,
Ok,
@@ -25,7 +26,7 @@ import {
err,
ok,
} from "@microsoft/teamsfx-api";
-import { assert } from "chai";
+import { assert, expect } from "chai";
import fs from "fs-extra";
import jsyaml from "js-yaml";
import "mocha";
@@ -33,8 +34,8 @@ import mockedEnv, { RestoreFn } from "mocked-env";
import * as os from "os";
import * as path from "path";
import sinon from "sinon";
-import { FxCore, getUuid } from "../../src";
-import { FeatureFlagName } from "../../src/common/constants";
+import { FxCore, PackageService, getUuid, teamsDevPortalClient } from "../../src";
+import { FeatureFlagName } from "../../src/common/featureFlags";
import { LaunchHelper } from "../../src/component/m365/launchHelper";
import {
TeamsfxConfigType,
@@ -48,6 +49,7 @@ import {
ILifecycle,
LifecycleName,
Output,
+ ProjectModel,
UnresolvedPlaceholders,
} from "../../src/component/configManager/interface";
import { YamlParser } from "../../src/component/configManager/parser";
@@ -67,7 +69,7 @@ import { ValidateAppPackageDriver } from "../../src/component/driver/teamsApp/va
import { ValidateWithTestCasesDriver } from "../../src/component/driver/teamsApp/validateTestCases";
import { createDriverContext } from "../../src/component/driver/util/utils";
import "../../src/component/feature/sso";
-import * as CopilotPluginHelper from "../../src/component/generator/copilotPlugin/helper";
+import * as CopilotPluginHelper from "../../src/component/generator/apiSpec/helper";
import { envUtil } from "../../src/component/utils/envUtil";
import { metadataUtil } from "../../src/component/utils/metadataUtil";
import { pathUtils } from "../../src/component/utils/pathUtils";
@@ -93,6 +95,12 @@ import {
import { HubOptions, PluginAvailabilityOptions } from "../../src/question/constants";
import { validationUtils } from "../../src/ui/validationUtils";
import { MockTools, randomAppName } from "./utils";
+import { UninstallInputs } from "../../build";
+import { CoreHookContext } from "../../src/core/types";
+import * as projectHelper from "../../src/common/projectSettingsHelper";
+import * as migrationUtil from "../../src/core/middleware/utils/v3MigrationUtils";
+import * as projMigrator from "../../src/core/middleware/projectMigratorV3";
+import { VersionSource, VersionState } from "../../src/common/versionMetadata";
const tools = new MockTools();
@@ -430,11 +438,12 @@ describe("Core basic APIs", () => {
// Cannot assert the full message because the mocked code can't get correct env file path
assert.include(
res.error.message,
- "The program cannot proceed as the following environment variables are missing: 'AAD_APP_OBJECT_ID', which are required for file: fake path. Make sure the required variables are set either by editing the .env file"
+ "Missing environment variables 'AAD_APP_OBJECT_ID' for file: fake path. Please edit the .env file"
);
+
assert.include(
res.error.message,
- "If you are developing with a new project created with Teams Toolkit, running provision or debug will register correct values for these environment variables"
+ "For new Teams Toolkit projects, make sure you've run provision or debug to set these variables correctly."
);
}
});
@@ -489,7 +498,9 @@ describe("Core basic APIs", () => {
};
const res = await core.phantomMigrationV3(inputs);
assert.isTrue(res.isErr());
- assert.isTrue(res._unsafeUnwrapErr().message.includes(new InvalidProjectError().message));
+ assert.isTrue(
+ res._unsafeUnwrapErr().message.includes(new InvalidProjectError(inputs.projectPath!).message)
+ );
await deleteTestProject(appName);
});
@@ -502,7 +513,9 @@ describe("Core basic APIs", () => {
};
const res = await core.phantomMigrationV3(inputs);
assert.isTrue(res.isErr());
- assert.isTrue(res._unsafeUnwrapErr().message.includes(new InvalidProjectError().message));
+ assert.isTrue(
+ res._unsafeUnwrapErr().message.includes(new InvalidProjectError(inputs.projectPath!).message)
+ );
});
it("phantomMigrationV3 return error for V5 project", async () => {
@@ -610,6 +623,500 @@ describe("Core basic APIs", () => {
restore();
}
});
+ it("uninstall with empty input", async () => {
+ const core = new FxCore(tools);
+ const inputs: UninstallInputs = {
+ platform: Platform.CLI,
+ };
+ const res = await core.uninstall(inputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall with invalid mode", async () => {
+ const core = new FxCore(tools);
+ const inputs = {
+ platform: Platform.CLI,
+ mode: "invalid",
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall by manifest ID - success", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").resolves(true);
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: [
+ "m365-app",
+ "app-registration",
+ "bot-framework-registration",
+ ],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+ });
+ it("uninstall by manifest ID - missing manifest ID", async () => {
+ const core = new FxCore(tools);
+ const inputs: UninstallInputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall by manifest ID - empty options", async () => {
+ const core = new FxCore(tools);
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+ });
+ it("uninstall by manifest ID - failed to get token", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(err(new SystemError("mockedSource", "mockedError", "mockedMessage")));
+ const inputs1 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["m365-app"],
+ nonInteractive: true,
+ };
+ const res1 = await core.uninstall(inputs1 as UninstallInputs);
+ assert.isTrue(res1.isErr());
+
+ const inputs2 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["app-registration"],
+ nonInteractive: true,
+ };
+ const res2 = await core.uninstall(inputs2 as UninstallInputs);
+ assert.isTrue(res2.isErr());
+
+ const inputs3 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["bot-framework-registration"],
+ nonInteractive: true,
+ };
+ const res3 = await core.uninstall(inputs3 as UninstallInputs);
+ assert.isTrue(res3.isErr());
+ });
+ it("uninstall by manifest ID - failed to get title ID", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").throws("error");
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: [
+ "m365-app",
+ "app-registration",
+ "bot-framework-registration",
+ ],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall by manifest ID - failed to get bot ID", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves(undefined);
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["bot-framework-registration"],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall by manifest ID - M365 App user cancel", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(tools.ui, "confirm").resolves(ok({ result: false } as InputResult));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").throws("error");
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").throws("error");
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["m365-app"],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ if (res.isErr()) {
+ assert.isTrue(res.error instanceof UserCancelError);
+ }
+ });
+ it("uninstall by manifest ID - TDP user cancel", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(tools.ui, "confirm").resolves(ok({ result: false } as InputResult));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").throws("error");
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").throws("error");
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["app-registration"],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ if (res.isErr()) {
+ assert.isTrue(res.error instanceof UserCancelError);
+ }
+ });
+ it("uninstall by manifest ID - Bot user cancel", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(tools.ui, "confirm").resolves(ok({ result: false } as InputResult));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").throws("error");
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").throws("error");
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeManifestId,
+ [QuestionNames.ManifestId]: "valid-manifest-id",
+ [QuestionNames.UninstallOptions]: ["bot-framework-registration"],
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ if (res.isErr()) {
+ assert.isTrue(res.error instanceof UserCancelError);
+ }
+ });
+ it("uninstall by env - success", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").resolves(true);
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const appName = await mockCliUninstallProject();
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ env: "dev",
+ [QuestionNames.UninstallOptions]: [
+ "m365-app",
+ "app-registration",
+ "bot-framework-registration",
+ ],
+ nonInteractive: true,
+ };
+
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+
+ const envRes = await envUtil.readEnv(path.join(os.tmpdir(), appName), "dev", false);
+ assert.isTrue(envRes.isOk());
+ if (envRes.isOk()) {
+ const envVars = envRes.value;
+ assert.isTrue(envVars["TEAMS_APP_ID"] === "");
+ assert.isTrue(envVars["M365_TITLE_ID"] === "");
+ assert.isTrue(envVars["BOT_ID"] === "");
+ }
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - missing env", async () => {
+ const core = new FxCore(tools);
+ const appName = await mockCliUninstallProject();
+
+ const inputs: UninstallInputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ nonInteractive: true,
+ };
+
+ const res = await core.uninstall(inputs);
+ assert.isTrue(res.isErr());
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - empty options", async () => {
+ const core = new FxCore(tools);
+ const appName = await mockCliUninstallProject();
+
+ const inputs: UninstallInputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ nonInteractive: true,
+ env: "dev",
+ };
+
+ const res = await core.uninstall(inputs);
+ assert.isTrue(res.isOk());
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - invalid yaml", async () => {
+ const core = new FxCore(tools);
+ const appName = await mockCliUninstallProject();
+ sandbox.stub(metadataUtil, "parse").resolves(err(new SystemError("", "", "")));
+ const inputs: UninstallInputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ nonInteractive: true,
+ env: "dev",
+ };
+ const res = await core.uninstall(inputs);
+ assert.isTrue(res.isErr());
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - empty provision actions", async () => {
+ const core = new FxCore(tools);
+ const appName = await mockCliUninstallProject();
+ sandbox.stub(metadataUtil, "parse").resolves(ok({} as ProjectModel));
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(err(new SystemError("mockedSource", "mockedError", "mockedMessage")));
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ nonInteractive: true,
+ env: "dev",
+ [QuestionNames.UninstallOptions]: [
+ "m365-app",
+ "app-registration",
+ "bot-framework-registration",
+ ],
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - empty env key name", async () => {
+ const core = new FxCore(tools);
+ sandbox.stub(metadataUtil, "parse").resolves(
+ ok({
+ provision: {
+ name: "provision",
+ driverDefs: [
+ {
+ uses: "teamsApp/create",
+ },
+ {
+ uses: "botFramework/create",
+ },
+ {
+ uses: "teamsApp/extendToM365",
+ },
+ ],
+ },
+ } as ProjectModel)
+ );
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").resolves(true);
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const appName = await mockCliUninstallProject();
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ env: "dev",
+ [QuestionNames.UninstallOptions]: [
+ "m365-app",
+ "app-registration",
+ "bot-framework-registration",
+ ],
+ nonInteractive: true,
+ };
+
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+
+ const envRes = await envUtil.readEnv(path.join(os.tmpdir(), appName), "dev", false);
+ assert.isTrue(envRes.isOk());
+ if (envRes.isOk()) {
+ const envVars = envRes.value;
+ assert.isTrue(envVars["TEAMS_APP_ID"] === "");
+ assert.isTrue(envVars["M365_TITLE_ID"] === "");
+ assert.isTrue(envVars["BOT_ID"] === "");
+ }
+ await deleteTestProject(appName);
+ });
+ it("uninstall by env - failed to get token", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(err(new SystemError("mockedSource", "mockedError", "mockedMessage")));
+ sandbox.stub(teamsDevPortalClient, "deleteApp").resolves(true);
+ sandbox.stub(teamsDevPortalClient, "getBotId").resolves("mocked-bot-id");
+ sandbox.stub(teamsDevPortalClient, "deleteBot").resolves();
+ sandbox.stub(PackageService.prototype, "retrieveTitleId").resolves("mocked-title-id");
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const appName = await mockCliUninstallProject();
+ const inputs1 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ env: "dev",
+ [QuestionNames.UninstallOptions]: ["m365-app"],
+ nonInteractive: true,
+ };
+
+ const res1 = await core.uninstall(inputs1 as UninstallInputs);
+ assert.isTrue(res1.isErr());
+
+ const inputs2 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ env: "dev",
+ [QuestionNames.UninstallOptions]: ["app-registration"],
+ nonInteractive: true,
+ };
+
+ const res2 = await core.uninstall(inputs2 as UninstallInputs);
+ assert.isTrue(res2.isErr());
+
+ const inputs3 = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeEnv,
+ projectPath: path.join(os.tmpdir(), appName),
+ env: "dev",
+ [QuestionNames.UninstallOptions]: ["bot-framework-registration"],
+ nonInteractive: true,
+ };
+
+ const res3 = await core.uninstall(inputs3 as UninstallInputs);
+ assert.isTrue(res3.isErr());
+ });
+ it("uninstall by title ID - success", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeTitleId,
+ [QuestionNames.TitleId]: "mocked-title-id",
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isOk());
+ });
+ it("uninstall by title ID - missing title ID", async () => {
+ const core = new FxCore(tools);
+ sandbox
+ .stub(tools.tokenProvider.m365TokenProvider, "getAccessToken")
+ .resolves(ok("mocked-token"));
+ sandbox.stub(PackageService.prototype, "unacquire").resolves();
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeTitleId,
+ nonInteractive: true,
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall by title ID - failed", async () => {
+ const core = new FxCore(tools);
+ sandbox.stub(core, "uninstallM365App").resolves(err(new SystemError("", "", "")));
+ const inputs = {
+ platform: Platform.CLI,
+ [QuestionNames.UninstallMode]: QuestionNames.UninstallModeTitleId,
+ nonInteractive: true,
+ [QuestionNames.TitleId]: "mocked-title-id",
+ };
+ const res = await core.uninstall(inputs as UninstallInputs);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall M365 App - invalid input", async () => {
+ const core = new FxCore(tools);
+ const res = await core.uninstallM365App(undefined, undefined);
+ assert.isTrue(res.isErr());
+ });
+ it("uninstall Bot Framework Registration - invalid input", async () => {
+ const core = new FxCore(tools);
+ const res = await core.uninstallBotFrameworRegistration(undefined, undefined);
+ assert.isTrue(res.isErr());
+ });
+ it("reset env var - happy path", async () => {
+ const core = new FxCore(tools);
+ const ctx: CoreHookContext = { arguments: [], envVars: { testKey: "oldValue" } };
+ core.resetEnvVar("testKey", ctx);
+ expect(ctx.envVars).to.deep.equal({ testKey: "" });
+ });
+ it("reset env var - undefine ctx", async () => {
+ const core = new FxCore(tools);
+ const ctx: CoreHookContext | undefined = undefined;
+ core.resetEnvVar("testKey", ctx);
+ assert.isUndefined(ctx);
+ });
+ it("reset env var - initialize envVars if it is undefined", async () => {
+ const core = new FxCore(tools);
+ const ctx: CoreHookContext = { arguments: [], envVars: undefined };
+ core.resetEnvVar("testKey", ctx, false);
+ expect(ctx.envVars).to.deep.equal({ testKey: "" });
+ });
+ it("reset env var - skipIfNotExist is true", async () => {
+ const core = new FxCore(tools);
+ const ctx: CoreHookContext = { arguments: [], envVars: { existingKey: "value" } };
+ core.resetEnvVar("testKey", ctx);
+ expect(ctx.envVars).to.deep.equal({ existingKey: "value" });
+ });
+ it("reset env var - skipIfNotExist is false", async () => {
+ const core = new FxCore(tools);
+ const ctx: CoreHookContext = { arguments: [], envVars: { existingKey: "value" } };
+ core.resetEnvVar("testKey", ctx, false);
+ expect(ctx.envVars).to.deep.equal({ existingKey: "value", testKey: "" });
+ });
});
describe("apply yaml template", async () => {
@@ -887,6 +1394,13 @@ async function mockV2Project(): Promise {
return appName;
}
+async function mockCliUninstallProject(): Promise {
+ const appName = randomAppName();
+ const projectPath = path.join(os.tmpdir(), appName);
+ await fs.copy(path.join(__dirname, "../samples/uninstall/"), path.join(projectPath));
+ return appName;
+}
+
async function deleteTestProject(appName: string) {
await fs.remove(path.join(os.tmpdir(), appName));
}
@@ -4640,4 +5154,50 @@ describe("addPlugin", async () => {
await fs.remove(inputs.projectPath!);
}
});
+
+ describe("projectVersionCheck", async () => {
+ it("invalid project", async () => {
+ sandbox.stub(projectHelper, "isValidProjectV3").returns(false);
+ sandbox.stub(projectHelper, "isValidProjectV2").returns(false);
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ [QuestionNames.Folder]: os.tmpdir(),
+ projectPath: "./",
+ };
+ const core = new FxCore(tools);
+ const result = await core.projectVersionCheck(inputs);
+ assert.isTrue(result.isErr());
+ });
+ it("version is undefined", async () => {
+ sandbox.stub(projectHelper, "isValidProjectV3").returns(true);
+ sandbox
+ .stub(migrationUtil, "getProjectVersionFromPath")
+ .resolves({ version: "", source: VersionSource.teamsapp });
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ [QuestionNames.Folder]: os.tmpdir(),
+ projectPath: "./",
+ };
+ const core = new FxCore(tools);
+ const result = await core.projectVersionCheck(inputs);
+ assert.isTrue(result.isErr());
+ });
+ it("no plugin", async () => {
+ sandbox.stub(projectHelper, "isValidProjectV3").returns(true);
+ sandbox
+ .stub(migrationUtil, "getProjectVersionFromPath")
+ .resolves({ version: "1.0", source: VersionSource.teamsapp });
+ sandbox.stub(migrationUtil, "getTrackingIdFromPath").resolves("xxxx-xxxx");
+ sandbox.stub(migrationUtil, "getVersionState").returns(VersionState.upgradeable);
+ sandbox.stub(projMigrator, "checkActiveResourcePlugins").resolves(false);
+ const inputs: Inputs = {
+ platform: Platform.VSCode,
+ [QuestionNames.Folder]: os.tmpdir(),
+ projectPath: "./",
+ };
+ const core = new FxCore(tools);
+ const result = await core.projectVersionCheck(inputs);
+ assert.isTrue(result.isErr());
+ });
+ });
});
diff --git a/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.dev.json b/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.dev.json
index df40a0feae..871d6e4438 100644
--- a/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.dev.json
+++ b/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.dev.json
@@ -1,6 +1,5 @@
{
"$schema": "https://aka.ms/teamsfx-env-config-schema",
- "description": "You can customize the TeamsFx config for different environments. Visit https://aka.ms/teamsfx-env-config to learn more about this.",
"manifest": {
"appName": {
"short": "testApp",
diff --git a/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.local.json b/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.local.json
index 710f559e5e..acdc00abaf 100644
--- a/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.local.json
+++ b/packages/fx-core/tests/core/middleware/testAssets/v3Migration/happyPath/.fx/configs/config.local.json
@@ -1,6 +1,5 @@
{
"$schema": "https://aka.ms/teamsfx-env-config-schema",
- "description": "You can customize the TeamsFx config for different environments. Visit https://aka.ms/teamsfx-env-config to learn more about this.",
"manifest": {
"appName": {
"short": "testApp-local",
diff --git a/packages/fx-core/tests/question/create.test.ts b/packages/fx-core/tests/question/create.test.ts
index a8253998ab..de2ced32cb 100644
--- a/packages/fx-core/tests/question/create.test.ts
+++ b/packages/fx-core/tests/question/create.test.ts
@@ -22,7 +22,7 @@ import "mocha";
import mockedEnv, { RestoreFn } from "mocked-env";
import * as path from "path";
import sinon from "sinon";
-import { FeatureFlagName } from "../../src/common/constants";
+import { FeatureFlagName } from "../../src/common/featureFlags";
import * as utils from "../../src/common/globalVars";
import { setTools } from "../../src/common/globalVars";
import { getLocalizedString } from "../../src/common/localizeUtils";
@@ -40,7 +40,6 @@ import {
CustomCopilotRagOptions,
MeArchitectureOptions,
NotificationTriggerOptions,
- OfficeAddinHostOptions,
ProgrammingLanguage,
ProjectTypeOptions,
QuestionNames,
@@ -57,7 +56,6 @@ import {
getLanguageOptions,
getSolutionName,
officeAddinFrameworkQuestion,
- officeAddinHostingQuestion,
programmingLanguageQuestion,
projectTypeQuestion,
} from "../../src/question";
@@ -251,7 +249,7 @@ describe("scaffold question", () => {
]);
});
- it("traverse in vscode me from new api (none auth)", async () => {
+ it("traverse in vscode me from new api (No authentication)", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
};
@@ -568,76 +566,7 @@ describe("scaffold question", () => {
QuestionNames.AppName,
]);
});
- it("traverse in vscode Office XML addin", async () => {
- const inputs: Inputs = {
- platform: Platform.VSCode,
- };
- const questions: string[] = [];
- const visitor: QuestionTreeVisitor = async (
- question: Question,
- ui: UserInteraction,
- inputs: Inputs
- ) => {
- questions.push(question.name);
- await callFuncs(question, inputs);
- if (question.name === QuestionNames.ProjectType) {
- const select = question as SingleSelectQuestion;
- const options = await select.dynamicOptions!(inputs);
- return ok({ type: "success", result: ProjectTypeOptions.officeXMLAddin().id });
- } else if (question.name === QuestionNames.OfficeAddinHost) {
- const select = question as SingleSelectQuestion;
- const options = await select.staticOptions;
- assert.deepEqual(options, [
- OfficeAddinHostOptions.outlook(),
- OfficeAddinHostOptions.word(),
- OfficeAddinHostOptions.excel(),
- OfficeAddinHostOptions.powerpoint(),
- ]);
- const title =
- typeof question.title === "function" ? await question.title(inputs) : question.title;
- assert.equal(
- title,
- getLocalizedString("core.createProjectQuestion.officeXMLAddin.create.title")
- );
- return ok({ type: "success", result: OfficeAddinHostOptions.excel().id });
- } else if (question.name === QuestionNames.Capabilities) {
- const select = question as SingleSelectQuestion;
- const options = await select.dynamicOptions!(inputs);
- const items = CapabilityOptions.officeAddinDynamicCapabilities(
- ProjectTypeOptions.officeXMLAddin().id,
- OfficeAddinHostOptions.excel().id
- );
- assert.deepEqual(options, items);
- const title =
- typeof question.title === "function" ? await question.title(inputs) : question.title;
- assert.equal(
- title,
- getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.create.title")
- );
- return ok({ type: "success", result: "excel-react" });
- } else if (question.name === QuestionNames.ProgrammingLanguage) {
- const select = question as SingleSelectQuestion;
- const options = await select.dynamicOptions!(inputs);
- assert.isTrue(options.length === 2);
- return ok({ type: "success", result: "typescript" });
- } else if (question.name === QuestionNames.Folder) {
- return ok({ type: "success", result: "./" });
- } else if (question.name === QuestionNames.AppName) {
- return ok({ type: "success", result: "test001" });
- }
- return ok({ type: "success", result: undefined });
- };
- await traverse(createProjectQuestionNode(), inputs, ui, undefined, visitor);
- assert.deepEqual(questions, [
- QuestionNames.ProjectType,
- QuestionNames.OfficeAddinHost,
- QuestionNames.Capabilities,
- QuestionNames.ProgrammingLanguage,
- QuestionNames.Folder,
- QuestionNames.AppName,
- ]);
- });
it("traverse in vscode Office addin", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
@@ -1617,7 +1546,7 @@ describe("scaffold question", () => {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 6);
- return ok({ type: "success", result: "copilot-plugin-type" });
+ return ok({ type: "success", result: "api-plugin-type" });
} else if (question.name === QuestionNames.Capabilities) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
@@ -1651,7 +1580,7 @@ describe("scaffold question", () => {
]);
});
- it("traverse in vscode Copilot Plugin from new API with api key auth", async () => {
+ it("traverse in vscode Copilot Plugin from new API with API Key authentication", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
};
@@ -1669,7 +1598,7 @@ describe("scaffold question", () => {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 6);
- return ok({ type: "success", result: "copilot-plugin-type" });
+ return ok({ type: "success", result: "api-plugin-type" });
} else if (question.name === QuestionNames.Capabilities) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
@@ -1723,7 +1652,7 @@ describe("scaffold question", () => {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 6);
- return ok({ type: "success", result: "copilot-plugin-type" });
+ return ok({ type: "success", result: "api-plugin-type" });
} else if (question.name === QuestionNames.Capabilities) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
@@ -2451,7 +2380,7 @@ describe("scaffold question", () => {
{
id: "get operation1",
label: "get operation1",
- detail: "API key auth(Bearer token auth)",
+ detail: "API Key authentication(Bearer token authentication)",
groupName: "GET",
data: {
authName: "bearerAuth",
@@ -2462,7 +2391,7 @@ describe("scaffold question", () => {
{
id: "get operation2",
label: "get operation2",
- detail: "None auth",
+ detail: "No authentication",
groupName: "GET",
data: {
serverUrl: "https://server2",
@@ -2471,7 +2400,7 @@ describe("scaffold question", () => {
{
id: "get operation3",
label: "get operation3",
- detail: "OAuth(Auth code flow)",
+ detail: "OAuth(Authorization code flow)",
groupName: "GET",
data: {
serverUrl: "https://server",
@@ -2537,7 +2466,7 @@ describe("scaffold question", () => {
{
id: "get operation1",
label: "get operation1",
- detail: "API key auth(Bearer token auth)",
+ detail: "API Key authentication(Bearer token authentication)",
groupName: "GET",
data: {
authName: "bearerAuth",
@@ -2548,7 +2477,7 @@ describe("scaffold question", () => {
{
id: "get operation2",
label: "get operation2",
- detail: "None auth",
+ detail: "No authentication",
groupName: "GET",
data: {
serverUrl: "https://server2",
@@ -2744,7 +2673,7 @@ describe("scaffold question", () => {
{
id: "GET /store/order",
label: "GET /store/order",
- detail: "None auth",
+ detail: "No authentication",
groupName: "GET",
data: {
serverUrl: "https://server2",
@@ -2866,7 +2795,7 @@ describe("scaffold question", () => {
serverUrl: "https://server",
},
groupName: "GET",
- detail: "None auth",
+ detail: "No authentication",
id: "GET /user/{userId}",
label: "GET /user/{userId}",
},
@@ -3383,15 +3312,9 @@ describe("scaffold question", () => {
});
describe("officeAddinStaticCapabilities()", () => {
- it("should return correct capabilities for specific host", () => {
- const capabilities = CapabilityOptions.officeAddinStaticCapabilities(
- OfficeAddinHostOptions.word().id
- );
- assert.equal(capabilities.length, 4);
- });
it("should return correct capabilities without specific host", () => {
const capabilities = CapabilityOptions.officeAddinStaticCapabilities();
- assert.equal(capabilities.length, 16);
+ assert.equal(capabilities.length, 2);
});
});
@@ -3408,20 +3331,6 @@ describe("scaffold question", () => {
);
assert.equal(capabilities.length, 3);
});
- it("should return correct capabilities for office xml addin with outlook host", () => {
- const capabilities = CapabilityOptions.officeAddinDynamicCapabilities(
- ProjectTypeOptions.officeXMLAddin().id,
- OfficeAddinHostOptions.outlook().id
- );
- assert.equal(capabilities.length, 2);
- });
- it("should return correct capabilities for office xml addin with word host", () => {
- const capabilities = CapabilityOptions.officeAddinDynamicCapabilities(
- ProjectTypeOptions.officeXMLAddin().id,
- OfficeAddinHostOptions.word().id
- );
- assert.equal(capabilities.length, 4);
- });
});
});
@@ -3516,37 +3425,6 @@ describe("scaffold question", () => {
assert.equal(lang, "typescript");
});
- it("office xml addin: normal project have ts and js", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: "word-react",
- };
- assert.isDefined(question.dynamicOptions);
- if (question.dynamicOptions) {
- const options = await question.dynamicOptions(inputs);
- assert.deepEqual(options, [
- { label: "TypeScript", id: "typescript" },
- { label: "JavaScript", id: "javascript" },
- ]);
- }
- });
-
- it("office xml addin: manifest-only project only have js option as default", async () => {
- const inputs: Inputs = {
- platform: Platform.CLI,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: "word-manifest",
- };
- assert.isDefined(question.dynamicOptions);
- if (question.dynamicOptions) {
- const options = await question.dynamicOptions(inputs);
- assert.deepEqual(options, [{ label: "JavaScript", id: "javascript" }]);
- }
- });
-
it("office addin: should have typescript as options", async () => {
const inputs: Inputs = { platform: Platform.CLI };
inputs[QuestionNames.Capabilities] = "json-taskpane";
@@ -3635,26 +3513,6 @@ describe("scaffold question", () => {
}
}
});
-
- it("office xml addin: patch coverage getLanguageOptions", async () => {
- sandbox.stub(OfficeAddinProjectConfig, "word").value({
- "word-taskpane": {
- localTemplate: "word-taskpane",
- title: "core.createProjectQuestion.officeXMLAddin.taskpane.title",
- detail: "core.createProjectQuestion.officeXMLAddin.taskpane.detail",
- framework: {
- default: {},
- },
- },
- });
- const inputs: Inputs = {
- platform: Platform.CLI,
- [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id,
- [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id,
- [QuestionNames.Capabilities]: "word-taskpane",
- };
- assert.deepEqual(getLanguageOptions(inputs), []);
- });
});
describe("folderQuestion", () => {
@@ -3673,16 +3531,6 @@ describe("scaffold question", () => {
});
});
- describe("officeAddinHostingQuestion", async () => {
- const q = officeAddinHostingQuestion();
- const options = await q.dynamicOptions!({ platform: Platform.VSCode });
- assert.equal(options.length, 4);
- if (typeof q.default === "function") {
- const defaultV = await q.default({ platform: Platform.VSCode });
- assert.isDefined(defaultV);
- }
- });
-
describe("officeAddinFrameworkQuestion", () => {
const question = officeAddinFrameworkQuestion();
it("office taskpane addin: should have default as options", async () => {
@@ -3742,18 +3590,6 @@ describe("scaffold question", () => {
afterEach(() => {
mockedEnvRestore();
});
- it("trigger from agent", async () => {
- const question = projectTypeQuestion();
- const inputs: Inputs = { platform: Platform.CLI, agent: "office" };
- assert.isDefined(question.dynamicOptions);
- if (question.dynamicOptions) {
- const options = (await question.dynamicOptions(inputs)) as OptionItem[];
- const officeAddinOption = options.find(
- (o) => o.id === ProjectTypeOptions.officeXMLAddin().id
- );
- assert.isDefined(officeAddinOption);
- }
- });
it("show customize GPT if CLI and enable declarative GPT() ", async () => {
mockedEnvRestore = mockedEnv({
[FeatureFlagName.CustomizeGpt]: "true",
diff --git a/packages/fx-core/tests/question/question.test.ts b/packages/fx-core/tests/question/question.test.ts
index 5cec803013..79cb53eb1d 100644
--- a/packages/fx-core/tests/question/question.test.ts
+++ b/packages/fx-core/tests/question/question.test.ts
@@ -24,7 +24,7 @@ import "mocha";
import mockedEnv, { RestoreFn } from "mocked-env";
import * as path from "path";
import sinon from "sinon";
-import { FeatureFlagName } from "../../src/common/constants";
+import { FeatureFlagName } from "../../src/common/featureFlags";
import { manifestUtils } from "../../src/component/driver/teamsApp/utils/ManifestUtils";
import {
newResourceGroupOption,
diff --git a/packages/fx-core/tests/samples/uninstall/env/.env.dev b/packages/fx-core/tests/samples/uninstall/env/.env.dev
new file mode 100644
index 0000000000..8e56da549c
--- /dev/null
+++ b/packages/fx-core/tests/samples/uninstall/env/.env.dev
@@ -0,0 +1,17 @@
+# This file includes environment variables that will be committed to git by default.
+
+# Built-in environment variables
+TEAMSFX_ENV=dev
+APP_NAME_SUFFIX=dev
+
+# Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups.
+AZURE_SUBSCRIPTION_ID=
+AZURE_RESOURCE_GROUP_NAME=
+RESOURCE_SUFFIX=
+
+# Generated during provision, you can also add your own variables.
+TEAMS_APP_ID=123
+M365_TITLE_ID=456
+BOT_ID=789
+TAB_AZURE_STORAGE_RESOURCE_ID=
+TAB_ENDPOINT=
diff --git a/packages/fx-core/tests/samples/uninstall/teamsapp.yml b/packages/fx-core/tests/samples/uninstall/teamsapp.yml
new file mode 100644
index 0000000000..3a4f3f84f0
--- /dev/null
+++ b/packages/fx-core/tests/samples/uninstall/teamsapp.yml
@@ -0,0 +1,150 @@
+# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
+# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
+# Visit https://aka.ms/teamsfx-actions for details on actions
+version: v1.5
+
+environmentFolderPath: ./env
+
+# Triggered when 'teamsapp provision' is executed
+provision:
+ # Creates a Teams app
+ - uses: teamsApp/create
+ with:
+ # Teams app name
+ name: ut-test${{APP_NAME_SUFFIX}}
+ # Write the information of created resources into environment file for
+ # the specified environment variable(s).
+ writeToEnvironmentFile:
+ teamsAppId: TEAMS_APP_ID
+
+ - uses: arm/deploy # Deploy given ARM templates parallelly.
+ with:
+ # AZURE_SUBSCRIPTION_ID is a built-in environment variable,
+ # if its value is empty, TeamsFx will prompt you to select a subscription.
+ # Referencing other environment variables with empty values
+ # will skip the subscription selection prompt.
+ subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
+ # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable,
+ # if its value is empty, TeamsFx will prompt you to select or create one
+ # resource group.
+ # Referencing other environment variables with empty values
+ # will skip the resource group selection prompt.
+ resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
+ templates:
+ - path: ./infra/azure.bicep # Relative path to this file
+ # Relative path to this yaml file.
+ # Placeholders will be replaced with corresponding environment
+ # variable before ARM deployment.
+ parameters: ./infra/azure.parameters.json
+ # Required when deploying ARM template
+ deploymentName: Create-resources-for-tab
+ # Teams Toolkit will download this bicep CLI version from github for you,
+ # will use bicep CLI in PATH if you remove this config.
+ bicepCliVersion: v0.9.1
+
+ # Validate using manifest schema
+ - uses: teamsApp/validateManifest
+ with:
+ # Path to manifest template
+ manifestPath: ./appPackage/manifest.json
+ # Build Teams app package with latest env value
+ - uses: teamsApp/zipAppPackage
+ with:
+ # Path to manifest template
+ manifestPath: ./appPackage/manifest.json
+ outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
+ # Validate app package using validation rules
+ - uses: teamsApp/validateAppPackage
+ with:
+ # Relative path to this file. This is the path for built zip file.
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Apply the Teams app manifest to an existing Teams app in
+ # Teams Developer Portal.
+ # Will use the app id in manifest file to determine which Teams app to update.
+ - uses: teamsApp/update
+ with:
+ # Relative path to this file. This is the path for built zip file.
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Extend your Teams app to Outlook and the Microsoft 365 app
+ - uses: teamsApp/extendToM365
+ with:
+ # Relative path to the build app package.
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Write the information of created resources into environment file for
+ # the specified environment variable(s).
+ writeToEnvironmentFile:
+ titleId: M365_TITLE_ID
+ appId: M365_APP_ID
+ # Create or update the bot registration on dev.botframework.com
+ - uses: botFramework/create
+ with:
+ botId: ${{BOT_ID}}
+ name: ut-test
+ messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
+ description: ""
+ channels:
+ - name: msteams
+
+# Triggered when 'teamsapp deploy' is executed
+deploy:
+ # Run npm command
+ - uses: cli/runNpmCommand
+ name: install dependencies
+ with:
+ args: install
+ - uses: cli/runNpmCommand
+ name: build app
+ with:
+ args: run build --if-present
+ # Deploy your application to Azure App Service using the zip deploy feature.
+ # For additional details, refer to https://aka.ms/zip-deploy-to-app-services.
+ - uses: azureAppService/zipDeploy
+ with:
+ # Deploy base folder
+ artifactFolder: .
+ # Ignore file location, leave blank will ignore nothing
+ ignoreFile: .webappignore
+ # The resource id of the cloud resource to be deployed to.
+ # This key will be generated by arm/deploy action automatically.
+ # You can replace it with your existing Azure Resource id
+ # or add it to your environment variable file.
+ resourceId: ${{TAB_AZURE_APP_SERVICE_RESOURCE_ID}}
+
+# Triggered when 'teamsapp publish' is executed
+publish:
+ # Validate using manifest schema
+ - uses: teamsApp/validateManifest
+ with:
+ # Path to manifest template
+ manifestPath: ./appPackage/manifest.json
+ # Build Teams app package with latest env value
+ - uses: teamsApp/zipAppPackage
+ with:
+ # Path to manifest template
+ manifestPath: ./appPackage/manifest.json
+ outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
+ # Validate app package using validation rules
+ - uses: teamsApp/validateAppPackage
+ with:
+ # Relative path to this file. This is the path for built zip file.
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Apply the Teams app manifest to an existing Teams app in
+ # Teams Developer Portal.
+ # Will use the app id in manifest file to determine which Teams app to update.
+ - uses: teamsApp/update
+ with:
+ # Relative path to this file. This is the path for built zip file.
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Publish the app to
+ # Teams Admin Center (https://admin.teams.microsoft.com/policies/manage-apps)
+ # for review and approval
+ - uses: teamsApp/publishAppPackage
+ with:
+ appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
+ # Write the information of created resources into environment file for
+ # the specified environment variable(s).
+ writeToEnvironmentFile:
+ publishedAppId: TEAMS_APP_PUBLISHED_APP_ID
+projectId: 3daab8cd-e801-4280-829a-a07cb10fe329
diff --git a/packages/metrics-ts/sample/package-lock.json b/packages/metrics-ts/sample/package-lock.json
deleted file mode 100644
index b8df66f2e4..0000000000
--- a/packages/metrics-ts/sample/package-lock.json
+++ /dev/null
@@ -1,3916 +0,0 @@
-{
- "name": "transformer-sample",
- "version": "0.0.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@cspotcode/source-map-support": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
- "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "0.3.9"
- }
- },
- "@jridgewell/resolve-uri": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz",
- "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==",
- "dev": true
- },
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz",
- "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==",
- "dev": true
- },
- "@jridgewell/trace-mapping": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
- "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "dev": true,
- "requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@microsoft/metrics-ts": {
- "version": "file:..",
- "dev": true,
- "requires": {
- "uuid": "^8.3.2"
- },
- "dependencies": {
- "@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "requires": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "requires": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "@babel/compat-data": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.5.tgz",
- "integrity": "sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg=="
- },
- "@babel/core": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz",
- "integrity": "sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ==",
- "requires": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.18.2",
- "@babel/helper-compilation-targets": "^7.18.2",
- "@babel/helper-module-transforms": "^7.18.0",
- "@babel/helpers": "^7.18.2",
- "@babel/parser": "^7.18.5",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.5",
- "@babel/types": "^7.18.4",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "@babel/generator": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz",
- "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==",
- "requires": {
- "@babel/types": "^7.18.2",
- "@jridgewell/gen-mapping": "^0.3.0",
- "jsesc": "^2.5.1"
- },
- "dependencies": {
- "@jridgewell/gen-mapping": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz",
- "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==",
- "requires": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- }
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz",
- "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==",
- "requires": {
- "@babel/compat-data": "^7.17.10",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.20.2",
- "semver": "^6.3.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "@babel/helper-environment-visitor": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz",
- "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ=="
- },
- "@babel/helper-function-name": {
- "version": "7.17.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz",
- "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==",
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.17.0"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz",
- "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==",
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.17.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.0",
- "@babel/types": "^7.18.0"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz",
- "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==",
- "requires": {
- "@babel/types": "^7.18.2"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
- },
- "@babel/helpers": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz",
- "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==",
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.2",
- "@babel/types": "^7.18.2"
- }
- },
- "@babel/highlight": {
- "version": "7.17.12",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz",
- "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- }
- }
- },
- "@babel/parser": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz",
- "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw=="
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- }
- }
- },
- "@babel/traverse": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz",
- "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==",
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.18.2",
- "@babel/helper-environment-visitor": "^7.18.2",
- "@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.18.5",
- "@babel/types": "^7.18.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
- }
- }
- },
- "@babel/types": {
- "version": "7.18.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz",
- "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@cspotcode/source-map-support": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
- "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "requires": {
- "@jridgewell/trace-mapping": "0.3.9"
- },
- "dependencies": {
- "@jridgewell/trace-mapping": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
- "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- }
- }
- },
- "@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
- }
- }
- },
- "@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "requires": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
- }
- },
- "@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
- },
- "@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "requires": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
- }
- }
- },
- "@istanbuljs/nyc-config-typescript": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-1.0.2.tgz",
- "integrity": "sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==",
- "requires": {
- "@istanbuljs/schema": "^0.1.2"
- }
- },
- "@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="
- },
- "@jridgewell/gen-mapping": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
- "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
- "requires": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@jridgewell/resolve-uri": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz",
- "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA=="
- },
- "@jridgewell/set-array": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz",
- "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ=="
- },
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz",
- "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w=="
- },
- "@jridgewell/trace-mapping": {
- "version": "0.3.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz",
- "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==",
- "requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
- },
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
- },
- "@tsconfig/node10": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
- "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA=="
- },
- "@tsconfig/node12": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz",
- "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA=="
- },
- "@tsconfig/node14": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz",
- "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg=="
- },
- "@tsconfig/node16": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
- "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
- },
- "@types/chai": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz",
- "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ=="
- },
- "@types/json-schema": {
- "version": "7.0.11",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
- "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
- },
- "@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
- },
- "@types/mocha": {
- "version": "8.2.3",
- "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz",
- "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw=="
- },
- "@types/node": {
- "version": "16.11.39",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz",
- "integrity": "sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw=="
- },
- "@types/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
- },
- "@typescript-eslint/eslint-plugin": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
- "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
- "requires": {
- "@typescript-eslint/experimental-utils": "4.33.0",
- "@typescript-eslint/scope-manager": "4.33.0",
- "debug": "^4.3.1",
- "functional-red-black-tree": "^1.0.1",
- "ignore": "^5.1.8",
- "regexpp": "^3.1.0",
- "semver": "^7.3.5",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/experimental-utils": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
- "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
- "requires": {
- "@types/json-schema": "^7.0.7",
- "@typescript-eslint/scope-manager": "4.33.0",
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/typescript-estree": "4.33.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^3.0.0"
- }
- },
- "@typescript-eslint/parser": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
- "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
- "requires": {
- "@typescript-eslint/scope-manager": "4.33.0",
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/typescript-estree": "4.33.0",
- "debug": "^4.3.1"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
- "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/visitor-keys": "4.33.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
- "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ=="
- },
- "@typescript-eslint/typescript-estree": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
- "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/visitor-keys": "4.33.0",
- "debug": "^4.3.1",
- "globby": "^11.0.3",
- "is-glob": "^4.0.1",
- "semver": "^7.3.5",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
- "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "eslint-visitor-keys": "^2.0.0"
- }
- },
- "@ungap/promise-all-settled": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
- "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
- },
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
- },
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="
- },
- "acorn-walk": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
- },
- "aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="
- },
- "ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "requires": {
- "type-fest": "^0.21.3"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="
- }
- }
- },
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "append-transform": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
- "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
- "requires": {
- "default-require-extensions": "^3.0.0"
- }
- },
- "archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="
- },
- "arg": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
- "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "array-includes": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
- "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5",
- "get-intrinsic": "^1.1.1",
- "is-string": "^1.0.7"
- }
- },
- "array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
- },
- "array.prototype.flat": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
- "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.2",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "assertion-error": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
- "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
- },
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "browser-stdout": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
- "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
- },
- "browserslist": {
- "version": "4.20.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz",
- "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==",
- "requires": {
- "caniuse-lite": "^1.0.30001349",
- "electron-to-chromium": "^1.4.147",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.5",
- "picocolors": "^1.0.0"
- }
- },
- "builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ=="
- },
- "caching-transform": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
- "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
- "requires": {
- "hasha": "^5.0.0",
- "make-dir": "^3.0.0",
- "package-hash": "^4.0.0",
- "write-file-atomic": "^3.0.0"
- }
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
- },
- "camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
- },
- "caniuse-lite": {
- "version": "1.0.30001352",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz",
- "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA=="
- },
- "chai": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
- "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
- "requires": {
- "assertion-error": "^1.1.0",
- "check-error": "^1.0.2",
- "deep-eql": "^3.0.1",
- "get-func-name": "^2.0.0",
- "loupe": "^2.3.1",
- "pathval": "^1.1.1",
- "type-detect": "^4.0.5"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "check-error": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
- "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA=="
- },
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
- },
- "cli-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
- "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
- "requires": {
- "restore-cursor": "^3.1.0"
- }
- },
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
- }
- }
- },
- "cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "colorette": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.18.tgz",
- "integrity": "sha512-rHDY1i4V4JBCXHnHwaVyA202CKSj2kUrjI5cSJQbTdnFeI4ShV3e19Fe7EQfzL2tjSrvYyWugdGAtEc1lLvGDg=="
- },
- "commander": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
- "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
- },
- "commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
- },
- "convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "requires": {
- "safe-buffer": "~5.1.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "cosmiconfig": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
- "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.2.1",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.10.0"
- }
- },
- "create-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
- "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "decamelize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
- "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="
- },
- "dedent": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
- "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
- },
- "deep-eql": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
- "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
- "requires": {
- "type-detect": "^4.0.0"
- }
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
- },
- "default-require-extensions": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
- "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
- "requires": {
- "strip-bom": "^4.0.0"
- },
- "dependencies": {
- "strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="
- }
- }
- },
- "define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "requires": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- }
- },
- "diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
- },
- "dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "requires": {
- "path-type": "^4.0.0"
- }
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.154",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.154.tgz",
- "integrity": "sha512-GbV9djOkrnj6xmW+YYVVEI3VCQnJ0pnSTu7TW2JyjKd5cakoiSaG5R4RbEtfaD92GsY10DzbU3GYRe+IOA9kqA=="
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "requires": {
- "once": "^1.4.0"
- }
- },
- "enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "requires": {
- "ansi-colors": "^4.1.1"
- }
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "es-abstract": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
- "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "regexp.prototype.flags": "^1.4.3",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- }
- },
- "es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
- },
- "es6-error": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
- "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
- },
- "eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "requires": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "dependencies": {
- "eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "requires": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
- }
- }
- },
- "eslint-import-resolver-node": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
- "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
- "requires": {
- "debug": "^3.2.7",
- "resolve": "^1.20.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "eslint-module-utils": {
- "version": "2.7.3",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
- "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==",
- "requires": {
- "debug": "^3.2.7",
- "find-up": "^2.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "eslint-plugin-import": {
- "version": "2.26.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
- "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
- "requires": {
- "array-includes": "^3.1.4",
- "array.prototype.flat": "^1.2.5",
- "debug": "^2.6.9",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-module-utils": "^2.7.3",
- "has": "^1.0.3",
- "is-core-module": "^2.8.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.values": "^1.1.5",
- "resolve": "^1.22.0",
- "tsconfig-paths": "^3.14.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- }
- }
- },
- "eslint-plugin-no-secrets": {
- "version": "0.8.9",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-secrets/-/eslint-plugin-no-secrets-0.8.9.tgz",
- "integrity": "sha512-CqaBxXrImABCtxMWspAnm8d5UKkpNylC7zqVveb+fJHEvsSiNGJlSWzdSIvBUnW1XhJXkzifNIZQC08rEII5Ng=="
- },
- "eslint-plugin-prettier": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz",
- "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==",
- "requires": {
- "prettier-linter-helpers": "^1.0.0"
- }
- },
- "eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- }
- },
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "requires": {
- "eslint-visitor-keys": "^2.0.0"
- }
- },
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
- },
- "espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "requires": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "requires": {
- "estraverse": "^5.1.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
- }
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "requires": {
- "estraverse": "^5.2.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
- }
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
- },
- "execa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
- "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
- "requires": {
- "cross-spawn": "^7.0.0",
- "get-stream": "^5.0.0",
- "human-signals": "^1.1.1",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.0",
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2",
- "strip-final-newline": "^2.0.0"
- }
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "fast-diff": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
- "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w=="
- },
- "fast-glob": {
- "version": "3.2.11",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
- "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
- "requires": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- }
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
- },
- "fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "find-cache-dir": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
- "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "find-up": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
- "requires": {
- "locate-path": "^2.0.0"
- }
- },
- "flat": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
- "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz",
- "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg=="
- },
- "foreground-child": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
- "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
- "requires": {
- "cross-spawn": "^7.0.0",
- "signal-exit": "^3.0.2"
- }
- },
- "fromentries": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
- "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg=="
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- }
- },
- "functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="
- },
- "functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
- },
- "get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig=="
- },
- "get-intrinsic": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
- "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- }
- },
- "get-own-enumerable-property-symbols": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
- "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g=="
- },
- "get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="
- },
- "get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "globals": {
- "version": "13.15.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
- "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
- },
- "growl": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
- "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ=="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "requires": {
- "get-intrinsic": "^1.1.1"
- }
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
- },
- "has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "hasha": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
- "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
- "requires": {
- "is-stream": "^2.0.0",
- "type-fest": "^0.8.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
- }
- }
- },
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
- },
- "html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
- },
- "human-signals": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
- "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
- },
- "ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
- },
- "indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "requires": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- }
- },
- "is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
- },
- "is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "requires": {
- "has-bigints": "^1.0.1"
- }
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
- },
- "is-core-module": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
- "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
- },
- "is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
- "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="
- },
- "is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-regexp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
- "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA=="
- },
- "is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="
- },
- "is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
- },
- "istanbul-lib-coverage": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
- "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="
- },
- "istanbul-lib-hook": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
- "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
- "requires": {
- "append-transform": "^2.0.0"
- }
- },
- "istanbul-lib-instrument": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
- "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
- "requires": {
- "@babel/core": "^7.7.5",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.0.0",
- "semver": "^6.3.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "istanbul-lib-processinfo": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
- "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
- "requires": {
- "archy": "^1.0.0",
- "cross-spawn": "^7.0.3",
- "istanbul-lib-coverage": "^3.2.0",
- "p-map": "^3.0.0",
- "rimraf": "^3.0.0",
- "uuid": "^8.3.2"
- },
- "dependencies": {
- "p-map": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
- "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- }
- }
- },
- "istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "requires": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "requires": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- }
- },
- "istanbul-reports": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz",
- "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==",
- "requires": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- }
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
- },
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
- },
- "lint-staged": {
- "version": "10.5.4",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz",
- "integrity": "sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==",
- "requires": {
- "chalk": "^4.1.0",
- "cli-truncate": "^2.1.0",
- "commander": "^6.2.0",
- "cosmiconfig": "^7.0.0",
- "debug": "^4.2.0",
- "dedent": "^0.7.0",
- "enquirer": "^2.3.6",
- "execa": "^4.1.0",
- "listr2": "^3.2.2",
- "log-symbols": "^4.0.0",
- "micromatch": "^4.0.2",
- "normalize-path": "^3.0.0",
- "please-upgrade-node": "^3.2.0",
- "string-argv": "0.3.1",
- "stringify-object": "^3.3.0"
- }
- },
- "listr2": {
- "version": "3.14.0",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
- "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
- "requires": {
- "cli-truncate": "^2.1.0",
- "colorette": "^2.0.16",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
- "rfdc": "^1.3.0",
- "rxjs": "^7.5.1",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
- }
- },
- "locate-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
- "requires": {
- "p-locate": "^2.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "lodash.flattendeep": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
- "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ=="
- },
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
- },
- "lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="
- },
- "log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "requires": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- }
- },
- "log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
- "requires": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "loupe": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
- "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
- "requires": {
- "get-func-name": "^2.0.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "requires": {
- "semver": "^6.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
- },
- "merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
- },
- "merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
- },
- "micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "requires": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- }
- },
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
- },
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
- },
- "mkdirp": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
- "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
- "requires": {
- "minimist": "^1.2.6"
- }
- },
- "mocha": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
- "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
- "requires": {
- "@ungap/promise-all-settled": "1.1.2",
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.3",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "7.2.0",
- "growl": "1.10.5",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "4.2.1",
- "ms": "2.1.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "which": "2.0.2",
- "workerpool": "6.2.0",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
- },
- "dependencies": {
- "ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
- },
- "debug": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
- "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "dependencies": {
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- }
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "requires": {
- "argparse": "^2.0.1"
- }
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "minimatch": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
- "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
- },
- "node-preload": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
- "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
- "requires": {
- "process-on-spawn": "^1.0.0"
- }
- },
- "node-releases": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
- "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q=="
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "requires": {
- "path-key": "^3.0.0"
- }
- },
- "nyc": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
- "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
- "requires": {
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "caching-transform": "^4.0.0",
- "convert-source-map": "^1.7.0",
- "decamelize": "^1.2.0",
- "find-cache-dir": "^3.2.0",
- "find-up": "^4.1.0",
- "foreground-child": "^2.0.0",
- "get-package-type": "^0.1.0",
- "glob": "^7.1.6",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-hook": "^3.0.0",
- "istanbul-lib-instrument": "^4.0.0",
- "istanbul-lib-processinfo": "^2.0.2",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.0.2",
- "make-dir": "^3.0.0",
- "node-preload": "^0.2.1",
- "p-map": "^3.0.0",
- "process-on-spawn": "^1.0.0",
- "resolve-from": "^5.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "spawn-wrap": "^2.0.0",
- "test-exclude": "^6.0.0",
- "yargs": "^15.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-map": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
- "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
- },
- "yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "requires": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- }
- }
- },
- "object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
- },
- "object.assign": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
- "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3",
- "has-symbols": "^1.0.1",
- "object-keys": "^1.1.1"
- }
- },
- "object.values": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
- "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "requires": {
- "wrappy": "1"
- }
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "requires": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- }
- },
- "p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
- "requires": {
- "p-try": "^1.0.0"
- }
- },
- "p-locate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
- "requires": {
- "p-limit": "^1.1.0"
- }
- },
- "p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="
- },
- "package-hash": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
- "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
- "requires": {
- "graceful-fs": "^4.1.15",
- "hasha": "^5.0.0",
- "lodash.flattendeep": "^4.4.0",
- "release-zalgo": "^1.0.0"
- }
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- },
- "pathval": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
- "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "requires": {
- "find-up": "^4.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- }
- }
- },
- "please-upgrade-node": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
- "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
- "requires": {
- "semver-compare": "^1.0.0"
- }
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
- },
- "prettier": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz",
- "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew=="
- },
- "prettier-linter-helpers": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
- "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
- "requires": {
- "fast-diff": "^1.1.2"
- }
- },
- "process-on-spawn": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
- "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
- "requires": {
- "fromentries": "^1.2.0"
- }
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
- },
- "pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- },
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
- },
- "randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "requires": {
- "safe-buffer": "^5.1.0"
- }
- },
- "readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- }
- },
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="
- },
- "release-zalgo": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
- "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
- "requires": {
- "es6-error": "^4.0.1"
- }
- },
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
- },
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
- },
- "require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
- },
- "resolve": {
- "version": "1.22.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
- "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
- "requires": {
- "is-core-module": "^2.8.1",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
- },
- "restore-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
- "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
- "requires": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- }
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
- },
- "rfdc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
- "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "rxjs": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz",
- "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==",
- "requires": {
- "tslib": "^2.1.0"
- },
- "dependencies": {
- "tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
- }
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- },
- "semver": {
- "version": "7.3.7",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
- "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "semver-compare": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
- "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="
- },
- "serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
- },
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- }
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- },
- "spawn-wrap": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
- "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
- "requires": {
- "foreground-child": "^2.0.0",
- "is-windows": "^1.0.2",
- "make-dir": "^3.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "which": "^2.0.1"
- }
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
- },
- "string-argv": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
- "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg=="
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- }
- },
- "stringify-object": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
- "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
- "requires": {
- "get-own-enumerable-property-symbols": "^3.0.0",
- "is-obj": "^1.0.1",
- "is-regexp": "^1.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
- },
- "strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
- },
- "table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
- "requires": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
- }
- }
- },
- "test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "requires": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "ts-node": {
- "version": "10.8.1",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz",
- "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==",
- "requires": {
- "@cspotcode/source-map-support": "^0.8.0",
- "@tsconfig/node10": "^1.0.7",
- "@tsconfig/node12": "^1.0.7",
- "@tsconfig/node14": "^1.0.0",
- "@tsconfig/node16": "^1.0.2",
- "acorn": "^8.4.1",
- "acorn-walk": "^8.1.1",
- "arg": "^4.1.0",
- "create-require": "^1.1.0",
- "diff": "^4.0.1",
- "make-error": "^1.1.1",
- "v8-compile-cache-lib": "^3.0.1",
- "yn": "3.1.1"
- },
- "dependencies": {
- "acorn": {
- "version": "8.7.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
- "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A=="
- },
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
- }
- }
- },
- "tsconfig-paths": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
- "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
- "requires": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.1",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "tslint": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
- "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "builtin-modules": "^1.1.1",
- "chalk": "^2.3.0",
- "commander": "^2.12.1",
- "diff": "^4.0.1",
- "glob": "^7.1.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "mkdirp": "^0.5.3",
- "resolve": "^1.3.2",
- "semver": "^5.3.0",
- "tslib": "^1.13.0",
- "tsutils": "^2.29.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
- },
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
- },
- "tsutils": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
- "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
- "requires": {
- "tslib": "^1.8.1"
- }
- }
- }
- },
- "tslint-config-prettier": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz",
- "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg=="
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "requires": {
- "tslib": "^1.8.1"
- }
- },
- "ttypescript": {
- "version": "1.5.13",
- "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.13.tgz",
- "integrity": "sha512-KT/RBfGGlVJFqEI8cVvI3nMsmYcFvPSZh8bU0qX+pAwbi7/ABmYkzn7l/K8skw0xmYjVCoyaV6WLsBQxdadybQ==",
- "requires": {
- "resolve": ">=1.9.0"
- }
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
- },
- "typedarray-to-buffer": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
- "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
- "requires": {
- "is-typedarray": "^1.0.0"
- }
- },
- "typescript": {
- "version": "4.7.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz",
- "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA=="
- },
- "unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- }
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
- },
- "v8-compile-cache": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
- "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
- },
- "v8-compile-cache-lib": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
- "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "requires": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- }
- },
- "which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
- },
- "word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
- },
- "workerpool": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
- "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A=="
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- }
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
- "requires": {
- "imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
- },
- "yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
- "requires": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
- }
- },
- "yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="
- },
- "yargs-unparser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
- "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
- "requires": {
- "camelcase": "^6.0.0",
- "decamelize": "^4.0.0",
- "flat": "^5.0.2",
- "is-plain-obj": "^2.1.0"
- }
- },
- "yn": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
- "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
- }
- }
- },
- "@tsconfig/node10": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
- "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
- "dev": true
- },
- "@tsconfig/node12": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz",
- "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==",
- "dev": true
- },
- "@tsconfig/node14": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz",
- "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==",
- "dev": true
- },
- "@tsconfig/node16": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
- "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
- "dev": true
- },
- "@types/node": {
- "version": "16.11.41",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
- "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==",
- "dev": true
- },
- "acorn": {
- "version": "8.7.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
- "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
- "dev": true
- },
- "acorn-walk": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "dev": true
- },
- "arg": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
- "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "dev": true
- },
- "create-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
- "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "dev": true
- },
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "is-core-module": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
- "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "resolve": {
- "version": "1.22.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
- "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
- "dev": true,
- "requires": {
- "is-core-module": "^2.8.1",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- },
- "supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true
- },
- "ts-node": {
- "version": "10.8.1",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz",
- "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==",
- "dev": true,
- "requires": {
- "@cspotcode/source-map-support": "^0.8.0",
- "@tsconfig/node10": "^1.0.7",
- "@tsconfig/node12": "^1.0.7",
- "@tsconfig/node14": "^1.0.0",
- "@tsconfig/node16": "^1.0.2",
- "acorn": "^8.4.1",
- "acorn-walk": "^8.1.1",
- "arg": "^4.1.0",
- "create-require": "^1.1.0",
- "diff": "^4.0.1",
- "make-error": "^1.1.1",
- "v8-compile-cache-lib": "^3.0.1",
- "yn": "3.1.1"
- }
- },
- "ttypescript": {
- "version": "1.5.13",
- "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.13.tgz",
- "integrity": "sha512-KT/RBfGGlVJFqEI8cVvI3nMsmYcFvPSZh8bU0qX+pAwbi7/ABmYkzn7l/K8skw0xmYjVCoyaV6WLsBQxdadybQ==",
- "dev": true,
- "requires": {
- "resolve": ">=1.9.0"
- }
- },
- "typescript": {
- "version": "4.7.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
- "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
- "dev": true
- },
- "v8-compile-cache-lib": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
- "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "dev": true
- },
- "yn": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
- "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "dev": true
- }
- }
-}
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index df0798da0d..6168e34582 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -51,10 +51,10 @@
"@microsoft/adaptivecards-tools": "workspace:*",
"@microsoft/microsoft-graph-client": "^3.0.7",
"axios": "^1.6.8",
- "botbuilder": "^4.22.1",
- "botbuilder-dialogs": "^4.22.1",
- "botframework-connector": "^4.22.1",
- "botframework-schema": "^4.22.1",
+ "botbuilder": "^4.22.3",
+ "botbuilder-dialogs": "^4.22.3",
+ "botframework-connector": "^4.22.3",
+ "botframework-schema": "^4.22.3",
"jwt-decode": "^3.1.2",
"tedious": "^14.3.0",
"uuid": "^8.3.2"
@@ -86,7 +86,7 @@
"adm-zip": "^0.5.9",
"assertion-error": "^2.0.0",
"axios-mock-adapter": "^1.20.0",
- "botbuilder-core": "^4.22.1",
+ "botbuilder-core": "^4.22.3",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"check-error": "^2.0.0",
diff --git a/packages/sdk/pnpm-lock.yaml b/packages/sdk/pnpm-lock.yaml
index 1e70ee336e..08a4515851 100644
--- a/packages/sdk/pnpm-lock.yaml
+++ b/packages/sdk/pnpm-lock.yaml
@@ -27,17 +27,17 @@ dependencies:
specifier: ^1.6.8
version: 1.6.8
botbuilder:
- specifier: ^4.22.1
- version: 4.22.1(supports-color@9.4.0)
+ specifier: ^4.22.3
+ version: 4.22.3(supports-color@9.4.0)
botbuilder-dialogs:
- specifier: ^4.22.1
- version: 4.22.1(supports-color@9.4.0)
+ specifier: ^4.22.3
+ version: 4.22.3(supports-color@9.4.0)
botframework-connector:
- specifier: ^4.22.1
- version: 4.22.1(supports-color@9.4.0)
+ specifier: ^4.22.3
+ version: 4.22.3(supports-color@9.4.0)
botframework-schema:
- specifier: ^4.22.1
- version: 4.22.1
+ specifier: ^4.22.3
+ version: 4.22.3
jwt-decode:
specifier: ^3.1.2
version: 3.1.2
@@ -119,8 +119,8 @@ devDependencies:
specifier: ^1.20.0
version: 1.20.0(axios@1.6.8)
botbuilder-core:
- specifier: ^4.22.1
- version: 4.22.1(supports-color@9.4.0)
+ specifier: ^4.22.3
+ version: 4.22.3(supports-color@9.4.0)
chai:
specifier: ^4.3.4
version: 4.3.4
@@ -439,7 +439,7 @@ packages:
'@azure/logger': 1.0.4
'@azure/msal-browser': 2.38.3
'@azure/msal-common': 7.6.0
- '@azure/msal-node': 1.14.6
+ '@azure/msal-node': 1.18.4
events: 3.3.0
jws: 4.0.0
open: 8.4.2
@@ -512,6 +512,7 @@ packages:
/@azure/msal-common@9.1.1:
resolution: {integrity: sha512-we9xR8lvu47fF0h+J8KyXoRy9+G/fPzm3QEa2TrdR3jaVS3LKAyE2qyMuUkNdbVkvzl8Zr9f7l+IUSP22HeqXw==}
engines: {node: '>=0.8.0'}
+ dev: false
/@azure/msal-node@1.14.6:
resolution: {integrity: sha512-em/qqFL5tLMxMPl9vormAs13OgZpmQoJbiQ/GlWr+BA77eCLoL+Ehr5xRHowYo+LFe5b+p+PJVkRvT+mLvOkwA==}
@@ -521,6 +522,16 @@ packages:
'@azure/msal-common': 9.1.1
jsonwebtoken: 9.0.2
uuid: 8.3.2
+ dev: false
+
+ /@azure/msal-node@1.18.4:
+ resolution: {integrity: sha512-Kc/dRvhZ9Q4+1FSfsTFDME/v6+R2Y1fuMty/TfwqE5p9GTPw08BPbKgeWinE8JRHRp+LemjQbUZsn4Q4l6Lszg==}
+ engines: {node: 10 || 12 || 14 || 16 || 18}
+ deprecated: A newer major version of this library is available. Please upgrade to the latest available version.
+ dependencies:
+ '@azure/msal-common': 13.3.1
+ jsonwebtoken: 9.0.2
+ uuid: 8.3.2
/@babel/code-frame@7.23.5:
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
@@ -1235,6 +1246,11 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
+ /@types/jsonwebtoken@8.3.5:
+ resolution: {integrity: sha512-VGM1gb+LwsQ5EPevvbvdnKncajBdYqNcrvixBif1BsiDQiSF1q+j4bBTvKC6Bt9n2kqNSx+yNTY2TVJ360E7EQ==}
+ dependencies:
+ '@types/node': 16.11.7
+
/@types/jsonwebtoken@9.0.2:
resolution: {integrity: sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==}
dependencies:
@@ -1875,6 +1891,15 @@ packages:
transitivePeerDependencies:
- debug
+ /axios@1.7.2:
+ resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
+ dependencies:
+ follow-redirects: 1.15.6
+ form-data: 4.0.0
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@@ -1936,58 +1961,60 @@ packages:
- supports-color
dev: true
- /botbuilder-core@4.22.1(supports-color@9.4.0):
- resolution: {integrity: sha512-ZT1hixW9Badsytm1YFzfXkfPrjaTWru1yIe4kPEtB4X7rorqdU1wvwMylqvi0x34oiUhwmJPcvm82c9VpRsVmw==}
+ /botbuilder-core@4.22.3(supports-color@9.4.0):
+ resolution: {integrity: sha512-159+ugNI/gp7u+ByYWIjVPE6csFEMfJzbYISf1HVFHhw0m/h0zEyXMvjoiwGu/fA7TI+TtpuFLdh75roEodOsw==}
dependencies:
- botbuilder-dialogs-adaptive-runtime-core: 4.22.1-preview
- botbuilder-stdlib: 4.22.1-internal
- botframework-connector: 4.22.1(supports-color@9.4.0)
- botframework-schema: 4.22.1
+ botbuilder-dialogs-adaptive-runtime-core: 4.22.3-preview
+ botbuilder-stdlib: 4.22.3-internal
+ botframework-connector: 4.22.3(supports-color@9.4.0)
+ botframework-schema: 4.22.3
uuid: 8.3.2
zod: 3.22.4
transitivePeerDependencies:
+ - debug
- encoding
- supports-color
- /botbuilder-dialogs-adaptive-runtime-core@4.22.1-preview:
- resolution: {integrity: sha512-Zzbbl2kKCHqAHbz/zf3ZG1JLCPVk2UD26gWjIVqqBgACdwMj2MPZ4w5FkBQ0eKHvSZvbNATVVqvP4NdHCd/AZQ==}
+ /botbuilder-dialogs-adaptive-runtime-core@4.22.3-preview:
+ resolution: {integrity: sha512-JbVKKmriLwUOgBI040unl5xVTmGhESFXnvC3O75nDzjFjdRpaIAwA2/L7ik6E3O4bOkwO2jDov2W+LWlbSnjXQ==}
dependencies:
dependency-graph: 0.10.0
- /botbuilder-dialogs@4.22.1(supports-color@9.4.0):
- resolution: {integrity: sha512-iCrB6w9XG2LWAXlt9PoNTIdx62D23nqx8+6TzoYN6WYoKMXZvoDQWtkopsr3EywCbsq/sAc5v3UmrvPyVK+dWA==}
+ /botbuilder-dialogs@4.22.3(supports-color@9.4.0):
+ resolution: {integrity: sha512-mrMVz+aiYoLCwIEpYzTyMXvrMVrxSl4OXWD1nFA7brlwbHwb6McG423I0DKoDTRN7buOLYY4CCWItXMp2mRq8Q==}
requiresBuild: true
dependencies:
'@microsoft/recognizers-text-choice': 1.1.4
'@microsoft/recognizers-text-date-time': 1.1.4
'@microsoft/recognizers-text-number': 1.3.1
'@microsoft/recognizers-text-suite': 1.1.4
- botbuilder-core: 4.22.1(supports-color@9.4.0)
- botbuilder-dialogs-adaptive-runtime-core: 4.22.1-preview
- botframework-connector: 4.22.1(supports-color@9.4.0)
+ botbuilder-core: 4.22.3(supports-color@9.4.0)
+ botbuilder-dialogs-adaptive-runtime-core: 4.22.3-preview
+ botframework-connector: 4.22.3(supports-color@9.4.0)
globalize: 1.7.0
lodash: 4.17.21
uuid: 8.3.2
zod: 3.22.4
transitivePeerDependencies:
+ - debug
- encoding
- supports-color
dev: false
- /botbuilder-stdlib@4.22.1-internal:
- resolution: {integrity: sha512-iPTO//HYfqwwvmbVtWZFkffRVSkxz/fesE60nMPVxGe93XkHSXgNVaZKjKnxjbX192LQFubae0777pCYBD6hsQ==}
+ /botbuilder-stdlib@4.22.3-internal:
+ resolution: {integrity: sha512-DZwHRHpEZQNDQ426RpSmEpNKm9V/5k11lpXmQ41Eq2g0LHdaz1TqgV97US+Mj7Xyp4Fngp23HWcGivU8bQeArA==}
- /botbuilder@4.22.1(supports-color@9.4.0):
- resolution: {integrity: sha512-dkg1RzN1GVmjZ0+J91U4VZ1Lyoq9Oal3NzZsTfO9fPNvNoxLYUGbbH1PGNcm0qEK4gp5XvNtuRgPi6Mm6q5MiA==}
+ /botbuilder@4.22.3(supports-color@9.4.0):
+ resolution: {integrity: sha512-vmsCBaqC6mvX9Kr6xVvU0Zlblh1d923HTXJqs196QspDMX9sedmxORfgX3u3P1vNXqx5jt4ODm52k5Aau+IP+w==}
dependencies:
'@azure/core-http': 3.0.4
- '@azure/msal-node': 1.14.6
- axios: 1.6.8
- botbuilder-core: 4.22.1(supports-color@9.4.0)
- botbuilder-stdlib: 4.22.1-internal
- botframework-connector: 4.22.1(supports-color@9.4.0)
- botframework-schema: 4.22.1
- botframework-streaming: 4.22.1
+ '@azure/msal-node': 1.18.4
+ axios: 1.7.2
+ botbuilder-core: 4.22.3(supports-color@9.4.0)
+ botbuilder-stdlib: 4.22.3-internal
+ botframework-connector: 4.22.3(supports-color@9.4.0)
+ botframework-schema: 4.22.3
+ botframework-streaming: 4.22.3
dayjs: 1.11.10
filenamify: 4.3.0
fs-extra: 7.0.1
@@ -2002,15 +2029,17 @@ packages:
- utf-8-validate
dev: false
- /botframework-connector@4.22.1(supports-color@9.4.0):
- resolution: {integrity: sha512-uo3KrIyj6D8P9kWk7AKd00XDkCuTk/LqH1Jx0jGQCkfjHCVFfGclgNZcqUdgZkQkWcisk5QOtTSPGAl4a92TpA==}
+ /botframework-connector@4.22.3(supports-color@9.4.0):
+ resolution: {integrity: sha512-xsGFfphSMECvaBJynWmvSXbG8o72WqX8Ba885kz/lxGXu1f6CjTObO0enxQdtH9O7YmCX4T0xOaHiFxnU2U61A==}
dependencies:
'@azure/core-http': 3.0.4
'@azure/identity': 2.1.0(supports-color@9.4.0)
- '@azure/msal-node': 1.14.6
+ '@azure/msal-node': 1.18.4
+ '@types/jsonwebtoken': 8.3.5
+ axios: 1.7.2
base64url: 3.0.1
- botbuilder-stdlib: 4.22.1-internal
- botframework-schema: 4.22.1
+ botbuilder-stdlib: 4.22.3-internal
+ botframework-schema: 4.22.3
cross-fetch: 3.1.8
https-proxy-agent: 7.0.4(supports-color@9.4.0)
jsonwebtoken: 9.0.2
@@ -2019,23 +2048,24 @@ packages:
rsa-pem-from-mod-exp: 0.8.6
zod: 3.22.4
transitivePeerDependencies:
+ - debug
- encoding
- supports-color
- /botframework-schema@4.22.1:
- resolution: {integrity: sha512-4hE7iMYMgLz+L+MrgkZ7Y1pir3ze5Puhjko0a/VKkLUXkoSTHcZ5P0mIqhl/lxu7TlrREtGanGsX0rWkQ8+FJA==}
+ /botframework-schema@4.22.3:
+ resolution: {integrity: sha512-8d/IgrFPrVIJFOqExASROYYaV4ikQvDIq60sEN2DphVS+Cnlvm65Tl/6vv+3c27A6xrih23nyvjgAafhLmZ1gQ==}
dependencies:
adaptivecards: 1.2.3
uuid: 8.3.2
zod: 3.22.4
- /botframework-streaming@4.22.1:
- resolution: {integrity: sha512-M/bxRowgjCwdCHZ/oKtyQdXN2pFx2AQWoSfoPwRv5nXr0I+W9Yl2m/2d1Y4W4xLbnGLxZtaJtLh5en7RBSnGVg==}
+ /botframework-streaming@4.22.3:
+ resolution: {integrity: sha512-N0lI6eezH1wj5fkB+L5W+lDLL3EOOpqfj6OEf7xgzIdoJrDZy4vK/du66ptzWKZveyWK2MDd5Xme+pOm2H6dRA==}
dependencies:
'@types/node': 10.17.60
'@types/ws': 6.0.4
uuid: 8.3.2
- ws: 7.5.9
+ ws: 7.5.10
transitivePeerDependencies:
- bufferutil
- utf-8-validate
@@ -6825,8 +6855,8 @@ packages:
typedarray-to-buffer: 3.1.5
dev: true
- /ws@7.5.9:
- resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==}
+ /ws@7.5.10:
+ resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}
engines: {node: '>=8.3.0'}
peerDependencies:
bufferutil: ^4.0.1
diff --git a/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts b/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts
index 616e63c43e..b1b732e3ec 100644
--- a/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts
+++ b/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { assert, expect, use as chaiUse } from "chai";
+import * as chai from "chai";
import * as chaiPromises from "chai-as-promised";
import { AccessToken } from "@azure/core-auth";
import * as sinon from "sinon";
@@ -9,7 +9,7 @@ import { getSSOToken, AADJwtPayLoad, SSOToken, getGraphToken } from "../helper.b
import jwtDecode from "jwt-decode";
import { AccountInfo, AuthenticationResult, PublicClientApplication } from "@azure/msal-browser";
-chaiUse(chaiPromises);
+chai.use(chaiPromises);
const env = (window as any).__env__;
describe("TeamsUserCredential Tests - Browser", () => {
@@ -41,10 +41,10 @@ describe("TeamsUserCredential Tests - Browser", () => {
clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID,
});
const info = await credential.getUserInfo();
- assert.strictEqual(info.preferredUserName, env.SDK_INTEGRATION_TEST_ACCOUNT.split(";")[0]);
- assert.strictEqual(info.displayName, "Integration Test");
- assert.strictEqual(info.objectId, TEST_USER_OBJECT_ID);
- assert.strictEqual(info.tenantId, TEST_AAD_TENANT_ID);
+ chai.assert.strictEqual(info.preferredUserName, env.SDK_INTEGRATION_TEST_ACCOUNT.split(";")[0]);
+ chai.assert.strictEqual(info.displayName, "TestBot");
+ chai.assert.strictEqual(info.objectId, TEST_USER_OBJECT_ID);
+ chai.assert.strictEqual(info.tenantId, TEST_AAD_TENANT_ID);
});
it("GetToken should success with consent scope", async function () {
@@ -77,8 +77,8 @@ describe("TeamsUserCredential Tests - Browser", () => {
// await expect(credential.getToken(["User.Read"])).to.be.eventually.have.property("token");
const accessToken = await credential.getToken(["User.Read"]);
const decodedToken = jwtDecode(accessToken!.token);
- assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000");
- assert.isTrue(decodedToken.scp!.includes("User.Read"));
+ chai.assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000");
+ chai.assert.isTrue(decodedToken.scp!.includes("User.Read"));
});
it("GetToken should throw UiRequiredError with unconsent scope", async function () {
@@ -86,7 +86,8 @@ describe("TeamsUserCredential Tests - Browser", () => {
initiateLoginEndpoint: FAKE_LOGIN_ENDPOINT,
clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID,
});
- await expect(credential.getToken(["Calendars.Read"]))
+ await chai
+ .expect(credential.getToken(["Calendars.Read"]))
.to.eventually.be.rejectedWith(ErrorWithCode)
.and.property("code", UIREQUIREDERROR);
});
diff --git a/packages/sdk/test/e2e/helper.browser.ts b/packages/sdk/test/e2e/helper.browser.ts
index 1224d313cc..198de0dd5d 100644
--- a/packages/sdk/test/e2e/helper.browser.ts
+++ b/packages/sdk/test/e2e/helper.browser.ts
@@ -37,7 +37,7 @@ export async function getSSOToken(): Promise {
username: env.SDK_INTEGRATION_TEST_ACCOUNT_NAME,
password: env.SDK_INTEGRATION_TEST_ACCOUNT_PASSWORD,
client_id: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID,
- scope: `api://localhost/${env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`,
+ scope: `api://localhost:53000/${env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`,
grant_type: "password",
};
const formBody = [];
diff --git a/packages/sdk/test/e2e/helper.ts b/packages/sdk/test/e2e/helper.ts
index 731f984822..717a8d0848 100644
--- a/packages/sdk/test/e2e/helper.ts
+++ b/packages/sdk/test/e2e/helper.ts
@@ -17,16 +17,6 @@ export function extractIntegrationEnvVariables() {
process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME = accountData[0];
process.env.SDK_INTEGRATION_TEST_ACCOUNT_PASSWORD = accountData[1];
}
- if (!process.env.SDK_INTEGRATION_TEST_SQL) {
- throw new Error("Please set env SDK_INTEGRATION_TEST_SQL");
- }
- const sqlData = process.env.SDK_INTEGRATION_TEST_SQL.split(";");
- if (sqlData.length === 4) {
- process.env.SDK_INTEGRATION_SQL_ENDPOINT = sqlData[0];
- process.env.SDK_INTEGRATION_SQL_DATABASE_NAME = sqlData[1];
- process.env.SDK_INTEGRATION_SQL_USER_NAME = sqlData[2];
- process.env.SDK_INTEGRATION_SQL_PASSWORD = sqlData[3];
- }
if (!process.env.SDK_INTEGRATION_TEST_AAD) {
throw new Error("Please set env SDK_INTEGRATION_TEST_AAD");
}
@@ -71,7 +61,7 @@ export async function getAccessToken(
if (scope) {
scopes = [scope];
} else {
- const defaultScope = `api://localhost/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`;
+ const defaultScope = `api://localhost:53000/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`;
scopes = [defaultScope!];
}
const pca = new msal.PublicClientApplication(msalConfig);
@@ -112,7 +102,7 @@ export async function getSsoTokenFromTeams(): Promise {
process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME!,
process.env.SDK_INTEGRATION_TEST_ACCOUNT_PASSWORD!,
process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID!,
- `api://localhost/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`
+ `api://localhost:53000/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}/access_as_user`
);
}
@@ -127,12 +117,7 @@ export function MockEnvironmentVariable(): () => void {
M365_TENANT_ID: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID,
M365_AUTHORITY_HOST: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST,
INITIATE_LOGIN_ENDPOINT: "fake_initiate_login_endpoint",
- M365_APPLICATION_ID_URI: `api://localhost/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}`,
-
- SQL_ENDPOINT: process.env.SDK_INTEGRATION_SQL_ENDPOINT,
- SQL_DATABASE_NAME: process.env.SDK_INTEGRATION_SQL_DATABASE_NAME,
- SQL_USER_NAME: process.env.SDK_INTEGRATION_SQL_USER_NAME,
- SQL_PASSWORD: process.env.SDK_INTEGRATION_SQL_PASSWORD,
+ M365_APPLICATION_ID_URI: `api://localhost:53000/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}`,
});
}
diff --git a/packages/sdk/test/e2e/node/sqlConnector.spec.ts b/packages/sdk/test/e2e/node/sqlConnector.spec.ts
deleted file mode 100644
index 52a5902cea..0000000000
--- a/packages/sdk/test/e2e/node/sqlConnector.spec.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-import { assert, use as chaiUse } from "chai";
-import * as chaiPromises from "chai-as-promised";
-import { Connection, Request } from "tedious";
-import { getTediousConnectionConfig, TeamsFx } from "../../../src";
-import {
- extractIntegrationEnvVariables,
- MockEnvironmentVariable,
- RestoreEnvironmentVariable,
-} from "../helper";
-
-chaiUse(chaiPromises);
-extractIntegrationEnvVariables();
-let restore: () => void;
-
-describe("DefaultTediousConnection Tests - Node", () => {
- let connection: Connection;
- // let sqlManagerClient: SqlManagementClient;
- // let resourceGroup: string | undefined;
- // let sqlName: string | undefined;
- // let subscriptionId: string | undefined;
- before(async () => {
- restore = MockEnvironmentVariable();
- // resourceGroup = process.env.SDK_INTEGRATION_RESOURCE_GROUP_NAME;
- // subscriptionId = process.env.SDK_INTEGRATION_TEST_ACCOUNT_SUBSCRIPTION_ID;
- // const sqlEndpoint: string | undefined = process.env.SDK_INTEGRATION_SQL_ENDPOINT;
- // sqlName = sqlEndpoint!.slice(0, sqlEndpoint!.indexOf("."));
-
- // const tokenCredential = await getSQLManagerClient();
- // sqlManagerClient = new SqlManagementClient(tokenCredential!, subscriptionId!);
- // await addLocalFirewall(sqlManagerClient, resourceGroup!, sqlName!);
- });
- after(async () => {
- RestoreEnvironmentVariable(restore);
- // await clearUpLocalFirewall(sqlManagerClient, resourceGroup!, sqlName!);
- });
- it("execQuery should success with username and password", async function () {
- connection = await getSQLConnection();
- const query = "select system_user as u, sysdatetime() as t";
- const result = await execQuery(query, connection);
- const userName = process.env.SDK_INTEGRATION_SQL_USER_NAME;
- assert.isNotNull(result);
- assert.isArray(result);
- assert.strictEqual(result![0]![0], userName);
-
- connection.close();
- });
-});
-
-const echoIpAddress = "https://api.ipify.org";
-const localRule = "FirewallAllowLocalIP";
-
-async function getSQLConnection(): Promise {
- const teamsfx = new TeamsFx();
- const config = await getTediousConnectionConfig(teamsfx);
- const connection = new Connection(config);
- return new Promise((resolve, reject) => {
- connection.on("connect", (error) => {
- if (error) {
- console.log(error);
- reject(connection);
- }
- resolve(connection);
- });
- connection.connect((err: any) => {
- if (err) {
- reject(err);
- }
- });
- });
-}
-
-async function execQuery(query: string, connection: Connection): Promise {
- return new Promise((resolve, reject) => {
- const res: any[] = [];
- const request = new Request(query, (err) => {
- if (err) {
- throw err;
- }
- });
-
- request.on("row", (columns) => {
- const row: string[] = [];
- columns.forEach((column) => {
- row.push(column.value);
- });
- res.push(row);
- });
- request.on("requestCompleted", () => {
- resolve(res);
- });
- request.on("error", () => {
- console.error("SQL execQuery failed");
- reject(res);
- });
- connection.execSql(request);
- });
-}
diff --git a/packages/server/package.json b/packages/server/package.json
index 8a1ff042d5..f7fc73df52 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -102,7 +102,7 @@
"underscore": "^1.12.1",
"validator": "^13.7.0",
"vscode-jsonrpc": "^6.0.0",
- "ws": "^8.2.3"
+ "ws": "^8.17.1"
},
"optionalDependencies": {
"keytar": "^7.7.0"
diff --git a/packages/server/pnpm-lock.yaml b/packages/server/pnpm-lock.yaml
index f4b98238fa..79aa052596 100644
--- a/packages/server/pnpm-lock.yaml
+++ b/packages/server/pnpm-lock.yaml
@@ -33,8 +33,8 @@ dependencies:
specifier: ^6.0.0
version: 6.0.0
ws:
- specifier: ^8.2.3
- version: 8.2.3
+ specifier: ^8.17.1
+ version: 8.17.1
optionalDependencies:
keytar:
@@ -5677,12 +5677,12 @@ packages:
typedarray-to-buffer: 3.1.5
dev: true
- /ws@8.2.3:
- resolution: {integrity: sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==}
+ /ws@8.17.1:
+ resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
- utf-8-validate: ^5.0.2
+ utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
diff --git a/packages/server/src/serverConnection.ts b/packages/server/src/serverConnection.ts
index e5207a6942..1e4db860a5 100644
--- a/packages/server/src/serverConnection.ts
+++ b/packages/server/src/serverConnection.ts
@@ -418,7 +418,7 @@ export default class ServerConnection implements IServerConnection {
const corrId = inputs.correlationId ? inputs.correlationId : "";
const res = await Correlator.runWithId(
corrId,
- (params) => listDevTunnels(inputs.devTunnelToken),
+ (params) => listDevTunnels(inputs.devTunnelToken, inputs.isGitHub),
inputs
);
return standardizeResult(res);
diff --git a/packages/spec-parser/src/adaptiveCardGenerator.ts b/packages/spec-parser/src/adaptiveCardGenerator.ts
index fbfd250560..4ebaa9fd4e 100644
--- a/packages/spec-parser/src/adaptiveCardGenerator.ts
+++ b/packages/spec-parser/src/adaptiveCardGenerator.ts
@@ -155,7 +155,7 @@ export class AdaptiveCardGenerator {
{
type: "Image",
url: `\${${name}}`,
- $when: `\${${name} != null}`,
+ $when: `\${${name} != null && ${name} != ''}`,
},
];
} else {
@@ -163,7 +163,7 @@ export class AdaptiveCardGenerator {
{
type: "Image",
url: "${$data}",
- $when: "${$data != null}",
+ $when: "${$data != null && $data != ''}",
},
];
}
diff --git a/packages/spec-parser/src/adaptiveCardWrapper.ts b/packages/spec-parser/src/adaptiveCardWrapper.ts
index 200e496698..f91c3ca4cd 100644
--- a/packages/spec-parser/src/adaptiveCardWrapper.ts
+++ b/packages/spec-parser/src/adaptiveCardWrapper.ts
@@ -86,7 +86,7 @@ export function inferPreviewCardTemplate(card: AdaptiveCard): PreviewCardTemplat
result.image = {
url: `\${${inferredProperties.imageUrl}}`,
alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
- $when: `\${${inferredProperties.imageUrl} != null}`,
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
};
}
diff --git a/packages/spec-parser/src/specFilter.ts b/packages/spec-parser/src/specFilter.ts
index ce9e095007..dea5b8edfc 100644
--- a/packages/spec-parser/src/specFilter.ts
+++ b/packages/spec-parser/src/specFilter.ts
@@ -8,6 +8,7 @@ import { SpecParserError } from "./specParserError";
import { ErrorType, ParseOptions } from "./interfaces";
import { ConstantString } from "./constants";
import { ValidatorFactory } from "./validators/validatorFactory";
+import { SpecOptimizer } from "./specOptimizer";
export class SpecFilter {
static specFilter(
@@ -55,7 +56,7 @@ export class SpecFilter {
}
newSpec.paths = newPaths;
- return newSpec;
+ return SpecOptimizer.optimize(newSpec);
} catch (err) {
throw new SpecParserError((err as Error).toString(), ErrorType.FilterSpecFailed);
}
diff --git a/packages/spec-parser/src/specOptimizer.ts b/packages/spec-parser/src/specOptimizer.ts
new file mode 100644
index 0000000000..8689e26ec8
--- /dev/null
+++ b/packages/spec-parser/src/specOptimizer.ts
@@ -0,0 +1,206 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+"use strict";
+
+import { OpenAPIV3 } from "openapi-types";
+
+export interface OptimizerOptions {
+ removeUnusedComponents: boolean;
+ removeUnusedTags: boolean;
+ removeUserDefinedRootProperty: boolean;
+ removeUnusedSecuritySchemas: boolean;
+}
+
+export class SpecOptimizer {
+ private static defaultOptions: OptimizerOptions = {
+ removeUnusedComponents: true,
+ removeUnusedTags: true,
+ removeUserDefinedRootProperty: true,
+ removeUnusedSecuritySchemas: true,
+ };
+
+ static optimize(spec: OpenAPIV3.Document, options?: OptimizerOptions): OpenAPIV3.Document {
+ const mergedOptions = {
+ ...SpecOptimizer.defaultOptions,
+ ...(options ?? {}),
+ } as Required;
+
+ const newSpec = JSON.parse(JSON.stringify(spec));
+
+ if (mergedOptions.removeUserDefinedRootProperty) {
+ SpecOptimizer.removeUserDefinedRootProperty(newSpec);
+ }
+
+ if (mergedOptions.removeUnusedComponents) {
+ SpecOptimizer.removeUnusedComponents(newSpec);
+ }
+
+ if (mergedOptions.removeUnusedTags) {
+ SpecOptimizer.removeUnusedTags(newSpec);
+ }
+
+ if (mergedOptions.removeUnusedSecuritySchemas) {
+ SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
+ }
+
+ return newSpec;
+ }
+
+ private static removeUnusedSecuritySchemas(spec: OpenAPIV3.Document): void {
+ if (!spec.components || !spec.components.securitySchemes) {
+ return;
+ }
+
+ const usedSecuritySchemas = new Set();
+
+ for (const pathKey in spec.paths) {
+ for (const methodKey in spec.paths[pathKey]) {
+ const operation: OpenAPIV3.OperationObject = (spec.paths[pathKey] as any)[methodKey];
+ if (operation.security) {
+ operation.security.forEach((securityReq) => {
+ for (const schemaKey in securityReq) {
+ usedSecuritySchemas.add(schemaKey);
+ }
+ });
+ }
+ }
+ }
+
+ if (spec.security) {
+ spec.security.forEach((securityReq) => {
+ for (const schemaKey in securityReq) {
+ usedSecuritySchemas.add(schemaKey);
+ }
+ });
+ }
+
+ for (const schemaKey in spec.components.securitySchemes) {
+ if (!usedSecuritySchemas.has(schemaKey)) {
+ delete spec.components.securitySchemes[schemaKey];
+ }
+ }
+
+ if (Object.keys(spec.components.securitySchemes).length === 0) {
+ delete spec.components.securitySchemes;
+ }
+
+ if (Object.keys(spec.components).length === 0) {
+ delete spec.components;
+ }
+ }
+
+ private static removeUnusedTags(spec: OpenAPIV3.Document): void {
+ if (!spec.tags) {
+ return;
+ }
+
+ const usedTags = new Set();
+
+ for (const pathKey in spec.paths) {
+ for (const methodKey in spec.paths[pathKey]) {
+ const operation: OpenAPIV3.OperationObject = (spec.paths[pathKey] as any)[methodKey];
+ if (operation.tags) {
+ operation.tags.forEach((tag) => usedTags.add(tag));
+ }
+ }
+ }
+
+ spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
+ }
+
+ private static removeUserDefinedRootProperty(spec: OpenAPIV3.Document): void {
+ for (const key in spec) {
+ if (key.startsWith("x-")) {
+ delete (spec as any)[key];
+ }
+ }
+ }
+
+ private static removeUnusedComponents(spec: OpenAPIV3.Document): void {
+ const components = spec.components;
+ if (!components) {
+ return;
+ }
+
+ delete spec.components;
+
+ const usedComponentsSet = new Set();
+
+ const specString = JSON.stringify(spec);
+ const componentReferences = SpecOptimizer.getComponentReferences(specString);
+
+ for (const reference of componentReferences) {
+ this.addComponent(reference, usedComponentsSet, components);
+ }
+
+ const newComponents: any = {};
+
+ for (const componentName of usedComponentsSet) {
+ const parts = componentName.split("/");
+ const component = this.getComponent(componentName, components);
+ if (component) {
+ let current = newComponents;
+ for (let i = 2; i < parts.length; i++) {
+ if (i === parts.length - 1) {
+ current[parts[i]] = component;
+ } else if (!current[parts[i]]) {
+ current[parts[i]] = {};
+ }
+ current = current[parts[i]];
+ }
+ }
+ }
+
+ // securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
+ if (components.securitySchemes) {
+ newComponents.securitySchemes = components.securitySchemes;
+ }
+
+ if (Object.keys(newComponents).length !== 0) {
+ spec.components = newComponents;
+ }
+ }
+
+ private static getComponentReferences(specString: string): string[] {
+ const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
+ const matchResult = matches.map((match) => match[1]);
+ return matchResult;
+ }
+
+ private static getComponent(componentPath: string, components: OpenAPIV3.ComponentsObject): any {
+ const parts = componentPath.split("/");
+ let current: any = components;
+
+ for (const part of parts) {
+ if (part === "#" || part === "components") {
+ continue;
+ }
+ current = current[part];
+ if (!current) {
+ return null;
+ }
+ }
+
+ return current;
+ }
+
+ private static addComponent(
+ componentName: string,
+ usedComponentsSet: Set,
+ components: OpenAPIV3.ComponentsObject
+ ) {
+ if (usedComponentsSet.has(componentName)) {
+ return;
+ }
+ usedComponentsSet.add(componentName);
+
+ const component = this.getComponent(componentName, components);
+ if (component) {
+ const componentString = JSON.stringify(component);
+ const componentReferences = SpecOptimizer.getComponentReferences(componentString);
+ for (const reference of componentReferences) {
+ this.addComponent(reference, usedComponentsSet, components);
+ }
+ }
+ }
+}
diff --git a/packages/spec-parser/src/utils.ts b/packages/spec-parser/src/utils.ts
index c6062aa3d1..647a34498e 100644
--- a/packages/spec-parser/src/utils.ts
+++ b/packages/spec-parser/src/utils.ts
@@ -125,16 +125,21 @@ export class Utils {
for (const code of ConstantString.ResponseCodeFor20X) {
const responseObject = operationObject?.responses?.[code] as OpenAPIV3.ResponseObject;
- if (responseObject?.content?.["application/json"]) {
- multipleMediaType = false;
- json = responseObject.content["application/json"];
- if (Utils.containMultipleMediaTypes(responseObject)) {
- multipleMediaType = true;
- if (!allowMultipleMediaType) {
- json = {};
+ if (responseObject?.content) {
+ for (const contentType of Object.keys(responseObject.content)) {
+ // json media type can also be "application/json; charset=utf-8"
+ if (contentType.indexOf("application/json") >= 0) {
+ multipleMediaType = false;
+ json = responseObject.content[contentType];
+ if (Utils.containMultipleMediaTypes(responseObject)) {
+ multipleMediaType = true;
+ if (!allowMultipleMediaType) {
+ json = {};
+ }
+ } else {
+ return { json, multipleMediaType };
+ }
}
- } else {
- break;
}
}
}
@@ -479,10 +484,12 @@ export class Utils {
currentCount += items.length;
} else {
- if (currentCount < maxCount) {
- result.push(element);
- currentCount++;
- }
+ result.push(element);
+ currentCount++;
+ }
+
+ if (currentCount >= maxCount) {
+ break;
}
}
diff --git a/packages/spec-parser/test/adaptiveCardGenerator.test.ts b/packages/spec-parser/test/adaptiveCardGenerator.test.ts
index 5d1c0f004c..223cb2abd6 100644
--- a/packages/spec-parser/test/adaptiveCardGenerator.test.ts
+++ b/packages/spec-parser/test/adaptiveCardGenerator.test.ts
@@ -90,7 +90,7 @@ describe("adaptiveCardGenerator", () => {
{
type: "Image",
url: "${photo_url}",
- $when: "${photo_url != null}",
+ $when: "${photo_url != null && photo_url != ''}",
},
{
type: "TextBlock",
@@ -183,7 +183,7 @@ describe("adaptiveCardGenerator", () => {
{
type: "Image",
url: `\${image}`,
- $when: `\${image != null}`,
+ $when: `\${image != null && image != ''}`,
},
],
},
@@ -520,7 +520,7 @@ describe("adaptiveCardGenerator", () => {
{
type: "Image",
url: "${$data}",
- $when: "${$data != null}",
+ $when: "${$data != null && $data != ''}",
},
],
},
@@ -797,7 +797,7 @@ describe("adaptiveCardGenerator", () => {
{
type: "Image",
url: `\${iconUrl}`,
- $when: `\${iconUrl != null}`,
+ $when: `\${iconUrl != null && iconUrl != ''}`,
},
],
},
diff --git a/packages/spec-parser/test/adaptiveCardWrapper.test.ts b/packages/spec-parser/test/adaptiveCardWrapper.test.ts
index 88cae215e5..0641776a68 100644
--- a/packages/spec-parser/test/adaptiveCardWrapper.test.ts
+++ b/packages/spec-parser/test/adaptiveCardWrapper.test.ts
@@ -34,7 +34,7 @@ describe("adaptiveCardWrapper", () => {
wrap: true,
},
{
- $when: "${imageUrl != null}",
+ $when: "${imageUrl != null && imageUrl != ''}",
type: "Image",
url: "${imageUrl}",
},
@@ -257,7 +257,7 @@ describe("adaptiveCardWrapper", () => {
expect(result.image).to.be.deep.equal({
url: "${photoUrl}",
alt: "${if(photoUrl, photoUrl, 'N/A')}",
- $when: "${photoUrl != null}",
+ $when: "${photoUrl != null && photoUrl != ''}",
});
});
});
@@ -333,7 +333,7 @@ describe("adaptiveCardWrapper", () => {
subtitle: "${if(petId, petId, 'N/A')}",
image: {
url: "${imageUrl}",
- $when: "${imageUrl != null}",
+ $when: "${imageUrl != null && imageUrl != ''}",
alt: "${if(imageUrl, imageUrl, 'N/A')}",
},
},
diff --git a/packages/spec-parser/test/manifestUpdater.test.ts b/packages/spec-parser/test/manifestUpdater.test.ts
index ebee89d41f..4b38811fec 100644
--- a/packages/spec-parser/test/manifestUpdater.test.ts
+++ b/packages/spec-parser/test/manifestUpdater.test.ts
@@ -232,7 +232,7 @@ describe("updateManifestWithAiPlugin", () => {
wrap: true,
},
{
- $when: "${imageUrl != null}",
+ $when: "${imageUrl != null && imageUrl != ''}",
type: "Image",
url: "${imageUrl}",
},
@@ -531,7 +531,7 @@ describe("updateManifestWithAiPlugin", () => {
wrap: true,
},
{
- $when: "${imageUrl != null}",
+ $when: "${imageUrl != null && imageUrl != ''}",
type: "Image",
url: "${imageUrl}",
},
@@ -738,7 +738,7 @@ describe("updateManifestWithAiPlugin", () => {
type: "Container",
},
{
- $when: "${imageUrl != null}",
+ $when: "${imageUrl != null && imageUrl != ''}",
type: "Image",
url: "${imageUrl}",
},
@@ -792,6 +792,249 @@ describe("updateManifestWithAiPlugin", () => {
expect(apiPlugin).to.deep.equal(expectedPlugins);
expect(warnings).to.deep.equal([]);
});
+
+ it("should not contain empty container in adaptive card", async () => {
+ const spec: any = {
+ openapi: "3.0.2",
+ info: {
+ title: "My API",
+ description: "My API description",
+ },
+ servers: [
+ {
+ url: "/v3",
+ },
+ ],
+ paths: {
+ "/pets": {
+ get: {
+ operationId: "getPets",
+ summary: "Get all pets",
+ description: "Returns all pets from the system that the user has access to",
+ parameters: [
+ {
+ name: "limit",
+ description: "Maximum number of pets to return",
+ required: true,
+ schema: {
+ type: "integer",
+ },
+ },
+ ],
+ responses: {
+ 200: {
+ content: {
+ "application/json; charset=utf-8": {
+ schema: {
+ type: "object",
+ properties: {
+ photos: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ id: {
+ type: "number",
+ },
+ sol: {
+ type: "number",
+ },
+ camera: {
+ type: "object",
+ properties: {
+ id: {
+ type: "number",
+ },
+ name: {
+ type: "string",
+ },
+ rover_id: {
+ type: "number",
+ },
+ full_name: {
+ type: "string",
+ },
+ },
+ },
+ img_src: {
+ type: "string",
+ },
+ earth_date: {
+ type: "string",
+ },
+ rover: {
+ type: "object",
+ properties: {
+ id: {
+ type: "number",
+ },
+ name: {
+ type: "string",
+ },
+ landing_date: {
+ type: "string",
+ },
+ launch_date: {
+ type: "string",
+ },
+ status: {
+ type: "string",
+ },
+ max_sol: {
+ type: "number",
+ },
+ max_date: {
+ type: "string",
+ },
+ total_photos: {
+ type: "number",
+ },
+ cameras: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ name: {
+ type: "string",
+ },
+ full_name: {
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+ const manifestPath = "/path/to/your/manifest.json";
+ const outputSpecPath = "/path/to/your/spec/outputSpec.yaml";
+ const pluginFilePath = "/path/to/your/ai-plugin.json";
+
+ const originalManifest = {
+ name: { short: "Original Name", full: "Original Full Name" },
+ description: { short: "Original Short Description", full: "Original Full Description" },
+ };
+ const expectedManifest = {
+ name: { short: "Original Name", full: "Original Full Name" },
+ description: { short: "My API", full: "My API description" },
+ copilotExtensions: {
+ plugins: [
+ {
+ file: "ai-plugin.json",
+ id: "plugin_1",
+ },
+ ],
+ },
+ };
+
+ const expectedPlugins: PluginManifestSchema = {
+ $schema: ConstantString.PluginManifestSchema,
+ schema_version: "v2.1",
+ name_for_human: "Original Name",
+ namespace: "originalname",
+ description_for_human: "My API description",
+ functions: [
+ {
+ name: "getPets",
+ description: "Returns all pets from the system that the user has access to",
+ capabilities: {
+ response_semantics: {
+ data_path: "$",
+ properties: {
+ title: "$.camera.name",
+ subtitle: "$.id",
+ },
+ static_template: {
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
+ body: [
+ {
+ type: "Container",
+ $data: "${photos}",
+ items: [
+ {
+ type: "TextBlock",
+ text: "photos.id: ${if(id, id, 'N/A')}",
+ wrap: true,
+ },
+ {
+ type: "TextBlock",
+ text: "photos.sol: ${if(sol, sol, 'N/A')}",
+ wrap: true,
+ },
+ {
+ type: "TextBlock",
+ text: "photos.camera.id: ${if(camera.id, camera.id, 'N/A')}",
+ wrap: true,
+ },
+ {
+ type: "TextBlock",
+ text: "photos.camera.name: ${if(camera.name, camera.name, 'N/A')}",
+ wrap: true,
+ },
+ {
+ type: "TextBlock",
+ text: "photos.camera.rover_id: ${if(camera.rover_id, camera.rover_id, 'N/A')}",
+ wrap: true,
+ },
+ ],
+ },
+ ],
+ type: "AdaptiveCard",
+ version: "1.5",
+ },
+ },
+ },
+ },
+ ],
+ runtimes: [
+ {
+ type: "OpenApi",
+ auth: {
+ type: "None",
+ },
+ spec: {
+ url: "spec/outputSpec.yaml",
+ },
+ run_for_functions: ["getPets"],
+ },
+ ],
+ };
+ sinon.stub(fs, "readJSON").resolves(originalManifest);
+ sinon
+ .stub(fs, "pathExists")
+ .withArgs(manifestPath)
+ .resolves(true)
+ .withArgs(pluginFilePath)
+ .resolves(false);
+
+ const options: ParseOptions = {
+ allowMethods: ["get", "post"],
+ allowResponseSemantics: true,
+ };
+ const [manifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(
+ manifestPath,
+ outputSpecPath,
+ pluginFilePath,
+ spec,
+ options
+ );
+
+ expect(manifest).to.deep.equal(expectedManifest);
+ expect(apiPlugin).to.deep.equal(expectedPlugins);
+ expect(warnings).to.deep.equal([]);
+ });
});
describe("auth", () => {
diff --git a/packages/spec-parser/test/specOptimizer.test.ts b/packages/spec-parser/test/specOptimizer.test.ts
new file mode 100644
index 0000000000..96209e94ae
--- /dev/null
+++ b/packages/spec-parser/test/specOptimizer.test.ts
@@ -0,0 +1,801 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { expect } from "chai";
+import "mocha";
+import sinon from "sinon";
+import { SpecOptimizer } from "../src/specOptimizer";
+
+describe("specOptimizer.test", () => {
+ afterEach(() => {
+ sinon.restore();
+ });
+
+ it("should remove unused components, unused tags, user defined root property, unused security", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ "x-user-defined": {
+ $ref: "#/components/schemas/Pet",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ tags: [
+ {
+ name: "user",
+ description: "user operations",
+ },
+ {
+ name: "pet",
+ description: "pet operations",
+ },
+ ],
+ security: [
+ {
+ api_key2: [],
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ tags: ["user"],
+ security: [
+ {
+ api_key: [],
+ },
+ ],
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "/user/{name}": {
+ get: {
+ operationId: "getUserByName",
+ parameters: [
+ {
+ name: "name",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ api_key2: {
+ type: "apiKey",
+ name: "api_key2",
+ in: "header",
+ },
+ api_key3: {
+ type: "apiKey",
+ name: "api_key3",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Pet: {
+ type: "string",
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ responses: {
+ "404NotFound": {
+ description: "The specified resource was not found.",
+ },
+ },
+ },
+ };
+
+ const expectedSpec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ tags: [
+ {
+ name: "user",
+ description: "user operations",
+ },
+ ],
+ security: [
+ {
+ api_key2: [],
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ tags: ["user"],
+ operationId: "getUserById",
+ security: [
+ {
+ api_key: [],
+ },
+ ],
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "/user/{name}": {
+ get: {
+ operationId: "getUserByName",
+ parameters: [
+ {
+ name: "name",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ api_key2: {
+ type: "apiKey",
+ name: "api_key2",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any);
+ expect(result).to.deep.equal(expectedSpec);
+ });
+
+ it("should maintain original spec when optimization is disabled", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ "x-user-defined": {
+ $ref: "#/components/schemas/Pet",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ tags: [
+ {
+ name: "user",
+ description: "user operations",
+ },
+ {
+ name: "pet",
+ description: "pet operations",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ tags: ["user"],
+ security: [
+ {
+ api_key: [],
+ },
+ ],
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ api_key2: {
+ type: "apiKey",
+ name: "api_key2",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Pet: {
+ type: "string",
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ responses: {
+ "404NotFound": {
+ description: "The specified resource was not found.",
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any, {
+ removeUnusedComponents: false,
+ removeUnusedTags: false,
+ removeUserDefinedRootProperty: false,
+ removeUnusedSecuritySchemas: false,
+ });
+ expect(result).to.deep.equal(spec);
+ });
+
+ it("should maintain original spec if no optimization can be performed", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ tags: [
+ {
+ name: "user",
+ description: "user operations",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ tags: ["user"],
+ security: [
+ {
+ api_key: [],
+ },
+ ],
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any);
+ expect(result).to.deep.equal(spec);
+ });
+
+ it("should remove securitySchemes if it empty after optimization", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const expectedSpec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ $ref: "#/components/schemas/User",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any);
+ expect(result).to.deep.equal(expectedSpec);
+ });
+
+ it("should remove components if it empty after optimization", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const expectedSpec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any);
+ expect(result).to.deep.equal(expectedSpec);
+ });
+
+ it("should works fine if matches unexpected component reference", () => {
+ const spec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ description: "#/components/schemas/Unexpected/Reference/Pattern",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ components: {
+ securitySchemes: {
+ api_key: {
+ type: "apiKey",
+ name: "api_key",
+ in: "header",
+ },
+ },
+ schemas: {
+ User: {
+ type: "object",
+ properties: {
+ order: {
+ $ref: "#/components/schemas/Order",
+ },
+ },
+ },
+ Order: {
+ type: "string",
+ },
+ },
+ },
+ };
+
+ const expectedSpec = {
+ openapi: "3.0.2",
+ info: {
+ title: "User Service",
+ version: "1.0.0",
+ },
+ servers: [
+ {
+ url: "https://server1",
+ },
+ ],
+ paths: {
+ "/user/{userId}": {
+ get: {
+ operationId: "getUserById",
+ description: "#/components/schemas/Unexpected/Reference/Pattern",
+ parameters: [
+ {
+ name: "userId",
+ in: "path",
+ required: true,
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "test",
+ content: {
+ "application/json": {
+ schema: {
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const result = SpecOptimizer.optimize(spec as any);
+ expect(result).to.deep.equal(expectedSpec);
+ });
+});
diff --git a/packages/spec-parser/test/utils.test.ts b/packages/spec-parser/test/utils.test.ts
index add04359a9..634cd397b2 100644
--- a/packages/spec-parser/test/utils.test.ts
+++ b/packages/spec-parser/test/utils.test.ts
@@ -428,6 +428,35 @@ describe("utils", () => {
expect(multipleMediaType).to.be.false;
});
+ it("should return the JSON response for application/json; charset=utf-8;", () => {
+ const operationObject = {
+ responses: {
+ "200": {
+ content: {
+ "application/json; charset=utf-8": {
+ schema: {
+ type: "object",
+ properties: {
+ message: { type: "string" },
+ },
+ },
+ },
+ },
+ },
+ },
+ } as any;
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
+ expect(json).to.deep.equal({
+ schema: {
+ type: "object",
+ properties: {
+ message: { type: "string" },
+ },
+ },
+ });
+ expect(multipleMediaType).to.be.false;
+ });
+
it("should return empty JSON response for status code 200 with multiple media type", () => {
const operationObject = {
responses: {
diff --git a/packages/tests/scripts/pvt.json b/packages/tests/scripts/pvt.json
index c5ddc1c4f9..88fd9f8c3f 100644
--- a/packages/tests/scripts/pvt.json
+++ b/packages/tests/scripts/pvt.json
@@ -9,10 +9,7 @@
"localdebug-notification-restify",
"localdebug-tab-regen-appid",
"treeview-newproject-spfx",
- "treeview-collaboration-spfx",
- "remotedebug-spfxreact-none",
- "remotedebug-spfxreact-minimal",
- "remotedebug-spfxreact",
+ "treeview-collaboration-spfx",
"remotedebug-spfxreact-globalpkg",
"remotedebug-spfxnone-globalpkg-addwebpart",
"remotedebug-spfxreact-addwebpart"
@@ -66,7 +63,12 @@
"localdebug-aiassistant-bot-ts",
"remotedebug-aichat-bot-py-win-only",
"remotedebug-msg-newapi-apikey-ts-win-only",
- "remotedebug-msg-newapi-apikey-win-only"
+ "remotedebug-msg-newapi-apikey-win-only",
+ "remotedebug-spfxreact-import-single",
+ "remotedebug-spfxreact-import-multiple",
+ "remotedebug-spfx-none",
+ "remotedebug-spfx-minimal",
+ "remotedebug-spfx-react"
],
"node-20": [
"localdebug-obo-tab"
diff --git a/packages/tests/scripts/randomCases.json b/packages/tests/scripts/randomCases.json
index fde3831dfb..fa7eafd99e 100644
--- a/packages/tests/scripts/randomCases.json
+++ b/packages/tests/scripts/randomCases.json
@@ -20,47 +20,17 @@
"sample-localdebug-incoming-webhook",
"basic-tab-debug-upgrade-debug",
"bot-debug-upgrade-debug",
- "bot-upgrade-debug"
- ]
- },
- {
- "os": {
- "windows-latest": {
- "node-16": [],
- "node-18": []
- },
- "ubuntu-latest": {
- "node-16": [],
- "node-18": []
- },
- "macos-latest": {
- "node-16": [],
- "node-18": []
- }
- },
- "cases": [
+ "bot-upgrade-debug",
+ "sample-remotedebug-todo-list-with-spfx",
+ "sample-remotedebug-todo-list-with-m365",
+ "sample-localdebug-react-retail-dashboard",
+ "sample-localdebug-spfx-productivity-dashboard",
+ "sample-remotedebug-react-retail-dashboard",
+ "sample-remotedebug-spfx-productivity-dashboard",
"sample-localdebug-npm-search",
"sample-localdebug-proactive-message"
]
},
- {
- "os": {
- "windows-latest": {
- "node-16": []
- },
- "ubuntu-latest": {
- "node-16": []
- },
- "macos-latest": {
- "node-16": []
- }
- },
- "cases": [
- "sample-localdebug-todo-list-with-spfx",
- "sample-localdebug-react-retail-dashboard",
- "sample-localdebug-spfx-productivity-dashboard"
- ]
- },
{
"os": {
"windows-latest": {
@@ -74,7 +44,8 @@
}
},
"cases": [
- "sample-localdebug-chef-bot"
+ "sample-localdebug-chef-bot",
+ "sample-remotedebug-chef-bot"
]
},
{
@@ -89,7 +60,6 @@
}
},
"cases": [
- "sample-localdebug-todo-list-with-m365",
"sample-localdebug-hello-world-tab-with-backend",
"sample-localdebug-graph-connector-bot",
"sample-localdebug-bot-sso",
@@ -114,7 +84,6 @@
"sample-remotedebug-hello-world-tab-with-backend",
"sample-remotedebug-npm-search",
"sample-remotedebug-hello-world-meeting",
- "sample-remotedebug-todo-list-with-m365",
"sample-remotedebug-one-productivity-hub",
"sample-remotedebug-stock-update",
"sample-remotedebug-query-org",
@@ -127,28 +96,6 @@
"bot-upgrade-provision-debug"
]
},
- {
- "os": {
- "windows-latest": {
- "node-16": []
- }
- },
- "cases": [
- "sample-remotedebug-chef-bot"
- ]
- },
- {
- "os": {
- "windows-latest": {
- "node-18": []
- }
- },
- "cases": [
- "sample-remotedebug-todo-list-with-spfx",
- "sample-remotedebug-react-retail-dashboard",
- "sample-remotedebug-spfx-productivity-dashboard"
- ]
- },
{
"os": {
"ubuntu-latest": {
@@ -174,7 +121,9 @@
"sample-localdebug-hello-world-tab-docker",
"sample-remotedebug-hello-world-tab-docker",
"basic-tab-provision-upgrade-provision-debug",
- "bot-provision-upgrade-provision-debug"
+ "bot-provision-upgrade-provision-debug",
+ "sample-localdebug-todo-list-with-spfx",
+ "sample-localdebug-todo-list-with-m365"
]
}
]
\ No newline at end of file
diff --git a/packages/tests/src/commonlib/constants.ts b/packages/tests/src/commonlib/constants.ts
index 51bb5d4f4f..4101a7ba96 100644
--- a/packages/tests/src/commonlib/constants.ts
+++ b/packages/tests/src/commonlib/constants.ts
@@ -47,6 +47,7 @@ export type CliCapabilities =
export type CliTriggerType =
| "http-restify"
| "http-functions"
+ | "http-and-timer-functions"
| "timer-functions";
export enum Resource {
diff --git a/packages/tests/src/e2e/bot/ProvisionAppServiceNotificationBot.tests.ts b/packages/tests/src/e2e/bot/ProvisionAppServiceNotificationBot.tests.ts
index 677f0c8a8d..9bf7209600 100644
--- a/packages/tests/src/e2e/bot/ProvisionAppServiceNotificationBot.tests.ts
+++ b/packages/tests/src/e2e/bot/ProvisionAppServiceNotificationBot.tests.ts
@@ -12,7 +12,7 @@ import { it } from "@microsoft/extra-shot-mocha";
describe("Provision Notification Node", () => {
it(
"Provision Resource: Notification Node",
- { testPlanCaseId: 15685832, author: "fanhu@microsoft.com" },
+ { testPlanCaseId: 24132569, author: "fanhu@microsoft.com" },
async function () {
await happyPathTest(Runtime.Node);
}
diff --git a/packages/tests/src/e2e/bot/ProvisionFuncHostedNotificationBot.tests.ts b/packages/tests/src/e2e/bot/ProvisionFuncHostedNotificationBot.tests.ts
index 5df5986e11..38a5a23554 100644
--- a/packages/tests/src/e2e/bot/ProvisionFuncHostedNotificationBot.tests.ts
+++ b/packages/tests/src/e2e/bot/ProvisionFuncHostedNotificationBot.tests.ts
@@ -16,4 +16,20 @@ describe("Provision for Node", () => {
await happyPathTest(Runtime.Node, "notification", ["http-functions"]);
}
);
+ it(
+ "Provision Resource: func hosted notification timer trigger",
+ { testPlanCaseId: 24132574, author: "qidon@microsoft.com" },
+ async function () {
+ await happyPathTest(Runtime.Node, "notification", ["timer-functions"]);
+ }
+ );
+ it(
+ "Provision Resource: func hosted notification http and timer triggers",
+ { testPlanCaseId: 24132576, author: "qidon@microsoft.com" },
+ async function () {
+ await happyPathTest(Runtime.Node, "notification", [
+ "http-and-timer-functions",
+ ]);
+ }
+ );
});
diff --git a/packages/tests/src/e2e/bot/ProvisionWorkflowBot.dotnet.dotnet.tests.ts b/packages/tests/src/e2e/bot/ProvisionWorkflowBot.dotnet.dotnet.tests.ts
new file mode 100644
index 0000000000..57abe7f788
--- /dev/null
+++ b/packages/tests/src/e2e/bot/ProvisionWorkflowBot.dotnet.dotnet.tests.ts
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/**
+ * @author dol
+ */
+
+import { Runtime } from "../../commonlib/constants";
+import { happyPathTest } from "./WorkflowBotHappyPathCommon";
+import { it } from "@microsoft/extra-shot-mocha";
+
+describe("Provision workflow Dotnet", () => {
+ it(
+ "Provision Resource: Workflow Dotnet",
+ { testPlanCaseId: 24692255, author: "dol@microsoft.com" },
+ async function () {
+ await happyPathTest(Runtime.Dotnet);
+ }
+ );
+});
diff --git a/packages/tests/src/e2e/frontend/BlazorAppHappyPath.tests.ts b/packages/tests/src/e2e/frontend/BlazorAppHappyPath.tests.ts
index f9cb2db67e..5f67311d80 100644
--- a/packages/tests/src/e2e/frontend/BlazorAppHappyPath.tests.ts
+++ b/packages/tests/src/e2e/frontend/BlazorAppHappyPath.tests.ts
@@ -57,7 +57,12 @@ describe("Blazor App", function () {
Capability.TabNonSso,
env
);
- const programCsPath = path.join(testFolder, appName, "App.razor");
+ const programCsPath = path.join(
+ testFolder,
+ appName,
+ "Components",
+ "App.razor"
+ );
chai.assert.isTrue(await fs.pathExists(programCsPath));
}
);
diff --git a/packages/tests/src/e2e/m365/ProvisionApiSpecMessageExtension.tests.ts b/packages/tests/src/e2e/m365/ProvisionApiSpecMessageExtension.tests.ts
index 5d55c5a41d..696985c279 100644
--- a/packages/tests/src/e2e/m365/ProvisionApiSpecMessageExtension.tests.ts
+++ b/packages/tests/src/e2e/m365/ProvisionApiSpecMessageExtension.tests.ts
@@ -38,7 +38,7 @@ describe("Provision V3 api-based-message-extension api-spec template", () => {
it(
"happy path: scaffold and provision",
- { testPlanCaseId: 25285721, author: "yuqzho@microsoft.com" },
+ { testPlanCaseId: 25284858, author: "yuqzho@microsoft.com" },
async function () {
const apiSpecPath = path.join(__dirname, "../", "testApiSpec.yml");
// create
diff --git a/packages/tests/src/e2e/samples/ProvisionChefBot.tests.ts b/packages/tests/src/e2e/samples/ProvisionChefBot.tests.ts
index d7e4798d08..6cfe64e1c4 100644
--- a/packages/tests/src/e2e/samples/ProvisionChefBot.tests.ts
+++ b/packages/tests/src/e2e/samples/ProvisionChefBot.tests.ts
@@ -31,10 +31,10 @@ class ChefBotTestCase extends CaseFactory {
fs.mkdirSync(path.resolve(projectPath, "env"), {
recursive: true,
});
- const userFile = path.resolve(projectPath, "env", ".env.dev.user");
+ const userFile = path.resolve(projectPath, "env", ".env.dev");
const KEY = "SECRET_OPENAI_KEY=MY_OPENAI_API_KEY";
fs.writeFileSync(userFile, KEY);
- console.log(`add key ${KEY} to .env.dev.user file`);
+ console.log(`add key ${KEY} to .env.dev file`);
}
}
diff --git a/packages/tests/src/e2e/scaffold/CopilotPluginFromExistingApi.tests.ts b/packages/tests/src/e2e/scaffold/CopilotPluginFromExistingApi.tests.ts
index 8cb3adeebe..bf040d5753 100644
--- a/packages/tests/src/e2e/scaffold/CopilotPluginFromExistingApi.tests.ts
+++ b/packages/tests/src/e2e/scaffold/CopilotPluginFromExistingApi.tests.ts
@@ -42,7 +42,6 @@ describe("Create Copilot plugin", () => {
async function () {
const env = Object.assign({}, process.env);
- env["API_COPILOT_PLUGIN"] = "true";
env["DEVELOP_COPILOT_PLUGIN"] = "true";
const apiSpecPath = path.join(__dirname, "../", "testApiSpec.yml");
diff --git a/packages/tests/src/e2e/scaffold/CopilotPluginFromScratch.tests.ts b/packages/tests/src/e2e/scaffold/CopilotPluginFromScratch.tests.ts
index 46c7d55ce4..0efb9ee299 100644
--- a/packages/tests/src/e2e/scaffold/CopilotPluginFromScratch.tests.ts
+++ b/packages/tests/src/e2e/scaffold/CopilotPluginFromScratch.tests.ts
@@ -42,7 +42,6 @@ describe("Create Copilot plugin", () => {
async function () {
const env = Object.assign({}, process.env);
- env["API_COPILOT_PLUGIN"] = "true";
env["DEVELOP_COPILOT_PLUGIN"] = "true";
// create
diff --git a/packages/tests/src/e2e/spfx/AddSPFxTabV3.tests.ts b/packages/tests/src/e2e/spfx/AddSPFxTabV3.tests.ts
index c3b0dd259a..ba49ab1ef4 100644
--- a/packages/tests/src/e2e/spfx/AddSPFxTabV3.tests.ts
+++ b/packages/tests/src/e2e/spfx/AddSPFxTabV3.tests.ts
@@ -145,6 +145,15 @@ describe("Start a new project", function () {
SharepointValidator.init();
SharepointValidator.validateDeploy(appId);
}
+
+ {
+ // preview
+ const result = await Executor.preview(
+ projectPath,
+ environmentNameManager.getDefaultEnvName()
+ );
+ expect(result.success).to.be.true;
+ }
}
);
diff --git a/packages/tests/src/e2e/spfx/CreateSPFxProject.tests.ts b/packages/tests/src/e2e/spfx/CreateSPFxProject.tests.ts
index bbdbfb43b1..be38bbf7b4 100644
--- a/packages/tests/src/e2e/spfx/CreateSPFxProject.tests.ts
+++ b/packages/tests/src/e2e/spfx/CreateSPFxProject.tests.ts
@@ -158,6 +158,15 @@ describe("Start a new project", function () {
// Validate publish result
await AppStudioValidator.validatePublish(teamsAppId!);
}
+
+ {
+ // preview
+ const result = await Executor.preview(
+ projectPath,
+ environmentNameManager.getDefaultEnvName()
+ );
+ expect(result.success).to.be.true;
+ }
}
);
diff --git a/packages/tests/src/scripts/clean.ts b/packages/tests/src/scripts/clean.ts
index a58a8e3675..7c5ea28aed 100644
--- a/packages/tests/src/scripts/clean.ts
+++ b/packages/tests/src/scripts/clean.ts
@@ -14,10 +14,10 @@ import {
import { getAppNamePrefix } from "../utils/nameUtil";
import { delay } from "../utils/retryHandler";
-const appStudioAppNamePrefixList: string[] = [Project.namePrefix];
-const appNamePrefixList: string[] = [Project.namePrefix];
-const aadNamePrefixList: string[] = [Project.namePrefix];
-const rgNamePrefixList: string[] = [Project.namePrefix];
+const appStudioAppNamePrefixList: string[] = [Project.namePrefix, "vs"];
+const appNamePrefixList: string[] = [Project.namePrefix, "vs"];
+const aadNamePrefixList: string[] = [Project.namePrefix, "vs"];
+const rgNamePrefixList: string[] = [Project.namePrefix, "vs"];
const excludePrefix: string = getAppNamePrefix();
async function main() {
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-aiassistant-bot-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-aiassistant-bot-ts.test.ts
index b074597c15..61737cde26 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-aiassistant-bot-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-aiassistant-bot-ts.test.ts
@@ -28,7 +28,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("aiassist", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("aiassist", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-py.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-py.test.ts
index 824b89ee47..b6a85b3ca6 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-py.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-py.test.ts
@@ -33,7 +33,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("aichat", "python");
+ localDebugTestContext = new LocalDebugTestContext("aichat", {
+ lang: "python",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-ts.test.ts
index addccb42e2..cfb656b4f2 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-aichat-bot-ts.test.ts
@@ -28,7 +28,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("aichat", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("aichat", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-bot-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-bot-ts.test.ts
index 725a0541c7..000279ae31 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-bot-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-bot-ts.test.ts
@@ -39,7 +39,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("bot", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("bot", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-command-and-response-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-command-and-response-ts.test.ts
index eb77f8ebf7..ac4e5755cd 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-command-and-response-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-command-and-response-ts.test.ts
@@ -47,7 +47,9 @@ describe("Command And Response Bot Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("crbot", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("crbot", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts
index ab86d9d508..d28aee18c5 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Ivan Chen
*/
@@ -24,10 +27,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext(
- "dashboard",
- "typescript"
- );
+ localDebugTestContext = new LocalDebugTestContext("dashboard", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts
index 02ec062415..71cd92eaa3 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Ivan Chen
*/
@@ -24,10 +27,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext(
- "dashboard",
- "javascript"
- );
+ localDebugTestContext = new LocalDebugTestContext("dashboard", {
+ lang: "javascript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling-ts.test.ts
index e95cb4a7ea..bf291df3af 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling-ts.test.ts
@@ -20,10 +20,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext(
- "linkunfurl",
- "typescript"
- );
+ localDebugTestContext = new LocalDebugTestContext("linkunfurl", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
@@ -58,7 +57,7 @@ describe("Local Debug Tests", function () {
Env.password
);
await localDebugTestContext.validateLocalStateForBot();
- await validateUnfurlCard(page);
+ await validateUnfurlCard(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling.test.ts
index a91f07df55..9243c1c276 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-link-unfurling.test.ts
@@ -63,7 +63,7 @@ describe("Local Debug Tests", function () {
Env.password
);
await localDebugTestContext.validateLocalStateForBot();
- await validateUnfurlCard(page);
+ await validateUnfurlCard(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey-ts.test.ts
index 86cc8e08c3..953a6fac75 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey-ts.test.ts
@@ -25,10 +25,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext(
- "msgapikey",
- "typescript"
- );
+ localDebugTestContext = new LocalDebugTestContext("msgapikey", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
@@ -67,7 +66,7 @@ describe("Local Debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey.test.ts
index 0712ad5bf9..0262e7f0f5 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-apikey.test.ts
@@ -60,7 +60,7 @@ describe("Local Debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-ts.test.ts
index a4913c8a61..2a107f4c8b 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi-ts.test.ts
@@ -20,10 +20,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext(
- "msgnewapi",
- "typescript"
- );
+ localDebugTestContext = new LocalDebugTestContext("msgnewapi", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
@@ -57,7 +56,7 @@ describe("Local Debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi.test.ts
index f2333d63c9..ca14ae96c2 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msg-newapi.test.ts
@@ -54,7 +54,7 @@ describe("Local Debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msg-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msg-ts.test.ts
index 26682c76b0..a489b9205b 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msg-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msg-ts.test.ts
@@ -28,7 +28,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("msg", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("msg", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msgsa-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msgsa-ts.test.ts
index f7e8e13255..6916409ac3 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msgsa-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msgsa-ts.test.ts
@@ -6,7 +6,7 @@
*/
import * as path from "path";
import { startDebugging, waitForTerminal } from "../../utils/vscodeOperation";
-import { initPage, validateMsg } from "../../utils/playwrightOperation";
+import { initPage, validateNpm } from "../../utils/playwrightOperation";
import { LocalDebugTestContext } from "./localdebugContext";
import { Timeout, LocalDebugTaskLabel } from "../../utils/constants";
import { Env } from "../../utils/env";
@@ -20,7 +20,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("msgsa", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("msgsa", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
@@ -52,7 +54,10 @@ describe("Local Debug Tests", function () {
Env.password
);
await localDebugTestContext.validateLocalStateForBot();
- await validateMsg(page);
+ await validateNpm(page, {
+ npmName: "axios",
+ appName: localDebugTestContext.appName,
+ });
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-msgsa.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-msgsa.test.ts
index e85cc9f5dc..2820b099de 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-msgsa.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-msgsa.test.ts
@@ -6,7 +6,7 @@
*/
import * as path from "path";
import { startDebugging, waitForTerminal } from "../../utils/vscodeOperation";
-import { initPage, validateMsg } from "../../utils/playwrightOperation";
+import { initPage, validateNpm } from "../../utils/playwrightOperation";
import { LocalDebugTestContext } from "./localdebugContext";
import { Timeout, LocalDebugTaskLabel } from "../../utils/constants";
import { Env } from "../../utils/env";
@@ -52,7 +52,10 @@ describe("Local Debug Tests", function () {
Env.password
);
await localDebugTestContext.validateLocalStateForBot();
- await validateMsg(page);
+ await validateNpm(page, {
+ npmName: "axios",
+ appName: localDebugTestContext.appName,
+ });
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-notification-func-timertrigger-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-notification-func-timertrigger-ts.test.ts
index 268a564af8..8ba2e7a92b 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-notification-func-timertrigger-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-notification-func-timertrigger-ts.test.ts
@@ -34,7 +34,9 @@ describe("Func Hosted and Timer-trigger Notification Bot Local Debug Tests", fun
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("ftNoti", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("ftNoti", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-notification-func-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-notification-func-ts.test.ts
index 9fe4b22531..495a84b9e5 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-notification-func-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-notification-func-ts.test.ts
@@ -33,7 +33,9 @@ describe("Func Hosted Notification Bot Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("funcNoti", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("funcNoti", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-notification-restify-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-notification-restify-ts.test.ts
index bb8d19b555..2b9350fa91 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-notification-restify-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-notification-restify-ts.test.ts
@@ -29,7 +29,9 @@ describe("Restify Notification Bot Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("restNoti", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("restNoti", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-notification-timertrigger-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-notification-timertrigger-ts.test.ts
index ab0a2dd603..741ff637c8 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-notification-timertrigger-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-notification-timertrigger-ts.test.ts
@@ -29,7 +29,9 @@ describe("Time-trigger Notification Bot Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("timeNoti", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("timeNoti", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts
index b298ae916e..6fa1acac72 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts
@@ -30,7 +30,9 @@ describe("Local Debug M365 Tests", function () {
process.env.TEAMSFX_M365_APP = "true";
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("m365lp", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("m365lp", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-spfx-minimal.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-spfx-minimal.test.ts
index 942f0951a4..d96ee34b4d 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-spfx-minimal.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-spfx-minimal.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Anne Fu
*/
@@ -6,19 +9,21 @@ import {
initPage,
validateTeamsWorkbench,
} from "../../utils/playwrightOperation";
-import { LocalDebugSpfxTestContext } from "./localdebugContext";
-import { Timeout, LocalDebugTaskLabel } from "../../utils/constants";
+import { LocalDebugTestContext } from "./localdebugContext";
+import { Timeout } from "../../utils/constants";
import { Env } from "../../utils/env";
import { it } from "../../utils/it";
describe("SPFx local debug", function () {
this.timeout(Timeout.testCase);
- let localDebugTestContext: LocalDebugSpfxTestContext;
+ let localDebugTestContext: LocalDebugTestContext;
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugSpfxTestContext("minimal");
+ localDebugTestContext = new LocalDebugTestContext("spfx", {
+ framework: "minimal",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-spfx-none.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-spfx-none.test.ts
index cf775e4f22..381573193d 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-spfx-none.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-spfx-none.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Anne Fu
*/
@@ -6,19 +9,21 @@ import {
initPage,
validateTeamsWorkbench,
} from "../../utils/playwrightOperation";
-import { LocalDebugSpfxTestContext } from "./localdebugContext";
-import { Timeout, LocalDebugTaskLabel } from "../../utils/constants";
+import { LocalDebugTestContext } from "./localdebugContext";
+import { Timeout } from "../../utils/constants";
import { Env } from "../../utils/env";
import { it } from "../../utils/it";
describe("SPFx local debug", function () {
this.timeout(Timeout.testCase);
- let localDebugTestContext: LocalDebugSpfxTestContext;
+ let localDebugTestContext: LocalDebugTestContext;
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugSpfxTestContext("none");
+ localDebugTestContext = new LocalDebugTestContext("spfx", {
+ framework: "none",
+ });
await localDebugTestContext.before();
});
@@ -47,7 +52,7 @@ describe("SPFx local debug", function () {
Env.username,
Env.password
);
- await validateTeamsWorkbench(page, Env.displayName);
+ await validateTeamsWorkbench(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-spfx.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-spfx.test.ts
index 40c2cc03f7..cfd6f387f5 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-spfx.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-spfx.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Anne Fu
*/
@@ -6,19 +9,21 @@ import {
initPage,
validateTeamsWorkbench,
} from "../../utils/playwrightOperation";
-import { LocalDebugSpfxTestContext } from "./localdebugContext";
-import { Timeout, LocalDebugTaskLabel } from "../../utils/constants";
+import { LocalDebugTestContext } from "./localdebugContext";
+import { Timeout } from "../../utils/constants";
import { Env } from "../../utils/env";
import { it } from "../../utils/it";
describe("SPFx local debug", function () {
this.timeout(Timeout.testCase);
- let localDebugTestContext: LocalDebugSpfxTestContext;
+ let localDebugTestContext: LocalDebugTestContext;
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugSpfxTestContext("react");
+ localDebugTestContext = new LocalDebugTestContext("spfx", {
+ framework: "react",
+ });
await localDebugTestContext.before();
});
@@ -47,7 +52,7 @@ describe("SPFx local debug", function () {
Env.username,
Env.password
);
- await validateTeamsWorkbench(page, Env.displayName);
+ await validateTeamsWorkbench(page, localDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-tab-nosso-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-tab-nosso-ts.test.ts
index 6796e3a7b5..3de7bdbcfd 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-tab-nosso-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-tab-nosso-ts.test.ts
@@ -39,7 +39,9 @@ describe("Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("tabnsso", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("tabnsso", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebug-workflow-bot-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-workflow-bot-ts.test.ts
index 9588a55dc2..b9a98d6f7a 100644
--- a/packages/tests/src/ui-test/localdebug/localdebug-workflow-bot-ts.test.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebug-workflow-bot-ts.test.ts
@@ -47,7 +47,9 @@ describe("Workflow Bot Local Debug Tests", function () {
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
- localDebugTestContext = new LocalDebugTestContext("workflow", "typescript");
+ localDebugTestContext = new LocalDebugTestContext("workflow", {
+ lang: "typescript",
+ });
await localDebugTestContext.before();
});
diff --git a/packages/tests/src/ui-test/localdebug/localdebugContext.ts b/packages/tests/src/ui-test/localdebug/localdebugContext.ts
index f557064a79..67acac0ed7 100644
--- a/packages/tests/src/ui-test/localdebug/localdebugContext.ts
+++ b/packages/tests/src/ui-test/localdebug/localdebugContext.ts
@@ -23,6 +23,7 @@ export type LocalDebugTestName =
| "crbot" // command an response bot
| "tabbot"
| "spfx"
+ | "spfximport"
| "botfunc"
| "template"
| "m365lp"
@@ -38,18 +39,28 @@ export type LocalDebugTestName =
export class LocalDebugTestContext extends TestContext {
public testName: LocalDebugTestName;
- public lang: "javascript" | "typescript" | "python" = "javascript";
- needMigrate: boolean | undefined;
+ public lang: "javascript" | "typescript" | "python";
+ public framework: "react" | "minimal" | "none";
+ public needMigrate: boolean | undefined;
+ public existingSpfxFolder: string;
constructor(
testName: LocalDebugTestName,
- lang: "javascript" | "typescript" | "python" = "javascript",
- needMigrate?: boolean
+ option?: {
+ lang?: "javascript" | "typescript" | "python";
+ framework?: "react" | "minimal" | "none";
+ needMigrate?: boolean;
+ existingSpfxFolder?: string;
+ }
) {
super(testName);
this.testName = testName;
- this.lang = lang;
- this.needMigrate = needMigrate;
+ this.lang = option?.lang ? option.lang : "javascript";
+ this.framework = option?.framework ? option.framework : "react";
+ this.needMigrate = option?.needMigrate;
+ this.existingSpfxFolder = option?.existingSpfxFolder
+ ? option.existingSpfxFolder
+ : "existingspfx";
}
public async before() {
@@ -180,7 +191,18 @@ export class LocalDebugTestContext extends TestContext {
case "spfx":
await execCommand(
this.testRootFolder,
- `teamsapp new --app-name ${this.appName} --interactive false --capability tab-spfx --spfx-framework-type none --spfx-webpart-name ${this.appName} --telemetry false`
+ `teamsapp new --app-name ${this.appName} --interactive false --capability tab-spfx --spfx-framework-type ${this.framework} --spfx-webpart-name ${this.appName} --telemetry false`
+ );
+ break;
+ case "spfximport":
+ const resourcePath = path.resolve(
+ __dirname,
+ "../../../.test-resources/",
+ this.existingSpfxFolder
+ );
+ await execCommand(
+ this.testRootFolder,
+ `teamsapp new --app-name ${this.appName} --interactive false --capability tab-spfx --spfx-solution import --spfx-folder ${resourcePath} --telemetry false`
);
break;
case "botfunc":
@@ -254,7 +276,7 @@ export class LocalDebugTestContext extends TestContext {
case "msgapikey":
await execCommand(
this.testRootFolder,
- `teamsapp new --app-name ${this.appName} --interactive false --capability search-app --me-architecture new-api --api-me-auth api-key --programming-language ${this.lang} --telemetry false`
+ `teamsapp new --app-name ${this.appName} --interactive false --capability search-app --me-architecture new-api --api-auth api-key --programming-language ${this.lang} --telemetry false`
);
break;
}
@@ -334,19 +356,3 @@ export class LocalDebugSampleTestContext extends LocalDebugTestContext {
this.sampleName = sampleName;
}
}
-
-export class LocalDebugSpfxTestContext extends LocalDebugTestContext {
- public framework: "react" | "minimal" | "none";
- constructor(framework: "react" | "minimal" | "none" = "react") {
- super("spfx");
- this.testName = "spfx";
- this.framework = framework;
- }
-
- public async createProject(): Promise {
- await execCommand(
- this.testRootFolder,
- `teamsapp new --app-name ${this.appName} --interactive false --capability tab-spfx --spfx-framework-type ${this.framework} --spfx-webpart-name ${this.appName} --telemetry false`
- );
- }
-}
diff --git a/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-provision-upgrade-provision-debug.test.ts
index ffd1ccd2f4..c0a894a1c5 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-provision-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -43,6 +44,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-upgrade-provision-debug.test.ts
index 58c87514ab..42aeea49aa 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-msg/4.0.0-msg-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -43,6 +44,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
index 2c3bead13d..9f2a096576 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
@@ -23,6 +23,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -55,7 +56,20 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
- await mirgationDebugTestContext.after(false, true, "dev");
+ await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug.test.ts
index 950e350ecc..9f0f31a07d 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-provision-upgrade-provision-debug.test.ts
@@ -23,6 +23,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -55,7 +56,20 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
- await mirgationDebugTestContext.after(false, true, "dev");
+ await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug-ts.test.ts
index f66eb1f1fd..833b980e15 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug-ts.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
getBotSiteEndpoint,
@@ -50,7 +51,20 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
- await mirgationDebugTestContext.after(false, true, "dev");
+ await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug.test.ts
index 20f9a926c0..0823547dae 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-notification-bot-restify/4.0.0-notification-bot-restify-upgrade-provision-debug.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
getBotSiteEndpoint,
@@ -50,7 +51,20 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
- await mirgationDebugTestContext.after(false, true, "dev");
+ await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
index 01d5fa1bc6..228d1a970c 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
@@ -18,6 +18,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
updateFunctionAuthorizationPolicy,
@@ -48,6 +49,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-upgrade-provision-debug.test.ts
index ef70722047..46e3033036 100644
--- a/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/4.0.0-sso-tab-bot-function/4.0.0-sso-tab-bot-function-upgrade-provision-debug.test.ts
@@ -18,6 +18,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
updateFunctionAuthorizationPolicy,
@@ -48,6 +49,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-debug-upgrade-debug.test.ts b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-debug-upgrade-debug.test.ts
index 76c6a909af..30c0ce4bcc 100644
--- a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-debug-upgrade-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-debug-upgrade-debug.test.ts
@@ -6,7 +6,6 @@ import {
Capability,
Notification,
LocalDebugTaskLabel,
- CliVersion,
} from "../../../utils/constants";
import { it } from "../../../utils/it";
import { Env } from "../../../utils/env";
diff --git a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-provision-upgrade-provision-debug.test.ts
index a7c39aa0b8..5ed98e03ca 100644
--- a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-provision-upgrade-provision-debug.test.ts
@@ -12,12 +12,9 @@ import {
validateNotification,
validateUpgrade,
upgradeByCommandPalette,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
-import {
- reRunProvision,
- reRunDeploy,
-} from "../../remotedebug/remotedebugContext";
import { CliHelper } from "../../cliHelper";
dotenv.config();
@@ -40,6 +37,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-upgrade-provision-debug.test.ts
index ca66a8b2b1..d8ebdf6e25 100644
--- a/packages/tests/src/ui-test/migration/basic-tab/basic-tab-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/basic-tab/basic-tab-upgrade-provision-debug.test.ts
@@ -12,9 +12,9 @@ import {
validateNotification,
validateUpgrade,
upgradeByCommandPalette,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
-import { runProvision, runDeploy } from "../../remotedebug/remotedebugContext";
import { CliHelper } from "../../cliHelper";
dotenv.config();
@@ -37,6 +37,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/bot/bot-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/bot/bot-provision-upgrade-provision-debug.test.ts
index ebe8f1e3c2..1b4e16faf8 100644
--- a/packages/tests/src/ui-test/migration/bot/bot-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/bot/bot-provision-upgrade-provision-debug.test.ts
@@ -14,12 +14,9 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
-import {
- reRunProvision,
- reRunDeploy,
-} from "../../remotedebug/remotedebugContext";
import { CliHelper } from "../../cliHelper";
describe("Migration Tests", function () {
@@ -40,6 +37,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/bot/bot-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/bot/bot-upgrade-provision-debug.test.ts
index 23b483d6cd..40bf9ddbec 100644
--- a/packages/tests/src/ui-test/migration/bot/bot-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/bot/bot-upgrade-provision-debug.test.ts
@@ -14,8 +14,8 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
-import { runProvision, runDeploy } from "../../remotedebug/remotedebugContext";
import { CliHelper } from "../../cliHelper";
describe("Migration Tests", function () {
@@ -36,6 +36,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/command-bot/command-bot-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/command-bot/command-bot-provision-upgrade-provision-debug.test.ts
index e208d1ef34..d4bafac56f 100644
--- a/packages/tests/src/ui-test/migration/command-bot/command-bot-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/command-bot/command-bot-provision-upgrade-provision-debug.test.ts
@@ -13,6 +13,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -34,6 +35,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/command-bot/command-bot-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/command-bot/command-bot-upgrade-provision-debug.test.ts
index b7059c8e26..d48a5092d9 100644
--- a/packages/tests/src/ui-test/migration/command-bot/command-bot-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/command-bot/command-bot-upgrade-provision-debug.test.ts
@@ -13,6 +13,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -34,6 +35,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-provision-upgrade-provision-debug.test.ts
index a88d8cc3ea..5e80af4d04 100644
--- a/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-provision-upgrade-provision-debug.test.ts
@@ -18,6 +18,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-upgrade-provision-debug.test.ts
index a8bd85f1ff..6029499704 100644
--- a/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/dashboard-tab/dashboard-tab-upgrade-provision-debug.test.ts
@@ -18,6 +18,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/migrationContext.ts b/packages/tests/src/ui-test/migration/migrationContext.ts
index 1734c203ab..62371d5ded 100644
--- a/packages/tests/src/ui-test/migration/migrationContext.ts
+++ b/packages/tests/src/ui-test/migration/migrationContext.ts
@@ -12,15 +12,16 @@ import {
} from "../../utils/constants";
import { TestContext } from "../testContext";
import { CliHelper } from "../cliHelper";
-import { stopDebugging } from "../../utils/vscodeOperation";
-import { Env } from "../../utils/env";
-import { dotenvUtil } from "../../utils/envUtil";
import {
- cleanAppStudio,
+ cleanUpAadApp,
cleanTeamsApp,
- GraphApiCleanHelper,
+ cleanAppStudio,
+ cleanUpLocalProject,
+ cleanUpResourceGroup,
createResourceGroup,
} from "../../utils/cleanHelper";
+import { Env } from "../../utils/env";
+import { dotenvUtil } from "../../utils/envUtil";
import { AzSqlHelper } from "../../utils/azureCliHelper";
import { runProvision, runDeploy } from "../remotedebug/remotedebugContext";
@@ -122,13 +123,39 @@ export class MigrationTestContext extends TestContext {
hasBotPlugin = false,
envName = "dev"
) {
- await stopDebugging();
await this.context!.close();
await this.browser!.close();
- if (envName != "local") {
- await AzSqlHelper.deleteResourceGroup(this.rgName);
- }
- await this.cleanResource(hasAadPlugin, hasBotPlugin);
+ if (envName === "local")
+ await this.cleanResource(hasAadPlugin, hasBotPlugin);
+ }
+
+ public async cleanUp(
+ appName: string,
+ projectPath: string,
+ hasAadPlugin = true,
+ hasBotPlugin = false,
+ hasApimPlugin = false,
+ envName = "dev"
+ ) {
+ const cleanUpAadAppPromise = cleanUpAadApp(
+ projectPath,
+ hasAadPlugin,
+ hasBotPlugin,
+ hasApimPlugin,
+ envName
+ );
+ return Promise.all([
+ // delete aad app
+ cleanUpAadAppPromise,
+ // uninstall Teams app
+ cleanTeamsApp(appName),
+ // delete Teams app in app studio
+ cleanAppStudio(appName),
+ // remove resouce group
+ cleanUpResourceGroup(appName, envName),
+ // remove project
+ cleanUpLocalProject(projectPath, cleanUpAadAppPromise),
+ ]);
}
public async getTeamsAppId(env: "local" | "dev" = "local"): Promise {
@@ -210,38 +237,6 @@ export class MigrationTestContext extends TestContext {
await CliHelper.debugProject(this.projectPath, env, v3);
}
- public async cleanResource(
- hasAadPlugin = true,
- hasBotPlugin = false
- ): Promise {
- try {
- const cleanService = await GraphApiCleanHelper.create(
- Env.cleanTenantId,
- Env.cleanClientId,
- Env.username,
- Env.password
- );
- if (hasAadPlugin) {
- const aadObjectId = await this.getAadObjectId();
- console.log(`delete AAD ${aadObjectId}`);
- await cleanService.deleteAad(aadObjectId);
- }
-
- if (hasBotPlugin) {
- const botAppId = await this.getBotAppId();
- const botObjectId = await cleanService.getAadObjectId(botAppId);
- if (botObjectId) {
- console.log(`delete Bot AAD ${botObjectId}`);
- await cleanService.deleteAad(botObjectId);
- }
- }
- } catch (e: any) {
- console.log(`Failed to clean resource, error message: ${e.message}`);
- }
- await cleanTeamsApp(this.appName);
- await cleanAppStudio(this.appName);
- }
-
public async provisionProject(
appName: string,
projectPath = "",
diff --git a/packages/tests/src/ui-test/migration/msg/msg-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/msg/msg-provision-upgrade-provision-debug.test.ts
index 06eb4dabb3..a8c6512705 100644
--- a/packages/tests/src/ui-test/migration/msg/msg-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/msg/msg-provision-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -36,6 +37,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/msg/msg-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/msg/msg-upgrade-provision-debug.test.ts
index 7186f766c1..a769b2d3f9 100644
--- a/packages/tests/src/ui-test/migration/msg/msg-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/msg/msg-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -36,6 +37,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug-ts.test.ts
index 867887b168..9886495a0f 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug-ts.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -44,6 +45,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug.test.ts
index df58327a60..d7b9f4801c 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-provision-upgrade-provision-debug.test.ts
@@ -23,6 +23,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -48,6 +49,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug-ts.test.ts
index 6ec13da00c..30ab8f85a9 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug-ts.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -44,6 +45,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug.test.ts
index ee2a3e0529..98bd57deba 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-func-http/notification-bot-func-upgrade-provision-debug.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -44,6 +45,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
index 3b138a2b1f..5e4d927949 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug-ts.test.ts
@@ -23,6 +23,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -49,6 +50,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug.test.ts
index f7a89327ea..96f86e2f34 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-provision-upgrade-provision-debug.test.ts
@@ -23,6 +23,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -49,6 +50,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug-ts.test.ts b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug-ts.test.ts
index 14045e94b3..4725b0a072 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug-ts.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug-ts.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -45,6 +46,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug.test.ts
index f97bc219ee..ca734cd080 100644
--- a/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/notification-bot-restify/notification-bot-restify-upgrade-provision-debug.test.ts
@@ -19,6 +19,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -45,6 +46,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(false, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ false,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-debug-upgrade-debug.test.ts b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-debug-upgrade-debug.test.ts
index 1e4727f560..8bc832b632 100644
--- a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-debug-upgrade-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-debug-upgrade-debug.test.ts
@@ -94,7 +94,10 @@ describe("Migration Tests", function () {
Env.username,
Env.password
);
- await validateQueryOrg(page, { displayName: Env.displayName });
+ await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: sampledebugContext.appName.substring(0, 10),
+ });
console.log("debug finish!");
}
);
diff --git a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-provision-upgrade-provision-debug.test.ts
index 5cdd97965d..d0a7c4e464 100644
--- a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-provision-upgrade-provision-debug.test.ts
@@ -81,7 +81,10 @@ describe("Migration Tests", function () {
Env.username,
Env.password
);
- await validateQueryOrg(page, { displayName: Env.displayName });
+ await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: sampledebugContext.appName.substring(0, 10),
+ });
console.log("debug finish!");
}
);
diff --git a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-debug.test.ts b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-debug.test.ts
index ea5a9773a7..b20ed4e3d4 100644
--- a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-debug.test.ts
@@ -91,7 +91,10 @@ describe("Migration Tests", function () {
Env.username,
Env.password
);
- await validateQueryOrg(page, { displayName: Env.displayName });
+ await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: sampledebugContext.appName.substring(0, 10),
+ });
console.log("debug finish!");
}
);
diff --git a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-provision-debug.test.ts
index 6231c2de11..78ac86eae5 100644
--- a/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sample-org-user-search-connector/sample-org-user-search-connector-upgrade-provision-debug.test.ts
@@ -77,7 +77,10 @@ describe("Migration Tests", function () {
Env.username,
Env.password
);
- await validateQueryOrg(page, { displayName: Env.displayName });
+ await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: sampledebugContext.appName.substring(0, 10),
+ });
console.log("debug finish!");
}
);
diff --git a/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-provision-upgrade-provision-debug.test.ts
index 20eadafb75..9b67e2c598 100644
--- a/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-provision-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -38,6 +39,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-upgrade-provision-debug.test.ts
index 8aa639dc43..58958ddb9a 100644
--- a/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/search-based-msg/search-based-message-extension-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -38,6 +39,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-provision-upgrade-provision-debug.test.ts
index 0e14830490..6683e915e8 100644
--- a/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-provision-upgrade-provision-debug.test.ts
@@ -10,6 +10,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -31,6 +32,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-upgrade-provision-debug.test.ts
index 3775ac6ffc..1f7682c1b4 100644
--- a/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-personal-tab/sso-personal-tab-upgrade-provision-debug.test.ts
@@ -10,6 +10,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -31,6 +32,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
index 92d142e050..e3b541081f 100644
--- a/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-provision-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-upgrade-provision-debug.test.ts
index 12b1f1f07e..e74e7a3728 100644
--- a/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab-bot-function/sso-tab-bot-function-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-provision-upgrade-provision-debug.test.ts
index 76efa7aa85..c9d5e794f2 100644
--- a/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-provision-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-upgrade-provision-debug.test.ts
index abdae935b2..6218432adf 100644
--- a/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab-func/sso-tab-function-upgrade-provision-debug.test.ts
@@ -15,6 +15,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import {
CLIVersionCheck,
@@ -39,6 +40,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab/sso-tab-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab/sso-tab-provision-upgrade-provision-debug.test.ts
index f768eaed57..55d61758d0 100644
--- a/packages/tests/src/ui-test/migration/sso-tab/sso-tab-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab/sso-tab-provision-upgrade-provision-debug.test.ts
@@ -10,6 +10,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -33,6 +34,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/sso-tab/sso-tab-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/sso-tab/sso-tab-upgrade-provision-debug.test.ts
index 10bb87aadd..c6a1eb5d52 100644
--- a/packages/tests/src/ui-test/migration/sso-tab/sso-tab-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/sso-tab/sso-tab-upgrade-provision-debug.test.ts
@@ -10,6 +10,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import * as dotenv from "dotenv";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -33,6 +34,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, false, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ false,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-provision-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-provision-upgrade-provision-debug.test.ts
index a8cbb292fa..6506a5ab94 100644
--- a/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-provision-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-provision-upgrade-provision-debug.test.ts
@@ -14,6 +14,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -35,6 +36,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-upgrade-provision-debug.test.ts b/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-upgrade-provision-debug.test.ts
index 23d06d2e7f..197c8d8ce3 100644
--- a/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-upgrade-provision-debug.test.ts
+++ b/packages/tests/src/ui-test/migration/workflow-bot/workflow-bot-upgrade-provision-debug.test.ts
@@ -14,6 +14,7 @@ import {
validateNotification,
upgradeByTreeView,
validateUpgrade,
+ execCommandIfExist,
} from "../../../utils/vscodeOperation";
import { CLIVersionCheck } from "../../../utils/commonUtils";
@@ -35,6 +36,19 @@ describe("Migration Tests", function () {
afterEach(async function () {
this.timeout(Timeout.finishTestCase);
await mirgationDebugTestContext.after(true, true, "dev");
+
+ //Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ console.log(
+ `[Successfully] start to clean up for ${mirgationDebugTestContext.projectPath}`
+ );
+ await mirgationDebugTestContext.cleanUp(
+ mirgationDebugTestContext.appName,
+ mirgationDebugTestContext.projectPath,
+ true,
+ true,
+ false
+ );
});
it(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-ts-win-only.test.ts
index b6c73235f7..50e86f98a2 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-ts-win-only.test.ts
@@ -68,7 +68,10 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("aiassist", appName, "TypeScript");
+ await createNewProject("aiassist", appName, {
+ lang: "TypeScript",
+ aiType: "OpenAI",
+ });
validateFileExist(projectPath, "src/index.ts");
const envPath = path.resolve(projectPath, "env", ".env.dev.user");
editDotEnvFile(envPath, "SECRET_OPENAI_API_KEY", "fake");
@@ -91,7 +94,7 @@ describe("Remote debug Tests", function () {
botCommand: "helloWorld",
expectedWelcomeMessage:
ValidationContent.AiAssistantBotWelcomeInstruction,
- expectedReplyMessage: ValidationContent.AiBotErrorMessage,
+ expectedReplyMessage: ValidationContent.AiBotErrorMessage2,
});
}
);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-win-only.test.ts
index e1d654cff1..87256ee412 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-aiassistant-bot-win-only.test.ts
@@ -68,7 +68,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("aiassist", appName);
+ await createNewProject("aiassist", appName, { aiType: "OpenAI" });
validateFileExist(projectPath, "src/index.js");
const envPath = path.resolve(projectPath, "env", ".env.dev.user");
editDotEnvFile(envPath, "SECRET_OPENAI_API_KEY", "fake");
@@ -91,7 +91,7 @@ describe("Remote debug Tests", function () {
botCommand: "helloWorld",
expectedWelcomeMessage:
ValidationContent.AiAssistantBotWelcomeInstruction,
- expectedReplyMessage: ValidationContent.AiBotErrorMessage,
+ expectedReplyMessage: ValidationContent.AiBotErrorMessage2,
});
}
);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-py-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-py-win-only.test.ts
index 90fb0855ce..c43c4beb6b 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-py-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-py-win-only.test.ts
@@ -69,7 +69,10 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("aichat", appName, "Python");
+ await createNewProject("aichat", appName, {
+ lang: "Python",
+ aiType: "Azure OpenAI",
+ });
validateFileExist(projectPath, "src/app.py");
const envPath = path.resolve(projectPath, "env", ".env.dev.user");
editDotEnvFile(envPath, "SECRET_AZURE_OPENAI_API_KEY", "fake");
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-ts-win-only.test.ts
index 0bd0e2c5a7..730eceb825 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-ts-win-only.test.ts
@@ -68,7 +68,10 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("aichat", appName, "TypeScript");
+ await createNewProject("aichat", appName, {
+ lang: "TypeScript",
+ aiType: "Azure OpenAI",
+ });
validateFileExist(projectPath, "src/index.ts");
const envPath = path.resolve(projectPath, "env", ".env.dev.user");
editDotEnvFile(envPath, "SECRET_AZURE_OPENAI_API_KEY", "fake");
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-win-only.test.ts
index f8fb08d30b..03042b2e79 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-aichat-bot-win-only.test.ts
@@ -68,7 +68,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("aichat", appName);
+ await createNewProject("aichat", appName, { aiType: "Azure OpenAI" });
validateFileExist(projectPath, "src/index.js");
const envPath = path.resolve(projectPath, "env", ".env.dev.user");
editDotEnvFile(envPath, "SECRET_AZURE_OPENAI_API_KEY", "fake");
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-bot-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-bot-ts-win-only.test.ts
index da476e966b..797a7d63a5 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-bot-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-bot-ts-win-only.test.ts
@@ -64,7 +64,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("bot", appName, "TypeScript");
+ await createNewProject("bot", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-command-and-response-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-command-and-response-ts-win-only.test.ts
index 06d1d709aa..2a52771a52 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-command-and-response-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-command-and-response-ts-win-only.test.ts
@@ -67,7 +67,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("crbot", appName, "TypeScript");
+ await createNewProject("crbot", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/index.ts");
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-ts-win-only.test.ts
index f51ebecd44..f223f41b7a 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-ts-win-only.test.ts
@@ -65,7 +65,7 @@ describe("Remote debug Tests", function () {
author: "v-ivanchen@microsoft.com",
},
async function () {
- await createNewProject("dashboard", appName, "TypeScript");
+ await createNewProject("dashboard", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-win-only.test.ts
index 74a9bf585d..c7388ead62 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-dashboard-win-only.test.ts
@@ -65,7 +65,7 @@ describe("Remote debug Tests", function () {
author: "v-ivanchen@microsoft.com",
},
async function () {
- await createNewProject("dashboard", appName, "JavaScript");
+ await createNewProject("dashboard", appName, { lang: "JavaScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-ts-win-only.test.ts
index 6fb951b52c..a05819034e 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-ts-win-only.test.ts
@@ -65,7 +65,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("linkunfurl", appName, "TypeScript");
+ await createNewProject("linkunfurl", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
@@ -77,7 +77,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateUnfurlCard(page);
+ await validateUnfurlCard(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-win-only.test.ts
index 0a0e1cb532..9b1411f251 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-link-unfurling-win-only.test.ts
@@ -77,7 +77,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateUnfurlCard(page);
+ await validateUnfurlCard(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-m365lp-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-m365lp-ts-win-only.test.ts
index 56d32db9c6..31fb169520 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-m365lp-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-m365lp-ts-win-only.test.ts
@@ -67,7 +67,7 @@ describe("Remote debug Tests", function () {
async function () {
//create tab project
const driver = VSBrowser.instance.driver;
- await createNewProject("m365lp", appName, "TypeScript");
+ await createNewProject("m365lp", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-ts-win-only.test.ts
index 0f12fc3a38..147e0cce7f 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-ts-win-only.test.ts
@@ -66,7 +66,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("msgapikey", appName, "TypeScript");
+ await createNewProject("msgapikey", appName, { lang: "TypeScript" });
const userFile = path.resolve(projectPath, "env", ".env.dev.user");
const SECRET_API_KEY = "SECRET_API_KEY=gbxEWvk4p3sg";
const KEY = "\n" + SECRET_API_KEY;
@@ -83,7 +83,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-win-only.test.ts
index 90a20be087..e57f213b20 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-apikey-win-only.test.ts
@@ -83,7 +83,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-ts-win-only.test.ts
index dc7da02268..10ceb10f23 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-ts-win-only.test.ts
@@ -65,7 +65,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("msgnewapi", appName, "TypeScript");
+ await createNewProject("msgnewapi", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
@@ -77,7 +77,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-win-only.test.ts
index 1e230a6900..09e6c87c98 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-newapi-win-only.test.ts
@@ -77,7 +77,7 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateApiMeResult(page);
+ await validateApiMeResult(page, remoteDebugTestContext.appName);
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-ts-win-only.test.ts
index c88a3d136b..d4a991f91f 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msg-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msg-ts-win-only.test.ts
@@ -64,7 +64,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("msg", appName, "TypeScript");
+ await createNewProject("msg", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-ts-win-only.test.ts
index 04a52848df..05ef19829d 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-ts-win-only.test.ts
@@ -17,7 +17,7 @@ import {
createNewProject,
} from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { initPage, validateMsg } from "../../utils/playwrightOperation";
+import { initPage, validateNpm } from "../../utils/playwrightOperation";
import { Env } from "../../utils/env";
describe("Remote debug Tests", function () {
@@ -64,7 +64,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("msgsa", appName, "TypeScript");
+ await createNewProject("msgsa", appName, { lang: "TypeScript" });
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
@@ -76,7 +76,10 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateMsg(page);
+ await validateNpm(page, {
+ npmName: "axios",
+ appName: remoteDebugTestContext.appName,
+ });
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-win-only.test.ts
index 7a0f8b90c7..35eb2ad29b 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-msgsa-win-only.test.ts
@@ -18,7 +18,7 @@ import {
createNewProject,
} from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { initPage, validateMsg } from "../../utils/playwrightOperation";
+import { initPage, validateNpm } from "../../utils/playwrightOperation";
import { Env } from "../../utils/env";
describe("Remote debug Tests", function () {
@@ -77,7 +77,10 @@ describe("Remote debug Tests", function () {
Env.username,
Env.password
);
- await validateMsg(page);
+ await validateNpm(page, {
+ npmName: "axios",
+ appName: remoteDebugTestContext.appName,
+ });
}
);
});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-timertrigger-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-timertrigger-ts-win-only.test.ts
index 816125559f..a741b5f4fe 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-timertrigger-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-timertrigger-ts-win-only.test.ts
@@ -73,7 +73,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("functimernoti", appName, "TypeScript");
+ await createNewProject("functimernoti", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/httpTrigger.ts");
validateFileExist(projectPath, "src/timerTrigger.ts");
await provisionProject(appName, projectPath);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-ts-win-only.test.ts
index d84305633c..e5b35c7c2d 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-func-ts-win-only.test.ts
@@ -71,7 +71,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("funcnoti", appName, "TypeScript");
+ await createNewProject("funcnoti", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/httpTrigger.ts");
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-restify-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-restify-ts-win-only.test.ts
index 4ee77edbcf..709541d490 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-restify-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-restify-ts-win-only.test.ts
@@ -71,7 +71,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("restnoti", appName, "TypeScript");
+ await createNewProject("restnoti", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/index.ts");
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-timertrigger-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-timertrigger-ts-win-only.test.ts
index ad68810bf5..58fe83c6d9 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-notification-timertrigger-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-notification-timertrigger-ts-win-only.test.ts
@@ -70,7 +70,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("timenoti", appName, "TypeScript");
+ await createNewProject("timenoti", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/timerTrigger.ts");
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-minimal.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-minimal.test.ts
similarity index 96%
rename from packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-minimal.test.ts
rename to packages/tests/src/ui-test/remotedebug/remotedebug-spfx-minimal.test.ts
index 06fd70d55e..570ec26c3a 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-minimal.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-minimal.test.ts
@@ -61,7 +61,9 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxmin", appName);
+ await createNewProject("spfx", appName, {
+ spfxFrameworkType: "Minimal",
+ });
validateFileExist(projectPath, "src/src/index.ts");
await clearNotifications();
await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-none.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-none.test.ts
similarity index 97%
rename from packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-none.test.ts
rename to packages/tests/src/ui-test/remotedebug/remotedebug-spfx-none.test.ts
index 97e038b375..5397c588a7 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-none.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-none.test.ts
@@ -61,7 +61,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxnone", appName);
+ await createNewProject("spfx", appName, { spfxFrameworkType: "None" });
validateFileExist(projectPath, "src/src/index.ts");
await clearNotifications();
await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-publish.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-publish.test.ts
index 1fd70d35ed..1323f6d5b3 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-publish.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-publish.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Helly Zhang
*/
@@ -53,7 +56,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxreact", appName);
+ await createNewProject("spfx", appName);
await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
await driver.sleep(Timeout.spfxProvision);
await getNotification(
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-react.test.ts
similarity index 97%
rename from packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact.test.ts
rename to packages/tests/src/ui-test/remotedebug/remotedebug-spfx-react.test.ts
index 098417396c..2c16f5851d 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfx-react.test.ts
@@ -61,7 +61,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxreact", appName);
+ await createNewProject("spfx", appName, { spfxFrameworkType: "React" });
validateFileExist(projectPath, "src/src/index.ts");
await clearNotifications();
await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxnone-globalpkg-addwebpart.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxnone-globalpkg-addwebpart.test.ts
index e1b65a6e3a..e0a33315d1 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxnone-globalpkg-addwebpart.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxnone-globalpkg-addwebpart.test.ts
@@ -11,11 +11,7 @@ import {
Timeout,
Notification,
} from "../../utils/constants";
-import {
- RemoteDebugTestContext,
- configSpfxGlobalEnv,
- runDeploy,
-} from "./remotedebugContext";
+import { RemoteDebugTestContext, runDeploy } from "./remotedebugContext";
import {
execCommandIfExist,
getNotification,
@@ -31,7 +27,10 @@ import {
import { Env } from "../../utils/env";
import { cleanUpLocalProject } from "../../utils/cleanHelper";
import { it } from "../../utils/it";
-import { validateFileExist } from "../../utils/commonUtils";
+import {
+ configSpfxGlobalEnv,
+ validateFileExist,
+} from "../../utils/commonUtils";
describe("Remote debug Tests", function () {
this.timeout(Timeout.testAzureCase);
@@ -69,7 +68,7 @@ describe("Remote debug Tests", function () {
async function () {
await configSpfxGlobalEnv();
const driver = VSBrowser.instance.driver;
- await createNewProject("gspfxnone", appName);
+ await createNewProject("gspfx", appName, { spfxFrameworkType: "None" });
validateFileExist(projectPath, "src/src/index.ts");
validateFileExist(projectPath, "src/.yo-rc.json");
await addSpfxWebPart("helloworld");
@@ -94,12 +93,10 @@ describe("Remote debug Tests", function () {
await driver.sleep(Timeout.longTimeWait);
// Validate app name is in the page
- await validateSpfx(page, {
- displayName: `Web part property value: ${appName}`,
- });
+ await validateSpfx(page, { displayName: appName });
await switchToTab(page, "helloworld");
await validateSpfx(page, {
- displayName: "Web part property value: helloworld",
+ displayName: "helloworld",
});
}
);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-addwebpart.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-addwebpart.test.ts
index 09f6f4db46..185f05e501 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-addwebpart.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-addwebpart.test.ts
@@ -66,7 +66,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxreact", appName);
+ await createNewProject("spfx", appName, { spfxFrameworkType: "React" });
validateFileExist(projectPath, "src/src/index.ts");
await addSpfxWebPart("helloworld");
await clearNotifications();
@@ -88,11 +88,11 @@ describe("Remote debug Tests", function () {
Env.password
);
await driver.sleep(Timeout.longTimeWait);
-
+ await validateSpfx(page, { displayName: appName });
// Validate app name is in the page
await switchToTab(page, "helloworld");
await validateSpfx(page, {
- displayName: "Web part property value: helloworld",
+ displayName: "helloworld",
});
}
);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-globalpkg.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-globalpkg.test.ts
index 54a2efeb34..45d609e560 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-globalpkg.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-globalpkg.test.ts
@@ -11,11 +11,7 @@ import {
Timeout,
Notification,
} from "../../utils/constants";
-import {
- RemoteDebugTestContext,
- configSpfxGlobalEnv,
- runDeploy,
-} from "./remotedebugContext";
+import { RemoteDebugTestContext, runDeploy } from "./remotedebugContext";
import {
execCommandIfExist,
getNotification,
@@ -26,7 +22,10 @@ import { initPage, validateSpfx } from "../../utils/playwrightOperation";
import { Env } from "../../utils/env";
import { cleanUpLocalProject } from "../../utils/cleanHelper";
import { it } from "../../utils/it";
-import { validateFileExist } from "../../utils/commonUtils";
+import {
+ configSpfxGlobalEnv,
+ validateFileExist,
+} from "../../utils/commonUtils";
describe("Remote debug Tests", function () {
this.timeout(Timeout.testAzureCase);
@@ -64,7 +63,7 @@ describe("Remote debug Tests", function () {
async function () {
await configSpfxGlobalEnv();
const driver = VSBrowser.instance.driver;
- await createNewProject("gspfxreact", appName);
+ await createNewProject("gspfx", appName, { spfxFrameworkType: "React" });
validateFileExist(projectPath, "src/src/index.ts");
validateFileExist(projectPath, "src/.yo-rc.json");
await clearNotifications();
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-multiple.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-multiple.test.ts
new file mode 100644
index 0000000000..4e7f8c1836
--- /dev/null
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-multiple.test.ts
@@ -0,0 +1,110 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/**
+ * @author Helly Zhang
+ */
+import * as path from "path";
+import { InputBox, VSBrowser } from "vscode-extension-tester";
+import {
+ CommandPaletteCommands,
+ Timeout,
+ Notification,
+} from "../../utils/constants";
+import { RemoteDebugTestContext, runDeploy } from "./remotedebugContext";
+import {
+ execCommandIfExist,
+ getNotification,
+ createNewProject,
+ clearNotifications,
+} from "../../utils/vscodeOperation";
+import {
+ initPage,
+ switchToTab,
+ validateSpfx,
+} from "../../utils/playwrightOperation";
+import { Env } from "../../utils/env";
+import { cleanUpLocalProject } from "../../utils/cleanHelper";
+import { it } from "../../utils/it";
+import {
+ configSpfxGlobalEnv,
+ generateYoSpfxProject,
+ validateFileExist,
+} from "../../utils/commonUtils";
+
+describe("Remote debug Tests", function () {
+ this.timeout(Timeout.testAzureCase);
+ let remoteDebugTestContext: RemoteDebugTestContext;
+ let testRootFolder: string;
+ let appName: string;
+ const appNameCopySuffix = "copy";
+ let newAppFolderName: string;
+ let projectPath: string;
+
+ beforeEach(async function () {
+ this.timeout(Timeout.prepareTestCase);
+ remoteDebugTestContext = new RemoteDebugTestContext("spfx");
+ testRootFolder = remoteDebugTestContext.testRootFolder;
+ appName = remoteDebugTestContext.appName;
+ newAppFolderName = appName + appNameCopySuffix;
+ projectPath = path.resolve(testRootFolder, newAppFolderName);
+ await remoteDebugTestContext.before();
+ });
+
+ afterEach(async function () {
+ this.timeout(Timeout.finishTestCase);
+ await remoteDebugTestContext.after();
+ // Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ cleanUpLocalProject(projectPath);
+ });
+
+ it(
+ "[auto] Import existing SPFx solution with multiple web parts",
+ {
+ testPlanCaseId: 24434596,
+ author: "v-helzha@microsoft.com",
+ },
+ async function () {
+ await configSpfxGlobalEnv();
+ await generateYoSpfxProject({
+ solutionName: "existingspfx",
+ componentName: appName,
+ });
+ await generateYoSpfxProject({
+ existingSolutionName: "existingspfx",
+ componentName: "helloworld",
+ });
+ const driver = VSBrowser.instance.driver;
+ await createNewProject("importspfx", appName);
+ validateFileExist(projectPath, "src/src/index.ts");
+ validateFileExist(projectPath, "src/.yo-rc.json");
+ await clearNotifications();
+ await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
+ await driver.sleep(Timeout.spfxProvision);
+ await getNotification(
+ Notification.ProvisionSucceeded,
+ Timeout.shortTimeWait
+ );
+ await runDeploy();
+
+ const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
+ projectPath
+ );
+ const page = await initPage(
+ remoteDebugTestContext.context!,
+ teamsAppId,
+ Env.username,
+ Env.password
+ );
+ await driver.sleep(Timeout.longTimeWait);
+
+ // Validate app name is in the page
+ await validateSpfx(page, { displayName: appName });
+ await switchToTab(page, "helloworld");
+ await validateSpfx(page, {
+ displayName: "helloworld",
+ });
+ }
+ );
+});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-single.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-single.test.ts
new file mode 100644
index 0000000000..2550a9c422
--- /dev/null
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-spfxreact-import-single.test.ts
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/**
+ * @author Helly Zhang
+ */
+import * as path from "path";
+import { InputBox, VSBrowser } from "vscode-extension-tester";
+import {
+ CommandPaletteCommands,
+ Timeout,
+ Notification,
+} from "../../utils/constants";
+import { RemoteDebugTestContext, runDeploy } from "./remotedebugContext";
+import {
+ execCommandIfExist,
+ getNotification,
+ createNewProject,
+ clearNotifications,
+} from "../../utils/vscodeOperation";
+import { initPage, validateSpfx } from "../../utils/playwrightOperation";
+import { Env } from "../../utils/env";
+import { cleanUpLocalProject } from "../../utils/cleanHelper";
+import { it } from "../../utils/it";
+import {
+ configSpfxGlobalEnv,
+ generateYoSpfxProject,
+ validateFileExist,
+} from "../../utils/commonUtils";
+
+describe("Remote debug Tests", function () {
+ this.timeout(Timeout.testAzureCase);
+ let remoteDebugTestContext: RemoteDebugTestContext;
+ let testRootFolder: string;
+ let appName: string;
+ const appNameCopySuffix = "copy";
+ let newAppFolderName: string;
+ let projectPath: string;
+
+ beforeEach(async function () {
+ this.timeout(Timeout.prepareTestCase);
+ remoteDebugTestContext = new RemoteDebugTestContext("spfx");
+ testRootFolder = remoteDebugTestContext.testRootFolder;
+ appName = remoteDebugTestContext.appName;
+ newAppFolderName = appName + appNameCopySuffix;
+ projectPath = path.resolve(testRootFolder, newAppFolderName);
+ await remoteDebugTestContext.before();
+ });
+
+ afterEach(async function () {
+ this.timeout(Timeout.finishTestCase);
+ await remoteDebugTestContext.after();
+ // Close the folder and cleanup local sample project
+ await execCommandIfExist("Workspaces: Close Workspace", Timeout.webView);
+ cleanUpLocalProject(projectPath);
+ });
+
+ it(
+ "[auto] Import existing SPFx solution with one web part",
+ {
+ testPlanCaseId: 24434342,
+ author: "v-helzha@microsoft.com",
+ },
+ async function () {
+ await configSpfxGlobalEnv();
+ await generateYoSpfxProject({
+ solutionName: "existingspfx",
+ componentName: appName,
+ });
+ const driver = VSBrowser.instance.driver;
+ await createNewProject("importspfx", appName);
+ validateFileExist(projectPath, "src/src/index.ts");
+ validateFileExist(projectPath, "src/.yo-rc.json");
+ await clearNotifications();
+ await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
+ await driver.sleep(Timeout.spfxProvision);
+ await getNotification(
+ Notification.ProvisionSucceeded,
+ Timeout.shortTimeWait
+ );
+ await runDeploy();
+
+ const teamsAppId = await remoteDebugTestContext.getTeamsAppId(
+ projectPath
+ );
+ const page = await initPage(
+ remoteDebugTestContext.context!,
+ teamsAppId,
+ Env.username,
+ Env.password
+ );
+ await driver.sleep(Timeout.longTimeWait);
+
+ // Validate app name is in the page
+ await validateSpfx(page, { displayName: appName });
+ }
+ );
+});
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-tab-nosso-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-tab-nosso-ts-win-only.test.ts
index 5dfc06acc9..bbe802ffe3 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-tab-nosso-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-tab-nosso-ts-win-only.test.ts
@@ -66,7 +66,7 @@ describe("Remote debug Tests", function () {
async function () {
//create tab project
const driver = VSBrowser.instance.driver;
- await createNewProject("tabnsso", appName, "TypeScript");
+ await createNewProject("tabnsso", appName, { lang: "TypeScript" });
await setSkuNameToB1(projectPath);
await driver.sleep(Timeout.shortTimeWait);
await provisionProject(appName, projectPath);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-workflow-bot-ts-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-workflow-bot-ts-win-only.test.ts
index 82e0af6ce7..bc161dd767 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebug-workflow-bot-ts-win-only.test.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebug-workflow-bot-ts-win-only.test.ts
@@ -72,7 +72,7 @@ describe("Remote debug Tests", function () {
},
async function () {
const driver = VSBrowser.instance.driver;
- await createNewProject("workflow", appName, "TypeScript");
+ await createNewProject("workflow", appName, { lang: "TypeScript" });
validateFileExist(projectPath, "src/index.ts");
await provisionProject(appName, projectPath);
await deployProject(projectPath, Timeout.botDeploy);
diff --git a/packages/tests/src/ui-test/remotedebug/remotedebugContext.ts b/packages/tests/src/ui-test/remotedebug/remotedebugContext.ts
index e88601f329..0b66d99a70 100644
--- a/packages/tests/src/ui-test/remotedebug/remotedebugContext.ts
+++ b/packages/tests/src/ui-test/remotedebug/remotedebugContext.ts
@@ -453,17 +453,3 @@ export async function setSkipAddingSqlUser(
parameters["skipAddingSqlUser"] = true;
return fs.writeJSON(parametersFilePath, parameters, { spaces: 4 });
}
-
-export async function configSpfxGlobalEnv() {
- try {
- console.log(`Start to set up global environment:`);
- const result = await execAsync(
- "npm install gulp-cli yo @microsoft/generator-sharepoint --global"
- );
- console.log(`[Successfully] set up global environment.`);
- console.log(`${result.stdout}`);
- } catch (error) {
- console.log(error);
- throw new Error(`Failed to set up global environment: ${error}`);
- }
-}
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-chef-bot.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-chef-bot.test.ts
index 2771847154..77fb1214c0 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-chef-bot.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-chef-bot.test.ts
@@ -30,7 +30,7 @@ class ChefBotTestCase extends CaseFactory {
const envFile = path.resolve(
sampledebugContext.projectPath,
"env",
- ".env.local.user"
+ ".env.local"
);
// create .env.local.user file
fs.writeFileSync(envFile, "SECRET_OPENAI_KEY=yourapikey");
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-dashboard.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-dashboard.test.ts
index 2b46387931..643c567dd1 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-dashboard.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-dashboard.test.ts
@@ -31,9 +31,7 @@ class DashboardTestCase extends CaseFactory {
teamsAppId,
Env.username,
Env.password,
- { dashboardFlag: true },
- true,
- true
+ { dashboardFlag: true }
);
}
}
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-outlook.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-outlook.test.ts
index cd1f41f89a..fd72bf966f 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-outlook.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-outlook.test.ts
@@ -12,7 +12,6 @@ import {
reopenPage,
} from "../../utils/playwrightOperation";
import { CaseFactory } from "./sampleCaseFactory";
-import { Env } from "../../utils/env";
import { SampledebugContext } from "./sampledebugContext";
class OutlookTabTestCase extends CaseFactory {
@@ -26,15 +25,7 @@ class OutlookTabTestCase extends CaseFactory {
sampledebugContext: SampledebugContext,
teamsAppId: string
): Promise {
- return await reopenPage(
- sampledebugContext.context!,
- teamsAppId,
- Env.username,
- Env.password,
- undefined,
- true,
- true
- );
+ return await reopenPage(sampledebugContext.context!, teamsAppId);
}
}
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-with-backend.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-with-backend.test.ts
index 0eb0182f68..00f180e994 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-with-backend.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-hello-world-tab-with-backend.test.ts
@@ -17,10 +17,14 @@ class HelloWorldTabBackEndTestCase extends CaseFactory {
page: Page,
options?: { includeFunction: boolean }
): Promise {
- return await validateTab(page, {
- displayName: Env.displayName,
- includeFunction: options?.includeFunction,
- });
+ return await validateTab(
+ page,
+ {
+ displayName: Env.displayName,
+ includeFunction: options?.includeFunction,
+ },
+ true
+ );
}
override async onCliValidate(
page: Page,
@@ -35,15 +39,7 @@ class HelloWorldTabBackEndTestCase extends CaseFactory {
sampledebugContext: SampledebugContext,
teamsAppId: string
): Promise {
- return await reopenPage(
- sampledebugContext.context!,
- teamsAppId,
- Env.username,
- Env.password,
- undefined,
- true,
- true
- );
+ return await reopenPage(sampledebugContext.context!, teamsAppId);
}
}
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-large-scale-notification.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-large-scale-notification.test.ts
index 0307b2213d..5fb17f92ce 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-large-scale-notification.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-large-scale-notification.test.ts
@@ -48,6 +48,14 @@ class LargeNotiTestCase extends CaseFactory {
console.log(`update connect string to ${configFilePath} file`);
}
+ override async onAfter(
+ sampledebugContext: SampledebugContext
+ ): Promise {
+ await sampledebugContext.sampleAfter(
+ `${sampledebugContext.appName}-dev-rg}`
+ );
+ }
+
override async onValidate(page: Page): Promise {
return await validateLargeNotificationBot(page);
}
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-query-org.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-query-org.test.ts
index e131f5bd85..fb9dc09d8f 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-query-org.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-query-org.test.ts
@@ -7,16 +7,37 @@
import { Page } from "playwright";
import { TemplateProject, LocalDebugTaskLabel } from "../../utils/constants";
-import { validateQueryOrg } from "../../utils/playwrightOperation";
+import { validateQueryOrg, reopenPage } from "../../utils/playwrightOperation";
import { CaseFactory } from "./sampleCaseFactory";
import { Env } from "../../utils/env";
+import { SampledebugContext } from "./sampledebugContext";
class QueryOrgTestCase extends CaseFactory {
- override async onValidate(page: Page): Promise {
- return await validateQueryOrg(page, { displayName: Env.displayName });
+ override async onValidate(
+ page: Page,
+ options?: { context: SampledebugContext }
+ ): Promise {
+ return await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: options?.context.appName.substring(0, 10) || "",
+ });
}
- override async onCliValidate(page: Page): Promise {
- return await validateQueryOrg(page, { displayName: Env.displayName });
+ override async onCliValidate(
+ page: Page,
+ options?: {
+ context: SampledebugContext;
+ }
+ ): Promise {
+ return await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: options?.context.appName.substring(0, 10) || "",
+ });
+ }
+ public override async onReopenPage(
+ sampledebugContext: SampledebugContext,
+ teamsAppId: string
+ ): Promise {
+ return await reopenPage(sampledebugContext.context!, teamsAppId);
}
}
@@ -25,9 +46,5 @@ new QueryOrgTestCase(
15554404,
"v-ivanchen@microsoft.com",
"local",
- [LocalDebugTaskLabel.StartLocalTunnel, LocalDebugTaskLabel.StartBot],
- {
- skipValidation: true,
- debug: "cli",
- }
+ [LocalDebugTaskLabel.StartLocalTunnel, LocalDebugTaskLabel.StartBot]
).test();
diff --git a/packages/tests/src/ui-test/samples/sample-localdebug-todo-list-with-m365.test.ts b/packages/tests/src/ui-test/samples/sample-localdebug-todo-list-with-m365.test.ts
index e5c60c129a..d237e4dfaa 100644
--- a/packages/tests/src/ui-test/samples/sample-localdebug-todo-list-with-m365.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-localdebug-todo-list-with-m365.test.ts
@@ -41,15 +41,7 @@ class TodoListM365TestCase extends CaseFactory {
sampledebugContext: SampledebugContext,
teamsAppId: string
): Promise {
- return await reopenPage(
- sampledebugContext.context!,
- teamsAppId,
- Env.username,
- Env.password,
- undefined,
- true,
- true
- );
+ return await reopenPage(sampledebugContext.context!, teamsAppId);
}
}
diff --git a/packages/tests/src/ui-test/samples/sample-remotedebug-query-org.test.ts b/packages/tests/src/ui-test/samples/sample-remotedebug-query-org.test.ts
index e5434e67b8..65dc4a1952 100644
--- a/packages/tests/src/ui-test/samples/sample-remotedebug-query-org.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-remotedebug-query-org.test.ts
@@ -10,13 +10,17 @@ import { TemplateProject } from "../../utils/constants";
import { validateQueryOrg } from "../../utils/playwrightOperation";
import { CaseFactory } from "./sampleCaseFactory";
import { Env } from "../../utils/env";
+import { SampledebugContext } from "./sampledebugContext";
class QueryOrgTestCase extends CaseFactory {
override async onValidate(
page: Page,
- option?: { displayName: string }
+ options?: { context: SampledebugContext }
): Promise {
- return await validateQueryOrg(page, { displayName: Env.displayName });
+ return await validateQueryOrg(page, {
+ displayName: Env.displayName,
+ appName: options?.context.appName.substring(0, 10) || "",
+ });
}
}
diff --git a/packages/tests/src/ui-test/samples/sample-remotedebug-todo-list-with-m365.test.ts b/packages/tests/src/ui-test/samples/sample-remotedebug-todo-list-with-m365.test.ts
index 55763a82ad..97e12167ad 100644
--- a/packages/tests/src/ui-test/samples/sample-remotedebug-todo-list-with-m365.test.ts
+++ b/packages/tests/src/ui-test/samples/sample-remotedebug-todo-list-with-m365.test.ts
@@ -46,26 +46,6 @@ class TodoListM365TestCase extends CaseFactory {
): Promise {
return await validateTodoList(page, { displayName: options?.displayName });
}
- override async onCliValidate(
- page: Page,
- options?: { displayName: string }
- ): Promise {
- return await validateTodoList(page, { displayName: options?.displayName });
- }
- public override async onReopenPage(
- sampledebugContext: SampledebugContext,
- teamsAppId: string
- ): Promise {
- return await reopenPage(
- sampledebugContext.context!,
- teamsAppId,
- Env.username,
- Env.password,
- undefined,
- true,
- true
- );
- }
}
new TodoListM365TestCase(
diff --git a/packages/tests/src/ui-test/samples/sampleCaseFactory.ts b/packages/tests/src/ui-test/samples/sampleCaseFactory.ts
index 18638aadf2..828b61d734 100644
--- a/packages/tests/src/ui-test/samples/sampleCaseFactory.ts
+++ b/packages/tests/src/ui-test/samples/sampleCaseFactory.ts
@@ -447,6 +447,7 @@ export abstract class CaseFactory {
},
(error) => {
const errorMsg = error.toString();
+ console.log("[error log]", errorMsg);
if (
// skip warning messages
errorMsg.includes(LocalDebugError.WarningError)
diff --git a/packages/tests/src/ui-test/treeview/treeview-collaboration-spfx.test.ts b/packages/tests/src/ui-test/treeview/treeview-collaboration-spfx.test.ts
index b9936ca6b2..9792341374 100644
--- a/packages/tests/src/ui-test/treeview/treeview-collaboration-spfx.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-collaboration-spfx.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Helly Zhang
*/
@@ -58,7 +61,7 @@ describe("Collaborator Tests SPFX", function () {
// //create SPFx project
const driver = VSBrowser.instance.driver;
- await createNewProject("spfxreact", appName);
+ await createNewProject("spfx", appName);
console.log("Finish create SPFX project");
await execCommandIfExist(CommandPaletteCommands.ProvisionCommand);
diff --git a/packages/tests/src/ui-test/treeview/treeview-invalidname.test.ts b/packages/tests/src/ui-test/treeview/treeview-invalidname.test.ts
index 39cec8c572..651918a23f 100644
--- a/packages/tests/src/ui-test/treeview/treeview-invalidname.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-invalidname.test.ts
@@ -17,14 +17,12 @@ import {
inputFolderPath,
} from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { getNodeVersion } from "../../utils/getNodeVersion";
import * as os from "os";
describe("New project Tests", function () {
this.timeout(Timeout.testCase);
let treeViewTestContext: TreeViewTestContext;
let testRootFolder: string;
- let nodeVersion: string | null;
const warnMsg =
"App name needs to begin with letters, include minimum two letters or digits, and exclude certain special characters.";
@@ -33,7 +31,6 @@ describe("New project Tests", function () {
this.timeout(Timeout.prepareTestCase);
treeViewTestContext = new TreeViewTestContext("treeview");
testRootFolder = treeViewTestContext.testRootFolder;
- nodeVersion = await getNodeVersion();
await treeViewTestContext.before();
});
diff --git a/packages/tests/src/ui-test/treeview/treeview-newproject-outlook-add-in.test.ts b/packages/tests/src/ui-test/treeview/treeview-newproject-outlook-add-in.test.ts
index 6cc8dad969..aea8a17a62 100644
--- a/packages/tests/src/ui-test/treeview/treeview-newproject-outlook-add-in.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-newproject-outlook-add-in.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Darren Miller
*/
@@ -8,13 +11,11 @@ import { Timeout } from "../../utils/constants";
import { TreeViewTestContext } from "./treeviewContext";
import { createNewProject } from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { getNodeVersion } from "../../utils/getNodeVersion";
describe("New project Tests", function () {
this.timeout(Timeout.testCase);
let treeViewTestContext: TreeViewTestContext;
let testRootFolder: string;
- let nodeVersion: string | null;
const appNameCopySuffix = "copy";
let newAppFolderName: string;
let projectPath: string;
@@ -24,7 +25,6 @@ describe("New project Tests", function () {
this.timeout(Timeout.prepareTestCase);
treeViewTestContext = new TreeViewTestContext("treeview");
testRootFolder = treeViewTestContext.testRootFolder;
- nodeVersion = await getNodeVersion();
await treeViewTestContext.before();
});
diff --git a/packages/tests/src/ui-test/treeview/treeview-newproject-spfx.test.ts b/packages/tests/src/ui-test/treeview/treeview-newproject-spfx.test.ts
index 4e10d5ce2a..09b32e438c 100644
--- a/packages/tests/src/ui-test/treeview/treeview-newproject-spfx.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-newproject-spfx.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Helly Zhang
*/
@@ -8,13 +11,11 @@ import { Timeout } from "../../utils/constants";
import { TreeViewTestContext } from "./treeviewContext";
import { createNewProject } from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { getNodeVersion } from "../../utils/getNodeVersion";
describe("New project Tests", function () {
this.timeout(Timeout.testCase);
let treeViewTestContext: TreeViewTestContext;
let testRootFolder: string;
- let nodeVersion: string | null;
const appNameCopySuffix = "copy";
let newAppFolderName: string;
let projectPath: string;
@@ -24,7 +25,6 @@ describe("New project Tests", function () {
this.timeout(Timeout.prepareTestCase);
treeViewTestContext = new TreeViewTestContext("treeview");
testRootFolder = treeViewTestContext.testRootFolder;
- nodeVersion = await getNodeVersion();
await treeViewTestContext.before();
});
@@ -41,7 +41,7 @@ describe("New project Tests", function () {
},
async function () {
const appName = treeViewTestContext.appName;
- await createNewProject("spfxreact", appName);
+ await createNewProject("spfx", appName);
newAppFolderName = appName + appNameCopySuffix;
projectPath = path.resolve(testRootFolder, newAppFolderName);
const filePath = path.join(projectPath, "src", "src", "index.ts");
diff --git a/packages/tests/src/ui-test/treeview/treeview-newproject-tab.test.ts b/packages/tests/src/ui-test/treeview/treeview-newproject-tab.test.ts
index 60c121087b..2925a7191b 100644
--- a/packages/tests/src/ui-test/treeview/treeview-newproject-tab.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-newproject-tab.test.ts
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
/**
* @author Helly Zhang
*/
@@ -8,13 +11,11 @@ import { Timeout } from "../../utils/constants";
import { TreeViewTestContext } from "./treeviewContext";
import { createNewProject } from "../../utils/vscodeOperation";
import { it } from "../../utils/it";
-import { getNodeVersion } from "../../utils/getNodeVersion";
describe("New project Tests", function () {
this.timeout(Timeout.testCase);
let treeViewTestContext: TreeViewTestContext;
let testRootFolder: string;
- let nodeVersion: string | null;
const appNameCopySuffix = "copy";
let newAppFolderName: string;
let projectPath: string;
@@ -24,7 +25,6 @@ describe("New project Tests", function () {
this.timeout(Timeout.prepareTestCase);
treeViewTestContext = new TreeViewTestContext("treeview");
testRootFolder = treeViewTestContext.testRootFolder;
- nodeVersion = await getNodeVersion();
await treeViewTestContext.before();
});
@@ -41,7 +41,7 @@ describe("New project Tests", function () {
},
async function () {
const appName = treeViewTestContext.appName;
- await createNewProject("tab", appName, "TypeScript");
+ await createNewProject("tab", appName, { lang: "TypeScript" });
newAppFolderName = appName + appNameCopySuffix;
projectPath = path.resolve(testRootFolder, newAppFolderName);
const filePath1 = path.join(projectPath, "src", "index.tsx");
diff --git a/packages/tests/src/ui-test/treeview/treeview-spfx-manifest.test.ts b/packages/tests/src/ui-test/treeview/treeview-spfx-manifest.test.ts
index 71fbc0119e..5c1a70ddd5 100644
--- a/packages/tests/src/ui-test/treeview/treeview-spfx-manifest.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-spfx-manifest.test.ts
@@ -37,7 +37,7 @@ describe("Execute Build Teams Package", function () {
author: "v-helzha@microsoft.com",
},
async function () {
- await createNewProject("spfxreact", treeViewTestContext.appName);
+ await createNewProject("spfx", treeViewTestContext.appName);
await zipAppPackage("dev");
await getNotification(
Notification.ZipAppPackageSucceeded,
diff --git a/packages/tests/src/ui-test/treeview/treeview-tab-manifest.test.ts b/packages/tests/src/ui-test/treeview/treeview-tab-manifest.test.ts
index fde33ded3a..1858aa9c35 100644
--- a/packages/tests/src/ui-test/treeview/treeview-tab-manifest.test.ts
+++ b/packages/tests/src/ui-test/treeview/treeview-tab-manifest.test.ts
@@ -13,19 +13,15 @@ import { TreeViewTestContext, zipAppPackage } from "./treeviewContext";
import { createEnv } from "../remotedebug/remotedebugContext";
import { Timeout, Notification } from "../../utils/constants";
import { it } from "../../utils/it";
-import { getNodeVersion } from "../../utils/getNodeVersion";
describe("Execute Build Teams Package", function () {
this.timeout(Timeout.testCase);
let treeViewTestContext: TreeViewTestContext;
- let nodeVersion: string | null;
beforeEach(async function () {
// ensure workbench is ready
this.timeout(Timeout.prepareTestCase);
treeViewTestContext = new TreeViewTestContext("treeview");
- nodeVersion = await getNodeVersion();
- console.log(`Node version is ${nodeVersion}`);
await treeViewTestContext.before();
});
diff --git a/packages/tests/src/utils/commonUtils.ts b/packages/tests/src/utils/commonUtils.ts
index 0e302b672f..a2f5cf07b8 100644
--- a/packages/tests/src/utils/commonUtils.ts
+++ b/packages/tests/src/utils/commonUtils.ts
@@ -8,10 +8,66 @@ import { dotenvUtil } from "./envUtil";
import { TestFilePath } from "./constants";
import { exec, spawn, SpawnOptionsWithoutStdio } from "child_process";
import { promisify } from "util";
-import { Executor } from "./executor";
export const execAsync = promisify(exec);
+export async function execute(
+ command: string,
+ cwd: string,
+ processEnv?: NodeJS.ProcessEnv,
+ timeout?: number,
+ skipErrorMessage?: string | undefined
+) {
+ let retryCount = 0;
+ const maxRetries = 2;
+
+ while (retryCount < maxRetries) {
+ // if failed, retry. 2 times at most.
+ try {
+ console.log(`[Start] "${command}" in ${cwd}.`);
+ const options = {
+ cwd,
+ env: processEnv ?? process.env,
+ timeout: timeout ?? 0,
+ };
+ const result = await execAsync(command, options);
+
+ if (result.stderr) {
+ if (skipErrorMessage && result.stderr.includes(skipErrorMessage)) {
+ console.log(`[Skip Warning] ${result.stderr}`);
+ return { success: true, ...result };
+ }
+ // the command exit with 0
+ console.log(
+ `[Pending] "${command}" in ${cwd} with some stderr: ${result.stderr}`
+ );
+ return { success: false, ...result };
+ } else {
+ console.log(`[Success] "${command}" in ${cwd}.`);
+ return { success: true, ...result };
+ }
+ } catch (e: any) {
+ if (e.killed && e.signal == "SIGTERM") {
+ console.error(`[Failed] "${command}" in ${cwd}. Timeout and killed.`);
+ } else {
+ console.error(
+ `[Failed] "${command}" in ${cwd} with error: ${e.message}`
+ );
+ }
+ retryCount++;
+ if (retryCount >= maxRetries) {
+ return { success: false, stdout: "", stderr: e.message as string };
+ }
+
+ console.log(
+ `Retrying "${command}" in ${cwd}. Attempt ${retryCount} of ${maxRetries}.`
+ );
+ }
+ }
+ console.log(`[Failed] Not executed command ${command}`);
+ return { success: false, stdout: "", stderr: "" };
+}
+
export async function execAsyncWithRetry(
command: string,
options: {
@@ -28,7 +84,7 @@ export async function execAsyncWithRetry(
while (retries > 0) {
retries--;
try {
- const result = await Executor.execute(
+ const result = await execute(
command,
options.cwd ? options.cwd : "",
options.env
@@ -47,7 +103,7 @@ export async function execAsyncWithRetry(
await sleep(10000);
}
}
- return Executor.execute(command, options.cwd ? options.cwd : "", options.env);
+ return execute(command, options.cwd ? options.cwd : "", options.env);
}
export async function sleep(ms: number): Promise {
@@ -261,7 +317,7 @@ export async function CLIVersionCheck(
let command = "";
if (version === "V2") command = `npx teamsfx --version`;
else if (version === "V3") command = `npx teamsapp --version`;
- const { success, stdout } = await Executor.execute(command, projectPath);
+ const { success, stdout } = await execute(command, projectPath);
chai.expect(success).to.eq(true);
const cliVersion = stdout.trim();
const versionGeneralRegex = /(\d\.\d+\.\d+).*$/;
@@ -367,3 +423,57 @@ export async function updateDeverloperInManifestFile(
console.log("Replaced the properties of developer in manifest file");
await fs.writeJSON(manifestFile, context, { spaces: 4 });
}
+
+export async function configSpfxGlobalEnv() {
+ try {
+ console.log(`Start to set up global environment:`);
+ const result = await execAsync(
+ "npm install gulp-cli yo @microsoft/generator-sharepoint --global"
+ );
+ console.log(`[Successfully] set up global environment.`);
+ console.log(`${result.stdout}`);
+ } catch (error) {
+ console.log(error);
+ throw new Error(`Failed to set up global environment: ${error}`);
+ }
+}
+
+export async function generateYoSpfxProject(option: {
+ solutionName?: string;
+ componentName: string;
+ componentType?: string;
+ existingSolutionName?: string;
+}) {
+ try {
+ if (option?.solutionName) {
+ console.log(`Start to generate SPFx project:`);
+ const resourcePath = path.resolve(__dirname, "../../.test-resources/");
+ const result = await execAsync(
+ `yo @microsoft/sharepoint --solution-name ${option.solutionName} --component-type webpart --framework react --component-name ${option.componentName} --skip-install true`,
+ {
+ cwd: resourcePath,
+ }
+ );
+ console.log(`[Successfully] completed to generate SPFx project.`);
+ console.log(`${result.stdout}`);
+ } else if (option?.existingSolutionName) {
+ console.log(`Start to add web part to SPFx project:`);
+ const resourcePath = path.resolve(
+ __dirname,
+ "../../.test-resources/",
+ option.existingSolutionName
+ );
+ const result = await execAsync(
+ `yo @microsoft/sharepoint --component-type webpart --framework react --component-name ${option.componentName} --skip-install true`,
+ {
+ cwd: resourcePath,
+ }
+ );
+ console.log(`[Successfully] completed to add web part to SPFx project.`);
+ console.log(`${result.stdout}`);
+ }
+ } catch (error) {
+ console.log(error);
+ throw new Error(`Failed to generate SPFx project: ${error}`);
+ }
+}
diff --git a/packages/tests/src/utils/commonUtils.ts.back b/packages/tests/src/utils/commonUtils.ts.back
deleted file mode 100644
index e66caf76f1..0000000000
--- a/packages/tests/src/utils/commonUtils.ts.back
+++ /dev/null
@@ -1,364 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-import { FeatureFlagName } from "./constants";
-import * as path from "path";
-import * as fs from "fs-extra";
-import * as chai from "chai";
-import { dotenvUtil } from "./envUtil";
-import { TestFilePath } from "./constants";
-import { exec, spawn, SpawnOptionsWithoutStdio } from "child_process";
-import { promisify } from "util";
-import { Executor } from "./executor";
-
-// export const execAsync = promisify(exec);
-export async function execAsync(
- cmd: string,
- opts?: {
- cwd?: string;
- env?: NodeJS.ProcessEnv;
- timeout?: number;
- }
-): Promise<{ stdout: string; stderr: string }> {
- opts || (opts = {});
- return new Promise((resolve, reject) => {
- let cmdUpdate = cmd;
- if (cmd.includes("teamsfx")) {
- const cmdStr = cmd.replace("teamsfx ", "");
- const filePath = path.resolve(__dirname, "./../../../cli/cliold.js");
- cmdUpdate = `npx ts-node ${filePath} ${cmdStr}`;
- } else if (cmd.includes("teamsapp")) {
- const cmdStr = cmd.replace("teamsapp ", "");
- const filePath = path.resolve(__dirname, "./../../../cli/cli.js");
- cmdUpdate = `npx ts-node ${filePath} ${cmdStr}`;
- }
- console.log("!! ------ Cmd: ", cmdUpdate);
- const child = exec(cmdUpdate, opts, (err, stdout, stderr) =>
- err
- ? reject(err)
- : resolve({
- stdout: stdout.toString(),
- stderr: stderr.toString(),
- })
- );
- });
-}
-
-export async function execAsyncWithRetry(
- command: string,
- options: {
- cwd?: string;
- env?: NodeJS.ProcessEnv;
- timeout?: number;
- },
- retries = 3,
- newCommand?: string
-): Promise<{
- stdout: string;
- stderr: string;
-}> {
- while (retries > 0) {
- retries--;
- try {
- const result = await Executor.execute(
- command,
- options.cwd ? options.cwd : "",
- options.env
- );
- } catch (e: any) {
- console.log(
- `Run \`${command}\` failed with error msg: ${JSON.stringify(e)}.`
- );
- if (e.killed && e.signal == "SIGTERM") {
- console.log(`Command ${command} killed due to timeout`);
- }
- if (newCommand) {
- command = newCommand;
- }
- await sleep(10000);
- }
- }
- return Executor.execute(command, options.cwd ? options.cwd : "", options.env);
-}
-
-export async function sleep(ms: number): Promise {
- return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-export function isInsiderPreviewEnabled(): boolean {
- const flag = process.env[FeatureFlagName.InsiderPreview];
- if (flag === "false") {
- console.log(`${FeatureFlagName.InsiderPreview} is false.`);
- return false;
- } else {
- console.log(`${FeatureFlagName.InsiderPreview} is true.`);
- return true;
- }
-}
-
-export async function updateProjectAppName(
- projectPath: string,
- appName: string
-) {
- const projectDataFile = path.join(".fx", "configs", "projectSettings.json");
- const configFilePath = path.resolve(projectPath, projectDataFile);
- const context = await fs.readJSON(configFilePath);
- context["appName"] = appName;
- return fs.writeJSON(configFilePath, context, { spaces: 4 });
-}
-
-export async function updateAppShortName(
- projectPath: string,
- appName: string,
- envName: "local" | "dev"
-) {
- const manifestDataFile = path.join(
- ".fx",
- "configs",
- `config.${envName}.json`
- );
- const configFilePath = path.resolve(projectPath, manifestDataFile);
- const context = await fs.readJSON(configFilePath);
- context["manifest"]["appName"]["short"] = appName;
- return fs.writeJSON(configFilePath, context, { spaces: 4 });
-}
-
-export async function getBotSiteEndpoint(
- projectPath: string,
- envName = "dev",
- endpoint = "BOT_DOMAIN"
-): Promise {
- const userDataFile = path.join(
- TestFilePath.configurationFolder,
- `.env.${envName}`
- );
- const configFilePath = path.resolve(projectPath, userDataFile);
- const context = dotenvUtil.deserialize(
- await fs.readFile(configFilePath, { encoding: "utf8" })
- );
- const endpointUrl =
- context.obj[`${endpoint}`] ??
- context.obj["PROVISIONOUTPUT__BOTOUTPUT__ENDPOINT"];
- const result = endpointUrl.includes("https://")
- ? endpointUrl
- : "https://" + endpointUrl;
- console.log(`BotSiteEndpoint: ${result}`);
- return typeof result === "string" ? result : undefined;
-}
-
-export function validateFileExist(projectPath: string, relativePath: string) {
- const filePath = path.resolve(projectPath, relativePath);
- chai.expect(fs.existsSync(filePath), `${filePath} must exist.`).to.eq(true);
-}
-
-export async function updateAadTemplate(
- projectPath: string,
- displayNameSuffix = "-updated"
-) {
- const filePath = path.resolve(projectPath, "aad.manifest.json");
- const context = await fs.readJSON(filePath);
- const updatedAppName = context["name"] + displayNameSuffix;
- context["name"] = updatedAppName;
- return fs.writeJSON(filePath, context, { spaces: 4 });
-}
-
-export function spawnCommand(
- command: string,
- args?: string[],
- options?: SpawnOptionsWithoutStdio | undefined,
- onData?: (data: string) => void,
- onError?: (data: string) => void
-) {
- const child = spawn(command, args, options);
- child.stdout.on("data", (data) => {
- const dataString = data.toString();
- if (onData) {
- onData(dataString);
- }
- });
- child.stderr.on("data", (data) => {
- const dataString = data.toString();
- if (onError) {
- onError(dataString);
- }
- });
- return child;
-}
-
-// promise timeout function
-export function timeoutPromise(timeout: number) {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve("timeout");
- }, timeout);
- });
-}
-
-export async function killPort(
- port: number
-): Promise<{ stdout: string; stderr: string }> {
- // windows
- if (process.platform === "win32") {
- const command = `for /f "tokens=5" %a in ('netstat -ano ^| find "${port}"') do @taskkill /f /pid %a`;
- console.log("run command: ", command);
- const result = await execAsync(command);
- return result;
- } else {
- const command = `kill -9 $(lsof -t -i:${port})`;
- console.log("run command: ", command);
- const result = await execAsync(command);
- return result;
- }
-}
-
-export async function killNgrok(): Promise<{ stdout: string; stderr: string }> {
- if (process.platform === "win32") {
- const command = `taskkill /f /im ngrok.exe`;
- console.log("run command: ", command);
- const result = await execAsync(command);
- return result;
- } else {
- const command = `kill -9 $(lsof -i | grep ngrok | awk '{print $2}')`;
- console.log("run command: ", command);
- const result = await execAsync(command);
- return result;
- }
-}
-
-export function editDotEnvFile(
- filePath: string,
- key: string,
- value: string
-): void {
- try {
- const envFileContent: string = fs.readFileSync(filePath, "utf-8");
- const envVars: { [key: string]: string } = envFileContent
- .split("\n")
- .reduce((acc: { [key: string]: string }, line: string) => {
- const [key, value] = line.split("=");
- if (key && value) {
- acc[key.trim()] = value.trim();
- }
- return acc;
- }, {});
- envVars[key] = value;
- const newEnvFileContent: string = Object.entries(envVars)
- .map(([key, value]) => `${key}=${value}`)
- .join("\n");
- fs.writeFileSync(filePath, newEnvFileContent);
- } catch (error) {
- console.log('Failed to edit ".env" file. FilePath: ' + filePath);
- }
-}
-
-export async function CLIVersionCheck(
- version: "V2" | "V3",
- projectPath: string
-): Promise<{ success: boolean; cliVersion: string }> {
- let command = "";
- if (version === "V2") command = `npx teamsfx --version`;
- else if (version === "V3") command = `npx teamsapp --version`;
- const { success, stdout } = await Executor.execute(command, projectPath);
- chai.expect(success).to.eq(true);
- const cliVersion = stdout.trim();
- const versionGeneralRegex = /(\d\.\d+\.\d+).*$/;
- const cliVersionOutputs = cliVersion.match(versionGeneralRegex);
- console.log(cliVersionOutputs![0]);
- let versionRegex;
- if (version === "V2") versionRegex = /^1\.\d+\.\d+.*$/;
- else if (version === "V3") versionRegex = /^[23]\.\d+\.\d+.*$/;
- else throw new Error(`Invalid version specified: ${version}`);
- chai.expect(cliVersionOutputs![0]).to.match(versionRegex);
- console.log(`CLI Version: ${cliVersion}`);
- return { success: true, cliVersion };
-}
-
-const policySnippets = {
- locationKey1: "var authorizedClientApplicationIds",
- locationValue1: `var allowedClientApplications = '["\${m365ClientId}","\${teamsMobileOrDesktopAppClientId}","\${teamsWebAppClientId}","\${officeWebAppClientId1}","\${officeWebAppClientId2}","\${outlookDesktopAppClientId}","\${outlookWebAppClientId1};\${outlookWebAppClientId2}"]'\n`,
- locationKey2: "ALLOWED_APP_IDS",
- locationValue2: ` WEBSITE_AUTH_AAD_ACL: '{"allowed_client_applications": \${allowedClientApplications}}}'\n`,
-};
-
-const locationValue1_320 = `var allowedClientApplications = '["\${m365ClientId}","\${teamsMobileOrDesktopAppClientId}","\${teamsWebAppClientId}","\${officeWebAppClientId1}","\${officeWebAppClientId2}","\${outlookDesktopAppClientId}","\${outlookWebAppClientId}"]'\n`;
-
-export async function updateFunctionAuthorizationPolicy(
- version: "4.2.5" | "4.0.0" | "3.2.0",
- projectPath: string
-): Promise {
- const fileName =
- version == "4.2.5" ? "azureFunctionApiConfig.bicep" : "function.bicep";
- const locationValue1 =
- version == "3.2.0" ? locationValue1_320 : policySnippets.locationValue1;
- const functionBicepPath = path.join(
- projectPath,
- "templates",
- "azure",
- "teamsFx",
- fileName
- );
- let content = await fs.readFile(functionBicepPath, "utf-8");
- content = updateContent(content, policySnippets.locationKey1, locationValue1);
- content = updateContent(
- content,
- policySnippets.locationKey2,
- policySnippets.locationValue2
- );
- await fs.writeFileSync(functionBicepPath, content);
-
- if (version == "3.2.0") {
- const fileName = "simpleAuth.bicep";
- const simpleAuthBicepPath = path.join(
- projectPath,
- "templates",
- "azure",
- "teamsFx",
- fileName
- );
- let content = await fs.readFile(simpleAuthBicepPath, "utf-8");
- content = updateContent(
- content,
- policySnippets.locationKey1,
- locationValue1
- );
- content = updateContent(
- content,
- policySnippets.locationKey2,
- policySnippets.locationValue2
- );
- await fs.writeFileSync(simpleAuthBicepPath, content);
- }
-}
-
-export function updateContent(
- content: string,
- key: string,
- value: string
-): string {
- const index = findNextEndLineIndexOfWord(content, key);
- const head = content.substring(0, index);
- const tail = content.substring(index + 1);
- return head + `\n${value}\n` + tail;
-}
-
-function findNextEndLineIndexOfWord(content: string, key: string): number {
- const index = content.indexOf(key);
- const result = content.indexOf("\n", index);
- return result;
-}
-
-export async function updateDeverloperInManifestFile(
- projectPath: string
-): Promise {
- const manifestFile = path.join(projectPath, "appPackage", `manifest.json`);
- const context = await fs.readJSON(manifestFile);
- //const context = await fs.readJSON(azureParametersFilePath);
- try {
- context["developer"]["websiteUrl"] = "https://www.example.com";
- context["developer"]["privacyUrl"] = "https://www.example.com/privacy";
- context["developer"]["termsOfUseUrl"] = "https://www.example.com/termofuse";
- } catch {
- console.log("Cannot set the propertie.");
- }
- console.log("Replaced the properties of developer in manifest file");
- await fs.writeJSON(manifestFile, context, { spaces: 4 });
-}
diff --git a/packages/tests/src/utils/constants.ts b/packages/tests/src/utils/constants.ts
index 414e8cf7e3..1afce7f8ba 100644
--- a/packages/tests/src/utils/constants.ts
+++ b/packages/tests/src/utils/constants.ts
@@ -171,8 +171,8 @@ export enum Capability {
RAG = "custom-copilot-rag",
Agent = "custom-copilot-agent",
TaskPane = "taskpane",
- CopilotPluginFromExistingAPI = "copilot-plugin-existing-api",
- CopilotPluginFromScratch = "copilot-plugin-new-api",
+ CopilotPluginFromExistingAPI = "api-plugin-existing-api",
+ CopilotPluginFromScratch = "api-plugin-new-api",
}
export enum Trigger {
@@ -337,7 +337,7 @@ export class CommandPaletteCommands {
public static readonly AddSpfxWebPart: string = "Teams: Add SPFx web part";
}
-export type OptionType =
+export type AppType =
| "tab"
| "tabnsso"
| "tabbot"
@@ -348,12 +348,8 @@ export type OptionType =
| "msg"
| "msgsa"
| "m365lp"
- | "spfxreact"
- | "spfxnone"
- | "spfxmin"
- | "gspfxreact"
- | "gspfxnone"
- | "gspfxmin"
+ | "spfx"
+ | "gspfx"
| "dashboard"
| "workflow"
| "timenoti"
@@ -365,7 +361,8 @@ export type OptionType =
| "aiassist"
| "msgnewapi"
| "msgopenapi"
- | "msgapikey";
+ | "msgapikey"
+ | "importspfx";
export class FeatureFlagName {
static readonly InsiderPreview = "__TEAMSFX_INSIDER_PREVIEW";
@@ -451,7 +448,7 @@ export class Notification {
}
export class CreateProjectQuestion {
- static readonly CustomCopilot = "Custom Copilot";
+ static readonly CustomCopilot = "Custom Engine Copilot";
static readonly Bot = "Bot";
static readonly Tab = "Tab";
static readonly MessageExtension = "Message Extension";
@@ -462,6 +459,7 @@ export class CreateProjectQuestion {
"Use globally installed SPFx";
static readonly NewAddinApp = "Start with an Outlook add-in";
static readonly CreateNewSpfxSolution = "Create New SPFx Solution";
+ static readonly ImportExistingSpfxSolution = "Import Existing SPFx Solution";
}
export class ValidationContent {
@@ -474,6 +472,7 @@ export class ValidationContent {
static readonly AiAssistantBotWelcomeInstruction =
"I'm an assistant bot. How can I help you today?";
static readonly AiBotErrorMessage = "The bot encountered an error or bug";
+ static readonly AiBotErrorMessage2 = "An AI request failed";
}
export class CliVersion {
diff --git a/packages/tests/src/utils/getNodeVersion.ts b/packages/tests/src/utils/getNodeVersion.ts
deleted file mode 100644
index e7ee6540ce..0000000000
--- a/packages/tests/src/utils/getNodeVersion.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import * as cp from "child_process";
-import * as os from "os";
-
-export interface ICommandResult {
- code: number;
- cmdOutput: string;
- cmdOutputIncludingStderr: string;
- formattedArgs: string;
-}
-
-export interface DebugLogger {
- debug(message: string): Promise;
-}
-
-export async function getNodeVersion(): Promise {
- const nodeVersionRegex =
- /v(?\d+)\.(?\d+)\.(?\d+)/gm;
- try {
- const output = await executeCommand(
- undefined,
- undefined,
- undefined,
- "node",
- "--version"
- );
- const match = nodeVersionRegex.exec(output);
- if (match && match.groups?.major_version) {
- return match.groups.major_version;
- } else {
- return null;
- }
- } catch (error) {
- console.debug(`Failed to run 'node --version', error = '${error}'`);
- return null;
- }
-}
-
-export async function executeCommand(
- workingDirectory: string | undefined,
- logger: DebugLogger | undefined,
- options: cp.SpawnOptions | undefined,
- command: string,
- ...args: string[]
-): Promise {
- const result: ICommandResult = await tryExecuteCommand(
- workingDirectory,
- logger,
- options,
- command,
- ...args
- );
- if (result.code !== 0) {
- const errorMessage = `Failed to run command: "${command} ${result.formattedArgs}", code: "${result.code}",
- output: "${result.cmdOutput}", error: "${result.cmdOutputIncludingStderr}"`;
- await logger?.debug(errorMessage);
- throw new Error(errorMessage);
- } else {
- await logger?.debug(
- `Finished running command: "${command} ${result.formattedArgs}".`
- );
- }
-
- return result.cmdOutput;
-}
-
-export async function tryExecuteCommand(
- workingDirectory: string | undefined,
- logger: DebugLogger | undefined,
- additionalOptions: cp.SpawnOptions | undefined,
- command: string,
- ...args: string[]
-): Promise {
- return await new Promise(
- (
- resolve: (res: ICommandResult) => void,
- reject: (e: Error) => void
- ): void => {
- let cmdOutput = "";
- let cmdOutputIncludingStderr = "";
- const formattedArgs: string = args.join(" ");
-
- workingDirectory = workingDirectory || os.tmpdir();
- const options: cp.SpawnOptions = {
- cwd: workingDirectory,
- shell: true,
- };
- Object.assign(options, additionalOptions);
-
- const childProc: cp.ChildProcess = cp.spawn(command, args, options);
- let timer: NodeJS.Timeout;
- if (options.timeout && options.timeout > 0) {
- // timeout only exists for exec not spawn
- timer = setTimeout(() => {
- childProc.kill();
- logger?.debug(
- `Stop exec due to timeout, command: "${command} ${formattedArgs}", options = '${JSON.stringify(
- options
- )}'`
- );
- reject(
- new Error(
- `Exec command: "${command} ${formattedArgs}" timeout, ${options.timeout} ms`
- )
- );
- }, options.timeout);
- }
- logger?.debug(
- `Running command: "${command} ${formattedArgs}", options = '${JSON.stringify(
- options
- )}'`
- );
-
- childProc.stdout?.on("data", (data: string | Buffer) => {
- data = data.toString();
- cmdOutput = cmdOutput.concat(data);
- cmdOutputIncludingStderr = cmdOutputIncludingStderr.concat(data);
- });
-
- childProc.stderr?.on("data", (data: string | Buffer) => {
- data = data.toString();
- cmdOutputIncludingStderr = cmdOutputIncludingStderr.concat(data);
- });
-
- childProc.on("error", (error) => {
- logger?.debug(
- `Failed to run command '${command} ${formattedArgs}': cmdOutputIncludingStderr: '${cmdOutputIncludingStderr}', error: ${error}`
- );
- if (timer) {
- clearTimeout(timer);
- }
- reject(error);
- });
- childProc.on("close", (code: number) => {
- logger?.debug(
- `Command finished with outputs, cmdOutputIncludingStderr: '${cmdOutputIncludingStderr}'`
- );
- if (timer) {
- clearTimeout(timer);
- }
- resolve({
- code,
- cmdOutput,
- cmdOutputIncludingStderr,
- formattedArgs,
- });
- });
- }
- );
-}
diff --git a/packages/tests/src/utils/playwrightOperation.ts b/packages/tests/src/utils/playwrightOperation.ts
index ba026a4e26..4bbad48946 100644
--- a/packages/tests/src/utils/playwrightOperation.ts
+++ b/packages/tests/src/utils/playwrightOperation.ts
@@ -342,6 +342,7 @@ export async function reopenPage(
await addBtn?.click();
}
await page.waitForTimeout(Timeout.shortTimeLoading);
+ console.log("[success] app loaded");
// verify add page is closed
await page?.waitForSelector("button>span:has-text('Add')", {
state: "detached",
@@ -456,7 +457,10 @@ export async function initTeamsPage(
await page?.waitForSelector(`h1:has-text('to a team')`);
try {
try {
- const items = await page?.waitForSelector("li.ui-dropdown__item");
+ // select 2nd li item
+ const items = await page?.waitForSelector(
+ "li.ui-dropdown__item:nth-child(2)"
+ );
await items?.click();
console.log("selected a team.");
} catch (error) {
@@ -465,7 +469,6 @@ export async function initTeamsPage(
);
await searchBtn?.click();
await page.waitForTimeout(Timeout.shortTimeLoading);
-
const items = await page?.waitForSelector("li.ui-dropdown__item");
await items?.click();
console.log("[catch] selected a team.");
@@ -825,54 +828,57 @@ export async function validateOneProducitvity(
export async function validateTab(
page: Page,
- options?: { displayName?: string; includeFunction?: boolean }
+ options?: { displayName?: string; includeFunction?: boolean },
+ rerun = false
) {
+ console.log("start to verify tab");
try {
const frameElementHandle = await page.waitForSelector(
`iframe[name="embedded-page-container"]`
);
const frame = await frameElementHandle?.contentFrame();
+ if (!rerun) {
+ await RetryHandler.retry(async () => {
+ console.log("Before popup");
+ const [popup] = await Promise.all([
+ page
+ .waitForEvent("popup")
+ .then((popup) =>
+ popup
+ .waitForEvent("close", {
+ timeout: Timeout.playwrightConsentPopupPage,
+ })
+ .catch(() => popup)
+ )
+ .catch(() => {}),
+ frame?.click('button:has-text("Authorize")', {
+ timeout: Timeout.playwrightAddAppButton,
+ force: true,
+ noWaitAfter: true,
+ clickCount: 2,
+ delay: 10000,
+ }),
+ ]);
+ console.log("after popup");
- await RetryHandler.retry(async () => {
- console.log("Before popup");
- const [popup] = await Promise.all([
- page
- .waitForEvent("popup")
- .then((popup) =>
- popup
- .waitForEvent("close", {
- timeout: Timeout.playwrightConsentPopupPage,
- })
- .catch(() => popup)
- )
- .catch(() => {}),
- frame?.click('button:has-text("Authorize")', {
- timeout: Timeout.playwrightAddAppButton,
- force: true,
- noWaitAfter: true,
- clickCount: 2,
- delay: 10000,
- }),
- ]);
- console.log("after popup");
-
- if (popup && !popup?.isClosed()) {
- await popup
- .click('button:has-text("Reload")', {
- timeout: Timeout.playwrightConsentPageReload,
- })
- .catch(() => {});
- await popup.click("input.button[type='submit'][value='Accept']");
- }
+ if (popup && !popup?.isClosed()) {
+ await popup
+ .click('button:has-text("Reload")', {
+ timeout: Timeout.playwrightConsentPageReload,
+ })
+ .catch(() => {});
+ await popup.click("input.button[type='submit'][value='Accept']");
+ }
- await frame?.waitForSelector(`b:has-text("${options?.displayName}")`);
- });
+ await frame?.waitForSelector(`b:has-text("${options?.displayName}")`);
+ });
+ }
if (options?.includeFunction) {
await RetryHandler.retry(async () => {
console.log("verify function info");
const authorizeButton = await frame?.waitForSelector(
- 'button:has-text("Call Azure Function")'
+ 'button:has-text("Authorize and call Azure Function")'
);
await authorizeButton?.click();
const backendElement = await frame?.waitForSelector(
@@ -1458,7 +1464,8 @@ export async function validateNpm(
`span:has-text("${searchPack}")`
);
await targetItem?.click();
- await page?.waitForSelector(`card span:has-text("${searchPack}")`);
+ await page.waitForTimeout(Timeout.shortTimeWait);
+ await page?.waitForSelector(`card:has-text("${searchPack}")`);
const sendBtn = await frame?.waitForSelector('button[name="send"]');
await sendBtn?.click();
console.log("verify npm search successfully!!!");
@@ -1619,15 +1626,12 @@ export async function validateDeeplinking(page: Page, displayName: string) {
export async function validateQueryOrg(
page: Page,
- options?: { displayName?: string }
+ options: { displayName?: string; appName: string }
) {
try {
console.log("start to verify query org");
await page.waitForTimeout(Timeout.shortTimeLoading);
- const frameElementHandle = await page.waitForSelector(
- "iframe.embedded-page-content"
- );
- const frame = await frameElementHandle?.contentFrame();
+ const frame = await page.waitForSelector("div#app");
try {
console.log("dismiss message");
await frame?.waitForSelector("div.ui-box");
@@ -1639,13 +1643,12 @@ export async function validateQueryOrg(
} catch (error) {
console.log("no message to dismiss");
}
- const inputBar = await frame?.waitForSelector(
- "div.ui-popup__content input.ui-box"
- );
+ await messageExtensionActivate(page, options.appName);
+ const inputBar = await page?.waitForSelector("div.ui-box input.ui-box");
await inputBar?.fill(options?.displayName || "");
await page.waitForTimeout(Timeout.shortTimeLoading);
- const loginBtn = await frame?.waitForSelector(
- 'div.ui-popup__content a:has-text("sign in")'
+ const loginBtn = await page?.waitForSelector(
+ 'div.ui-box a:has-text("sign in")'
);
// todo add more verify
// await RetryHandler.retry(async () => {
@@ -2026,6 +2029,7 @@ export async function validateTeamsWorkbench(page: Page, displayName: string) {
const frame = await frameElementHandle?.contentFrame();
await frame?.click('button:has-text("Load debug scripts")');
console.log("Debug scripts loaded");
+ await validateSpfx(page, { displayName: displayName });
} catch (error) {
await page.screenshot({
path: getPlaywrightScreenshotPath("error"),
@@ -2040,7 +2044,11 @@ export async function validateSpfx(
options?: { displayName?: string }
) {
try {
- const frame = await page.waitForSelector("div#app");
+ const frameElementHandle = await page.waitForSelector(
+ `iframe[name="embedded-page-container"]`
+ );
+ const frame = await frameElementHandle?.contentFrame();
+ await frame?.waitForSelector(`text=Web part property value`);
await frame?.waitForSelector(`text=${options?.displayName}`);
console.log(`Found: "${options?.displayName}"`);
} catch (error) {
@@ -2523,15 +2531,12 @@ export async function validateCreatedCard(page: Page, appName: string) {
}
}
-export async function validateUnfurlCard(page: Page) {
+export async function validateUnfurlCard(page: Page, appName: string) {
try {
- const frameElementHandle = await page.waitForSelector(
- "iframe.embedded-page-content"
- );
- const frame = await frameElementHandle?.contentFrame();
+ const frame = await page.waitForSelector("div#app");
console.log("start to validate unfurl an adaptive card");
const unfurlurl = "https://www.botframework.com/";
- await frame?.press("div.ui-box input.ui-box", "Escape");
+ //await frame?.press("div.ui-box input.ui-box", "Escape");
const msgTxtbox = await frame?.waitForSelector("div[data-tid='ckeditor']");
await msgTxtbox?.focus();
await msgTxtbox?.fill(unfurlurl);
@@ -2683,7 +2688,10 @@ export async function validateTodoListSpfx(page: Page) {
console.log("start to verify todo list spfx");
try {
console.log("check result...");
- const spfxFrame = await page.waitForSelector("div#app");
+ const frameElementHandle = await page.waitForSelector(
+ `iframe[name="embedded-page-container"]`
+ );
+ const spfxFrame = await frameElementHandle?.contentFrame();
// title
console.log("check title");
const title = await spfxFrame?.waitForSelector(
@@ -2718,22 +2726,19 @@ export async function validateTodoListSpfx(page: Page) {
}
}
-export async function validateApiMeResult(page: Page) {
+export async function validateApiMeResult(page: Page, appName: string) {
try {
- const frameElementHandle = await page.waitForSelector(
- "iframe.embedded-page-content"
- );
- const frame = await frameElementHandle?.contentFrame();
+ await messageExtensionActivate(page, appName);
console.log("start to validate search command");
- const searchcmdInput = await frame?.waitForSelector(
+ const searchcmdInput = await page?.waitForSelector(
"div.ui-box input.ui-box"
);
- await searchcmdInput?.type("Karin");
+ await searchcmdInput?.fill("Karin");
try {
- await frame?.waitForSelector('ul[datatid="app-picker-list"]');
+ await page?.waitForSelector('ul[datatid="app-picker-list"]');
console.log("verify search successfully!!!");
} catch (error) {
- await frame?.waitForSelector(
+ await page?.waitForSelector(
'div.ui-box span:has-text("Unable to reach app. Please try again.")'
);
assert.fail("Unable to reach app. Please try again.");
diff --git a/packages/tests/src/utils/vscodeOperation.ts b/packages/tests/src/utils/vscodeOperation.ts
index 978161d9de..39f98403ef 100644
--- a/packages/tests/src/utils/vscodeOperation.ts
+++ b/packages/tests/src/utils/vscodeOperation.ts
@@ -18,15 +18,13 @@ import {
SideBarView,
EditorView,
WebElement,
- ModalDialog,
} from "vscode-extension-tester";
import {
CommandPaletteCommands,
Extension,
- OptionType,
Timeout,
- TreeViewCommands,
CreateProjectQuestion,
+ AppType,
} from "./constants";
import { RetryHandler } from "./retryHandler";
import isWsl from "is-wsl";
@@ -543,18 +541,30 @@ async function setInputTextWsl(
}
export async function createNewProject(
- option: OptionType,
+ appType: AppType,
appName: string,
- lang?: "JavaScript" | "TypeScript" | "Python",
- testRootFolder?: string,
- appNameCopySuffix = "copy"
+ option?: {
+ lang?: "JavaScript" | "TypeScript" | "Python";
+ spfxFrameworkType?: "React" | "None" | "Minimal";
+ aiType?: "Azure OpenAI" | "OpenAI";
+ testRootFolder?: string;
+ appNameCopySuffix?: string;
+ }
): Promise {
const driver = VSBrowser.instance.driver;
let scaffoldingTime = 60 * 1000;
const scaffoldingSpfxTime = 7 * 60 * 1000;
- if (!testRootFolder) {
- testRootFolder = path.resolve(__dirname, "../../resource/");
- }
+ const appNameCopySuffix = option?.appNameCopySuffix
+ ? option.appNameCopySuffix
+ : "copy";
+ const testRootFolder = option?.testRootFolder
+ ? option.testRootFolder
+ : path.resolve(__dirname, "../../resource/");
+ const aiType = option?.aiType ? option.aiType : "OpenAI";
+ const spfxFrameworkType = option?.spfxFrameworkType
+ ? option.spfxFrameworkType
+ : "React";
+ const lang = option?.lang ? option.lang : "JavaScript";
await execCommandIfExist(
CommandPaletteCommands.CreateProjectCommand,
Timeout.webView
@@ -562,17 +572,13 @@ export async function createNewProject(
console.log("Create new project: ", appName);
const input = await InputBox.create();
// if exist click it
- switch (option) {
+ switch (appType) {
case "tabnsso": {
await input.selectQuickPick(CreateProjectQuestion.Tab);
await input.selectQuickPick("Basic Tab");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "tab": {
@@ -580,11 +586,7 @@ export async function createNewProject(
await input.selectQuickPick("React with Fluent UI");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "bot": {
@@ -592,11 +594,7 @@ export async function createNewProject(
await input.selectQuickPick("Basic Bot");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "crbot": {
@@ -607,11 +605,7 @@ export async function createNewProject(
await input.confirm();
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "funcnoti": {
@@ -628,11 +622,7 @@ export async function createNewProject(
);
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "restnoti": {
@@ -644,11 +634,7 @@ export async function createNewProject(
await input.confirm();
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "msg": {
@@ -656,11 +642,7 @@ export async function createNewProject(
await input.selectQuickPick("Collect Form Input and Process Data");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "msgsa": {
@@ -669,11 +651,7 @@ export async function createNewProject(
await input.selectQuickPick("Start with a Bot");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "m365lp": {
@@ -681,39 +659,10 @@ export async function createNewProject(
await input.selectQuickPick("React with Fluent UI");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
- break;
- }
- case "spfxreact": {
- scaffoldingTime = scaffoldingSpfxTime;
- await input.selectQuickPick(CreateProjectQuestion.Tab);
- await driver.sleep(Timeout.input);
- // await input.selectQuickPick("SPFx");
- await input.setText("SPFx");
- await input.confirm();
- await driver.sleep(Timeout.input);
- await input.selectQuickPick(CreateProjectQuestion.CreateNewSpfxSolution);
- // Wait for Node version check
- await driver.sleep(Timeout.longTimeWait);
- await input.selectQuickPick(
- CreateProjectQuestion.SpfxSharepointFrameworkInTtk
- );
- await driver.sleep(Timeout.input);
- // Choose React or None
- await input.selectQuickPick("React");
- // Input Web Part Name
- await input.setText(appName);
- await driver.sleep(Timeout.input);
- await input.confirm();
- // Input Web Part Description
- await driver.sleep(Timeout.input);
+ await input.selectQuickPick(lang);
break;
}
- case "spfxnone": {
+ case "spfx": {
scaffoldingTime = scaffoldingSpfxTime;
// Choose Tab(SPFx)
await input.selectQuickPick(CreateProjectQuestion.Tab);
@@ -730,7 +679,7 @@ export async function createNewProject(
);
await driver.sleep(Timeout.input);
// Choose React or None
- await input.selectQuickPick("None");
+ await input.selectQuickPick(spfxFrameworkType);
// Input Web Part Name
await input.setText(appName);
await driver.sleep(Timeout.input);
@@ -739,33 +688,7 @@ export async function createNewProject(
await driver.sleep(Timeout.input);
break;
}
- case "spfxmin": {
- scaffoldingTime = scaffoldingSpfxTime;
- // Choose Tab(SPFx)
- await input.selectQuickPick(CreateProjectQuestion.Tab);
- await driver.sleep(Timeout.input);
- // await input.selectQuickPick("SPFx");
- await input.setText("SPFx");
- await input.confirm();
- await driver.sleep(Timeout.input);
- await input.selectQuickPick(CreateProjectQuestion.CreateNewSpfxSolution);
- // Wait for Node version check
- await driver.sleep(Timeout.longTimeWait);
- await input.selectQuickPick(
- CreateProjectQuestion.SpfxSharepointFrameworkInTtk
- );
- await driver.sleep(Timeout.input);
- // Choose React or None
- await input.selectQuickPick("Minimal");
- // Input Web Part Name
- await input.setText(appName);
- await driver.sleep(Timeout.input);
- await input.confirm();
- // Input Web Part Description
- await driver.sleep(Timeout.input);
- break;
- }
- case "gspfxreact": {
+ case "gspfx": {
await input.selectQuickPick(CreateProjectQuestion.Tab);
await driver.sleep(Timeout.input);
// await input.selectQuickPick("SPFx");
@@ -780,7 +703,7 @@ export async function createNewProject(
);
await driver.sleep(Timeout.input);
// Choose React or None
- await input.selectQuickPick("React");
+ await input.selectQuickPick(spfxFrameworkType);
// Input Web Part Name
await input.setText(appName);
await driver.sleep(Timeout.input);
@@ -789,27 +712,33 @@ export async function createNewProject(
await driver.sleep(Timeout.input);
break;
}
- case "gspfxnone": {
+ case "importspfx": {
await input.selectQuickPick(CreateProjectQuestion.Tab);
await driver.sleep(Timeout.input);
// await input.selectQuickPick("SPFx");
await input.setText("SPFx");
await input.confirm();
await driver.sleep(Timeout.input);
- await input.selectQuickPick(CreateProjectQuestion.CreateNewSpfxSolution);
- // Wait for Node version check
- await driver.sleep(Timeout.longTimeWait);
await input.selectQuickPick(
- CreateProjectQuestion.SpfxSharepointFrameworkGlobalEnvInTtk
+ CreateProjectQuestion.ImportExistingSpfxSolution
);
await driver.sleep(Timeout.input);
- // Choose React or None
- await input.selectQuickPick("None");
- // Input Web Part Name
- await input.setText(appName);
+
+ // Input folder path
+ const resourcePath = path.resolve(
+ __dirname,
+ "../../.test-resources/existingspfx"
+ );
+ console.log("choose project path: ", resourcePath);
+ await input.selectQuickPick("Browse...");
+ await inputFolderPath(driver, input, resourcePath);
await driver.sleep(Timeout.input);
+ if (os.type() === "Windows_NT") {
+ await input.sendKeys("\\");
+ } else if (os.type() === "Linux") {
+ await input.sendKeys("/");
+ }
await input.confirm();
- // Input Web Part Description
await driver.sleep(Timeout.input);
break;
}
@@ -821,11 +750,7 @@ export async function createNewProject(
await input.selectQuickPick("Dashboard");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "workflow": {
@@ -833,11 +758,7 @@ export async function createNewProject(
await input.selectQuickPick("Sequential Workflow in Chat");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "timenoti": {
@@ -849,11 +770,7 @@ export async function createNewProject(
);
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "functimernoti": {
@@ -865,11 +782,7 @@ export async function createNewProject(
);
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "addin": {
@@ -902,11 +815,7 @@ export async function createNewProject(
await input.selectQuickPick("Link Unfurling");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "aichat": {
@@ -915,13 +824,9 @@ export async function createNewProject(
await input.selectQuickPick("Basic AI Chatbot");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
await driver.sleep(Timeout.input);
- await input.selectQuickPick("Azure OpenAI");
+ await input.selectQuickPick(aiType);
await driver.sleep(Timeout.input);
// input fake Azure OpenAI Key
await input.setText("fake");
@@ -948,11 +853,7 @@ export async function createNewProject(
await input.selectQuickPick("Build with Assistants API");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
await driver.sleep(Timeout.input);
// input fake OpenAI Key
await input.setText("fake");
@@ -968,11 +869,7 @@ export async function createNewProject(
await input.selectQuickPick("None");
await driver.sleep(Timeout.input);
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
case "msgopenapi": {
@@ -1000,11 +897,7 @@ export async function createNewProject(
await input.selectQuickPick("Start with a new API");
await input.selectQuickPick("API Key");
// Choose programming language
- if (lang) {
- await input.selectQuickPick(lang);
- } else {
- await input.selectQuickPick("JavaScript");
- }
+ await input.selectQuickPick(lang);
break;
}
default:
diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json
index 8de31ef4da..8c4e286b4c 100644
--- a/packages/vscode-extension/package.json
+++ b/packages/vscode-extension/package.json
@@ -103,14 +103,14 @@
}
},
"teamsfx-copilot-plugin": {
- "description": "Copilot Plugin icon in scaffold questions",
+ "description": "API Plugin icon in scaffold questions",
"default": {
"fontPath": "./media/font/teamstoolkit.woff",
"fontCharacter": "\\E005"
}
},
"teamsfx-custom-copilot": {
- "description": "Custom Copilot icon in scaffold questions",
+ "description": "Custom Engine Copilot icon in scaffold questions",
"default": {
"fontPath": "./media/font/teamstoolkit.woff",
"fontCharacter": "\\E006"
@@ -171,11 +171,6 @@
"view": "teamsfx-project-and-check-upgradeV3",
"contents": "%teamstoolkit.viewsWelcome.teamsfx-project-and-check-upgradeV3.content%",
"enablement": "fx-extension.initialized"
- },
- {
- "view": "teamsfx-feedback",
- "contents": "%teamstoolkit.viewsWelcome.teamsfx-feedback.content%",
- "enablement": "fx-extension.initialized"
}
],
"views": {
@@ -222,12 +217,6 @@
"when": "false",
"visibility": "collapsed"
},
- {
- "id": "teamsfx-feedback",
- "name": "Feedback",
- "when": "false",
- "visibility": "visible"
- },
{
"id": "teamsfx-empty-project",
"name": "Teams Toolkit",
@@ -592,10 +581,6 @@
"command": "fx-extension.checkProjectUpgrade",
"when": "fx-extension.canUpgradeV3"
},
- {
- "command": "fx-extension.openSurvey",
- "when": "false"
- },
{
"command": "fx-extension.openOfficeDevLifecycleLink",
"when": "false"
@@ -914,10 +899,6 @@
"title": "%teamstoolkit.commands.signOut.title%",
"icon": "$(sign-out)"
},
- {
- "command": "fx-extension.openSurvey",
- "title": "%teamstoolkit.commandsTreeViewProvider.openSurveyTitle%"
- },
{
"command": "fx-extension.addWebpart",
"title": "%teamstoolkit.commmands.addWebpart.title%",
@@ -1739,6 +1720,7 @@
"jsonc-parser": "^3.0.0",
"log4js": "^6.4.0",
"node-rsa": "^1.1.1",
+ "office-addin-manifest": "^1.13.1",
"query-string": "6.14.1",
"react-collapsible": "^2.10.0",
"react-copy-to-clipboard": "^5.1.0",
diff --git a/packages/vscode-extension/package.nls.json b/packages/vscode-extension/package.nls.json
index 7eb6e449dd..a1297eddbc 100644
--- a/packages/vscode-extension/package.nls.json
+++ b/packages/vscode-extension/package.nls.json
@@ -151,7 +151,6 @@
"teamstoolkit.commandsTreeViewProvider.getStartedTitle": "Get Started",
"teamstoolkit.commandsTreeViewProvider.reportIssuesDescription": "Report any issues and let us know your feedback",
"teamstoolkit.commandsTreeViewProvider.reportIssuesTitle": "Report Issues on GitHub",
- "teamstoolkit.commandsTreeViewProvider.openSurveyTitle": "We Would Love Your Feedback",
"teamstoolkit.commandsTreeViewProvider.samplesDescription": "Get started with a sample from our sample gallery",
"teamstoolkit.commandsTreeViewProvider.samplesTitle": "View Samples",
"teamstoolkit.commandsTreeViewProvider.teamsDevPortalDescription": "Manage your Teams app registration and access more tools",
@@ -322,7 +321,7 @@
"teamstoolkit.localDebug.useTestTool": "Alternatively, you can skip this step by choosing the %s option.",
"teamstoolkit.localDebug.launchTeamsDesktopClientError": "Unable to launch Teams desktop client.",
"teamstoolkit.localDebug.launchTeamsDesktopClientStoppedError": "Task to launch Teams desktop client stopped with exit code '%s'.",
- "teamstoolkit.localDebug.launchTeamsDesktopClientMessage": "Before proceeding, make sure your Teams desktop login matches your current Microsoft 365 account %s used in Teams Toolkit.",
+ "teamstoolkit.localDebug.launchTeamsDesktopClientMessage": "Before proceeding, make sure your Teams desktop login matches your current Microsoft 365 account%s used in Teams Toolkit.",
"teamstoolkit.migrateTeamsManifest.progressTitle": "Upgrade Teams Manifest to extend in Outlook and the Microsoft 365 app",
"teamstoolkit.migrateTeamsManifest.selectFileConfig.name": "Select Teams Manifest to Upgrade",
"teamstoolkit.migrateTeamsManifest.selectFileConfig.title": "Select Teams Manifest to Upgrade",
@@ -409,7 +408,6 @@
"teamstoolkit.publishInDevPortal.confirmFile.placeholder": "Confirm zip file is correctly selected",
"teamstoolkit.upgrade.changelog": "Changelog",
"teamstoolkit.webview.samplePageTitle": "Samples",
- "teamstoolkit.webview.surveyPageTitle": "Teams Toolkit Survey",
"teamstoolkit.webview.accountHelp": "Account Help",
"teamstoolkit.taskDefinitions.command.prerequisites.description": "Validate prerequisites.\n See https://aka.ms/teamsfx-tasks/check-prerequisites for details and how to customize the arguments.",
"teamstoolkit.taskDefinitions.command.startLocalTunnel.description": "Start the local tunneling service.\n See https://aka.ms/teamsfx-tasks/local-tunnel for details and how to customize the arguments.",
@@ -450,8 +448,6 @@
"teamstoolkit.viewsWelcome.teamsfx-empty-project-with-chat-with-api-copilot-plugin.content": "Jumpstart right into Teams Toolkit and [get an overview of the fundamentals](command:fx-extension.openWelcome?%5B%22SideBar%22%5D) or start [building an intelligent app for Microsoft 365](command:fx-extension.buildIntelligentAppsWalkthrough?%5B%22SideBar%22%5D) today.\nWalk through the steps to build a real-world Teams app.\n[Documentation](command:fx-extension.openDocument?%5B%22SideBar%22%5D)\n[How-to Guides](command:fx-extension.selectTutorials?%5B%22SideBar%22%5D)\nCreate a project or explore our samples.\n[Create a New App](command:fx-extension.create?%5B%22SideBar%22%5D)\n[View Samples](command:fx-extension.openSamples?%5B%22SideBar%22%5D)\nCreate your new app effortlessly with Github Copilot.\n[Create App with Github Copilot](command:fx-extension.invokeChat?%5B%22SideBar%22%5D)",
"teamstoolkit.viewsWelcome.teamsfx-empty-project-new-user-with-chat.content": "Jumpstart right into Teams Toolkit and [get an overview of the fundamentals](command:fx-extension.openWelcome?%5B%22SideBar%22%5D) today.\nCreate a project or explore our samples.\n[Create a New App](command:fx-extension.create?%5B%22SideBar%22%5D)\n[View Samples](command:fx-extension.openSamples?%5B%22SideBar%22%5D)\nWalk through the steps to build a real-world Teams app.\n[Documentation](command:fx-extension.openDocument?%5B%22SideBar%22%5D)\n[How-to Guides](command:fx-extension.selectTutorials?%5B%22SideBar%22%5D)\nCreate your new app effortlessly with Github Copilot.\n[Create App with Github Copilot](command:fx-extension.invokeChat?%5B%22SideBar%22%5D)",
"teamstoolkit.viewsWelcome.teamsfx-empty-project-new-user-with-chat-with-api-copilot-plugin.content": "Jumpstart right into Teams Toolkit and [get an overview of the fundamentals](command:fx-extension.openWelcome?%5B%22SideBar%22%5D) or start [building an intelligent app for Microsoft 365](command:fx-extension.buildIntelligentAppsWalkthrough?%5B%22SideBar%22%5D) today.\nCreate a project or explore our samples.\n[Create a New App](command:fx-extension.create?%5B%22SideBar%22%5D)\n[View Samples](command:fx-extension.openSamples?%5B%22SideBar%22%5D)\nWalk through the steps to build a real-world Teams app.\n[Documentation](command:fx-extension.openDocument?%5B%22SideBar%22%5D)\n[How-to Guides](command:fx-extension.selectTutorials?%5B%22SideBar%22%5D)\nCreate your new app effortlessly with Github Copilot.\n[Create App with Github Copilot](command:fx-extension.invokeChat?%5B%22SideBar%22%5D)",
-
- "teamstoolkit.viewsWelcome.teamsfx-feedback.content": "Take 2 minutes to help us improve, your feedback matters!\n[We Would Love Your Feedback](command:fx-extension.openSurvey)",
"teamstoolkit.walkthroughs.description": "Jumpstart your Teams app development experience",
"teamstoolkit.walkthroughs.withChat.description": "Jumpstart your Teams app development experience or use @teams in Github Copilot Extension",
"_teamstoolkit.walkthroughs.withChat.description.comment": "@teams is a command which should not be translated.",
@@ -522,16 +518,16 @@
"teamstoolkit.walkthroughs.buildIntelligentApps.twoPathsToIntelligentApps.title": "Two Paths to Intelligent Apps",
"teamstoolkit.walkthroughs.buildIntelligentApps.twoPathsToIntelligentApps.description": "Build your intelligent apps with Microsoft 365 in two ways:\n🎯 Extend Microsoft Copilot with a plugin, Or\n✨ Build your own Copilot in Teams using Teams AI Library and Azure services",
- "teamstoolkit.walkthroughs.buildIntelligentApps.copilotPlugin.title": "Copilot Plugin",
+ "teamstoolkit.walkthroughs.buildIntelligentApps.copilotPlugin.title": "API Plugin",
"teamstoolkit.walkthroughs.buildIntelligentApps.copilotPlugin.description": "Transform your app into a plugin to enhance Copilot's skills and boost user productivity in daily tasks and workflows. Explore [Copilot Extensibility](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/)\n[Check Copilot Access](command:fx-extension.checkCopilotAccess?%5B%22WalkThrough%22%5D)",
"teamstoolkit.walkthroughs.buildIntelligentApps.buildPlugin.title": "Build a Plugin",
"teamstoolkit.walkthroughs.buildIntelligentApps.buildPlugin.description": "Expand, enrich, and customize Copilot with plugins and Graph connectors in any of the following ways\n[OpenAPI Description Document](command:fx-extension.createFromWalkthrough?%5B%22WalkThrough%22%2C%20%7B%22project-type%22%3A%20%22copilot-plugin-type%22%7D%5D)\n[Teams Message Extension](command:fx-extension.createFromWalkthrough?%5B%22WalkThrough%22%2C%20%7B%22capabilities%22%3A%20%22search-app%22%2C%20%22project-type%22%3A%20%22me-type%22%2C%20%22me-architecture%22%3A%20%22bot-plugin%22%7D%5D)\n[Graph Connector](command:fx-extension.openSamples?%5B%22WalkThrough%22%2C%20%22gc-nodejs-typescript-food-catalog%22%5D)",
- "teamstoolkit.walkthroughs.buildIntelligentApps.customCopilot.title": "Custom Copilot",
+ "teamstoolkit.walkthroughs.buildIntelligentApps.customCopilot.title": "Custom Engine Copilot",
"teamstoolkit.walkthroughs.buildIntelligentApps.customCopilot.description": "Build your intelligent, natural language-driven experiences in Teams, leveraging its vast user base for collaboration. \nTeams toolkit integrates with Azure OpenAI and Teams AI Library to streamline copilot development and offer unique Teams-based capabilities. \nExplore [Teams AI Library](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/teams%20conversational%20ai/teams-conversation-ai-overview) and [Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview)",
- "teamstoolkit.walkthroughs.buildIntelligentApps.buildCustomCopilot.title": "Build Custom Copilot",
+ "teamstoolkit.walkthroughs.buildIntelligentApps.buildCustomCopilot.title": "Build Custom Engine Copilot",
"teamstoolkit.walkthroughs.buildIntelligentApps.buildCustomCopilot.description": "Build an AI agent bot for common tasks or an intelligent chatbot to answer specific questions\n[Build a Basic AI Chatbot](command:fx-extension.createFromWalkthrough?%5B%22WalkThrough%22%2C%20%7B%22capabilities%22%3A%20%22custom-copilot-basic%22%2C%20%22project-type%22%3A%20%22custom-copilot-type%22%7D%5D)\n[Build an AI Agent](command:fx-extension.createFromWalkthrough?%5B%22WalkThrough%22%2C%20%7B%22capabilities%22%3A%20%22custom-copilot-agent%22%2C%20%22project-type%22%3A%20%22custom-copilot-type%22%7D%5D)\n[Build a Bot to Chat with Your Data](command:fx-extension.createFromWalkthrough?%5B%22WalkThrough%22%2C%20%7B%22capabilities%22%3A%20%22custom-copilot-rag%22%2C%20%22project-type%22%3A%20%22custom-copilot-type%22%7D%5D)",
"teamstoolkit.walkthroughs.buildIntelligentApps.intelligentAppResources.title": "Intelligent App Resources",
diff --git a/packages/vscode-extension/pnpm-lock.yaml b/packages/vscode-extension/pnpm-lock.yaml
index 7b426f8be2..cb22fda36a 100644
--- a/packages/vscode-extension/pnpm-lock.yaml
+++ b/packages/vscode-extension/pnpm-lock.yaml
@@ -86,6 +86,9 @@ dependencies:
node-rsa:
specifier: ^1.1.1
version: 1.1.1
+ office-addin-manifest:
+ specifier: ^1.13.1
+ version: 1.13.2
query-string:
specifier: 6.14.1
version: 6.14.1
@@ -2269,6 +2272,20 @@ packages:
resolution: {integrity: sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==}
dev: true
+ /@microsoft/teams-manifest@0.1.4:
+ resolution: {integrity: sha512-VVFnItrOi2MS7seQC/EkFGyqJNkR2jRASTeSaUhyJ+pdnrUszYPRqyOwBzFw4HmXBmlnOD1WTfRgwdeav/KpgA==}
+ dependencies:
+ '@types/fs-extra': 11.0.4
+ '@types/node-fetch': 2.6.11
+ ajv: 8.12.0
+ ajv-draft-04: 1.0.0(ajv@8.12.0)
+ ajv-formats: 3.0.1(ajv@8.12.0)
+ fs-extra: 9.1.0
+ node-fetch: 2.7.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
/@microsoft/tiktokenizer@1.0.4:
resolution: {integrity: sha512-M3jur8c4gwungkRyT0q0zXjp5rBWRmBMdE/VwW5yQtKDKCQkoms/1GTKEkeFOM2GKyfpxfMqj+n7G90Sz3fI6g==}
engines: {node: '>=18.0.0'}
@@ -2647,7 +2664,6 @@ packages:
dependencies:
'@types/jsonfile': 6.1.4
'@types/node': 14.14.21
- dev: true
/@types/fs-extra@9.0.5:
resolution: {integrity: sha512-wr3t7wIW1c0A2BIJtdVp4EflriVaVVAsCAIHVzzh8B+GiFv9X1xeJjCs4upRXtzp7kQ6lP5xvskjoD4awJ1ZeA==}
@@ -2706,7 +2722,6 @@ packages:
resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==}
dependencies:
'@types/node': 14.14.21
- dev: true
/@types/lodash@4.14.181:
resolution: {integrity: sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==}
@@ -2740,9 +2755,15 @@ packages:
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
dev: true
+ /@types/node-fetch@2.6.11:
+ resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
+ dependencies:
+ '@types/node': 14.14.21
+ form-data: 4.0.0
+ dev: false
+
/@types/node@14.14.21:
resolution: {integrity: sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==}
- dev: true
/@types/parse-json@4.0.2:
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -3412,6 +3433,11 @@ packages:
engines: {node: '>= 10.0.0'}
dev: true
+ /adm-zip@0.5.12:
+ resolution: {integrity: sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==}
+ engines: {node: '>=6.0'}
+ dev: false
+
/agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
@@ -3435,6 +3461,28 @@ packages:
indent-string: 4.0.0
dev: true
+ /ajv-draft-04@1.0.0(ajv@8.12.0):
+ resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
+ peerDependencies:
+ ajv: ^8.5.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+ dependencies:
+ ajv: 8.12.0
+ dev: false
+
+ /ajv-formats@3.0.1(ajv@8.12.0):
+ resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+ dependencies:
+ ajv: 8.12.0
+ dev: false
+
/ajv-keywords@3.5.2(ajv@6.12.6):
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
peerDependencies:
@@ -3459,7 +3507,6 @@ packages:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
- dev: true
/ansi-colors@4.1.1:
resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==}
@@ -3519,6 +3566,15 @@ packages:
default-require-extensions: 3.0.1
dev: true
+ /applicationinsights@1.8.10:
+ resolution: {integrity: sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A==}
+ dependencies:
+ cls-hooked: 4.2.2
+ continuation-local-storage: 3.2.1
+ diagnostic-channel: 0.3.1
+ diagnostic-channel-publishers: 0.4.4(diagnostic-channel@0.3.1)
+ dev: false
+
/aproba@2.0.0:
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
dev: true
@@ -3666,6 +3722,21 @@ packages:
engines: {node: '>=8'}
dev: true
+ /async-hook-jl@1.7.6:
+ resolution: {integrity: sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==}
+ engines: {node: ^4.7 || >=6.9 || >=7.3}
+ dependencies:
+ stack-chain: 1.3.7
+ dev: false
+
+ /async-listener@0.6.10:
+ resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==}
+ engines: {node: <=0.11.8 || >0.11.10}
+ dependencies:
+ semver: 5.7.2
+ shimmer: 1.2.1
+ dev: false
+
/async-mutex@0.3.1:
resolution: {integrity: sha512-vRfQwcqBnJTLzVQo72Sf7KIUbcSUP5hNchx6udI1U6LuPQpfePgdjJzlCe76yFZ8pxlLjn9lwcl/Ya0TSOv0Tw==}
dependencies:
@@ -3686,7 +3757,6 @@ packages:
/at-least-node@1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
- dev: true
/atob@2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
@@ -4261,6 +4331,15 @@ packages:
kind-of: 6.0.3
shallow-clone: 3.0.1
+ /cls-hooked@4.2.2:
+ resolution: {integrity: sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==}
+ engines: {node: ^4.7 || >=6.9 || >=7.3 || >=8.2.1}
+ dependencies:
+ async-hook-jl: 1.7.6
+ emitter-listener: 1.1.2
+ semver: 5.7.2
+ dev: false
+
/collection-visit@1.0.0:
resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
engines: {node: '>=0.10.0'}
@@ -4328,6 +4407,11 @@ packages:
engines: {node: '>= 6'}
dev: true
+ /commander@6.2.1:
+ resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
+ engines: {node: '>= 6'}
+ dev: false
+
/commander@7.2.0:
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
engines: {node: '>= 10'}
@@ -4389,6 +4473,13 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
+ /continuation-local-storage@3.2.1:
+ resolution: {integrity: sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==}
+ dependencies:
+ async-listener: 0.6.10
+ emitter-listener: 1.1.2
+ dev: false
+
/convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
dev: true
@@ -5132,6 +5223,20 @@ packages:
- supports-color
dev: true
+ /diagnostic-channel-publishers@0.4.4(diagnostic-channel@0.3.1):
+ resolution: {integrity: sha512-l126t01d2ZS9EreskvEtZPrcgstuvH3rbKy82oUhUrVmBaGx4hO9wECdl3cvZbKDYjMF3QJDB5z5dL9yWAjvZQ==}
+ peerDependencies:
+ diagnostic-channel: '*'
+ dependencies:
+ diagnostic-channel: 0.3.1
+ dev: false
+
+ /diagnostic-channel@0.3.1:
+ resolution: {integrity: sha512-6eb9YRrimz8oTr5+JDzGmSYnXy5V7YnK5y/hd8AUDK1MssHjQKm9LlD6NSrHx4vMDF3+e/spI2hmWTviElgWZA==}
+ dependencies:
+ semver: 5.7.2
+ dev: false
+
/diff@4.0.2:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
@@ -5290,6 +5395,12 @@ packages:
resolution: {integrity: sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==}
dev: true
+ /emitter-listener@1.1.2:
+ resolution: {integrity: sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==}
+ dependencies:
+ shimmer: 1.2.1
+ dev: false
+
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -5928,7 +6039,6 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
- dev: true
/fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
@@ -6184,6 +6294,15 @@ packages:
universalify: 2.0.1
dev: true
+ /fs-extra@7.0.1:
+ resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
+ engines: {node: '>=6 <7 || >=8'}
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 4.0.0
+ universalify: 0.1.2
+ dev: false
+
/fs-extra@8.1.0:
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
engines: {node: '>=6 <7 || >=8'}
@@ -6203,6 +6322,16 @@ packages:
universalify: 1.0.0
dev: true
+ /fs-extra@9.1.0:
+ resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ at-least-node: 1.0.0
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.1
+ dev: false
+
/fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
@@ -6781,6 +6910,10 @@ packages:
once: 1.4.0
wrappy: 1.0.2
+ /inherits@2.0.3:
+ resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==}
+ dev: false
+
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -7290,7 +7423,6 @@ packages:
/json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
- dev: true
/json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
@@ -7332,7 +7464,6 @@ packages:
universalify: 2.0.1
optionalDependencies:
graceful-fs: 4.2.11
- dev: true
/jsonparse@1.3.1:
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
@@ -8431,7 +8562,18 @@ packages:
optional: true
dependencies:
whatwg-url: 5.0.0
- dev: true
+
+ /node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ dependencies:
+ whatwg-url: 5.0.0
+ dev: false
/node-gyp-build@4.8.0:
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
@@ -8634,6 +8776,34 @@ packages:
es-abstract: 1.22.3
dev: true
+ /office-addin-manifest@1.13.2:
+ resolution: {integrity: sha512-+IBmcMbgoAsjE7FOO15HeVQD91GbWd3mcdmq43xulFaI5uC5bYhw70TI7XEUUYRrPU1iLFGbdYNHvsjFfNdqzQ==}
+ hasBin: true
+ dependencies:
+ '@microsoft/teams-manifest': 0.1.4
+ adm-zip: 0.5.12
+ chalk: 2.4.2
+ commander: 6.2.1
+ fs-extra: 7.0.1
+ node-fetch: 2.6.7
+ office-addin-usage-data: 1.6.11
+ path: 0.12.7
+ uuid: 8.3.2
+ xml2js: 0.5.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /office-addin-usage-data@1.6.11:
+ resolution: {integrity: sha512-8n86S1PkAktGFtrM2kYVX8zbgo/i8VyH6RzO3ApX6GeFOeTWJPtYVWmGs7WklkoTlZGTwDjfiR+noB0vWA9Vpg==}
+ hasBin: true
+ dependencies:
+ applicationinsights: 1.8.10
+ commander: 6.2.1
+ readline-sync: 1.4.10
+ uuid: 8.3.2
+ dev: false
+
/on-exit-leak-free@0.2.0:
resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==}
dev: true
@@ -8866,6 +9036,13 @@ packages:
engines: {node: '>=8'}
dev: true
+ /path@0.12.7:
+ resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==}
+ dependencies:
+ process: 0.11.10
+ util: 0.10.4
+ dev: false
+
/pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
@@ -9094,7 +9271,6 @@ packages:
/process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
- dev: true
/progress@2.0.3:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
@@ -9168,7 +9344,6 @@ packages:
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- dev: true
/qs@6.11.0:
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
@@ -9394,6 +9569,11 @@ packages:
picomatch: 2.3.1
dev: true
+ /readline-sync@1.4.10:
+ resolution: {integrity: sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==}
+ engines: {node: '>= 0.8.0'}
+ dev: false
+
/real-require@0.1.0:
resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==}
engines: {node: '>= 12.13.0'}
@@ -9574,7 +9754,6 @@ packages:
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
- dev: true
/require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
@@ -9763,7 +9942,6 @@ packages:
/sax@1.3.0:
resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
- dev: true
/scheduler@0.20.2:
resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
@@ -9940,6 +10118,10 @@ packages:
engines: {node: '>=8'}
dev: true
+ /shimmer@1.2.1:
+ resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
+ dev: false
+
/side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
@@ -10174,6 +10356,10 @@ packages:
minipass: 3.3.6
dev: true
+ /stack-chain@1.3.7:
+ resolution: {integrity: sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==}
+ dev: false
+
/static-extend@0.1.2:
resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
engines: {node: '>=0.10.0'}
@@ -10645,7 +10831,6 @@ packages:
/tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
- dev: true
/ts-dedent@2.2.0:
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
@@ -10976,7 +11161,6 @@ packages:
/universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
- dev: true
/unix-crypt-td-js@1.1.4:
resolution: {integrity: sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==}
@@ -11013,7 +11197,6 @@ packages:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.1
- dev: true
/urix@0.1.0:
resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
@@ -11053,6 +11236,12 @@ packages:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
+ /util@0.10.4:
+ resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==}
+ dependencies:
+ inherits: 2.0.3
+ dev: false
+
/utila@0.4.0:
resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
dev: true
@@ -11225,7 +11414,6 @@ packages:
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
- dev: true
/webpack-cli@5.1.4(webpack@5.88.2):
resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==}
@@ -11341,7 +11529,6 @@ packages:
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
- dev: true
/which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
@@ -11438,6 +11625,19 @@ packages:
typedarray-to-buffer: 3.1.5
dev: true
+ /xml2js@0.5.0:
+ resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ sax: 1.3.0
+ xmlbuilder: 11.0.1
+ dev: false
+
+ /xmlbuilder@11.0.1:
+ resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
+ engines: {node: '>=4.0'}
+ dev: false
+
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
diff --git a/packages/vscode-extension/src/constants.ts b/packages/vscode-extension/src/constants.ts
index 5cbe4046e8..aa10686a5f 100644
--- a/packages/vscode-extension/src/constants.ts
+++ b/packages/vscode-extension/src/constants.ts
@@ -21,6 +21,11 @@ export enum PrereleaseState {
Version = "teamsToolkit:prerelease:version",
}
+export enum ResourceInfo {
+ Subscription = "Subscription",
+ ResourceGroup = "Resource Group",
+}
+
export enum GlobalKey {
OpenWalkThrough = "fx-extension.openWalkThrough",
OpenReadMe = "fx-extension.openReadMe",
diff --git a/packages/vscode-extension/src/controls/PanelType.ts b/packages/vscode-extension/src/controls/PanelType.ts
index 2e24adb1cf..b222973222 100644
--- a/packages/vscode-extension/src/controls/PanelType.ts
+++ b/packages/vscode-extension/src/controls/PanelType.ts
@@ -3,7 +3,6 @@
export enum PanelType {
SampleGallery = "sample-gallery",
- Survey = "survey",
RespondToCardActions = "respond-to-card-actions",
AccountHelp = "account-help",
FunctionBasedNotificationBotReadme = "function-based-notification-bot-readme",
diff --git a/packages/vscode-extension/src/controls/Survey.scss b/packages/vscode-extension/src/controls/Survey.scss
deleted file mode 100644
index bcc7ec6d47..0000000000
--- a/packages/vscode-extension/src/controls/Survey.scss
+++ /dev/null
@@ -1,116 +0,0 @@
-.survey-page {
- max-width: 770px;
- margin: auto;
- font-size: var(--vscode-font-size);
-
- .logo {
- text-align: center;
- }
-
- .logo-text {
- display: inline-block;
- font-size: 20px;
- }
-
- .survey-body {
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
-
- .highlight {
- color: var(--vscode-textLink-foreground);
- }
-
- .question {
- display: flex;
- flex-direction: column;
- justify-content: center;
- margin: auto;
- text-align: center;
- width: 100%;
- }
-
- .question-background {
- display: flex;
- flex-direction: column;
- justify-content: center;
- margin: auto;
- text-align: center;
- width: 100%;
- background-color: var(--vscode-editor-selectionBackground);
- }
-
- .question-title {
- flex: 100%;
- width: 100%;
- text-align: left;
- flex-direction: row;
- }
-
- .question-desc {
- display: flex;
- flex-direction: row;
- }
-
- .question-desc-first {
- flex: 100%;
- text-align: left;
- }
-
- .question-desc-last {
- flex: 100%;
- text-align: right;
- }
-
- .question-label {
- display: flex;
- flex-direction: row;
- }
-
- .question-label-item {
- flex-direction: row;
- flex: 100%;
- }
-
- .question-textfield {
- margin: auto;
- width: 100%;
- flex: 100%;
- }
-
- .question-radio {
- display: flex;
- flex-direction: row;
- }
-
- .question-radio-item {
- flex: 100%;
- }
-
- .submit-div {
- display: flex;
- justify-content: center;
- align-items: center;
- border-top: 30px;
- }
-
- .submit-button {
- background-color: var(--vscode-button-background);
- color: var(--vscode-button-foreground);
- border: none;
- margin-top: 20px;
- padding: 1px 50px;
- }
-
- .validation-error {
- text-align: center;
- padding: 5px 0 10px 0;
- color: var(--vscode-errorForeground);
- }
-
- .thankyou-page {
- margin: auto;
- font-size: 20px;
- }
-}
diff --git a/packages/vscode-extension/src/controls/Survey.tsx b/packages/vscode-extension/src/controls/Survey.tsx
deleted file mode 100644
index 9ec2ca6212..0000000000
--- a/packages/vscode-extension/src/controls/Survey.tsx
+++ /dev/null
@@ -1,334 +0,0 @@
-import * as React from "react";
-import "./Survey.scss";
-import { Commands } from "./Commands";
-import {
- TelemetryEvent,
- TelemetryProperty,
- TelemetrySurveyDataProperty,
- TelemetryTriggerFrom,
-} from "../telemetry/extTelemetryEvents";
-import { Separator, TextField } from "@fluentui/react";
-import TeamsIcon from "../../img/webview/survey/microsoft-teams.svg";
-
-type QuestionChoice = { key: string; val: number };
-
-const q1: QuestionChoice[] = [
- { key: "Extremely Dissatisfied", val: 0 },
- { key: "Moderately Dissatisfied", val: 1 },
- { key: "Slightly Dissatisfied", val: 2 },
- { key: "Neither Satisfied nor Dissatisfied", val: 3 },
- { key: "Slightly Satisfied", val: 4 },
- { key: "Moderately Satisfied", val: 5 },
- { key: "Extremely Satisfied", val: 6 },
-];
-
-const q1Title: JSX.Element = (
-
-
- Overall, how satisfied or dissatisfied are you
- with the Teams Toolkit extension in Visual Studio Code?
-
-
-);
-
-const q2: QuestionChoice[] = [
- { key: "0", val: 0 },
- { key: "1", val: 1 },
- { key: "2", val: 2 },
- { key: "3", val: 3 },
- { key: "4", val: 4 },
- { key: "5", val: 5 },
- { key: "6", val: 6 },
- { key: "7", val: 7 },
- { key: "8", val: 8 },
- { key: "9", val: 9 },
- { key: "10", val: 10 },
-];
-
-const q2Title: JSX.Element = (
-
-
- How likely are you to recommend the Teams Toolkit extension
- in Visual Studio Code to a friend or colleague?
-
-
-);
-
-const q2Desc: string[] = ["Not at all likely", "Extremely likely"];
-
-const q3Title: JSX.Element = (
-
- (Optional)
-
- {" "}
- What is the primary purpose of the Teams app you're
- creating? What is motivating you to develop Teams apps?
-
-
-);
-
-const q4Title: JSX.Element = (
-
- (Optional)
-
- {" "}
- What, if anything, do you find
- frustrating or unappealing
- {" "}
- about the Teams Toolkit in Visual Studio Code? What{" "}
- new capabilities would you like to see for the Teams
- Toolkit?
-
-
-);
-
-const q5Title: JSX.Element = (
-
- (Optional)
-
- {" "}
- What do you like best about the Teams Toolkit in Visual
- Studio Code?
-
-
-);
-
-class SurveyQuestionChoice extends React.Component {
- myRef: any;
-
- constructor(props: any) {
- super(props);
- this.state = {
- selectedOption: undefined,
- };
- this.onValueChange = this.onValueChange.bind(this);
- this.myRef = React.createRef();
- }
-
- onValueChange(event: any) {
- this.setState({
- selectedOption: event.target.value,
- });
- }
-
- render() {
- let desc;
- if (this.props.desc) {
- desc = (
-
-
{this.props.desc[0]}
-
{this.props.desc[1]}
-
- );
- } else {
- desc = undefined;
- }
-
- return (
-
- {this.props.title}
-
- {desc}
-
- {this.props.items.map((item: any) => {
- return
{item.key}
;
- })}
-
-
- {this.props.items.map((item: any) => {
- return (
-
-
-
- );
- })}
-
-
- );
- }
-}
-
-class SurveyQuestionTextField extends React.Component {
- myRef: any;
- constructor(props: any) {
- super(props);
- this.state = {
- inputValue: undefined,
- };
-
- this.onValueChange = this.onValueChange.bind(this);
- this.myRef = React.createRef();
- }
-
- onValueChange(
- ev: React.FormEvent,
- newText: string | undefined
- ) {
- this.setState({
- inputValue: newText,
- });
- }
-
- render() {
- return (
-
-
{this.props.title}
-
-
-
-
-
- );
- }
-}
-
-export default class Survey extends React.Component {
- constructor(props: any) {
- super(props);
- this.state = {
- q1Score: React.createRef(),
- q2Score: React.createRef(),
- q3Text: React.createRef(),
- q4Text: React.createRef(),
- q5Text: React.createRef(),
- };
- }
-
- render() {
- if (this.state.surveyTaken === true) {
- return (
-
-
- Thank you for taking the time to complete this survey. You can close this page now.
-
-
- );
- } else {
- return (
-
-
-
-
-
Microsoft Teams Toolkit
-
-
-
- 👋 Hi! I'm Zhenya Savchenko, a Program Manager on the Teams Framework Engineering
- Team. In this 5-10 minute survey, we need your help understanding your experience
- developing Teams apps with the Toolkit in Visual Studio Code.
-
-
-
- Note: Below, you'll have options to answer some open questions. We
- need your help shaping our roadmap! Thank you - your help is very much appreciated!
-
-
-
-
-
-
- {this.state.showQ1Error && (
-
Please answer this question.
- )}
-
-
- {this.state.showQ2Error && (
-
Please answer this question.
- )}
-
-
-
-
-
-
-
-
-
- Submit
-
-
-
-
-
- );
- }
- }
-
- onClick = (event: any) => {
- const q1Score = this.state.q1Score.current.state.selectedOption;
- const q2Score = this.state.q2Score.current.state.selectedOption;
- const q3Text = this.state.q3Text.current.state.inputValue;
- const q4Text = this.state.q4Text.current.state.inputValue;
- const q5Text = this.state.q5Text.current.state.inputValue;
- let sendTelemetry = true;
-
- if (q1Score === undefined) {
- this.setState({ showQ1Error: true });
- sendTelemetry = false;
- } else {
- this.setState({ showQ1Error: false });
- }
-
- if (q2Score === undefined) {
- this.setState({ showQ2Error: true });
- sendTelemetry = false;
- } else {
- this.setState({ showQ2Error: false });
- }
-
- console.log(this.state);
- console.log(sendTelemetry);
- if (sendTelemetry) {
- vscode.postMessage({
- command: Commands.SendTelemetryEvent,
- data: {
- eventName: TelemetryEvent.SurveyData,
- properties: {
- [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Webview,
- [TelemetrySurveyDataProperty.Q1Title]:
- "Overall, how satisfied or dissatisfied are you with the Teams Toolkit extension in Visual Studio Code?",
- [TelemetrySurveyDataProperty.Q1Result]: q1Score,
- [TelemetrySurveyDataProperty.Q2Title]:
- "How likely are you to recommend the Teams Toolkit extension in Visual Studio Code to a friend or colleague?",
- [TelemetrySurveyDataProperty.Q2Result]: q2Score,
- [TelemetrySurveyDataProperty.Q3Title]:
- "What is the primary purpose of the Teams app you're creating? What is motivating you to develop Teams apps?",
- [TelemetrySurveyDataProperty.Q3Result]: q3Text,
- [TelemetrySurveyDataProperty.Q4Title]:
- "What, if anything, do you find frustrating or unappealing about the Teams Toolkit in Visual Studio Code? What new capabilities would you like to see for the Teams Toolkit?",
- [TelemetrySurveyDataProperty.Q4Result]: q4Text,
- [TelemetrySurveyDataProperty.Q5Title]:
- "What do you like best about the Teams Toolkit in Visual Studio Code?",
- [TelemetrySurveyDataProperty.Q5Result]: q5Text,
- },
- },
- });
-
- this.setState({ surveyTaken: true });
- }
- };
-}
diff --git a/packages/vscode-extension/src/controls/index.tsx b/packages/vscode-extension/src/controls/index.tsx
index 5a3bdada38..b7fed20779 100644
--- a/packages/vscode-extension/src/controls/index.tsx
+++ b/packages/vscode-extension/src/controls/index.tsx
@@ -7,7 +7,6 @@ import { initializeIcons } from "@fluentui/react/lib/Icons";
import { PanelType } from "./PanelType";
import SampleGallery from "./sampleGallery/SampleGallery";
-import Survey from "./Survey";
import AccountHelp from "./webviewDocs/accountHelp";
import FunctionBasedNotificationBot from "./webviewDocs/functionBasedNotificationBot";
import RestifyServerNotificationBot from "./webviewDocs/restifyServerNotificationBot";
@@ -27,23 +26,20 @@ function App(props: any) {
initializeIcons();
let initialIndex = 0;
- if (panelType === PanelType.Survey) {
+ if (panelType === PanelType.RespondToCardActions) {
initialIndex = 1;
- } else if (panelType === PanelType.RespondToCardActions) {
- initialIndex = 2;
} else if (panelType === PanelType.AccountHelp) {
- initialIndex = 3;
+ initialIndex = 2;
} else if (panelType === PanelType.FunctionBasedNotificationBotReadme) {
- initialIndex = 4;
+ initialIndex = 3;
} else if (panelType === PanelType.RestifyServerNotificationBotReadme) {
- initialIndex = 5;
+ initialIndex = 4;
}
return (
}
/>
-
diff --git a/packages/vscode-extension/src/controls/openWelcomePage.ts b/packages/vscode-extension/src/controls/openWelcomePage.ts
index 45de99cb9f..ecf754d427 100644
--- a/packages/vscode-extension/src/controls/openWelcomePage.ts
+++ b/packages/vscode-extension/src/controls/openWelcomePage.ts
@@ -4,8 +4,8 @@
import { globalStateGet, globalStateUpdate } from "@microsoft/teamsfx-core";
import * as vscode from "vscode";
import { TelemetryTriggerFrom } from "../telemetry/extTelemetryEvents";
-import { openBuildIntelligentAppsWalkthroughHandler } from "../handlers";
-import { openWelcomeHandler } from "../handlers/openLinkHandlers";
+import { openBuildIntelligentAppsWalkthroughHandler } from "../handlers/walkthrough";
+import { openWelcomeHandler } from "../handlers/controlHandlers";
const welcomePageKey = "ms-teams-vscode-extension.welcomePage.shown";
diff --git a/packages/vscode-extension/src/controls/webviewPanel.ts b/packages/vscode-extension/src/controls/webviewPanel.ts
index 9ab3e46cdd..90ff1f74b8 100644
--- a/packages/vscode-extension/src/controls/webviewPanel.ts
+++ b/packages/vscode-extension/src/controls/webviewPanel.ts
@@ -299,8 +299,6 @@ export class WebviewPanel {
switch (panelType) {
case PanelType.SampleGallery:
return localize("teamstoolkit.webview.samplePageTitle");
- case PanelType.Survey:
- return localize("teamstoolkit.webview.surveyPageTitle");
case PanelType.RespondToCardActions:
return localize("teamstoolkit.guides.cardActionResponse.label");
case PanelType.AccountHelp:
diff --git a/packages/vscode-extension/src/debug/depsChecker/common.ts b/packages/vscode-extension/src/debug/depsChecker/common.ts
index 595abcbb17..5976599994 100644
--- a/packages/vscode-extension/src/debug/depsChecker/common.ts
+++ b/packages/vscode-extension/src/debug/depsChecker/common.ts
@@ -33,15 +33,14 @@ import {
import * as os from "os";
import * as util from "util";
import * as vscode from "vscode";
-
import { signedOut } from "../../commonlib/common/constant";
import VsCodeLogInstance from "../../commonlib/log";
import M365TokenInstance from "../../commonlib/m365Login";
import { ExtensionErrors, ExtensionSource } from "../../error/error";
import { VS_CODE_UI } from "../../qm/vsc_ui";
import { tools, workspaceUri } from "../../globalVariables";
-import { checkCopilotCallback } from "../../handlers/checkCopilotCallback";
-import { ProgressHandler } from "../../progressHandler";
+import { checkCopilotCallback } from "../../handlers/accounts/checkAccessCallback";
+import { ProgressHandler } from "../progressHandler";
import { ExtTelemetry } from "../../telemetry/extTelemetry";
import { TelemetryEvent, TelemetryProperty } from "../../telemetry/extTelemetryEvents";
import { getDefaultString, localize } from "../../utils/localizeUtils";
diff --git a/packages/vscode-extension/src/progressHandler.ts b/packages/vscode-extension/src/debug/progressHandler.ts
similarity index 98%
rename from packages/vscode-extension/src/progressHandler.ts
rename to packages/vscode-extension/src/debug/progressHandler.ts
index 96e4af9a43..4a3c56f6cf 100644
--- a/packages/vscode-extension/src/progressHandler.ts
+++ b/packages/vscode-extension/src/debug/progressHandler.ts
@@ -8,7 +8,7 @@ import * as util from "util";
import { ProgressLocation, window } from "vscode";
import { IProgressHandler, ok } from "@microsoft/teamsfx-api";
-import { localize } from "./utils/localizeUtils";
+import { localize } from "../utils/localizeUtils";
export class ProgressHandler implements IProgressHandler {
private totalSteps: number;
diff --git a/packages/vscode-extension/src/debug/taskTerminal/baseTunnelTaskTerminal.ts b/packages/vscode-extension/src/debug/taskTerminal/baseTunnelTaskTerminal.ts
index 23e75cf6a4..e6898952ec 100644
--- a/packages/vscode-extension/src/debug/taskTerminal/baseTunnelTaskTerminal.ts
+++ b/packages/vscode-extension/src/debug/taskTerminal/baseTunnelTaskTerminal.ts
@@ -19,7 +19,7 @@ import {
import VsCodeLogInstance from "../../commonlib/log";
import { ExtensionErrors, ExtensionSource } from "../../error/error";
import * as globalVariables from "../../globalVariables";
-import { ProgressHandler } from "../../progressHandler";
+import { ProgressHandler } from "../progressHandler";
import {
TelemetryEvent,
TelemetryProperty,
diff --git a/packages/vscode-extension/src/debug/taskTerminal/devTunnelTaskTerminal.ts b/packages/vscode-extension/src/debug/taskTerminal/devTunnelTaskTerminal.ts
index 064f2f7337..5c4c37b2b6 100644
--- a/packages/vscode-extension/src/debug/taskTerminal/devTunnelTaskTerminal.ts
+++ b/packages/vscode-extension/src/debug/taskTerminal/devTunnelTaskTerminal.ts
@@ -15,7 +15,12 @@ import {
} from "@microsoft/dev-tunnels-management";
import { TraceLevel } from "@microsoft/dev-tunnels-ssh";
import { err, FxError, ok, Result, SystemError, UserError, Void } from "@microsoft/teamsfx-api";
-import { TaskDefaultValue, TunnelType } from "@microsoft/teamsfx-core";
+import {
+ featureFlagManager,
+ FeatureFlags,
+ TaskDefaultValue,
+ TunnelType,
+} from "@microsoft/teamsfx-core";
import VsCodeLogInstance from "../../commonlib/log";
import { ExtensionErrors } from "../../error/error";
@@ -27,7 +32,6 @@ import {
TelemetryProperty,
TelemetrySuccess,
} from "../../telemetry/extTelemetryEvents";
-import { FeatureFlags, isFeatureFlagEnabled } from "../../featureFlags";
import { devTunnelDisplayMessages } from "../common/debugConstants";
import { maskValue } from "../localTelemetryReporter";
import { BaseTaskTerminal } from "./baseTaskTerminal";
@@ -106,7 +110,7 @@ export class DevTunnelTaskTerminal extends BaseTunnelTaskTerminal {
static create(taskDefinition: vscode.TaskDefinition): DevTunnelTaskTerminal {
const tunnelManagementClientImpl = new TunnelManagementHttpClient(
- isFeatureFlagEnabled(FeatureFlags.DevTunnelTest)
+ featureFlagManager.getBooleanValue(FeatureFlags.DevTunnelTest)
? TunnelManagementTestUserAgent
: TunnelManagementUserAgent,
ManagementApiVersions.Version20230927preview,
diff --git a/packages/vscode-extension/src/debug/taskTerminal/launchDesktopClientTerminal.ts b/packages/vscode-extension/src/debug/taskTerminal/launchDesktopClientTerminal.ts
index af39aee7d7..23e3efb952 100644
--- a/packages/vscode-extension/src/debug/taskTerminal/launchDesktopClientTerminal.ts
+++ b/packages/vscode-extension/src/debug/taskTerminal/launchDesktopClientTerminal.ts
@@ -71,7 +71,7 @@ export class LaunchDesktopClientTerminal extends BaseTaskTerminal {
});
let username = "";
if (accountInfo.isOk() && accountInfo.value["unique_name"]) {
- username = "(" + (accountInfo.value["unique_name"] as string) + ")";
+ username = " (" + (accountInfo.value["unique_name"] as string) + ")";
}
if (config.obj[showDebugDesktopClientWizard] === "false") {
void vscode.window
diff --git a/packages/vscode-extension/src/debug/taskTerminal/utils/devTunnelStateManager.ts b/packages/vscode-extension/src/debug/taskTerminal/utils/devTunnelStateManager.ts
index 441d091a44..53c35bc4c7 100644
--- a/packages/vscode-extension/src/debug/taskTerminal/utils/devTunnelStateManager.ts
+++ b/packages/vscode-extension/src/debug/taskTerminal/utils/devTunnelStateManager.ts
@@ -8,9 +8,8 @@
import { Mutex, withTimeout } from "async-mutex";
import * as fs from "fs-extra";
import * as path from "path";
-import { isFeatureFlagEnabled } from "@microsoft/teamsfx-core";
+import { featureFlagManager, FeatureFlags } from "@microsoft/teamsfx-core";
import { context, workspaceUri } from "../../../globalVariables";
-import { FeatureFlags } from "../../../featureFlags";
interface IDevTunnelState {
tunnelId?: string;
@@ -29,7 +28,7 @@ export class DevTunnelStateManager {
}
public static create(): DevTunnelStateManager {
- const stateService = isFeatureFlagEnabled(FeatureFlags.DevTunnelTest)
+ const stateService = featureFlagManager.getBooleanValue(FeatureFlags.DevTunnelTest)
? new FileStateService()
: new VSCodeStateService();
return new DevTunnelStateManager(stateService);
diff --git a/packages/vscode-extension/src/error/common.ts b/packages/vscode-extension/src/error/common.ts
index 4b4268e73e..ec7ad5fb6c 100644
--- a/packages/vscode-extension/src/error/common.ts
+++ b/packages/vscode-extension/src/error/common.ts
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { UserError, SystemError, FxError, Result, err } from "@microsoft/teamsfx-api";
+import { UserError, SystemError, FxError, Result, err, ok } from "@microsoft/teamsfx-api";
import { isUserCancelError, ConcurrentError } from "@microsoft/teamsfx-core";
import { Uri, commands, window } from "vscode";
import {
@@ -10,7 +10,6 @@ import {
openTestToolDisplayMessage,
} from "../debug/common/debugConstants";
import { workspaceUri } from "../globalVariables";
-import { debugInTestToolHandler } from "../handlers/debugInTestTool";
import { ExtTelemetry } from "../telemetry/extTelemetry";
import { anonymizeFilePaths } from "../utils/fileSystemUtils";
import { localize } from "../utils/localizeUtils";
@@ -24,7 +23,11 @@ export async function showError(e: UserError | SystemError) {
const errorCode = `${e.source}.${e.name}`;
const runTestTool = {
title: localize("teamstoolkit.handlers.debugInTestTool"),
- run: () => debugInTestToolHandler("message")(),
+ run: async () => {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MessageDebugInTestTool);
+ await commands.executeCommand("workbench.action.quickOpen", "debug Debug in Test Tool");
+ return ok(null);
+ },
};
const recommendTestTool =
e.recommendedOperation === RecommendedOperations.DebugInTestTool &&
diff --git a/packages/vscode-extension/src/extension.ts b/packages/vscode-extension/src/extension.ts
index 370d9394d1..1c48cc5672 100644
--- a/packages/vscode-extension/src/extension.ts
+++ b/packages/vscode-extension/src/extension.ts
@@ -15,13 +15,13 @@ import {
AuthSvcScopes,
FeatureFlags as CoreFeatureFlags,
Correlator,
+ FeatureFlags,
VersionState,
featureFlagManager,
teamsDevPortalClient,
} from "@microsoft/teamsfx-core";
import * as semver from "semver";
import * as vscode from "vscode";
-
import {
CHAT_EXECUTE_COMMAND_ID,
CHAT_OPENURL_COMMAND_ID,
@@ -60,10 +60,11 @@ import { disableRunIcon, registerRunIcon } from "./debug/runIconHandler";
import { TeamsfxDebugProvider } from "./debug/teamsfxDebugProvider";
import { registerTeamsfxTaskAndDebugEvents } from "./debug/teamsfxTaskHandler";
import { TeamsfxTaskProvider } from "./debug/teamsfxTaskProvider";
+import { showError } from "./error/common";
import * as exp from "./exp";
import { TreatmentVariableValue, TreatmentVariables } from "./exp/treatmentVariables";
-import { FeatureFlags } from "./featureFlags";
import {
+ diagnosticCollection,
initializeGlobalVariables,
isExistingUser,
isOfficeAddInProject,
@@ -73,14 +74,64 @@ import {
unsetIsTeamsFxProject,
workspaceUri,
} from "./globalVariables";
-import * as handlers from "./handlers";
-import { checkCopilotAccessHandler } from "./handlers/checkCopilotAccess";
-import { checkCopilotCallback } from "./handlers/checkCopilotCallback";
-import { checkSideloadingCallback } from "./handlers/checkSideloading";
+import {
+ editAadManifestTemplateHandler,
+ openPreviewAadFileHandler,
+ updateAadAppManifestHandler,
+} from "./handlers/aadManifestHandlers";
+import {
+ azureAccountSignOutHelpHandler,
+ cmpAccountsHandler,
+ createAccountHandler,
+} from "./handlers/accounts/accountHandlers";
+import { activate as activateHandlers } from "./handlers/activate";
+import { autoOpenProjectHandler } from "./handlers/autoOpenProjectHandler";
+import {
+ checkCopilotCallback,
+ checkSideloadingCallback,
+} from "./handlers/accounts/checkAccessCallback";
+import { checkCopilotAccessHandler } from "./handlers/accounts/checkCopilotAccess";
+import { manageCollaboratorHandler } from "./handlers/collaboratorHandlers";
+import {
+ openFolderHandler,
+ openLifecycleTreeview,
+ openSamplesHandler,
+ openWelcomeHandler,
+ saveTextDocumentHandler,
+} from "./handlers/controlHandlers";
import * as copilotChatHandlers from "./handlers/copilotChatHandlers";
-import { debugInTestToolHandler } from "./handlers/debugInTestTool";
+import {
+ debugInTestToolHandler,
+ selectAndDebugHandler,
+ treeViewLocalDebugHandler,
+ treeViewPreviewHandler,
+} from "./handlers/debugHandlers";
+import { decryptSecret } from "./handlers/decryptSecret";
import { downloadSampleApp } from "./handlers/downloadSample";
-import { deployHandler, provisionHandler, publishHandler } from "./handlers/lifecycleHandlers";
+import {
+ createNewEnvironment,
+ openConfigStateFile,
+ refreshEnvironment,
+} from "./handlers/envHandlers";
+import {
+ addWebpartHandler,
+ copilotPluginAddAPIHandler,
+ createNewProjectHandler,
+ deployHandler,
+ provisionHandler,
+ publishHandler,
+ scaffoldFromDeveloperPortalHandler,
+} from "./handlers/lifecycleHandlers";
+import {
+ buildPackageHandler,
+ publishInDeveloperPortalHandler,
+ updatePreviewManifest,
+ validateManifestHandler,
+} from "./handlers/manifestHandlers";
+import {
+ migrateTeamsManifestHandler,
+ migrateTeamsTabAppHandler,
+} from "./handlers/migrationHandler";
import * as officeDevHandlers from "./handlers/officeDevHandlers";
import {
openAccountLinkHandler,
@@ -91,14 +142,34 @@ import {
openDocumentHandler,
openDocumentLinkHandler,
openEnvLinkHandler,
+ openExternalHandler,
openHelpFeedbackLinkHandler,
openLifecycleLinkHandler,
openM365AccountHandler,
openReportIssues,
- openWelcomeHandler,
+ openResourceGroupInPortal,
+ openSubscriptionInPortal,
} from "./handlers/openLinkHandlers";
+import {
+ checkUpgrade,
+ getDotnetPathHandler,
+ getPathDelimiterHandler,
+ installAdaptiveCardExt,
+ triggerV3MigrationHandler,
+ validateGetStartedPrerequisitesHandler,
+} from "./handlers/prerequisiteHandlers";
+import { openReadMeHandler } from "./handlers/readmeHandlers";
+import {
+ refreshCopilotCallback,
+ refreshSideloadingCallback,
+} from "./handlers/accounts/refreshAccessHandlers";
import { showOutputChannelHandler } from "./handlers/showOutputChannel";
-import { createProjectFromWalkthroughHandler } from "./handlers/walkthrough";
+import { signinAzureCallback, signinM365Callback } from "./handlers/accounts/signinAccountHandlers";
+import { openTutorialHandler, selectTutorialsHandler } from "./handlers/tutorialHandlers";
+import {
+ createProjectFromWalkthroughHandler,
+ openBuildIntelligentAppsWalkthroughHandler,
+} from "./handlers/walkthrough";
import { ManifestTemplateHoverProvider } from "./hoverProvider";
import {
CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID,
@@ -114,21 +185,24 @@ import { ExtTelemetry } from "./telemetry/extTelemetry";
import { TelemetryEvent, TelemetryTriggerFrom } from "./telemetry/extTelemetryEvents";
import accountTreeViewProviderInstance from "./treeview/account/accountTreeViewProvider";
import officeDevTreeViewManager from "./treeview/officeDevTreeViewManager";
+import { TreeViewCommand } from "./treeview/treeViewCommand";
import TreeViewManagerInstance from "./treeview/treeViewManager";
import { UriHandler, setUriEventHandler } from "./uriHandler";
-import { delay, hasAdaptiveCardInWorkspace, isM365Project } from "./utils/commonUtils";
+import { signOutAzure, signOutM365 } from "./utils/accountUtils";
+import { acpInstalled, delay, hasAdaptiveCardInWorkspace } from "./utils/commonUtils";
import { updateAutoOpenGlobalKey } from "./utils/globalStateUtils";
import { loadLocalizedStrings } from "./utils/localizeUtils";
-import { checkProjectTypeAndSendTelemetry } from "./utils/projectChecker";
+import { checkProjectTypeAndSendTelemetry, isM365Project } from "./utils/projectChecker";
import { ReleaseNote } from "./utils/releaseNote";
import { ExtensionSurvey } from "./utils/survey";
+import { getSettingsVersion, projectVersionCheck } from "./utils/telemetryUtils";
export async function activate(context: vscode.ExtensionContext) {
- process.env[FeatureFlags.ChatParticipant] = (
+ const value =
IsChatParticipantEnabled &&
semver.gte(vscode.version, "1.90.0-insider") &&
- vscode.version.includes("insider")
- ).toString();
+ vscode.version.includes("insider");
+ featureFlagManager.setBooleanValue(FeatureFlags.ChatParticipant, value);
configMgr.registerConfigChangeCallback();
@@ -161,7 +235,7 @@ export async function activate(context: vscode.ExtensionContext) {
}
// Call activate function of toolkit core.
- handlers.activate();
+ activateHandlers();
// Init VSC context key
await initializeContextKey(context, isTeamsFxProject);
@@ -207,7 +281,7 @@ export async function activate(context: vscode.ExtensionContext) {
export async function deactivate() {
await ExtTelemetry.cacheTelemetryEventAsync(TelemetryEvent.Deactivate);
await ExtTelemetry.dispose();
- handlers.cmdHdlDisposeTreeView();
+ TreeViewManagerInstance.dispose();
await disableRunIcon();
}
@@ -217,7 +291,7 @@ function activateTeamsFxRegistration(context: vscode.ExtensionContext) {
registerTreeViewCommandsInHelper(context);
registerTeamsFxCommands(context);
registerMenuCommands(context);
- handlers.registerAccountMenuCommands(context);
+ registerAccountMenuCommands(context);
TreeViewManagerInstance.registerTreeViews(context);
accountTreeViewProviderInstance.subscribeToStatusChanges({
@@ -239,7 +313,7 @@ function activateTeamsFxRegistration(context: vscode.ExtensionContext) {
);
if (vscode.workspace.isTrusted) {
- registerCodelensAndHoverProviders(context);
+ registerLanguageFeatures(context);
}
registerDebugConfigProviders(context);
@@ -254,10 +328,7 @@ function activateTeamsFxRegistration(context: vscode.ExtensionContext) {
// Register teamsfx task provider
const taskProvider: TeamsfxTaskProvider = new TeamsfxTaskProvider();
context.subscriptions.push(vscode.tasks.registerTaskProvider(TeamsFxTaskType, taskProvider));
-
- context.subscriptions.push(
- vscode.workspace.onWillSaveTextDocument(handlers.saveTextDocumentHandler)
- );
+ context.subscriptions.push(vscode.workspace.onWillSaveTextDocument(saveTextDocumentHandler));
}
function activateOfficeDevRegistration(context: vscode.ExtensionContext) {
@@ -279,13 +350,13 @@ function registerActivateCommands(context: vscode.ExtensionContext) {
// non-teamsfx project upgrade
const checkUpgradeCmd = vscode.commands.registerCommand(
"fx-extension.checkProjectUpgrade",
- (...args) => Correlator.run(handlers.checkUpgrade, args)
+ (...args) => Correlator.run(checkUpgrade, args)
);
context.subscriptions.push(checkUpgradeCmd);
// user can manage account in non-teamsfx project
const cmpAccountsCmd = vscode.commands.registerCommand("fx-extension.cmpAccounts", (...args) =>
- Correlator.run(handlers.cmpAccountsHandler, args)
+ Correlator.run(cmpAccountsHandler, args)
);
context.subscriptions.push(cmpAccountsCmd);
@@ -293,7 +364,7 @@ function registerActivateCommands(context: vscode.ExtensionContext) {
registerInCommandController(
context,
CommandKeys.Create,
- handlers.createNewProjectHandler,
+ createNewProjectHandler,
"createProject"
);
context.subscriptions.push(
@@ -314,44 +385,40 @@ function registerActivateCommands(context: vscode.ExtensionContext) {
);
// Show lifecycle view
- const openLifecycleTreeview = vscode.commands.registerCommand(
+ const openLifecycleTreeviewCmd = vscode.commands.registerCommand(
"fx-extension.openLifecycleTreeview",
- (...args) => Correlator.run(handlers.openLifecycleTreeview, args)
+ (...args) => Correlator.run(openLifecycleTreeview, args)
);
- context.subscriptions.push(openLifecycleTreeview);
+ context.subscriptions.push(openLifecycleTreeviewCmd);
// Documentation
registerInCommandController(context, CommandKeys.OpenDocument, openDocumentHandler);
// README
- registerInCommandController(context, CommandKeys.OpenReadMe, handlers.openReadMeHandler);
+ registerInCommandController(context, CommandKeys.OpenReadMe, openReadMeHandler);
// View samples
- registerInCommandController(context, CommandKeys.OpenSamples, handlers.openSamplesHandler);
+ registerInCommandController(context, CommandKeys.OpenSamples, openSamplesHandler);
// Quick start
registerInCommandController(context, CommandKeys.OpenWelcome, openWelcomeHandler);
registerInCommandController(
context,
CommandKeys.BuildIntelligentAppsWalkthrough,
- handlers.openBuildIntelligentAppsWalkthroughHandler
+ openBuildIntelligentAppsWalkthroughHandler
);
// Tutorials
- registerInCommandController(
- context,
- "fx-extension.selectTutorials",
- handlers.selectTutorialsHandler
- );
+ registerInCommandController(context, "fx-extension.selectTutorials", selectTutorialsHandler);
// Sign in to M365
- registerInCommandController(context, CommandKeys.SigninM365, handlers.signinM365Callback);
+ registerInCommandController(context, CommandKeys.SigninM365, signinM365Callback);
// Prerequisites check
registerInCommandController(
context,
CommandKeys.ValidateGetStartedPrerequisites,
- handlers.validateGetStartedPrerequisitesHandler
+ validateGetStartedPrerequisitesHandler
);
// commmand: check copilot access
@@ -360,20 +427,20 @@ function registerActivateCommands(context: vscode.ExtensionContext) {
// Upgrade command to update Teams manifest
const migrateTeamsManifestCmd = vscode.commands.registerCommand(
"fx-extension.migrateTeamsManifest",
- () => Correlator.run(handlers.migrateTeamsManifestHandler)
+ () => Correlator.run(migrateTeamsManifestHandler)
);
context.subscriptions.push(migrateTeamsManifestCmd);
// Upgrade command to update Teams Client SDK
const migrateTeamsTabAppCmd = vscode.commands.registerCommand(
"fx-extension.migrateTeamsTabApp",
- () => Correlator.run(handlers.migrateTeamsTabAppHandler)
+ () => Correlator.run(migrateTeamsTabAppHandler)
);
context.subscriptions.push(migrateTeamsTabAppCmd);
// Register local debug run icon
const runIconCmd = vscode.commands.registerCommand("fx-extension.selectAndDebug", (...args) =>
- Correlator.run(handlers.selectAndDebugHandler, args)
+ Correlator.run(selectAndDebugHandler, args)
);
context.subscriptions.push(runIconCmd);
@@ -391,7 +458,7 @@ function registerInternalCommands(context: vscode.ExtensionContext) {
registerInCommandController(
context,
"fx-extension.openFromTdp",
- handlers.scaffoldFromDeveloperPortalHandler,
+ scaffoldFromDeveloperPortalHandler,
"openFromTdp"
);
@@ -410,62 +477,53 @@ function registerInternalCommands(context: vscode.ExtensionContext) {
// Register backend extensions install command
const backendExtensionsInstallCmd = vscode.commands.registerCommand(
"fx-extension.backend-extensions-install",
- () => Correlator.runWithId(getLocalDebugSessionId(), handlers.backendExtensionsInstallHandler)
+ () => Correlator.runWithId(getLocalDebugSessionId(), triggerV3MigrationHandler)
);
context.subscriptions.push(backendExtensionsInstallCmd);
// Referenced by tasks.json
const getPathDelimiterCmd = vscode.commands.registerCommand(
"fx-extension.get-path-delimiter",
- () => Correlator.run(handlers.getPathDelimiterHandler)
+ () => Correlator.run(getPathDelimiterHandler)
);
context.subscriptions.push(getPathDelimiterCmd);
const getDotnetPathCmd = vscode.commands.registerCommand("fx-extension.get-dotnet-path", () =>
- Correlator.run(handlers.getDotnetPathHandler)
+ Correlator.run(getDotnetPathHandler)
);
context.subscriptions.push(getDotnetPathCmd);
const installAppInTeamsCmd = vscode.commands.registerCommand(
"fx-extension.install-app-in-teams",
- () => Correlator.runWithId(getLocalDebugSessionId(), handlers.installAppInTeams)
+ () => Correlator.runWithId(getLocalDebugSessionId(), triggerV3MigrationHandler)
);
context.subscriptions.push(installAppInTeamsCmd);
- const openSurveyCmd = vscode.commands.registerCommand("fx-extension.openSurvey", (...args) =>
- Correlator.run(handlers.openSurveyHandler, [TelemetryTriggerFrom.TreeView])
- );
- context.subscriptions.push(openSurveyCmd);
-
const openTutorial = vscode.commands.registerCommand("fx-extension.openTutorial", (...args) =>
- Correlator.run(handlers.openTutorialHandler, [
- TelemetryTriggerFrom.QuickPick,
- ...(args as unknown[]),
- ])
+ Correlator.run(openTutorialHandler, [TelemetryTriggerFrom.QuickPick, ...(args as unknown[])])
);
context.subscriptions.push(openTutorial);
const preDebugCheckCmd = vscode.commands.registerCommand("fx-extension.pre-debug-check", () =>
- Correlator.runWithId(getLocalDebugSessionId(), handlers.preDebugCheckHandler)
+ Correlator.runWithId(getLocalDebugSessionId(), triggerV3MigrationHandler)
);
context.subscriptions.push(preDebugCheckCmd);
// localdebug session starts from environment checker
const validateDependenciesCmd = vscode.commands.registerCommand(
"fx-extension.validate-dependencies",
- () => Correlator.runWithId(startLocalDebugSession(), handlers.validateAzureDependenciesHandler)
+ () => Correlator.runWithId(startLocalDebugSession(), triggerV3MigrationHandler)
);
context.subscriptions.push(validateDependenciesCmd);
// localdebug session starts from prerequisites checker
const validatePrerequisitesCmd = vscode.commands.registerCommand(
"fx-extension.validate-local-prerequisites",
- // Do not run with Correlator because it is handled inside `validateLocalPrerequisitesHandler()`.
- handlers.validateLocalPrerequisitesHandler
+ triggerV3MigrationHandler
);
context.subscriptions.push(validatePrerequisitesCmd);
- registerInCommandController(context, CommandKeys.SigninAzure, handlers.signinAzureCallback);
+ registerInCommandController(context, CommandKeys.SigninAzure, signinAzureCallback);
}
/**
@@ -517,18 +575,9 @@ function registerOfficeChatParticipant(context: vscode.ExtensionContext) {
function registerTreeViewCommandsInDevelopment(context: vscode.ExtensionContext) {
// Open adaptive card
- registerInCommandController(
- context,
- "fx-extension.OpenAdaptiveCardExt",
- handlers.installAdaptiveCardExt
- );
+ registerInCommandController(context, "fx-extension.OpenAdaptiveCardExt", installAdaptiveCardExt);
- registerInCommandController(
- context,
- "fx-extension.addWebpart",
- handlers.addWebpart,
- "addWebpart"
- );
+ registerInCommandController(context, "fx-extension.addWebpart", addWebpartHandler, "addWebpart");
}
function registerTreeViewCommandsInLifecycle(context: vscode.ExtensionContext) {
@@ -536,12 +585,7 @@ function registerTreeViewCommandsInLifecycle(context: vscode.ExtensionContext) {
registerInCommandController(context, CommandKeys.Provision, provisionHandler, "provision");
// Zip Teams metadata package
- registerInCommandController(
- context,
- "fx-extension.build",
- handlers.buildPackageHandler,
- "buildPackage"
- );
+ registerInCommandController(context, "fx-extension.build", buildPackageHandler, "buildPackage");
// Deploy to the cloud
registerInCommandController(context, CommandKeys.Deploy, deployHandler, "deploy");
@@ -553,7 +597,7 @@ function registerTreeViewCommandsInLifecycle(context: vscode.ExtensionContext) {
registerInCommandController(
context,
"fx-extension.publishInDeveloperPortal",
- handlers.publishInDeveloperPortalHandler,
+ publishInDeveloperPortalHandler,
"publishInDeveloperPortal"
);
@@ -570,28 +614,28 @@ function registerTreeViewCommandsInHelper(context: vscode.ExtensionContext) {
* TeamsFx related commands, they will show in command palette after extension is initialized
*/
function registerTeamsFxCommands(context: vscode.ExtensionContext) {
- const createNewEnvironment = vscode.commands.registerCommand(
+ const createNewEnvCmd = vscode.commands.registerCommand(
// TODO: fix trigger from
"fx-extension.addEnvironment",
- (...args) => Correlator.run(handlers.createNewEnvironment, args)
+ (...args) => Correlator.run(createNewEnvironment, args)
);
- context.subscriptions.push(createNewEnvironment);
+ context.subscriptions.push(createNewEnvCmd);
const updateAadAppManifest = vscode.commands.registerCommand(
"fx-extension.updateAadAppManifest",
- (...args) => Correlator.run(handlers.updateAadAppManifest, args)
+ (...args) => Correlator.run(updateAadAppManifestHandler, args)
);
context.subscriptions.push(updateAadAppManifest);
const updateManifestCmd = vscode.commands.registerCommand(
"fx-extension.updatePreviewFile",
- (...args) => Correlator.run(handlers.updatePreviewManifest, args)
+ (...args) => Correlator.run(updatePreviewManifest, args)
);
context.subscriptions.push(updateManifestCmd);
const validateManifestCmd = vscode.commands.registerCommand(
"fx-extension.validateManifest",
- (...args) => Correlator.run(handlers.validateManifestHandler, args)
+ (...args) => Correlator.run(validateManifestHandler, args)
);
context.subscriptions.push(validateManifestCmd);
@@ -603,25 +647,25 @@ function registerTeamsFxCommands(context: vscode.ExtensionContext) {
const decryptCmd = vscode.commands.registerCommand(
"fx-extension.decryptSecret",
- (cipher: string, selection) => Correlator.run(handlers.decryptSecret, cipher, selection)
+ (cipher: string, selection) => Correlator.run(decryptSecret, cipher, selection)
);
context.subscriptions.push(decryptCmd);
const openConfigStateCmd = vscode.commands.registerCommand(
"fx-extension.openConfigState",
- (...args) => Correlator.run(handlers.openConfigStateFile, args)
+ (...args) => Correlator.run(openConfigStateFile, args)
);
context.subscriptions.push(openConfigStateCmd);
const editAadManifestTemplateCmd = vscode.commands.registerCommand(
"fx-extension.editAadManifestTemplate",
- (...args) => Correlator.run(handlers.editAadManifestTemplate, args)
+ (...args) => Correlator.run(editAadManifestTemplateHandler, args)
);
context.subscriptions.push(editAadManifestTemplateCmd);
- registerInCommandController(context, CommandKeys.Preview, handlers.treeViewPreviewHandler);
+ registerInCommandController(context, CommandKeys.Preview, treeViewPreviewHandler);
- registerInCommandController(context, "fx-extension.openFolder", handlers.openFolderHandler);
+ registerInCommandController(context, "fx-extension.openFolder", openFolderHandler);
const checkSideloading = vscode.commands.registerCommand(
"fx-extension.checkSideloading",
@@ -642,8 +686,7 @@ function registerTeamsFxCommands(context: vscode.ExtensionContext) {
function registerMenuCommands(context: vscode.ExtensionContext) {
const createNewEnvironmentWithIcon = vscode.commands.registerCommand(
"fx-extension.addEnvironmentWithIcon",
- (...args) =>
- Correlator.run(handlers.createNewEnvironment, [TelemetryTriggerFrom.ViewTitleNavigation])
+ (...args) => Correlator.run(createNewEnvironment, [TelemetryTriggerFrom.ViewTitleNavigation])
);
context.subscriptions.push(createNewEnvironmentWithIcon);
@@ -655,8 +698,7 @@ function registerMenuCommands(context: vscode.ExtensionContext) {
const createAccountCmd = vscode.commands.registerCommand(
"fx-extension.createAccount",
- (...args) =>
- Correlator.run(handlers.createAccountHandler, [TelemetryTriggerFrom.ViewTitleNavigation])
+ (...args) => Correlator.run(createAccountHandler, [TelemetryTriggerFrom.ViewTitleNavigation])
);
context.subscriptions.push(createAccountCmd);
@@ -664,17 +706,17 @@ function registerMenuCommands(context: vscode.ExtensionContext) {
"fx-extension.manageCollaborator",
async (node: Record) => {
const envName = node.identifier;
- await Correlator.run(handlers.manageCollaboratorHandler, envName);
+ await Correlator.run(manageCollaboratorHandler, envName);
}
);
context.subscriptions.push(manageCollaborator);
- registerInCommandController(context, CommandKeys.LocalDebug, handlers.treeViewLocalDebugHandler);
+ registerInCommandController(context, CommandKeys.LocalDebug, treeViewLocalDebugHandler);
registerInCommandController(
context,
"fx-extension.localdebugWithIcon",
- handlers.treeViewLocalDebugHandler
+ treeViewLocalDebugHandler
);
registerInCommandController(
@@ -735,29 +777,29 @@ function registerMenuCommands(context: vscode.ExtensionContext) {
const azureAccountSignOutHelpCmd = vscode.commands.registerCommand(
"fx-extension.azureAccountSignOutHelp",
- (...args) => Correlator.run(handlers.azureAccountSignOutHelpHandler, args)
+ (...args) => Correlator.run(azureAccountSignOutHelpHandler, args)
);
context.subscriptions.push(azureAccountSignOutHelpCmd);
const aadManifestTemplateCodeLensCmd = vscode.commands.registerCommand(
"fx-extension.openPreviewAadFile",
- (...args) => Correlator.run(handlers.openPreviewAadFile, args)
+ (...args) => Correlator.run(openPreviewAadFileHandler, args)
);
context.subscriptions.push(aadManifestTemplateCodeLensCmd);
- const openResourceGroupInPortal = vscode.commands.registerCommand(
+ const openResourceGroupInPortalCmd = vscode.commands.registerCommand(
"fx-extension.openResourceGroupInPortal",
async (node: Record) => {
const envName = node.identifier;
- await Correlator.run(handlers.openResourceGroupInPortal, envName);
+ await Correlator.run(openResourceGroupInPortal, envName);
}
);
- context.subscriptions.push(openResourceGroupInPortal);
+ context.subscriptions.push(openResourceGroupInPortalCmd);
const openManifestSchemaCmd = vscode.commands.registerCommand(
"fx-extension.openSchema",
async (...args) => {
- await Correlator.run(handlers.openExternalHandler, args);
+ await Correlator.run(openExternalHandler, args);
}
);
context.subscriptions.push(openManifestSchemaCmd);
@@ -765,41 +807,36 @@ function registerMenuCommands(context: vscode.ExtensionContext) {
const addAPICmd = vscode.commands.registerCommand(
"fx-extension.copilotPluginAddAPI",
async (...args) => {
- await Correlator.run(handlers.copilotPluginAddAPIHandler, args);
+ await Correlator.run(copilotPluginAddAPIHandler, args);
}
);
context.subscriptions.push(addAPICmd);
- const openSubscriptionInPortal = vscode.commands.registerCommand(
+ const openSubscriptionInPortalCmd = vscode.commands.registerCommand(
"fx-extension.openSubscriptionInPortal",
async (node: Record) => {
const envName = node.identifier;
- await Correlator.run(handlers.openSubscriptionInPortal, envName);
+ await Correlator.run(openSubscriptionInPortal, envName);
}
);
- context.subscriptions.push(openSubscriptionInPortal);
+ context.subscriptions.push(openSubscriptionInPortalCmd);
- registerInCommandController(
- context,
- "fx-extension.previewWithIcon",
- handlers.treeViewPreviewHandler
- );
+ registerInCommandController(context, "fx-extension.previewWithIcon", treeViewPreviewHandler);
- const refreshEnvironment = vscode.commands.registerCommand(
+ const refreshEnvironmentH = vscode.commands.registerCommand(
"fx-extension.refreshEnvironment",
- (...args) =>
- Correlator.run(handlers.refreshEnvironment, [TelemetryTriggerFrom.ViewTitleNavigation])
+ (...args) => Correlator.run(refreshEnvironment, [TelemetryTriggerFrom.ViewTitleNavigation])
);
- context.subscriptions.push(refreshEnvironment);
+ context.subscriptions.push(refreshEnvironmentH);
const refreshSideloading = vscode.commands.registerCommand(
"fx-extension.refreshSideloading",
- (...args) => Correlator.run(handlers.refreshSideloadingCallback, args)
+ (...args) => Correlator.run(refreshSideloadingCallback, args)
);
context.subscriptions.push(refreshSideloading);
const refreshCopilot = vscode.commands.registerCommand("fx-extension.refreshCopilot", (...args) =>
- Correlator.run(handlers.refreshCopilotCallback, args)
+ Correlator.run(refreshCopilotCallback, args)
);
context.subscriptions.push(refreshCopilot);
}
@@ -822,7 +859,7 @@ function registerOfficeDevMenuCommands(context: vscode.ExtensionContext) {
);
context.subscriptions.push(installDependencyCmd);
- registerInCommandController(context, CommandKeys.LocalDebug, handlers.treeViewLocalDebugHandler);
+ registerInCommandController(context, CommandKeys.LocalDebug, treeViewLocalDebugHandler);
const stopDebugging = vscode.commands.registerCommand("fx-extension.stopDebugging", () =>
Correlator.run(officeDevHandlers.stopOfficeAddInDebug)
@@ -893,6 +930,32 @@ function registerOfficeDevMenuCommands(context: vscode.ExtensionContext) {
context.subscriptions.push(reportIssueCmd);
}
+function registerAccountMenuCommands(context: vscode.ExtensionContext) {
+ // Register SignOut tree view command
+ context.subscriptions.push(
+ vscode.commands.registerCommand("fx-extension.signOut", async (node: TreeViewCommand) => {
+ try {
+ switch (node.contextValue) {
+ case "signedinM365": {
+ await Correlator.run(async () => {
+ await signOutM365(true);
+ });
+ break;
+ }
+ case "signedinAzure": {
+ await Correlator.run(async () => {
+ await signOutAzure(true);
+ });
+ break;
+ }
+ }
+ } catch (e) {
+ void showError(e as FxError);
+ }
+ })
+ );
+}
+
async function initializeContextKey(context: vscode.ExtensionContext, isTeamsFxProject: boolean) {
await vscode.commands.executeCommand("setContext", "fx-extension.isSPFx", isSPFxProject);
@@ -926,7 +989,7 @@ async function initializeContextKey(context: vscode.ExtensionContext, isTeamsFxP
const upgradeable = await checkProjectUpgradable();
if (upgradeable) {
await vscode.commands.executeCommand("setContext", "fx-extension.canUpgradeV3", true);
- await handlers.checkUpgrade([TelemetryTriggerFrom.Auto]);
+ await checkUpgrade([TelemetryTriggerFrom.Auto]);
}
}
@@ -942,7 +1005,7 @@ async function setTDPIntegrationEnabledContext() {
);
}
-function registerCodelensAndHoverProviders(context: vscode.ExtensionContext) {
+function registerLanguageFeatures(context: vscode.ExtensionContext) {
// Setup CodeLens provider for userdata file
const codelensProvider = new CryptoCodeLensProvider();
const envDataSelector = {
@@ -1101,6 +1164,8 @@ function registerCodelensAndHoverProviders(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.languages.registerCodeLensProvider(yamlFileSelector, yamlCodelensProvider)
);
+
+ context.subscriptions.push(diagnosticCollection);
}
function registerOfficeDevCodeLensProviders(context: vscode.ExtensionContext) {
@@ -1155,7 +1220,7 @@ async function runBackgroundAsyncTasks(
true
);
- ExtTelemetry.settingsVersion = await handlers.getSettingsVersion();
+ ExtTelemetry.settingsVersion = await getSettingsVersion();
await ExtTelemetry.sendCachedTelemetryEventsAsync();
const releaseNote = new ReleaseNote(context);
@@ -1182,7 +1247,7 @@ async function runBackgroundAsyncTasks(
async function runTeamsFxBackgroundTasks() {
const upgradeable = await checkProjectUpgradable();
if (isTeamsFxProject) {
- await handlers.autoOpenProjectHandler();
+ await autoOpenProjectHandler();
await TreeViewManagerInstance.updateTreeViewsByContent(upgradeable);
}
}
@@ -1212,7 +1277,7 @@ function runCommand(commandName: string, ...args: unknown[]) {
}
async function checkProjectUpgradable(): Promise {
- const versionCheckResult = await handlers.projectVersionCheck();
+ const versionCheckResult = await projectVersionCheck();
if (versionCheckResult.isErr()) {
unsetIsTeamsFxProject();
return false;
@@ -1248,7 +1313,7 @@ async function detectedTeamsFxProject(context: vscode.ExtensionContext) {
}
async function recommendACPExtension(): Promise {
- if (!handlers.acpInstalled() && (await hasAdaptiveCardInWorkspace())) {
- await handlers.installAdaptiveCardExt(TelemetryTriggerFrom.Auto);
+ if (!acpInstalled() && (await hasAdaptiveCardInWorkspace())) {
+ await installAdaptiveCardExt(TelemetryTriggerFrom.Auto);
}
}
diff --git a/packages/vscode-extension/src/featureFlags.ts b/packages/vscode-extension/src/featureFlags.ts
deleted file mode 100644
index 1974d4aba9..0000000000
--- a/packages/vscode-extension/src/featureFlags.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-export class FeatureFlags {
- static readonly InsiderPreview = "__TEAMSFX_INSIDER_PREVIEW";
- static readonly TelemetryTest = "TEAMSFX_TELEMETRY_TEST";
- static readonly DevTunnelTest = "TEAMSFX_DEV_TUNNEL_TEST";
- static readonly Preview = "TEAMSFX_PREVIEW";
- static readonly DevelopCopilotPlugin = "DEVELOP_COPILOT_PLUGIN";
- static readonly ChatParticipant = "TEAMSFX_CHAT_PARTICIPANT";
-}
-
-// Determine whether feature flag is enabled based on environment variable setting
-
-export function isFeatureFlagEnabled(featureFlagName: string, defaultValue = false): boolean {
- const flag = process.env[featureFlagName];
-
- if (flag === undefined) {
- return defaultValue; // allows consumer to set a default value when environment variable not set
- } else {
- return flag === "1" || flag.toLowerCase() === "true"; // can enable feature flag by set environment variable value to "1" or "true"
- }
-}
-
-export function getAllFeatureFlags(): string[] | undefined {
- const result = Object.values(FeatureFlags)
- .filter((featureFlag: string) => {
- return isFeatureFlagEnabled(featureFlag);
- })
- .map((featureFlag) => {
- return featureFlag;
- });
-
- return result;
-}
diff --git a/packages/vscode-extension/src/globalVariables.ts b/packages/vscode-extension/src/globalVariables.ts
index 9c0ffa3abb..4a2e9cda23 100644
--- a/packages/vscode-extension/src/globalVariables.ts
+++ b/packages/vscode-extension/src/globalVariables.ts
@@ -28,6 +28,7 @@ export let defaultExtensionLogPath: string;
export let commandIsRunning = false;
export let core: FxCore;
export let tools: Tools;
+export let diagnosticCollection: vscode.DiagnosticCollection; // Collection of diagnositcs after running app validation.
if (vscode.workspace && vscode.workspace.workspaceFolders) {
if (vscode.workspace.workspaceFolders.length > 0) {
@@ -87,3 +88,7 @@ export function setTools(toolsInstance: Tools) {
export function setCore(coreInstance: FxCore) {
core = coreInstance;
}
+
+export function setDiagnosticCollection(collection: vscode.DiagnosticCollection) {
+ diagnosticCollection = collection;
+}
diff --git a/packages/vscode-extension/src/handlers.ts b/packages/vscode-extension/src/handlers.ts
deleted file mode 100644
index 6929f89def..0000000000
--- a/packages/vscode-extension/src/handlers.ts
+++ /dev/null
@@ -1,2499 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-/* eslint-disable @typescript-eslint/no-floating-promises */
-
-/**
- * @author Huajie Zhang
- */
-"use strict";
-
-import {
- AppPackageFolderName,
- BuildFolderName,
- ConfigFolderName,
- CoreCallbackEvent,
- CreateProjectResult,
- Func,
- FxError,
- Inputs,
- M365TokenProvider,
- ManifestTemplateFileName,
- ManifestUtil,
- OptionItem,
- Result,
- SelectFileConfig,
- SelectFolderConfig,
- SingleSelectConfig,
- Stage,
- StaticOptions,
- SubscriptionInfo,
- SystemError,
- UserError,
- Void,
- Warning,
- err,
- ok,
-} from "@microsoft/teamsfx-api";
-import {
- AppStudioScopes,
- AuthSvcScopes,
- CapabilityOptions,
- Correlator,
- DepsManager,
- DepsType,
- FxCore,
- Hub,
- InvalidProjectError,
- JSONSyntaxError,
- MetadataV3,
- QuestionNames,
- askSubscription,
- assembleError,
- environmentManager,
- generateScaffoldingSummary,
- getHashedEnv,
- getProjectMetadata,
- globalStateGet,
- globalStateUpdate,
- isUserCancelError,
- isValidOfficeAddInProject,
- isValidProject,
- manifestUtils,
- pathUtils,
- pluginManifestUtils,
- teamsDevPortalClient,
-} from "@microsoft/teamsfx-core";
-import * as fs from "fs-extra";
-import * as path from "path";
-import * as util from "util";
-import * as vscode from "vscode";
-import { ExtensionContext, QuickPickItem, Uri, commands, env, window, workspace } from "vscode";
-import commandController from "./commandController";
-import azureAccountManager from "./commonlib/azureLogin";
-import { signedIn, signedOut } from "./commonlib/common/constant";
-import VsCodeLogInstance from "./commonlib/log";
-import M365TokenInstance from "./commonlib/m365Login";
-import { AzurePortalUrl, CommandKey, GlobalKey } from "./constants";
-import { PanelType } from "./controls/PanelType";
-import { WebviewPanel } from "./controls/webviewPanel";
-import { checkPrerequisitesForGetStarted } from "./debug/depsChecker/getStartedChecker";
-import { vscodeLogger } from "./debug/depsChecker/vscodeLogger";
-import { vscodeTelemetry } from "./debug/depsChecker/vscodeTelemetry";
-import { openHubWebClient } from "./debug/launch";
-import { selectAndDebug } from "./debug/runIconHandler";
-import { showError, wrapError } from "./error/common";
-import { ExtensionErrors, ExtensionSource } from "./error/error";
-import * as exp from "./exp/index";
-import { TreatmentVariableValue } from "./exp/treatmentVariables";
-import {
- context,
- core,
- initializeGlobalVariables,
- isOfficeAddInProject,
- isSPFxProject,
- isTeamsFxProject,
- setCommandIsRunning,
- setCore,
- setTools,
- tools,
- workspaceUri,
-} from "./globalVariables";
-import { invokeTeamsAgent } from "./handlers/copilotChatHandlers";
-import { processResult, runCommand } from "./handlers/sharedOpts";
-import { TeamsAppMigrationHandler } from "./migration/migrationHandler";
-import { VS_CODE_UI } from "./qm/vsc_ui";
-import { ExtTelemetry } from "./telemetry/extTelemetry";
-import {
- AccountType,
- InProductGuideInteraction,
- TelemetryEvent,
- TelemetryProperty,
- TelemetrySuccess,
- TelemetryTriggerFrom,
- TelemetryUpdateAppReason,
-} from "./telemetry/extTelemetryEvents";
-import accountTreeViewProviderInstance from "./treeview/account/accountTreeViewProvider";
-import { AzureAccountNode } from "./treeview/account/azureNode";
-import { AccountItemStatus } from "./treeview/account/common";
-import { M365AccountNode } from "./treeview/account/m365Node";
-import envTreeProviderInstance from "./treeview/environmentTreeViewProvider";
-import { TreeViewCommand } from "./treeview/treeViewCommand";
-import TreeViewManagerInstance from "./treeview/treeViewManager";
-import { getAppName } from "./utils/appDefinitionUtils";
-import {
- checkCoreNotEmpty,
- getLocalDebugMessageTemplate,
- openFolderInExplorer,
-} from "./utils/commonUtils";
-import { getResourceGroupNameFromEnv, getSubscriptionInfoFromEnv } from "./utils/envTreeUtils";
-import { getDefaultString, localize } from "./utils/localizeUtils";
-import { triggerV3Migration } from "./utils/migrationUtils";
-import { updateProjectStatus } from "./utils/projectStatusUtils";
-import { ExtensionSurvey } from "./utils/survey";
-import { getSystemInputs } from "./utils/systemEnvUtils";
-import { getTriggerFromProperty, isTriggerFromWalkThrough } from "./utils/telemetryUtils";
-import { openFolder, openOfficeDevFolder } from "./utils/workspaceUtils";
-import { openWelcomeHandler } from "./handlers/openLinkHandlers";
-
-export function activate(): Result {
- const result: Result = ok(Void);
- const validProject = isValidProject(workspaceUri?.fsPath);
- if (validProject) {
- const fixedProjectSettings = getProjectMetadata(workspaceUri?.fsPath);
- ExtTelemetry.addSharedProperty(
- TelemetryProperty.ProjectId,
- fixedProjectSettings?.projectId as string
- );
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenTeamsApp, {});
- void azureAccountManager.setStatusChangeMap(
- "successfully-sign-in-azure",
- (status, token, accountInfo) => {
- if (status === signedIn) {
- void window.showInformationMessage(localize("teamstoolkit.handlers.azureSignIn"));
- } else if (status === signedOut) {
- void window.showInformationMessage(localize("teamstoolkit.handlers.azureSignOut"));
- }
- return Promise.resolve();
- },
- false
- );
- }
- try {
- const m365Login: M365TokenProvider = M365TokenInstance;
- const m365NotificationCallback = (
- status: string,
- token: string | undefined,
- accountInfo: Record | undefined
- ) => {
- if (status === signedIn) {
- void window.showInformationMessage(localize("teamstoolkit.handlers.m365SignIn"));
- } else if (status === signedOut) {
- void window.showInformationMessage(localize("teamstoolkit.handlers.m365SignOut"));
- }
- return Promise.resolve();
- };
-
- void M365TokenInstance.setStatusChangeMap(
- "successfully-sign-in-m365",
- { scopes: AppStudioScopes },
- m365NotificationCallback,
- false
- );
- setTools({
- logProvider: VsCodeLogInstance,
- tokenProvider: {
- azureAccountProvider: azureAccountManager,
- m365TokenProvider: m365Login,
- },
- telemetryReporter: ExtTelemetry.reporter,
- ui: VS_CODE_UI,
- expServiceProvider: exp.getExpService(),
- });
- setCore(new FxCore(tools));
- core.on(CoreCallbackEvent.lock, async (command: string) => {
- setCommandIsRunning(true);
- await commandController.lockedByOperation(command);
- });
- core.on(CoreCallbackEvent.unlock, async (command: string) => {
- setCommandIsRunning(false);
- await commandController.unlockedByOperation(command);
- });
- const workspacePath = workspaceUri?.fsPath;
- if (workspacePath) {
- addFileSystemWatcher(workspacePath);
- }
-
- if (workspacePath) {
- // refresh env tree when env config files added or deleted.
- workspace.onDidCreateFiles(async (event) => {
- await refreshEnvTreeOnFileChanged(workspacePath, event.files);
- });
-
- workspace.onDidDeleteFiles(async (event) => {
- await refreshEnvTreeOnFileChanged(workspacePath, event.files);
- });
-
- workspace.onDidRenameFiles(async (event) => {
- const files = [];
- for (const f of event.files) {
- files.push(f.newUri);
- files.push(f.oldUri);
- }
-
- await refreshEnvTreeOnFileChanged(workspacePath, files);
- });
-
- workspace.onDidSaveTextDocument(async (event) => {
- await refreshEnvTreeOnFileContentChanged(workspacePath, event.uri.fsPath);
- });
- }
- } catch (e) {
- const FxError: FxError = {
- name: (e as Error).name,
- source: ExtensionSource,
- message: (e as Error).message,
- stack: (e as Error).stack,
- timestamp: new Date(),
- };
- void showError(FxError);
- return err(FxError);
- }
- return result;
-}
-
-// only used for telemetry
-export async function getSettingsVersion(): Promise {
- if (core) {
- const input = getSystemInputs();
- input.ignoreEnvInfo = true;
-
- // TODO: from the experience of 'is-from-sample':
- // in some circumstances, getProjectConfig() returns undefined even projectSettings.json is valid.
- // This is a workaround to prevent that. We can change to the following code after the root cause is found.
- // const projectConfig = await core.getProjectConfig(input);
- // ignore errors for telemetry
- // if (projectConfig.isOk()) {
- // return projectConfig.value?.settings?.version;
- // }
- const versionCheckResult = await projectVersionCheck();
- if (versionCheckResult.isOk()) {
- return versionCheckResult.value.currentVersion;
- }
- }
- return undefined;
-}
-
-async function refreshEnvTreeOnFileChanged(workspacePath: string, files: readonly Uri[]) {
- let needRefresh = false;
- for (const file of files) {
- // check if file is env config
- const res = await core.isEnvFile(workspacePath, file.fsPath);
- if (res.isOk() && res.value) {
- needRefresh = true;
- break;
- }
- }
-
- if (needRefresh) {
- await envTreeProviderInstance.reloadEnvironments();
- }
-}
-
-export function addFileSystemWatcher(workspacePath: string) {
- if (isValidProject(workspaceUri?.fsPath)) {
- const packageLockFileWatcher = vscode.workspace.createFileSystemWatcher("**/package-lock.json");
-
- packageLockFileWatcher.onDidCreate(async (event) => {
- await sendSDKVersionTelemetry(event.fsPath);
- });
-
- packageLockFileWatcher.onDidChange(async (event) => {
- await sendSDKVersionTelemetry(event.fsPath);
- });
-
- const yorcFileWatcher = vscode.workspace.createFileSystemWatcher("**/.yo-rc.json");
- yorcFileWatcher.onDidCreate((event) => {
- refreshSPFxTreeOnFileChanged();
- });
- yorcFileWatcher.onDidChange((event) => {
- refreshSPFxTreeOnFileChanged();
- });
- yorcFileWatcher.onDidDelete((event) => {
- refreshSPFxTreeOnFileChanged();
- });
- }
-}
-
-export function refreshSPFxTreeOnFileChanged() {
- initializeGlobalVariables(context);
-
- TreeViewManagerInstance.updateTreeViewsOnSPFxChanged();
-}
-
-export async function sendSDKVersionTelemetry(filePath: string) {
- const packageLockFile = (await fs.readJson(filePath).catch(() => {})) as {
- dependencies: { [key: string]: { version: string } };
- };
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.UpdateSDKPackages, {
- [TelemetryProperty.BotbuilderVersion]: packageLockFile?.dependencies["botbuilder"]?.version,
- [TelemetryProperty.TeamsFxVersion]:
- packageLockFile?.dependencies["@microsoft/teamsfx"]?.version,
- [TelemetryProperty.TeamsJSVersion]:
- packageLockFile?.dependencies["@microsoft/teams-js"]?.version,
- });
-}
-
-async function refreshEnvTreeOnFileContentChanged(workspacePath: string, filePath: string) {
- const projectSettingsPath = path.resolve(
- workspacePath,
- `.${ConfigFolderName}`,
- "configs",
- "projectSettings.json"
- );
-
- // check if file is project config
- if (path.normalize(filePath) === path.normalize(projectSettingsPath)) {
- await envTreeProviderInstance.reloadEnvironments();
- }
-}
-
-export async function createNewProjectHandler(...args: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateProjectStart, getTriggerFromProperty(args));
- let inputs: Inputs | undefined;
- if (args?.length === 1) {
- if (!!args[0].teamsAppFromTdp) {
- inputs = getSystemInputs();
- inputs.teamsAppFromTdp = args[0].teamsAppFromTdp;
- }
- } else if (args?.length === 2) {
- // from copilot chat
- inputs = { ...getSystemInputs(), ...args[1] };
- }
- const result = await runCommand(Stage.create, inputs);
- if (result.isErr()) {
- return err(result.error);
- }
-
- const res = result.value as CreateProjectResult;
- if (res.shouldInvokeTeamsAgent) {
- await invokeTeamsAgent([TelemetryTriggerFrom.CreateAppQuestionFlow]);
- return result;
- }
- const projectPathUri = Uri.file(res.projectPath);
- // If it is triggered in @office /create for code gen, then do no open the temp folder.
- if (isValidOfficeAddInProject(projectPathUri.fsPath) && inputs?.agent === "office") {
- return result;
- }
- // show local debug button by default
- if (isValidOfficeAddInProject(projectPathUri.fsPath)) {
- await openOfficeDevFolder(projectPathUri, true, res.warnings, args);
- } else {
- await openFolder(projectPathUri, true, res.warnings, args);
- }
- return result;
-}
-
-export async function selectAndDebugHandler(args?: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.RunIconDebugStart, getTriggerFromProperty(args));
- const result = await selectAndDebug();
- await processResult(TelemetryEvent.RunIconDebug, result);
- return result;
-}
-
-export async function treeViewLocalDebugHandler(): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewLocalDebug);
- await vscode.commands.executeCommand("workbench.action.quickOpen", "debug ");
-
- return ok(null);
-}
-
-export async function treeViewPreviewHandler(...args: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.TreeViewPreviewStart,
- getTriggerFromProperty(args)
- );
- const properties: { [key: string]: string } = {};
-
- try {
- const env = args[1]?.identifier as string;
- const inputs = getSystemInputs();
- inputs.env = env;
- properties[TelemetryProperty.Env] = env;
-
- const result = await core.previewWithManifest(inputs);
- if (result.isErr()) {
- throw result.error;
- }
-
- const hub = inputs[QuestionNames.M365Host] as Hub;
- const url = result.value;
- properties[TelemetryProperty.Hub] = hub;
-
- await openHubWebClient(hub, url);
- } catch (error) {
- const assembledError = assembleError(error);
- void showError(assembledError);
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.TreeViewPreview,
- assembledError,
- properties
- );
- return err(assembledError);
- }
-
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewPreview, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- ...properties,
- });
- return ok(null);
-}
-
-export async function validateManifestHandler(args?: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.ValidateManifestStart,
- getTriggerFromProperty(args)
- );
-
- const inputs = getSystemInputs();
- return await runCommand(Stage.validateApplication, inputs);
-}
-
-/**
- * Ask user to select environment, local is included
- */
-export async function askTargetEnvironment(): Promise> {
- const projectPath = workspaceUri?.fsPath;
- if (!isValidProject(projectPath)) {
- return err(new InvalidProjectError());
- }
- const envProfilesResult = await environmentManager.listAllEnvConfigs(projectPath!);
- if (envProfilesResult.isErr()) {
- return err(envProfilesResult.error);
- }
- const config: SingleSelectConfig = {
- name: "targetEnvName",
- title: "Select an environment",
- options: envProfilesResult.value,
- };
- const selectedEnv = await VS_CODE_UI.selectOption(config);
- if (selectedEnv.isErr()) {
- return err(selectedEnv.error);
- } else {
- return ok(selectedEnv.value.result as string);
- }
-}
-
-export async function buildPackageHandler(...args: unknown[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.BuildStart, getTriggerFromProperty(args));
- return await runCommand(Stage.createAppPackage);
-}
-
-let lastAppPackageFile: string | undefined;
-
-export async function publishInDeveloperPortalHandler(
- ...args: unknown[]
-): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.PublishInDeveloperPortalStart,
- getTriggerFromProperty(args)
- );
- const workspacePath = workspaceUri?.fsPath;
- const zipDefaultFolder: string | undefined = path.join(
- workspacePath!,
- BuildFolderName,
- AppPackageFolderName
- );
-
- let files: string[] = [];
- if (await fs.pathExists(zipDefaultFolder)) {
- files = await fs.readdir(zipDefaultFolder);
- files = files
- .filter((file) => path.extname(file).toLowerCase() === ".zip")
- .map((file) => {
- return path.join(zipDefaultFolder, file);
- });
- }
- while (true) {
- const selectFileConfig: SelectFileConfig = {
- name: "appPackagePath",
- title: localize("teamstoolkit.publishInDevPortal.selectFile.title"),
- placeholder: localize("teamstoolkit.publishInDevPortal.selectFile.placeholder"),
- filters: {
- "Zip files": ["zip"],
- },
- };
- if (lastAppPackageFile && fs.existsSync(lastAppPackageFile)) {
- selectFileConfig.default = lastAppPackageFile;
- } else {
- selectFileConfig.possibleFiles = files.map((file) => {
- const appPackageFilename = path.basename(file);
- const appPackageFilepath = path.dirname(file);
- return {
- id: file,
- label: `$(file) ${appPackageFilename}`,
- description: appPackageFilepath,
- };
- });
- }
- const selectFileResult = await VS_CODE_UI.selectFile(selectFileConfig);
- if (selectFileResult.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.PublishInDeveloperPortal,
- selectFileResult.error,
- getTriggerFromProperty(args)
- );
- return ok(null);
- }
- if (
- (lastAppPackageFile && selectFileResult.value.result === lastAppPackageFile) ||
- (!lastAppPackageFile && files.indexOf(selectFileResult.value.result!) !== -1)
- ) {
- // user selected file in options
- lastAppPackageFile = selectFileResult.value.result;
- break;
- }
- // final confirmation
- lastAppPackageFile = selectFileResult.value.result!;
- const appPackageFilename = path.basename(lastAppPackageFile);
- const appPackageFilepath = path.dirname(lastAppPackageFile);
- const confirmOption: SingleSelectConfig = {
- options: [
- {
- id: "yes",
- label: `$(file) ${appPackageFilename}`,
- description: appPackageFilepath,
- },
- ],
- name: "confirm",
- title: localize("teamstoolkit.publishInDevPortal.selectFile.title"),
- placeholder: localize("teamstoolkit.publishInDevPortal.confirmFile.placeholder"),
- step: 2,
- };
- const confirm = await VS_CODE_UI.selectOption(confirmOption);
- if (confirm.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.PublishInDeveloperPortal,
- confirm.error,
- getTriggerFromProperty(args)
- );
- return ok(null);
- }
- if (confirm.value.type === "success") {
- break;
- }
- }
- const inputs = getSystemInputs();
- inputs["appPackagePath"] = lastAppPackageFile;
- const res = await runCommand(Stage.publishInDeveloperPortal, inputs);
- if (res.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.PublishInDeveloperPortal,
- res.error,
- getTriggerFromProperty(args)
- );
- }
- return res;
-}
-
-export function openFolderHandler(...args: unknown[]): Promise> {
- const scheme = "file://";
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenFolder, {
- [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Notification,
- });
- if (args && args.length > 0 && args[0]) {
- let path = args[0] as string;
- if (path.startsWith(scheme)) {
- path = path.substring(scheme.length);
- }
- const uri = Uri.file(path);
- openFolderInExplorer(uri.fsPath);
- }
- return Promise.resolve(ok(null));
-}
-
-export async function addWebpart(...args: unknown[]) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.AddWebpartStart, getTriggerFromProperty(args));
-
- return await runCommand(Stage.addWebpart);
-}
-
-export async function validateAzureDependenciesHandler(): Promise {
- try {
- await triggerV3Migration();
- return undefined;
- } catch (error: any) {
- void showError(error as FxError);
- return "1";
- }
-}
-
-/**
- * Check & install required local prerequisites before local debug.
- */
-export async function validateLocalPrerequisitesHandler(): Promise {
- try {
- await triggerV3Migration();
- return undefined;
- } catch (error: any) {
- void showError(error as FxError);
- return "1";
- }
-}
-
-/*
- * Prompt window to let user install the app in Teams
- */
-export async function installAppInTeams(): Promise {
- try {
- await triggerV3Migration();
- return undefined;
- } catch (error: any) {
- void showError(error as FxError);
- return "1";
- }
-}
-
-/**
- * Check required prerequisites in Get Started Page.
- */
-export async function validateGetStartedPrerequisitesHandler(
- ...args: unknown[]
-): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.ClickValidatePrerequisites,
- getTriggerFromProperty(args)
- );
- const result = await checkPrerequisitesForGetStarted();
- if (result.isErr()) {
- void showError(result.error);
- // // return non-zero value to let task "exit ${command:xxx}" to exit
- // return "1";
- }
- return result;
-}
-
-/**
- * install functions binding before launch local debug
- */
-export async function backendExtensionsInstallHandler(): Promise {
- try {
- await triggerV3Migration();
- return undefined;
- } catch (error: any) {
- void showError(error as FxError);
- return "1";
- }
-}
-
-/**
- * Get path delimiter
- * Usage like ${workspaceFolder}/devTools/func${command:...}${env:PATH}
- */
-export function getPathDelimiterHandler(): string {
- return path.delimiter;
-}
-
-/**
- * Get dotnet path to be referenced by task definition.
- * Usage like ${command:...}${env:PATH} so need to include delimiter as well
- */
-export async function getDotnetPathHandler(): Promise {
- try {
- const depsManager = new DepsManager(vscodeLogger, vscodeTelemetry);
- const dotnetStatus = (await depsManager.getStatus([DepsType.Dotnet]))?.[0];
- if (dotnetStatus?.isInstalled && dotnetStatus?.details?.binFolders !== undefined) {
- return `${path.delimiter}${dotnetStatus.details.binFolders
- .map((f: string) => path.dirname(f))
- .join(path.delimiter)}${path.delimiter}`;
- }
- } catch (error: any) {
- void showError(assembleError(error));
- }
-
- return `${path.delimiter}`;
-}
-
-/**
- * call localDebug on core
- */
-export async function preDebugCheckHandler(): Promise {
- try {
- await triggerV3Migration();
- return undefined;
- } catch (error: any) {
- void showError(error as FxError);
- return "1";
- }
-}
-
-export async function createAccountHandler(args: any[]): Promise {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccountStart, getTriggerFromProperty(args));
- const m365Option: OptionItem = {
- id: "createAccountM365",
- label: `$(add) ${localize("teamstoolkit.commands.createAccount.m365")}`,
- description: localize("teamstoolkit.commands.createAccount.requireSubscription"),
- };
- const azureOption: OptionItem = {
- id: "createAccountAzure",
- label: `$(add) ${localize("teamstoolkit.commands.createAccount.azure")}`,
- description: localize("teamstoolkit.commands.createAccount.free"),
- };
- const option: SingleSelectConfig = {
- name: "CreateAccounts",
- title: localize("teamstoolkit.commands.createAccount.title"),
- options: [m365Option, azureOption],
- };
- const result = await VS_CODE_UI.selectOption(option);
- if (result.isOk()) {
- if (result.value.result === m365Option.id) {
- await VS_CODE_UI.openUrl("https://developer.microsoft.com/microsoft-365/dev-program");
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccount, {
- [TelemetryProperty.AccountType]: AccountType.M365,
- ...getTriggerFromProperty(args),
- });
- } else if (result.value.result === azureOption.id) {
- await VS_CODE_UI.openUrl("https://azure.microsoft.com/en-us/free/");
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccount, {
- [TelemetryProperty.AccountType]: AccountType.Azure,
- ...getTriggerFromProperty(args),
- });
- }
- } else {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.CreateAccount, result.error, {
- ...getTriggerFromProperty(args),
- });
- }
- return;
-}
-
-export async function openBuildIntelligentAppsWalkthroughHandler(
- ...args: unknown[]
-): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.WalkThroughBuildIntelligentApps,
- getTriggerFromProperty(args)
- );
- const data = await vscode.commands.executeCommand(
- "workbench.action.openWalkthrough",
- "TeamsDevApp.ms-teams-vscode-extension#buildIntelligentApps"
- );
- return Promise.resolve(ok(data));
-}
-
-export async function checkUpgrade(args?: any[]) {
- const triggerFrom = getTriggerFromProperty(args);
- const input = getSystemInputs();
- if (triggerFrom?.[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.Auto) {
- input["isNonmodalMessage"] = true;
- // not await here to avoid blocking the UI.
- void core.phantomMigrationV3(input).then((result) => {
- if (result.isErr()) {
- void showError(result.error);
- }
- });
- return;
- } else if (
- triggerFrom[TelemetryProperty.TriggerFrom] &&
- (triggerFrom[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.SideBar ||
- triggerFrom[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.CommandPalette)
- ) {
- input["skipUserConfirm"] = true;
- }
- const result = await core.phantomMigrationV3(input);
- if (result.isErr()) {
- void showError(result.error);
- }
-}
-
-export async function openSurveyHandler(args?: any[]) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.Survey, {
- ...getTriggerFromProperty(args),
- // eslint-disable-next-line no-secrets/no-secrets
- message: getDefaultString("teamstoolkit.commandsTreeViewProvider.openSurveyTitle"),
- });
- const survey = ExtensionSurvey.getInstance();
- await survey.openSurveyLink();
-}
-
-export async function autoOpenProjectHandler(): Promise {
- const isOpenWalkThrough = (await globalStateGet(GlobalKey.OpenWalkThrough, false)) as boolean;
- const isOpenReadMe = (await globalStateGet(GlobalKey.OpenReadMe, "")) as string;
- const isOpenSampleReadMe = (await globalStateGet(GlobalKey.OpenSampleReadMe, false)) as boolean;
- const createWarnings = (await globalStateGet(GlobalKey.CreateWarnings, "")) as string;
- const autoInstallDependency = (await globalStateGet(GlobalKey.AutoInstallDependency)) as boolean;
- if (isOpenWalkThrough) {
- await showLocalDebugMessage();
- await openWelcomeHandler([TelemetryTriggerFrom.Auto]);
- await globalStateUpdate(GlobalKey.OpenWalkThrough, false);
-
- if (workspaceUri?.fsPath) {
- await ShowScaffoldingWarningSummary(workspaceUri.fsPath, createWarnings);
- await globalStateUpdate(GlobalKey.CreateWarnings, "");
- }
- }
- if (isOpenReadMe === workspaceUri?.fsPath) {
- await showLocalDebugMessage();
- await openReadMeHandler(TelemetryTriggerFrom.Auto);
- await updateProjectStatus(workspaceUri.fsPath, CommandKey.OpenReadMe, ok(null));
- await globalStateUpdate(GlobalKey.OpenReadMe, "");
-
- await ShowScaffoldingWarningSummary(workspaceUri.fsPath, createWarnings);
- await globalStateUpdate(GlobalKey.CreateWarnings, "");
- }
- if (isOpenSampleReadMe) {
- await showLocalDebugMessage();
- await openSampleReadmeHandler([TelemetryTriggerFrom.Auto]);
- await globalStateUpdate(GlobalKey.OpenSampleReadMe, false);
- }
- if (autoInstallDependency) {
- await autoInstallDependencyHandler();
- await globalStateUpdate(GlobalKey.AutoInstallDependency, false);
- }
-}
-
-export async function openReadMeHandler(...args: unknown[]) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ClickOpenReadMe, getTriggerFromProperty(args));
- if (!isTeamsFxProject && !isOfficeAddInProject) {
- const createProject = {
- title: localize("teamstoolkit.handlers.createProjectTitle"),
- run: async (): Promise => {
- await Correlator.run(
- async () => await createNewProjectHandler(TelemetryTriggerFrom.Notification)
- );
- },
- };
-
- const openFolder = {
- title: localize("teamstoolkit.handlers.openFolderTitle"),
- run: async (): Promise => {
- await commands.executeCommand("vscode.openFolder");
- },
- };
-
- void vscode.window
- .showInformationMessage(
- localize("teamstoolkit.handlers.createProjectNotification"),
- createProject,
- openFolder
- )
- .then((selection) => {
- selection?.run();
- });
- } else if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) {
- const workspaceFolder = workspace.workspaceFolders[0];
- const workspacePath: string = workspaceFolder.uri.fsPath;
- // show README.md or src/README.md(SPFx) in workspace root folder
- const rootReadmePath = `${workspacePath}/README.md`;
- const uri = (await fs.pathExists(rootReadmePath))
- ? Uri.file(rootReadmePath)
- : Uri.file(`${workspacePath}/src/README.md`);
-
- if (TreatmentVariableValue.inProductDoc) {
- const content = await fs.readFile(uri.fsPath, "utf8");
- if (content.includes("## Get Started with the Notification bot")) {
- // A notification bot project.
- if (content.includes("restify")) {
- // Restify server notification bot.
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.InteractWithInProductDoc, {
- [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Auto,
- [TelemetryProperty.Interaction]: InProductGuideInteraction.Open,
- [TelemetryProperty.Identifier]: PanelType.RestifyServerNotificationBotReadme,
- });
- WebviewPanel.createOrShow(PanelType.RestifyServerNotificationBotReadme);
- } else {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.InteractWithInProductDoc, {
- [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Auto,
- [TelemetryProperty.Interaction]: InProductGuideInteraction.Open,
- [TelemetryProperty.Identifier]: PanelType.FunctionBasedNotificationBotReadme,
- });
- WebviewPanel.createOrShow(PanelType.FunctionBasedNotificationBotReadme);
- }
- }
- }
-
- // Always open README.md in current panel instead of side-by-side.
- await workspace.openTextDocument(uri);
- const PreviewMarkdownCommand = "markdown.showPreview";
- await vscode.commands.executeCommand(PreviewMarkdownCommand, uri);
- }
- return ok(null);
-}
-
-export async function openSampleReadmeHandler(args?: any) {
- if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) {
- const workspaceFolder = workspace.workspaceFolders[0];
- const workspacePath: string = workspaceFolder.uri.fsPath;
- const uri = Uri.file(`${workspacePath}/README.md`);
- await workspace.openTextDocument(uri);
- if (isTriggerFromWalkThrough(args as unknown[])) {
- const PreviewMarkdownCommand = "markdown.showPreviewToSide";
- await commands.executeCommand(PreviewMarkdownCommand, uri);
- } else {
- const PreviewMarkdownCommand = "markdown.showPreview";
- await commands.executeCommand(PreviewMarkdownCommand, uri);
- }
- }
-}
-
-export async function autoInstallDependencyHandler() {
- await VS_CODE_UI.runCommand({
- cmd: "npm i",
- workingDirectory: "${workspaceFolder}/src",
- shellName: localize("teamstoolkit.handlers.autoInstallDependency"),
- iconPath: "cloud-download",
- });
-}
-
-export async function showLocalDebugMessage() {
- const shouldShowLocalDebugMessage = (await globalStateGet(
- GlobalKey.ShowLocalDebugMessage,
- false
- )) as boolean;
-
- if (!shouldShowLocalDebugMessage) {
- return;
- } else {
- await globalStateUpdate(GlobalKey.ShowLocalDebugMessage, false);
- }
-
- const hasLocalEnv = await fs.pathExists(path.join(workspaceUri!.fsPath, "teamsapp.local.yml"));
-
- const appName = (await getAppName()) ?? localize("teamstoolkit.handlers.fallbackAppName");
- const isWindows = process.platform === "win32";
- const folderLink = encodeURI(workspaceUri!.toString());
- const openFolderCommand = `command:fx-extension.openFolder?%5B%22${folderLink}%22%5D`;
-
- if (hasLocalEnv) {
- const localDebug = {
- title: localize("teamstoolkit.handlers.localDebugTitle"),
- run: async (): Promise => {
- await selectAndDebug();
- },
- };
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ShowLocalDebugNotification);
-
- const messageTemplate = await getLocalDebugMessageTemplate(isWindows);
-
- let message = util.format(messageTemplate, appName, workspaceUri?.fsPath);
- if (isWindows) {
- message = util.format(messageTemplate, appName, openFolderCommand);
- }
- void vscode.window.showInformationMessage(message, localDebug).then((selection) => {
- if (selection?.title === localize("teamstoolkit.handlers.localDebugTitle")) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ClickLocalDebug);
- selection.run();
- }
- });
- } else {
- const provision = {
- title: localize("teamstoolkit.handlers.provisionTitle"),
- run: async (): Promise => {
- await vscode.commands.executeCommand(CommandKey.Provision, [
- TelemetryTriggerFrom.Notification,
- ]);
- },
- };
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ShowProvisionNotification);
- const message = isWindows
- ? util.format(
- localize("teamstoolkit.handlers.provisionDescription"),
- appName,
- openFolderCommand
- )
- : util.format(
- localize("teamstoolkit.handlers.provisionDescription.fallback"),
- appName,
- workspaceUri?.fsPath
- );
- void vscode.window.showInformationMessage(message, provision).then((selection) => {
- if (selection?.title === localize("teamstoolkit.handlers.provisionTitle")) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ClickProvision);
- selection.run();
- }
- });
- }
-}
-
-export async function ShowScaffoldingWarningSummary(
- workspacePath: string,
- warning: string
-): Promise {
- try {
- let createWarnings: Warning[] = [];
-
- if (warning) {
- try {
- createWarnings = JSON.parse(warning) as Warning[];
- } catch (e) {
- const error = new JSONSyntaxError(warning, e, "vscode");
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.ShowScaffoldingWarningSummaryError,
- error
- );
- }
- }
- const manifestRes = await manifestUtils._readAppManifest(
- path.join(workspacePath, AppPackageFolderName, ManifestTemplateFileName)
- );
- let message;
- if (manifestRes.isOk()) {
- const teamsManifest = manifestRes.value;
- const commonProperties = ManifestUtil.parseCommonProperties(teamsManifest);
- if (commonProperties.capabilities.includes("plugin")) {
- const apiSpecFilePathRes = await pluginManifestUtils.getApiSpecFilePathFromTeamsManifest(
- teamsManifest,
- path.join(workspacePath, AppPackageFolderName, ManifestTemplateFileName)
- );
- if (apiSpecFilePathRes.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.ShowScaffoldingWarningSummaryError,
- apiSpecFilePathRes.error
- );
- } else {
- message = generateScaffoldingSummary(
- createWarnings,
- teamsManifest,
- path.relative(workspacePath, apiSpecFilePathRes.value[0])
- );
- }
- }
- if (commonProperties.isApiME) {
- message = generateScaffoldingSummary(
- createWarnings,
- manifestRes.value,
- teamsManifest.composeExtensions?.[0].apiSpecificationFile ?? ""
- );
- }
-
- if (message) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ShowScaffoldingWarningSummary);
- VsCodeLogInstance.outputChannel.show();
- void VsCodeLogInstance.info(message);
- }
- } else {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.ShowScaffoldingWarningSummaryError,
- manifestRes.error
- );
- }
- } catch (e) {
- const error = assembleError(e);
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.ShowScaffoldingWarningSummaryError, error);
- }
-}
-
-export async function openSamplesHandler(...args: unknown[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.Samples, getTriggerFromProperty(args));
- WebviewPanel.createOrShow(PanelType.SampleGallery, args);
- return Promise.resolve(ok(null));
-}
-
-export async function openExternalHandler(args?: any[]) {
- if (args && args.length > 0) {
- const url = (args[0] as { url: string }).url;
- return env.openExternal(Uri.parse(url));
- }
-}
-
-export async function createNewEnvironment(args?: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.CreateNewEnvironmentStart,
- getTriggerFromProperty(args)
- );
- const result = await runCommand(Stage.createEnv);
- if (!result.isErr()) {
- await envTreeProviderInstance.reloadEnvironments();
- }
- return result;
-}
-
-export async function refreshEnvironment(args?: any[]): Promise> {
- return await envTreeProviderInstance.reloadEnvironments();
-}
-
-function getSubscriptionUrl(subscriptionInfo: SubscriptionInfo): string {
- const subscriptionId = subscriptionInfo.subscriptionId;
- const tenantId = subscriptionInfo.tenantId;
-
- return `${AzurePortalUrl}/#@${tenantId}/resource/subscriptions/${subscriptionId}`;
-}
-
-enum ResourceInfo {
- Subscription = "Subscription",
- ResourceGroup = "Resource Group",
-}
-
-export async function openSubscriptionInPortal(env: string): Promise> {
- const telemetryProperties: { [p: string]: string } = {};
- telemetryProperties[TelemetryProperty.Env] = getHashedEnv(env);
-
- const subscriptionInfo = await getSubscriptionInfoFromEnv(env);
- if (subscriptionInfo) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenSubscriptionInPortal, telemetryProperties);
-
- const url = getSubscriptionUrl(subscriptionInfo);
- await vscode.env.openExternal(vscode.Uri.parse(url));
-
- return ok(Void);
- } else {
- const resourceInfoNotFoundError = new UserError(
- ExtensionSource,
- ExtensionErrors.EnvResourceInfoNotFoundError,
- util.format(
- localize("teamstoolkit.handlers.resourceInfoNotFound"),
- ResourceInfo.Subscription,
- env
- )
- );
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.OpenSubscriptionInPortal,
- resourceInfoNotFoundError,
- telemetryProperties
- );
-
- return err(resourceInfoNotFoundError);
- }
-}
-
-export async function openResourceGroupInPortal(env: string): Promise> {
- const telemetryProperties: { [p: string]: string } = {};
- telemetryProperties[TelemetryProperty.Env] = getHashedEnv(env);
-
- const subscriptionInfo = await getSubscriptionInfoFromEnv(env);
- const resourceGroupName = await getResourceGroupNameFromEnv(env);
-
- if (subscriptionInfo && resourceGroupName) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenResourceGroupInPortal, telemetryProperties);
-
- const url = `${getSubscriptionUrl(subscriptionInfo)}/resourceGroups/${resourceGroupName}`;
- await vscode.env.openExternal(vscode.Uri.parse(url));
-
- return ok(Void);
- } else {
- let errorMessage = "";
- if (subscriptionInfo) {
- errorMessage = util.format(
- localize("teamstoolkit.handlers.resourceInfoNotFound"),
- ResourceInfo.ResourceGroup,
- env
- );
- } else if (resourceGroupName) {
- errorMessage = util.format(
- localize("teamstoolkit.handlers.resourceInfoNotFound"),
- ResourceInfo.Subscription,
- env
- );
- } else {
- errorMessage = util.format(
- localize("teamstoolkit.handlers.resourceInfoNotFound"),
- `${ResourceInfo.Subscription} and ${ResourceInfo.ResourceGroup}`,
- env
- );
- }
-
- const resourceInfoNotFoundError = new UserError(
- ExtensionSource,
- ExtensionErrors.EnvResourceInfoNotFoundError,
- errorMessage
- );
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.OpenSubscriptionInPortal,
- resourceInfoNotFoundError,
- telemetryProperties
- );
-
- return err(resourceInfoNotFoundError);
- }
-}
-
-export async function grantPermission(env?: string): Promise> {
- let result: Result = ok(Void);
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.GrantPermissionStart);
-
- let inputs: Inputs | undefined;
- try {
- const checkCoreRes = checkCoreNotEmpty();
- if (checkCoreRes.isErr()) {
- throw checkCoreRes.error;
- }
-
- inputs = getSystemInputs();
- inputs.env = env;
- result = await core.grantPermission(inputs);
- if (result.isErr()) {
- throw result.error;
- }
- const grantSucceededMsg = util.format(
- localize("teamstoolkit.handlers.grantPermissionSucceededV3"),
- inputs.email
- );
-
- window.showInformationMessage(grantSucceededMsg);
- VsCodeLogInstance.info(grantSucceededMsg);
- } catch (e) {
- result = wrapError(e);
- }
-
- await processResult(TelemetryEvent.GrantPermission, result, inputs);
- return result;
-}
-
-export async function listCollaborator(env?: string): Promise> {
- let result: Result = ok(Void);
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ListCollaboratorStart);
-
- let inputs: Inputs | undefined;
- try {
- const checkCoreRes = checkCoreNotEmpty();
- if (checkCoreRes.isErr()) {
- throw checkCoreRes.error;
- }
-
- inputs = getSystemInputs();
- inputs.env = env;
-
- result = await core.listCollaborator(inputs);
- if (result.isErr()) {
- throw result.error;
- }
-
- // TODO: For short-term workaround. Remove after webview is ready.
- VsCodeLogInstance.outputChannel.show();
- } catch (e) {
- result = wrapError(e);
- }
-
- await processResult(TelemetryEvent.ListCollaborator, result, inputs);
- return result;
-}
-
-export async function manageCollaboratorHandler(env?: string): Promise> {
- let result: any = ok(Void);
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageCollaboratorStart);
-
- try {
- const collaboratorCommandSelection: SingleSelectConfig = {
- name: "collaborationCommand",
- title: localize("teamstoolkit.manageCollaborator.command"),
- options: [
- {
- id: "grantPermission",
- label: localize("teamstoolkit.manageCollaborator.grantPermission.label"),
- detail: localize("teamstoolkit.manageCollaborator.grantPermission.description"),
- },
- {
- id: "listCollaborator",
- label: localize("teamstoolkit.manageCollaborator.listCollaborator.label"),
- detail: localize("teamstoolkit.manageCollaborator.listCollaborator.description"),
- },
- ],
- returnObject: false,
- };
- const collaboratorCommand = await VS_CODE_UI.selectOption(collaboratorCommandSelection);
- if (collaboratorCommand.isErr()) {
- throw collaboratorCommand.error;
- }
-
- const command = collaboratorCommand.value.result;
- switch (command) {
- case "grantPermission":
- result = await grantPermission(env);
- break;
-
- case "listCollaborator":
- default:
- result = await listCollaborator(env);
- break;
- }
- } catch (e) {
- result = wrapError(e);
- }
-
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageCollaborator);
- return result;
-}
-
-export function saveTextDocumentHandler(document: vscode.TextDocumentWillSaveEvent) {
- if (!isValidProject(workspaceUri?.fsPath)) {
- return;
- }
-
- let reason: TelemetryUpdateAppReason | undefined = undefined;
- switch (document.reason) {
- case vscode.TextDocumentSaveReason.Manual:
- reason = TelemetryUpdateAppReason.Manual;
- break;
- case vscode.TextDocumentSaveReason.AfterDelay:
- reason = TelemetryUpdateAppReason.AfterDelay;
- break;
- case vscode.TextDocumentSaveReason.FocusOut:
- reason = TelemetryUpdateAppReason.FocusOut;
- break;
- }
-
- let curDirectory = path.dirname(document.document.fileName);
- while (curDirectory) {
- if (isValidProject(curDirectory)) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.UpdateTeamsApp, {
- [TelemetryProperty.UpdateTeamsAppReason]: reason,
- });
- return;
- }
-
- if (curDirectory === path.join(curDirectory, "..")) {
- break;
- }
- curDirectory = path.join(curDirectory, "..");
- }
-}
-
-export function registerAccountMenuCommands(context: ExtensionContext) {
- // Register SignOut tree view command
- context.subscriptions.push(
- commands.registerCommand("fx-extension.signOut", async (node: TreeViewCommand) => {
- try {
- switch (node.contextValue) {
- case "signedinM365": {
- await Correlator.run(async () => {
- await signOutM365(true);
- });
- break;
- }
- case "signedinAzure": {
- await Correlator.run(async () => {
- await signOutAzure(true);
- });
- break;
- }
- }
- } catch (e) {
- void showError(e as FxError);
- }
- })
- );
-}
-
-export function cmdHdlDisposeTreeView() {
- TreeViewManagerInstance.dispose();
-}
-
-export async function cmpAccountsHandler(args: any[]) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageAccount, getTriggerFromProperty(args));
- const signInAzureOption: VscQuickPickItem = {
- id: "signInAzure",
- label: localize("teamstoolkit.handlers.signInAzure"),
- function: () => signInAzure(),
- };
-
- const signOutAzureOption: VscQuickPickItem = {
- id: "signOutAzure",
- label: localize("teamstoolkit.handlers.signOutOfAzure"),
- function: async () =>
- await Correlator.run(async () => {
- await signOutAzure(false);
- }),
- };
-
- const signInM365Option: VscQuickPickItem = {
- id: "signinM365",
- label: localize("teamstoolkit.handlers.signIn365"),
- function: () => signInM365(),
- };
-
- const signOutM365Option: VscQuickPickItem = {
- id: "signOutM365",
- label: localize("teamstoolkit.handlers.signOutOfM365"),
- function: async () =>
- await Correlator.run(async () => {
- await signOutM365(false);
- }),
- };
-
- const createAccountsOption: VscQuickPickItem = {
- id: "createAccounts",
- label: `$(add) ${localize("teamstoolkit.commands.createAccount.title")}`,
- function: async () => {
- await Correlator.run(() => createAccountHandler([]));
- },
- };
-
- //TODO: hide subscription list until core or api expose the get subscription list API
- // let selectSubscriptionOption: VscQuickPickItem = {
- // id: "selectSubscription",
- // label: "Specify an Azure Subscription",
- // function: () => selectSubscription(),
- // detail: "4 subscriptions discovered"
- // };
-
- const quickPick = window.createQuickPick();
-
- const quickItemOptionArray: VscQuickPickItem[] = [];
-
- const m365AccountRes = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
- const m365Account = m365AccountRes.isOk() ? m365AccountRes.value : undefined;
- if (m365Account && m365Account.status === "SignedIn") {
- const accountInfo = m365Account.accountInfo;
- const email = (accountInfo as any).upn ? (accountInfo as any).upn : undefined;
- if (email !== undefined) {
- signOutM365Option.label = signOutM365Option.label.concat(email);
- }
- quickItemOptionArray.push(signOutM365Option);
- } else {
- quickItemOptionArray.push(signInM365Option);
- }
-
- const azureAccount = await azureAccountManager.getStatus();
- if (azureAccount.status === "SignedIn") {
- const accountInfo = azureAccount.accountInfo;
- const email = (accountInfo as any).email || (accountInfo as any).upn;
- if (email !== undefined) {
- signOutAzureOption.label = signOutAzureOption.label.concat(email);
- }
- quickItemOptionArray.push(signOutAzureOption);
- } else {
- quickItemOptionArray.push(signInAzureOption);
- }
-
- quickItemOptionArray.push(createAccountsOption);
- quickPick.items = quickItemOptionArray;
- quickPick.onDidChangeSelection((selection) => {
- if (selection[0]) {
- (selection[0] as VscQuickPickItem).function().catch(console.error);
- quickPick.hide();
- }
- });
- quickPick.onDidHide(() => quickPick.dispose());
- quickPick.show();
-}
-
-export async function decryptSecret(cipher: string, selection: vscode.Range): Promise {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.EditSecretStart, {
- [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Other,
- });
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return;
- }
- const inputs = getSystemInputs();
- const result = await core.decrypt(cipher, inputs);
- if (result.isOk()) {
- const editedSecret = await VS_CODE_UI.inputText({
- name: "Secret Editor",
- title: localize("teamstoolkit.handlers.editSecretTitle"),
- default: result.value,
- });
- if (editedSecret.isOk() && editedSecret.value.result) {
- const newCiphertext = await core.encrypt(editedSecret.value.result, inputs);
- if (newCiphertext.isOk()) {
- await editor.edit((editBuilder) => {
- editBuilder.replace(selection, newCiphertext.value);
- });
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.EditSecret, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- });
- } else {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.EditSecret, newCiphertext.error);
- }
- }
- } else {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.EditSecret, result.error);
- void window.showErrorMessage(result.error.message);
- }
-}
-
-const acExtId = "TeamsDevApp.vscode-adaptive-cards";
-
-export async function installAdaptiveCardExt(
- ...args: unknown[]
-): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.AdaptiveCardPreviewerInstall,
- getTriggerFromProperty(args)
- );
- if (acpInstalled()) {
- await vscode.window.showInformationMessage(
- localize("teamstoolkit.handlers.adaptiveCardExtUsage")
- );
- } else {
- const selection = await vscode.window.showInformationMessage(
- localize("teamstoolkit.handlers.installAdaptiveCardExt"),
- "Install",
- "Cancel"
- );
- if (selection === "Install") {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.AdaptiveCardPreviewerInstallConfirm,
- getTriggerFromProperty(args)
- );
- await vscode.commands.executeCommand("workbench.extensions.installExtension", acExtId);
- } else {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.AdaptiveCardPreviewerInstallCancel,
- getTriggerFromProperty(args)
- );
- }
- }
- return Promise.resolve(ok(null));
-}
-
-export function acpInstalled(): boolean {
- const extension = vscode.extensions.getExtension(acExtId);
- return !!extension;
-}
-
-export async function openPreviewAadFile(args: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.PreviewAadManifestFile,
- getTriggerFromProperty(args)
- );
- const workspacePath = workspaceUri?.fsPath;
- const validProject = isValidProject(workspacePath);
- if (!validProject) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.PreviewAadManifestFile,
- new InvalidProjectError()
- );
- return err(new InvalidProjectError());
- }
-
- const selectedEnv = await askTargetEnvironment();
- if (selectedEnv.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, selectedEnv.error);
- return err(selectedEnv.error);
- }
- const envName = selectedEnv.value;
-
- const func: Func = {
- namespace: "fx-solution-azure",
- method: "buildAadManifest",
- params: {
- type: "",
- },
- };
-
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.BuildAadManifestStart,
- getTriggerFromProperty(args)
- );
- const inputs = getSystemInputs();
- inputs.env = envName;
- const res = await runCommand(Stage.buildAad, inputs);
-
- if (res.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, res.error);
- return err(res.error);
- }
-
- const manifestFile = `${workspacePath as string}/${BuildFolderName}/aad.${envName}.json`;
-
- if (fs.existsSync(manifestFile)) {
- void workspace.openTextDocument(manifestFile).then((document) => {
- void window.showTextDocument(document);
- });
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.PreviewAadManifestFile, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- });
- return ok(manifestFile);
- } else {
- const error = new SystemError(
- ExtensionSource,
- "FileNotFound",
- util.format(localize("teamstoolkit.handlers.fileNotFound"), manifestFile)
- );
- void showError(error);
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, error);
- return err(error);
- }
-}
-
-export async function openConfigStateFile(args: any[]): Promise {
- let telemetryStartName = TelemetryEvent.OpenManifestConfigStateStart;
- let telemetryName = TelemetryEvent.OpenManifestConfigState;
-
- if (args && args.length > 0 && args[0].from === "aad") {
- telemetryStartName = TelemetryEvent.OpenAadConfigStateStart;
- telemetryName = TelemetryEvent.OpenAadConfigState;
- }
-
- ExtTelemetry.sendTelemetryEvent(telemetryStartName);
- const workspacePath = workspaceUri?.fsPath;
- if (!workspacePath) {
- const noOpenWorkspaceError = new UserError(
- ExtensionSource,
- ExtensionErrors.NoWorkspaceError,
- localize("teamstoolkit.handlers.noOpenWorkspace")
- );
- void showError(noOpenWorkspaceError);
- ExtTelemetry.sendTelemetryErrorEvent(telemetryName, noOpenWorkspaceError);
- return err(noOpenWorkspaceError);
- }
-
- if (!isValidProject(workspacePath)) {
- const invalidProjectError = new UserError(
- ExtensionSource,
- ExtensionErrors.InvalidProject,
- localize("teamstoolkit.handlers.invalidProject")
- );
- void showError(invalidProjectError);
- ExtTelemetry.sendTelemetryErrorEvent(telemetryName, invalidProjectError);
- return err(invalidProjectError);
- }
-
- let sourcePath: string | undefined = undefined;
- let env: string | undefined = undefined;
- if (args && args.length > 0) {
- env = args[0].env;
- if (!env) {
- const envRes: Result = await askTargetEnvironment();
- if (envRes.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(telemetryName, envRes.error);
- return err(envRes.error);
- }
- env = envRes.value;
- }
-
- // Load env folder from yml
- const envFolder = await pathUtils.getEnvFolderPath(workspacePath);
- if (envFolder.isOk() && envFolder.value) {
- sourcePath = path.resolve(`${envFolder.value}/.env.${env as string}`);
- } else if (envFolder.isErr()) {
- return err(envFolder.error);
- }
- } else {
- const invalidArgsError = new SystemError(
- ExtensionSource,
- ExtensionErrors.InvalidArgs,
- util.format(localize("teamstoolkit.handlers.invalidArgs"), args ? JSON.stringify(args) : args)
- );
- void showError(invalidArgsError);
- ExtTelemetry.sendTelemetryErrorEvent(telemetryName, invalidArgsError);
- return err(invalidArgsError);
- }
-
- if (sourcePath && !(await fs.pathExists(sourcePath))) {
- const noEnvError = new UserError(
- ExtensionSource,
- ExtensionErrors.EnvFileNotFoundError,
- util.format(localize("teamstoolkit.handlers.findEnvFailed"), env)
- );
- void showError(noEnvError);
- ExtTelemetry.sendTelemetryErrorEvent(telemetryName, noEnvError);
- return err(noEnvError);
- }
-
- void workspace.openTextDocument(sourcePath as string).then((document) => {
- void window.showTextDocument(document);
- });
- ExtTelemetry.sendTelemetryEvent(telemetryName, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- });
-}
-
-export async function updatePreviewManifest(args: any[]): Promise {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.UpdatePreviewManifestStart,
- getTriggerFromProperty(args && args.length > 1 ? [args[1]] : undefined)
- );
- let env: string | undefined;
- if (args && args.length > 0) {
- const filePath = args[0].fsPath as string;
- if (!filePath.endsWith("manifest.template.json")) {
- const envReg = /manifest\.(\w+)\.json$/;
- const result = envReg.exec(filePath);
- if (result && result.length >= 2) {
- env = result[1];
- }
- }
- }
-
- const inputs = getSystemInputs();
- const result = await runCommand(Stage.deployTeams, inputs);
-
- if (!args || args.length === 0) {
- const workspacePath = workspaceUri?.fsPath;
- const inputs = getSystemInputs();
- inputs.ignoreEnvInfo = true;
- const env = await core.getSelectedEnv(inputs);
- if (env.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.UpdatePreviewManifest, env.error);
- return err(env.error);
- }
- const manifestPath = `${
- workspacePath as string
- }/${AppPackageFolderName}/${BuildFolderName}/manifest.${env.value as string}.json`;
- void workspace.openTextDocument(manifestPath).then((document) => {
- void window.showTextDocument(document);
- });
- }
- return result;
-}
-
-export async function copilotPluginAddAPIHandler(args: any[]) {
- // Telemetries are handled in runCommand()
- const inputs = getSystemInputs();
- if (args && args.length > 0) {
- const filePath = args[0].fsPath as string;
- const isFromApiPlugin: boolean = args[0].isFromApiPlugin ?? false;
- if (!isFromApiPlugin) {
- // Codelens for API ME. Trigger from manifest.json
- inputs[QuestionNames.ManifestPath] = filePath;
- } else {
- inputs[QuestionNames.Capabilities] = CapabilityOptions.copilotPluginApiSpec().id;
- inputs[QuestionNames.DestinationApiSpecFilePath] = filePath;
- inputs[QuestionNames.ManifestPath] = args[0].manifestPath;
- }
- }
- const result = await runCommand(Stage.copilotPluginAddAPI, inputs);
- return result;
-}
-
-export function editAadManifestTemplate(args: any[]) {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.EditAadManifestTemplate,
- getTriggerFromProperty(args && args.length > 1 ? [args[1]] : undefined)
- );
- if (args && args.length > 1) {
- const workspacePath = workspaceUri?.fsPath;
- const manifestPath = `${workspacePath as string}/${MetadataV3.aadManifestFileName}`;
- void workspace.openTextDocument(manifestPath).then((document) => {
- void window.showTextDocument(document);
- });
- }
-}
-
-export async function signOutAzure(isFromTreeView: boolean) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.SignOutStart, {
- [TelemetryProperty.TriggerFrom]: isFromTreeView
- ? TelemetryTriggerFrom.TreeView
- : TelemetryTriggerFrom.CommandPalette,
- [TelemetryProperty.AccountType]: AccountType.Azure,
- });
- await vscode.window.showInformationMessage(
- localize("teamstoolkit.commands.azureAccount.signOutHelp")
- );
-}
-
-export async function signOutM365(isFromTreeView: boolean) {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.SignOutStart, {
- [TelemetryProperty.TriggerFrom]: isFromTreeView
- ? TelemetryTriggerFrom.TreeView
- : TelemetryTriggerFrom.CommandPalette,
- [TelemetryProperty.AccountType]: AccountType.M365,
- });
- let result = false;
- result = await M365TokenInstance.signout();
- if (result) {
- accountTreeViewProviderInstance.m365AccountNode.setSignedOut();
- await envTreeProviderInstance.refreshRemoteEnvWarning();
- }
-}
-
-export async function signInAzure() {
- await vscode.commands.executeCommand("fx-extension.signinAzure");
-}
-
-export async function signInM365() {
- await vscode.commands.executeCommand("fx-extension.signinM365");
-}
-
-export interface VscQuickPickItem extends QuickPickItem {
- /**
- * Current id of the option item.
- */
- id: string;
-
- function: () => Promise;
-}
-
-export async function migrateTeamsTabAppHandler(): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsTabAppStart);
- const selection = await VS_CODE_UI.showMessage(
- "warn",
- localize("teamstoolkit.migrateTeamsTabApp.warningMessage"),
- true,
- localize("teamstoolkit.migrateTeamsTabApp.upgrade")
- );
- const userCancelError = new UserError(
- ExtensionSource,
- ExtensionErrors.UserCancel,
- localize("teamstoolkit.common.userCancel")
- );
- if (
- selection.isErr() ||
- selection.value !== localize("teamstoolkit.migrateTeamsTabApp.upgrade")
- ) {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, userCancelError);
- return ok(null);
- }
- const selectFolderConfig: SelectFolderConfig = {
- name: localize("teamstoolkit.migrateTeamsTabApp.selectFolderConfig.name"),
- title: localize("teamstoolkit.migrateTeamsTabApp.selectFolderConfig.title"),
- };
- const selectFolderResult = await VS_CODE_UI.selectFolder(selectFolderConfig);
- if (selectFolderResult.isErr() || selectFolderResult.value.type !== "success") {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, userCancelError);
- return ok(null);
- }
- const tabAppPath = selectFolderResult.value.result as string;
-
- const progressBar = VS_CODE_UI.createProgressBar(
- localize("teamstoolkit.migrateTeamsTabApp.progressTitle"),
- 2
- );
- await progressBar.start();
-
- const migrationHandler = new TeamsAppMigrationHandler(tabAppPath);
- let result: Result = ok(null);
- let packageUpdated: Result = ok(true);
- let updateFailedFiles: string[] = [];
- try {
- // Update package.json to use @microsoft/teams-js v2
- await progressBar.next(localize("teamstoolkit.migrateTeamsTabApp.updatingPackageJson"));
- VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsTabApp.updatingPackageJson"));
- packageUpdated = await migrationHandler.updatePackageJson();
- if (packageUpdated.isErr()) {
- throw packageUpdated.error;
- } else if (!packageUpdated.value) {
- // no change in package.json, show warning.
- const warningMessage = util.format(
- localize("teamstoolkit.migrateTeamsTabApp.updatePackageJsonWarning"),
- path.join(tabAppPath, "package.json")
- );
- VsCodeLogInstance.warning(warningMessage);
- void VS_CODE_UI.showMessage("warn", warningMessage, false, "OK");
- } else {
- // Update codes to use @microsoft/teams-js v2
- await progressBar.next(localize("teamstoolkit.migrateTeamsTabApp.updatingCodes"));
- VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsTabApp.updatingCodes"));
- const failedFiles = await migrationHandler.updateCodes();
- if (failedFiles.isErr()) {
- throw failedFiles.error;
- } else {
- updateFailedFiles = failedFiles.value;
- if (failedFiles.value.length > 0) {
- VsCodeLogInstance.warning(
- util.format(
- localize("teamstoolkit.migrateTeamsTabApp.updateCodesErrorOutput"),
- failedFiles.value.length,
- failedFiles.value.join(", ")
- )
- );
- void VS_CODE_UI.showMessage(
- "warn",
- util.format(
- localize("teamstoolkit.migrateTeamsTabApp.updateCodesErrorMessage"),
- failedFiles.value.length,
- failedFiles.value[0]
- ),
- false,
- "OK"
- );
- }
- }
- }
- } catch (error) {
- result = wrapError(error as Error);
- }
-
- if (result.isErr()) {
- await progressBar.end(false);
- void showError(result.error);
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, result.error);
- } else {
- await progressBar.end(true);
- if (!packageUpdated.isErr() && packageUpdated.value) {
- void VS_CODE_UI.showMessage(
- "info",
- util.format(localize("teamstoolkit.migrateTeamsTabApp.success"), tabAppPath),
- false
- );
- }
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsTabApp, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- [TelemetryProperty.UpdateFailedFiles]: updateFailedFiles.length.toString(),
- });
- }
- return result;
-}
-
-export async function migrateTeamsManifestHandler(): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsManifestStart);
- const selection = await VS_CODE_UI.showMessage(
- "warn",
- localize("teamstoolkit.migrateTeamsManifest.warningMessage"),
- true,
- localize("teamstoolkit.migrateTeamsManifest.upgrade")
- );
- const userCancelError = new UserError(
- ExtensionSource,
- ExtensionErrors.UserCancel,
- localize("teamstoolkit.common.userCancel")
- );
- if (
- selection.isErr() ||
- selection.value !== localize("teamstoolkit.migrateTeamsManifest.upgrade")
- ) {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, userCancelError);
- return ok(null);
- }
- const selectFileConfig: SelectFileConfig = {
- name: localize("teamstoolkit.migrateTeamsManifest.selectFileConfig.name"),
- title: localize("teamstoolkit.migrateTeamsManifest.selectFileConfig.title"),
- };
- const selectFileResult = await VS_CODE_UI.selectFile(selectFileConfig);
- if (selectFileResult.isErr() || selectFileResult.value.type !== "success") {
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, userCancelError);
- return ok(null);
- }
- const manifestPath = selectFileResult.value.result as string;
-
- const progressBar = VS_CODE_UI.createProgressBar(
- localize("teamstoolkit.migrateTeamsManifest.progressTitle"),
- 1
- );
- await progressBar.start();
-
- const migrationHandler = new TeamsAppMigrationHandler(manifestPath);
- let result: Result = ok(null);
-
- try {
- // Update Teams manifest
- await progressBar.next(localize("teamstoolkit.migrateTeamsManifest.updateManifest"));
- VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsManifest.updateManifest"));
- result = await migrationHandler.updateManifest();
- if (result.isErr()) {
- throw result.error;
- }
- } catch (error) {
- result = wrapError(error as Error);
- }
-
- if (result.isErr()) {
- await progressBar.end(false);
- void showError(result.error);
- ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, result.error);
- } else {
- await progressBar.end(true);
- void VS_CODE_UI.showMessage(
- "info",
- util.format(localize("teamstoolkit.migrateTeamsManifest.success"), manifestPath),
- false
- );
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsManifest, {
- [TelemetryProperty.Success]: TelemetrySuccess.Yes,
- });
- }
- return result;
-}
-
-export async function openLifecycleTreeview(args?: any[]) {
- ExtTelemetry.sendTelemetryEvent(
- TelemetryEvent.ClickOpenLifecycleTreeview,
- getTriggerFromProperty(args)
- );
- if (isTeamsFxProject) {
- await vscode.commands.executeCommand("teamsfx-lifecycle.focus");
- } else {
- await vscode.commands.executeCommand("workbench.view.extension.teamsfx");
- }
-}
-
-export async function updateAadAppManifest(args: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.DeployAadManifestStart);
- const inputs = getSystemInputs();
- return await runCommand(Stage.deployAad, inputs);
-}
-
-export async function selectTutorialsHandler(
- ...args: unknown[]
-): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ViewGuidedTutorials, getTriggerFromProperty(args));
- const config: SingleSelectConfig = {
- name: "tutorialName",
- title: localize("teamstoolkit.commandsTreeViewProvider.guideTitle"),
- options: isSPFxProject
- ? [
- {
- id: "cicdPipeline",
- label: `${localize("teamstoolkit.guides.cicdPipeline.label")}`,
- detail: localize("teamstoolkit.guides.cicdPipeline.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-add-cicd-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- ]
- : [
- {
- id: "cardActionResponse",
- label: `${localize("teamstoolkit.guides.cardActionResponse.label")}`,
- detail: localize("teamstoolkit.guides.cardActionResponse.detail"),
- groupName: localize("teamstoolkit.guide.scenario"),
- data: "https://aka.ms/teamsfx-workflow-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "sendNotification",
- label: `${localize("teamstoolkit.guides.sendNotification.label")}`,
- detail: localize("teamstoolkit.guides.sendNotification.detail"),
- groupName: localize("teamstoolkit.guide.scenario"),
- data: "https://aka.ms/teamsfx-notification-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "commandAndResponse",
- label: `${localize("teamstoolkit.guides.commandAndResponse.label")}`,
- detail: localize("teamstoolkit.guides.commandAndResponse.detail"),
- groupName: localize("teamstoolkit.guide.scenario"),
- data: "https://aka.ms/teamsfx-command-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "dashboardApp",
- label: `${localize("teamstoolkit.guides.dashboardApp.label")}`,
- detail: localize("teamstoolkit.guides.dashboardApp.detail"),
- groupName: localize("teamstoolkit.guide.scenario"),
- data: "https://aka.ms/teamsfx-dashboard-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addTab",
- label: `${localize("teamstoolkit.guides.addTab.label")}`,
- detail: localize("teamstoolkit.guides.addTab.detail"),
- groupName: localize("teamstoolkit.guide.capability"),
- data: "https://aka.ms/teamsfx-add-tab",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addBot",
- label: `${localize("teamstoolkit.guides.addBot.label")}`,
- detail: localize("teamstoolkit.guides.addBot.detail"),
- groupName: localize("teamstoolkit.guide.capability"),
- data: "https://aka.ms/teamsfx-add-bot",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addME",
- label: `${localize("teamstoolkit.guides.addME.label")}`,
- detail: localize("teamstoolkit.guides.addME.detail"),
- groupName: localize("teamstoolkit.guide.capability"),
- data: "https://aka.ms/teamsfx-add-message-extension",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- ...[
- {
- id: "addOutlookAddin",
- label: `${localize("teamstoolkit.guides.addOutlookAddin.label")}`,
- detail: localize("teamstoolkit.guides.addOutlookAddin.detail"),
- groupName: localize("teamstoolkit.guide.capability"),
- data: "https://aka.ms/teamsfx-add-outlook-add-in",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- ],
- {
- id: "addSso",
- label: `${localize("teamstoolkit.guides.addSso.label")}`,
- detail: localize("teamstoolkit.guides.addSso.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-add-sso-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "connectApi",
- label: `${localize("teamstoolkit.guides.connectApi.label")}`,
- detail: localize("teamstoolkit.guides.connectApi.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-add-api-connection-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "cicdPipeline",
- label: `${localize("teamstoolkit.guides.cicdPipeline.label")}`,
- detail: localize("teamstoolkit.guides.cicdPipeline.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-add-cicd-new",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "mobilePreview",
- label: `${localize("teamstoolkit.guides.mobilePreview.label")}`,
- detail: localize("teamstoolkit.guides.mobilePreview.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-mobile",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "multiTenant",
- label: `${localize("teamstoolkit.guides.multiTenant.label")}`,
- detail: localize("teamstoolkit.guides.multiTenant.detail"),
- groupName: localize("teamstoolkit.guide.development"),
- data: "https://aka.ms/teamsfx-multi-tenant",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addAzureFunction",
- label: localize("teamstoolkit.guides.addAzureFunction.label"),
- detail: localize("teamstoolkit.guides.addAzureFunction.detail"),
- groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
- data: "https://aka.ms/teamsfx-add-azure-function",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addAzureSql",
- label: localize("teamstoolkit.guides.addAzureSql.label"),
- detail: localize("teamstoolkit.guides.addAzureSql.detail"),
- groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
- data: "https://aka.ms/teamsfx-add-azure-sql",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addAzureAPIM",
- label: localize("teamstoolkit.guides.addAzureAPIM.label"),
- detail: localize("teamstoolkit.guides.addAzureAPIM.detail"),
- groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
- data: "https://aka.ms/teamsfx-add-azure-apim",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- {
- id: "addAzureKeyVault",
- label: localize("teamstoolkit.guides.addAzureKeyVault.label"),
- detail: localize("teamstoolkit.guides.addAzureKeyVault.detail"),
- groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
- data: "https://aka.ms/teamsfx-add-azure-keyvault",
- buttons: [
- {
- iconPath: "file-symlink-file",
- tooltip: localize("teamstoolkit.guide.tooltip.github"),
- command: "fx-extension.openTutorial",
- },
- ],
- },
- ],
- returnObject: true,
- };
- if (TreatmentVariableValue.inProductDoc && !isSPFxProject) {
- (config.options as StaticOptions).splice(0, 1, {
- id: "cardActionResponse",
- label: `${localize("teamstoolkit.guides.cardActionResponse.label")}`,
- description: localize("teamstoolkit.common.recommended"),
- detail: localize("teamstoolkit.guides.cardActionResponse.detail"),
- groupName: localize("teamstoolkit.guide.scenario"),
- data: "https://aka.ms/teamsfx-card-action-response",
- buttons: [
- {
- iconPath: "file-code",
- tooltip: localize("teamstoolkit.guide.tooltip.inProduct"),
- command: "fx-extension.openTutorial",
- },
- ],
- });
- }
-
- const selectedTutorial = await VS_CODE_UI.selectOption(config);
- if (selectedTutorial.isErr()) {
- return err(selectedTutorial.error);
- } else {
- const tutorial = selectedTutorial.value.result as OptionItem;
- return openTutorialHandler([TelemetryTriggerFrom.Auto, tutorial]);
- }
-}
-
-export function openTutorialHandler(args?: any[]): Promise> {
- if (!args || args.length !== 2) {
- // should never happen
- return Promise.resolve(ok(null));
- }
- const tutorial = args[1] as OptionItem;
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenTutorial, {
- ...getTriggerFromProperty(args),
- [TelemetryProperty.TutorialName]: tutorial.id,
- });
- if (
- TreatmentVariableValue.inProductDoc &&
- (tutorial.id === "cardActionResponse" || tutorial.data === "cardActionResponse")
- ) {
- WebviewPanel.createOrShow(PanelType.RespondToCardActions);
- return Promise.resolve(ok(null));
- }
- return VS_CODE_UI.openUrl(tutorial.data as string);
-}
-
-export async function azureAccountSignOutHelpHandler(
- args?: any[]
-): Promise> {
- return Promise.resolve(ok(false));
-}
-
-export async function signinM365Callback(...args: unknown[]): Promise> {
- let node: M365AccountNode | undefined;
- if (args && args.length > 1) {
- node = args[1] as M365AccountNode;
- if (node && node.status === AccountItemStatus.SignedIn) {
- return ok(null);
- }
- }
-
- const triggerFrom = getTriggerFromProperty(args);
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.LoginClick, {
- [TelemetryProperty.AccountType]: AccountType.M365,
- ...triggerFrom,
- });
-
- const tokenRes = await tools.tokenProvider.m365TokenProvider.getJsonObject({
- scopes: AppStudioScopes,
- showDialog: true,
- });
- const token = tokenRes.isOk() ? tokenRes.value : undefined;
- if (token !== undefined && node) {
- node.setSignedIn((token as any).upn ? (token as any).upn : "");
- }
-
- await envTreeProviderInstance.refreshRemoteEnvWarning();
- return ok(null);
-}
-
-export async function refreshSideloadingCallback(args?: any[]): Promise> {
- const status = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
- if (status.isOk() && status.value.token !== undefined) {
- accountTreeViewProviderInstance.m365AccountNode.updateChecks(status.value.token, true, false);
- }
-
- return ok(null);
-}
-
-export async function refreshCopilotCallback(args?: any[]): Promise> {
- const status = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
- if (status.isOk() && status.value.token !== undefined) {
- accountTreeViewProviderInstance.m365AccountNode.updateChecks(status.value.token, false, true);
- }
-
- return ok(null);
-}
-
-export async function signinAzureCallback(...args: unknown[]): Promise> {
- let node: AzureAccountNode | undefined;
- if (args && args.length > 1) {
- node = args[1] as AzureAccountNode;
- if (node && node.status === AccountItemStatus.SignedIn) {
- return ok(null);
- }
- }
-
- if (azureAccountManager.getAccountInfo() === undefined) {
- // make sure user has not logged in
- const triggerFrom = getTriggerFromProperty(args);
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.LoginClick, {
- [TelemetryProperty.AccountType]: AccountType.Azure,
- ...triggerFrom,
- });
- }
- try {
- await azureAccountManager.getIdentityCredentialAsync(true);
- } catch (error) {
- if (!isUserCancelError(error)) {
- return err(error);
- }
- }
- return ok(null);
-}
-
-export async function selectSubscriptionCallback(args?: any[]): Promise> {
- tools.telemetryReporter?.sendTelemetryEvent(TelemetryEvent.SelectSubscription, {
- [TelemetryProperty.TriggerFrom]: args
- ? TelemetryTriggerFrom.TreeView
- : TelemetryTriggerFrom.Other,
- });
- const askSubRes = await askSubscription(
- tools.tokenProvider.azureAccountProvider,
- VS_CODE_UI,
- undefined
- );
- if (askSubRes.isErr()) return err(askSubRes.error);
- await azureAccountManager.setSubscription(askSubRes.value.subscriptionId);
- return ok(null);
-}
-
-/**
- * scaffold based on app id from Developer Portal
- */
-export async function scaffoldFromDeveloperPortalHandler(
- ...args: any[]
-): Promise> {
- if (!args || args.length < 1) {
- // should never happen
- return ok(null);
- }
-
- const appId = args[0];
- const properties: { [p: string]: string } = {
- teamsAppId: appId,
- };
-
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.HandleUrlFromDeveloperProtalStart, properties);
- const loginHint = args.length < 2 ? undefined : args[1];
- const progressBar = VS_CODE_UI.createProgressBar(
- localize("teamstoolkit.devPortalIntegration.checkM365Account.progressTitle"),
- 1
- );
-
- await progressBar.start();
- let token = undefined;
- try {
- const tokenRes = await M365TokenInstance.signInWhenInitiatedFromTdp(
- { scopes: AppStudioScopes },
- loginHint
- );
- if (tokenRes.isErr()) {
- if ((tokenRes.error as any).displayMessage) {
- void window.showErrorMessage((tokenRes.error as any).displayMessage);
- } else {
- void vscode.window.showErrorMessage(
- localize("teamstoolkit.devPortalIntegration.generalError.message")
- );
- }
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.HandleUrlFromDeveloperProtal,
- tokenRes.error,
- properties
- );
- await progressBar.end(false);
- return err(tokenRes.error);
- }
- token = tokenRes.value;
-
- // set region
- const AuthSvcTokenRes = await M365TokenInstance.getAccessToken({ scopes: AuthSvcScopes });
- if (AuthSvcTokenRes.isOk()) {
- await teamsDevPortalClient.setRegionEndpointByToken(AuthSvcTokenRes.value);
- }
-
- await progressBar.end(true);
- } catch (e) {
- void vscode.window.showErrorMessage(
- localize("teamstoolkit.devPortalIntegration.generalError.message")
- );
- await progressBar.end(false);
- const error = assembleError(e);
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.HandleUrlFromDeveloperProtal,
- error,
- properties
- );
- return err(error);
- }
-
- let appDefinition;
- try {
- appDefinition = await teamsDevPortalClient.getApp(token, appId);
- } catch (error: any) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.HandleUrlFromDeveloperProtal,
- error,
- properties
- );
- void vscode.window.showErrorMessage(
- localize("teamstoolkit.devPortalIntegration.getTeamsAppError.message")
- );
- return err(error);
- }
-
- const res = await createNewProjectHandler({ teamsAppFromTdp: appDefinition });
-
- if (res.isErr()) {
- ExtTelemetry.sendTelemetryErrorEvent(
- TelemetryEvent.HandleUrlFromDeveloperProtal,
- res.error,
- properties
- );
- return err(res.error);
- }
-
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.HandleUrlFromDeveloperProtal, properties);
- return ok(null);
-}
-
-export async function projectVersionCheck() {
- return await core.projectVersionCheck(getSystemInputs());
-}
diff --git a/packages/vscode-extension/src/handlers/aadManifestHandlers.ts b/packages/vscode-extension/src/handlers/aadManifestHandlers.ts
new file mode 100644
index 0000000000..3c2ea9276a
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/aadManifestHandlers.ts
@@ -0,0 +1,107 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as vscode from "vscode";
+import * as util from "util";
+import * as fs from "fs-extra";
+import {
+ Result,
+ FxError,
+ err,
+ Stage,
+ BuildFolderName,
+ ok,
+ SystemError,
+} from "@microsoft/teamsfx-api";
+import { isValidProject, InvalidProjectError, MetadataV3 } from "@microsoft/teamsfx-core";
+import { showError } from "../error/common";
+import { ExtensionSource } from "../error/error";
+import { workspaceUri } from "../globalVariables";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetrySuccess,
+} from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { runCommand } from "./sharedOpts";
+import { askTargetEnvironment } from "./envHandlers";
+
+export async function openPreviewAadFileHandler(args: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.PreviewAadManifestFile,
+ getTriggerFromProperty(args)
+ );
+ const workspacePath = workspaceUri?.fsPath;
+ const validProject = isValidProject(workspacePath);
+ if (!validProject) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.PreviewAadManifestFile,
+ new InvalidProjectError(workspacePath || "")
+ );
+ return err(new InvalidProjectError(workspacePath || ""));
+ }
+
+ const selectedEnv = await askTargetEnvironment();
+ if (selectedEnv.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, selectedEnv.error);
+ return err(selectedEnv.error);
+ }
+ const envName = selectedEnv.value;
+
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.BuildAadManifestStart,
+ getTriggerFromProperty(args)
+ );
+ const inputs = getSystemInputs();
+ inputs.env = envName;
+ const res = await runCommand(Stage.buildAad, inputs);
+
+ if (res.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, res.error);
+ return err(res.error);
+ }
+
+ const manifestFile = `${workspacePath as string}/${BuildFolderName}/aad.${envName}.json`;
+
+ if (fs.existsSync(manifestFile)) {
+ void vscode.workspace.openTextDocument(manifestFile).then((document) => {
+ void vscode.window.showTextDocument(document);
+ });
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.PreviewAadManifestFile, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ });
+ return ok(manifestFile);
+ } else {
+ const error = new SystemError(
+ ExtensionSource,
+ "FileNotFound",
+ util.format(localize("teamstoolkit.handlers.fileNotFound"), manifestFile)
+ );
+ void showError(error);
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.PreviewAadManifestFile, error);
+ return err(error);
+ }
+}
+
+export function editAadManifestTemplateHandler(args: any[]) {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.EditAadManifestTemplate,
+ getTriggerFromProperty(args && args.length > 1 ? [args[1]] : undefined)
+ );
+ if (args && args.length > 1) {
+ const workspacePath = workspaceUri?.fsPath;
+ const manifestPath = `${workspacePath as string}/${MetadataV3.aadManifestFileName}`;
+ void vscode.workspace.openTextDocument(manifestPath).then((document) => {
+ void vscode.window.showTextDocument(document);
+ });
+ }
+}
+
+export async function updateAadAppManifestHandler(args: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.DeployAadManifestStart);
+ const inputs = getSystemInputs();
+ return await runCommand(Stage.deployAad, inputs);
+}
diff --git a/packages/vscode-extension/src/handlers/accounts/accountHandlers.ts b/packages/vscode-extension/src/handlers/accounts/accountHandlers.ts
new file mode 100644
index 0000000000..e482ecebaf
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/accounts/accountHandlers.ts
@@ -0,0 +1,148 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { QuickPickItem, window } from "vscode";
+import { FxError, OptionItem, Result, SingleSelectConfig, ok } from "@microsoft/teamsfx-api";
+import { Correlator, AppStudioScopes } from "@microsoft/teamsfx-core";
+import { ExtTelemetry } from "../../telemetry/extTelemetry";
+import { AccountType, TelemetryEvent, TelemetryProperty } from "../../telemetry/extTelemetryEvents";
+import { signInAzure, signOutAzure, signInM365, signOutM365 } from "../../utils/accountUtils";
+import { localize } from "../../utils/localizeUtils";
+import { getTriggerFromProperty } from "../../utils/telemetryUtils";
+import azureAccountManager from "../../commonlib/azureLogin";
+import M365TokenInstance from "../../commonlib/m365Login";
+import { VS_CODE_UI } from "../../qm/vsc_ui";
+
+export interface VscQuickPickItem extends QuickPickItem {
+ /**
+ * Current id of the option item.
+ */
+ id: string;
+ function: () => Promise;
+}
+
+export async function createAccountHandler(args: any[]): Promise {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccountStart, getTriggerFromProperty(args));
+ const m365Option: OptionItem = {
+ id: "createAccountM365",
+ label: `$(add) ${localize("teamstoolkit.commands.createAccount.m365")}`,
+ description: localize("teamstoolkit.commands.createAccount.requireSubscription"),
+ };
+ const azureOption: OptionItem = {
+ id: "createAccountAzure",
+ label: `$(add) ${localize("teamstoolkit.commands.createAccount.azure")}`,
+ description: localize("teamstoolkit.commands.createAccount.free"),
+ };
+ const option: SingleSelectConfig = {
+ name: "CreateAccounts",
+ title: localize("teamstoolkit.commands.createAccount.title"),
+ options: [m365Option, azureOption],
+ };
+ const result = await VS_CODE_UI.selectOption(option);
+ if (result.isOk()) {
+ if (result.value.result === m365Option.id) {
+ await VS_CODE_UI.openUrl("https://developer.microsoft.com/microsoft-365/dev-program");
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccount, {
+ [TelemetryProperty.AccountType]: AccountType.M365,
+ ...getTriggerFromProperty(args),
+ });
+ } else if (result.value.result === azureOption.id) {
+ await VS_CODE_UI.openUrl("https://azure.microsoft.com/en-us/free/");
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateAccount, {
+ [TelemetryProperty.AccountType]: AccountType.Azure,
+ ...getTriggerFromProperty(args),
+ });
+ }
+ } else {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.CreateAccount, result.error, {
+ ...getTriggerFromProperty(args),
+ });
+ }
+ return;
+}
+
+export async function cmpAccountsHandler(args: any[]) {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageAccount, getTriggerFromProperty(args));
+ const signInAzureOption: VscQuickPickItem = {
+ id: "signInAzure",
+ label: localize("teamstoolkit.handlers.signInAzure"),
+ function: () => signInAzure(),
+ };
+
+ const signOutAzureOption: VscQuickPickItem = {
+ id: "signOutAzure",
+ label: localize("teamstoolkit.handlers.signOutOfAzure"),
+ function: async () =>
+ await Correlator.run(async () => {
+ await signOutAzure(false);
+ }),
+ };
+
+ const signInM365Option: VscQuickPickItem = {
+ id: "signinM365",
+ label: localize("teamstoolkit.handlers.signIn365"),
+ function: () => signInM365(),
+ };
+
+ const signOutM365Option: VscQuickPickItem = {
+ id: "signOutM365",
+ label: localize("teamstoolkit.handlers.signOutOfM365"),
+ function: async () =>
+ await Correlator.run(async () => {
+ await signOutM365(false);
+ }),
+ };
+
+ const createAccountsOption: VscQuickPickItem = {
+ id: "createAccounts",
+ label: `$(add) ${localize("teamstoolkit.commands.createAccount.title")}`,
+ function: async () => {
+ await Correlator.run(() => createAccountHandler([]));
+ },
+ };
+
+ const quickPick = window.createQuickPick();
+ const quickItemOptionArray: VscQuickPickItem[] = [];
+
+ const m365AccountRes = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
+ const m365Account = m365AccountRes.isOk() ? m365AccountRes.value : undefined;
+ if (m365Account && m365Account.status === "SignedIn") {
+ const accountInfo = m365Account.accountInfo;
+ const email = (accountInfo as any).upn ? (accountInfo as any).upn : undefined;
+ if (email !== undefined) {
+ signOutM365Option.label = signOutM365Option.label.concat(email);
+ }
+ quickItemOptionArray.push(signOutM365Option);
+ } else {
+ quickItemOptionArray.push(signInM365Option);
+ }
+
+ const azureAccount = await azureAccountManager.getStatus();
+ if (azureAccount.status === "SignedIn") {
+ const accountInfo = azureAccount.accountInfo;
+ const email = (accountInfo as any).email || (accountInfo as any).upn;
+ if (email !== undefined) {
+ signOutAzureOption.label = signOutAzureOption.label.concat(email);
+ }
+ quickItemOptionArray.push(signOutAzureOption);
+ } else {
+ quickItemOptionArray.push(signInAzureOption);
+ }
+
+ quickItemOptionArray.push(createAccountsOption);
+ quickPick.items = quickItemOptionArray;
+ quickPick.onDidChangeSelection((selection) => {
+ if (selection[0]) {
+ (selection[0] as VscQuickPickItem).function().catch(console.error);
+ quickPick.hide();
+ }
+ });
+ quickPick.onDidHide(() => quickPick.dispose());
+ quickPick.show();
+}
+
+export async function azureAccountSignOutHelpHandler(
+ args?: any[]
+): Promise> {
+ return Promise.resolve(ok(false));
+}
diff --git a/packages/vscode-extension/src/handlers/checkSideloading.ts b/packages/vscode-extension/src/handlers/accounts/checkAccessCallback.ts
similarity index 53%
rename from packages/vscode-extension/src/handlers/checkSideloading.ts
rename to packages/vscode-extension/src/handlers/accounts/checkAccessCallback.ts
index f8224b7b60..4d9d0270b5 100644
--- a/packages/vscode-extension/src/handlers/checkSideloading.ts
+++ b/packages/vscode-extension/src/handlers/accounts/checkAccessCallback.ts
@@ -2,16 +2,33 @@
// Licensed under the MIT license.
import { Result, FxError, ok } from "@microsoft/teamsfx-api";
-import { PanelType } from "../controls/PanelType";
-import { WebviewPanel } from "../controls/webviewPanel";
-import { VS_CODE_UI } from "../qm/vsc_ui";
-import { ExtTelemetry } from "../telemetry/extTelemetry";
+import { localize } from "../../utils/localizeUtils";
+import { VS_CODE_UI } from "../../qm/vsc_ui";
+import { ExtTelemetry } from "../../telemetry/extTelemetry";
import {
TelemetryEvent,
TelemetryProperty,
TelemetryTriggerFrom,
-} from "../telemetry/extTelemetryEvents";
-import { localize } from "../utils/localizeUtils";
+} from "../../telemetry/extTelemetryEvents";
+import { WebviewPanel } from "../../controls/webviewPanel";
+import { PanelType } from "../../controls/PanelType";
+
+export async function checkCopilotCallback(args?: any[]): Promise> {
+ VS_CODE_UI.showMessage(
+ "warn",
+ localize("teamstoolkit.accountTree.copilotMessage"),
+ false,
+ localize("teamstoolkit.accountTree.copilotEnroll")
+ )
+ .then(async (result) => {
+ if (result.isOk() && result.value === localize("teamstoolkit.accountTree.copilotEnroll")) {
+ await VS_CODE_UI.openUrl("https://aka.ms/PluginsEarlyAccess");
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenCopilotEnroll);
+ }
+ })
+ .catch((_error) => {});
+ return Promise.resolve(ok(null));
+}
export function checkSideloadingCallback(args?: any[]): Promise> {
VS_CODE_UI.showMessage(
diff --git a/packages/vscode-extension/src/handlers/checkCopilotAccess.ts b/packages/vscode-extension/src/handlers/accounts/checkCopilotAccess.ts
similarity index 87%
rename from packages/vscode-extension/src/handlers/checkCopilotAccess.ts
rename to packages/vscode-extension/src/handlers/accounts/checkCopilotAccess.ts
index f200f4f0d6..cf4f7c5247 100644
--- a/packages/vscode-extension/src/handlers/checkCopilotAccess.ts
+++ b/packages/vscode-extension/src/handlers/accounts/checkCopilotAccess.ts
@@ -2,11 +2,10 @@
// Licensed under the MIT license.
import * as vscode from "vscode";
-import M365TokenInstance from "../commonlib/m365Login";
-import { signedIn } from "../commonlib/common/constant";
-import { localize } from "../utils/localizeUtils";
-import VsCodeLogInstance from "../commonlib/log";
-import { signInM365 } from "../handlers";
+import M365TokenInstance from "../../commonlib/m365Login";
+import { signedIn } from "../../commonlib/common/constant";
+import { localize } from "../../utils/localizeUtils";
+import VsCodeLogInstance from "../../commonlib/log";
import { FxError, Result, err, ok } from "@microsoft/teamsfx-api";
import {
AppStudioScopes,
@@ -14,7 +13,8 @@ import {
PackageService,
SummaryConstant,
} from "@microsoft/teamsfx-core";
-import { wrapError } from "../error/common";
+import { wrapError } from "../../error/common";
+import { signInM365 } from "../../utils/accountUtils";
export async function checkCopilotAccessHandler(): Promise> {
// check m365 login status, if not logged in, pop up a message
diff --git a/packages/vscode-extension/src/handlers/accounts/refreshAccessHandlers.ts b/packages/vscode-extension/src/handlers/accounts/refreshAccessHandlers.ts
new file mode 100644
index 0000000000..a0a864c994
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/accounts/refreshAccessHandlers.ts
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { Result, FxError, ok } from "@microsoft/teamsfx-api";
+import { AppStudioScopes } from "@microsoft/teamsfx-core";
+import accountTreeViewProviderInstance from "../../treeview/account/accountTreeViewProvider";
+import M365TokenInstance from "../../commonlib/m365Login";
+
+export async function refreshSideloadingCallback(args?: any[]): Promise> {
+ const status = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
+ if (status.isOk() && status.value.token !== undefined) {
+ accountTreeViewProviderInstance.m365AccountNode.updateChecks(status.value.token, true, false);
+ }
+
+ return ok(null);
+}
+
+export async function refreshCopilotCallback(args?: any[]): Promise> {
+ const status = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
+ if (status.isOk() && status.value.token !== undefined) {
+ accountTreeViewProviderInstance.m365AccountNode.updateChecks(status.value.token, false, true);
+ }
+
+ return ok(null);
+}
diff --git a/packages/vscode-extension/src/handlers/accounts/signinAccountHandlers.ts b/packages/vscode-extension/src/handlers/accounts/signinAccountHandlers.ts
new file mode 100644
index 0000000000..c28add735d
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/accounts/signinAccountHandlers.ts
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { Result, FxError, ok, err } from "@microsoft/teamsfx-api";
+import { AppStudioScopes, isUserCancelError } from "@microsoft/teamsfx-core";
+import { tools } from "../../globalVariables";
+import { ExtTelemetry } from "../../telemetry/extTelemetry";
+import { AccountType, TelemetryEvent, TelemetryProperty } from "../../telemetry/extTelemetryEvents";
+import { AzureAccountNode } from "../../treeview/account/azureNode";
+import { AccountItemStatus } from "../../treeview/account/common";
+import { M365AccountNode } from "../../treeview/account/m365Node";
+import { getTriggerFromProperty } from "../../utils/telemetryUtils";
+import envTreeProviderInstance from "../../treeview/environmentTreeViewProvider";
+import azureAccountManager from "../../commonlib/azureLogin";
+
+export async function signinM365Callback(...args: unknown[]): Promise> {
+ let node: M365AccountNode | undefined;
+ if (args && args.length > 1) {
+ node = args[1] as M365AccountNode;
+ if (node && node.status === AccountItemStatus.SignedIn) {
+ return ok(null);
+ }
+ }
+
+ const triggerFrom = getTriggerFromProperty(args);
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.LoginClick, {
+ [TelemetryProperty.AccountType]: AccountType.M365,
+ ...triggerFrom,
+ });
+
+ const tokenRes = await tools.tokenProvider.m365TokenProvider.getJsonObject({
+ scopes: AppStudioScopes,
+ showDialog: true,
+ });
+ const token = tokenRes.isOk() ? tokenRes.value : undefined;
+ if (token !== undefined && node) {
+ node.setSignedIn((token as any).upn ? (token as any).upn : "");
+ }
+
+ await envTreeProviderInstance.reloadEnvironments();
+ return ok(null);
+}
+
+export async function signinAzureCallback(...args: unknown[]): Promise> {
+ let node: AzureAccountNode | undefined;
+ if (args && args.length > 1) {
+ node = args[1] as AzureAccountNode;
+ if (node && node.status === AccountItemStatus.SignedIn) {
+ return ok(null);
+ }
+ }
+
+ if (azureAccountManager.getAccountInfo() === undefined) {
+ // make sure user has not logged in
+ const triggerFrom = getTriggerFromProperty(args);
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.LoginClick, {
+ [TelemetryProperty.AccountType]: AccountType.Azure,
+ ...triggerFrom,
+ });
+ }
+ try {
+ await azureAccountManager.getIdentityCredentialAsync(true);
+ } catch (error) {
+ if (!isUserCancelError(error)) {
+ return err(error);
+ }
+ }
+ return ok(null);
+}
diff --git a/packages/vscode-extension/src/handlers/activate.ts b/packages/vscode-extension/src/handlers/activate.ts
new file mode 100644
index 0000000000..24fca0910a
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/activate.ts
@@ -0,0 +1,190 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as path from "path";
+import {
+ Result,
+ Void,
+ FxError,
+ ok,
+ M365TokenProvider,
+ CoreCallbackEvent,
+ err,
+ ConfigFolderName,
+} from "@microsoft/teamsfx-api";
+import {
+ isValidProject,
+ getProjectMetadata,
+ AppStudioScopes,
+ FxCore,
+} from "@microsoft/teamsfx-core";
+import { workspace, window, Uri, FileRenameEvent } from "vscode";
+import azureAccountManager from "../commonlib/azureLogin";
+import VsCodeLogInstance from "../commonlib/log";
+import M365TokenInstance from "../commonlib/m365Login";
+import commandController from "../commandController";
+import { signedIn, signedOut } from "../commonlib/common/constant";
+import { showError } from "../error/common";
+import { ExtensionSource } from "../error/error";
+import {
+ core,
+ workspaceUri,
+ setTools,
+ setCore,
+ tools,
+ setCommandIsRunning,
+} from "../globalVariables";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import envTreeProviderInstance from "../treeview/environmentTreeViewProvider";
+import { localize } from "../utils/localizeUtils";
+import { TelemetryEvent, TelemetryProperty } from "../telemetry/extTelemetryEvents";
+import { getExpService } from "../exp/index";
+import { addFileSystemWatcher } from "../utils/fileSystemWatcher";
+
+export function activate(): Result {
+ const result: Result = ok(Void);
+ const validProject = isValidProject(workspaceUri?.fsPath);
+ if (validProject) {
+ const fixedProjectSettings = getProjectMetadata(workspaceUri?.fsPath);
+ ExtTelemetry.addSharedProperty(
+ TelemetryProperty.ProjectId,
+ fixedProjectSettings?.projectId as string
+ );
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenTeamsApp, {});
+ void azureAccountManager.setStatusChangeMap(
+ "successfully-sign-in-azure",
+ (status, token, accountInfo) => {
+ if (status === signedIn) {
+ void window.showInformationMessage(localize("teamstoolkit.handlers.azureSignIn"));
+ } else if (status === signedOut) {
+ void window.showInformationMessage(localize("teamstoolkit.handlers.azureSignOut"));
+ }
+ return Promise.resolve();
+ },
+ false
+ );
+ }
+ try {
+ const m365Login: M365TokenProvider = M365TokenInstance;
+ const m365NotificationCallback = (
+ status: string,
+ token: string | undefined,
+ accountInfo: Record | undefined
+ ) => {
+ if (status === signedIn) {
+ void window.showInformationMessage(localize("teamstoolkit.handlers.m365SignIn"));
+ } else if (status === signedOut) {
+ // eslint-disable-next-line no-secrets/no-secrets
+ void window.showInformationMessage(localize("teamstoolkit.handlers.m365SignOut"));
+ }
+ return Promise.resolve();
+ };
+
+ void M365TokenInstance.setStatusChangeMap(
+ "successfully-sign-in-m365",
+ { scopes: AppStudioScopes },
+ m365NotificationCallback,
+ false
+ );
+ setTools({
+ logProvider: VsCodeLogInstance,
+ tokenProvider: {
+ azureAccountProvider: azureAccountManager,
+ m365TokenProvider: m365Login,
+ },
+ telemetryReporter: ExtTelemetry.reporter,
+ ui: VS_CODE_UI,
+ expServiceProvider: getExpService(),
+ });
+ setCore(new FxCore(tools));
+ core.on(CoreCallbackEvent.lock, async (command: string) => {
+ setCommandIsRunning(true);
+ await commandController.lockedByOperation(command);
+ });
+ core.on(CoreCallbackEvent.unlock, async (command: string) => {
+ setCommandIsRunning(false);
+ await commandController.unlockedByOperation(command);
+ });
+ const workspacePath = workspaceUri?.fsPath;
+ if (workspacePath) {
+ addFileSystemWatcher(workspacePath);
+ }
+
+ if (workspacePath) {
+ // refresh env tree when env config files added or deleted.
+ workspace.onDidCreateFiles(async (event) => {
+ await refreshEnvTreeOnEnvFileChanged(workspacePath, event.files);
+ });
+
+ workspace.onDidDeleteFiles(async (event) => {
+ await refreshEnvTreeOnEnvFileChanged(workspacePath, event.files);
+ });
+
+ workspace.onDidRenameFiles(async (event) => {
+ await refreshEnvTreeOnFilesNameChanged(workspacePath, event);
+ });
+
+ workspace.onDidSaveTextDocument(async (event) => {
+ await refreshEnvTreeOnProjectSettingFileChanged(workspacePath, event.uri.fsPath);
+ });
+ }
+ } catch (e) {
+ const FxError: FxError = {
+ name: (e as Error).name,
+ source: ExtensionSource,
+ message: (e as Error).message,
+ stack: (e as Error).stack,
+ timestamp: new Date(),
+ };
+ void showError(FxError);
+ return err(FxError);
+ }
+ return result;
+}
+
+export async function refreshEnvTreeOnFilesNameChanged(
+ workspacePath: string,
+ event: FileRenameEvent
+) {
+ const files = [];
+ for (const f of event.files) {
+ files.push(f.newUri);
+ files.push(f.oldUri);
+ }
+
+ await refreshEnvTreeOnEnvFileChanged(workspacePath, files);
+}
+
+export async function refreshEnvTreeOnEnvFileChanged(workspacePath: string, files: readonly Uri[]) {
+ let needRefresh = false;
+ for (const file of files) {
+ // check if file is env config
+ const res = await core.isEnvFile(workspacePath, file.fsPath);
+ if (res.isOk() && res.value) {
+ needRefresh = true;
+ break;
+ }
+ }
+
+ if (needRefresh) {
+ await envTreeProviderInstance.reloadEnvironments();
+ }
+}
+
+export async function refreshEnvTreeOnProjectSettingFileChanged(
+ workspacePath: string,
+ filePath: string
+) {
+ const projectSettingsPath = path.resolve(
+ workspacePath,
+ `.${ConfigFolderName}`,
+ "configs",
+ "projectSettings.json"
+ );
+
+ // check if file is project config
+ if (path.normalize(filePath) === path.normalize(projectSettingsPath)) {
+ await envTreeProviderInstance.reloadEnvironments();
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/autoOpenProjectHandler.ts b/packages/vscode-extension/src/handlers/autoOpenProjectHandler.ts
new file mode 100644
index 0000000000..723eb564b8
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/autoOpenProjectHandler.ts
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { ok } from "@microsoft/teamsfx-api";
+import { globalStateGet, globalStateUpdate } from "@microsoft/teamsfx-core";
+import { GlobalKey, CommandKey } from "../constants";
+import { workspaceUri } from "../globalVariables";
+import { TelemetryTriggerFrom } from "../telemetry/extTelemetryEvents";
+import {
+ autoInstallDependencyHandler,
+ showLocalDebugMessage,
+ ShowScaffoldingWarningSummary,
+} from "../utils/autoOpenHelper";
+import { updateProjectStatus } from "../utils/projectStatusUtils";
+import { openWelcomeHandler } from "./controlHandlers";
+import { openReadMeHandler, openSampleReadmeHandler } from "./readmeHandlers";
+
+export async function autoOpenProjectHandler(): Promise {
+ const isOpenWalkThrough = (await globalStateGet(GlobalKey.OpenWalkThrough, false)) as boolean;
+ const isOpenReadMe = (await globalStateGet(GlobalKey.OpenReadMe, "")) as string;
+ const isOpenSampleReadMe = (await globalStateGet(GlobalKey.OpenSampleReadMe, false)) as boolean;
+ const createWarnings = (await globalStateGet(GlobalKey.CreateWarnings, "")) as string;
+ const autoInstallDependency = (await globalStateGet(GlobalKey.AutoInstallDependency)) as boolean;
+ if (isOpenWalkThrough) {
+ await showLocalDebugMessage();
+ await openWelcomeHandler([TelemetryTriggerFrom.Auto]);
+ await globalStateUpdate(GlobalKey.OpenWalkThrough, false);
+
+ if (workspaceUri?.fsPath) {
+ await ShowScaffoldingWarningSummary(workspaceUri.fsPath, createWarnings);
+ await globalStateUpdate(GlobalKey.CreateWarnings, "");
+ }
+ }
+ if (isOpenReadMe === workspaceUri?.fsPath) {
+ await showLocalDebugMessage();
+ await openReadMeHandler(TelemetryTriggerFrom.Auto);
+ await updateProjectStatus(workspaceUri.fsPath, CommandKey.OpenReadMe, ok(null));
+ await globalStateUpdate(GlobalKey.OpenReadMe, "");
+
+ await ShowScaffoldingWarningSummary(workspaceUri.fsPath, createWarnings);
+ await globalStateUpdate(GlobalKey.CreateWarnings, "");
+ }
+ if (isOpenSampleReadMe) {
+ await showLocalDebugMessage();
+ await openSampleReadmeHandler([TelemetryTriggerFrom.Auto]);
+ await globalStateUpdate(GlobalKey.OpenSampleReadMe, false);
+ }
+ if (autoInstallDependency) {
+ await autoInstallDependencyHandler();
+ await globalStateUpdate(GlobalKey.AutoInstallDependency, false);
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/checkCopilotCallback.ts b/packages/vscode-extension/src/handlers/checkCopilotCallback.ts
deleted file mode 100644
index 798385626c..0000000000
--- a/packages/vscode-extension/src/handlers/checkCopilotCallback.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-import { Result, FxError, ok } from "@microsoft/teamsfx-api";
-import { VS_CODE_UI } from "../qm/vsc_ui";
-import { ExtTelemetry } from "../telemetry/extTelemetry";
-import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
-import { localize } from "../utils/localizeUtils";
-
-export async function checkCopilotCallback(args?: any[]): Promise> {
- VS_CODE_UI.showMessage(
- "warn",
- localize("teamstoolkit.accountTree.copilotMessage"),
- false,
- localize("teamstoolkit.accountTree.copilotEnroll")
- )
- .then(async (result) => {
- if (result.isOk() && result.value === localize("teamstoolkit.accountTree.copilotEnroll")) {
- await VS_CODE_UI.openUrl("https://aka.ms/PluginsEarlyAccess");
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenCopilotEnroll);
- }
- })
- .catch((_error) => {});
- return Promise.resolve(ok(null));
-}
diff --git a/packages/vscode-extension/src/handlers/collaboratorHandlers.ts b/packages/vscode-extension/src/handlers/collaboratorHandlers.ts
new file mode 100644
index 0000000000..90ba9c7ea5
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/collaboratorHandlers.ts
@@ -0,0 +1,122 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as util from "util";
+import { window } from "vscode";
+import { Result, FxError, SingleSelectConfig, Inputs } from "@microsoft/teamsfx-api";
+import { wrapError } from "../error/common";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { checkCoreNotEmpty } from "../utils/commonUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+import { processResult } from "./sharedOpts";
+import { core } from "../globalVariables";
+import VsCodeLogInstance from "../commonlib/log";
+
+export async function manageCollaboratorHandler(env?: string): Promise> {
+ let result: Result;
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageCollaboratorStart);
+
+ try {
+ const collaboratorCommandSelection: SingleSelectConfig = {
+ name: "collaborationCommand",
+ title: localize("teamstoolkit.manageCollaborator.command"),
+ options: [
+ {
+ id: "grantPermission",
+ label: localize("teamstoolkit.manageCollaborator.grantPermission.label"),
+ detail: localize("teamstoolkit.manageCollaborator.grantPermission.description"),
+ },
+ {
+ id: "listCollaborator",
+ label: localize("teamstoolkit.manageCollaborator.listCollaborator.label"),
+ detail: localize("teamstoolkit.manageCollaborator.listCollaborator.description"),
+ },
+ ],
+ returnObject: false,
+ };
+ const collaboratorCommand = await VS_CODE_UI.selectOption(collaboratorCommandSelection);
+ if (collaboratorCommand.isErr()) {
+ throw collaboratorCommand.error;
+ }
+
+ const command = collaboratorCommand.value.result;
+ switch (command) {
+ case "grantPermission":
+ result = await grantPermission(env);
+ break;
+
+ case "listCollaborator":
+ default:
+ result = await listCollaborator(env);
+ break;
+ }
+ } catch (e) {
+ result = wrapError(e);
+ }
+
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageCollaborator);
+ return result;
+}
+
+export async function grantPermission(env?: string): Promise> {
+ let result: Result;
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.GrantPermissionStart);
+
+ let inputs: Inputs | undefined;
+ try {
+ const checkCoreRes = checkCoreNotEmpty();
+ if (checkCoreRes.isErr()) {
+ throw checkCoreRes.error;
+ }
+
+ inputs = getSystemInputs();
+ inputs.env = env;
+ result = await core.grantPermission(inputs);
+ if (result.isErr()) {
+ throw result.error;
+ }
+ const grantSucceededMsg = util.format(
+ localize("teamstoolkit.handlers.grantPermissionSucceededV3"),
+ inputs.email
+ );
+
+ void window.showInformationMessage(grantSucceededMsg);
+ VsCodeLogInstance.info(grantSucceededMsg);
+ } catch (e) {
+ result = wrapError(e);
+ }
+
+ await processResult(TelemetryEvent.GrantPermission, result, inputs);
+ return result;
+}
+
+export async function listCollaborator(env?: string): Promise> {
+ let result: Result;
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ListCollaboratorStart);
+
+ let inputs: Inputs | undefined;
+ try {
+ const checkCoreRes = checkCoreNotEmpty();
+ if (checkCoreRes.isErr()) {
+ throw checkCoreRes.error;
+ }
+
+ inputs = getSystemInputs();
+ inputs.env = env;
+
+ result = await core.listCollaborator(inputs);
+ if (result.isErr()) {
+ throw result.error;
+ }
+
+ VsCodeLogInstance.outputChannel.show();
+ } catch (e) {
+ result = wrapError(e);
+ }
+
+ await processResult(TelemetryEvent.ListCollaborator, result, inputs);
+ return result;
+}
diff --git a/packages/vscode-extension/src/handlers/controlHandlers.ts b/packages/vscode-extension/src/handlers/controlHandlers.ts
new file mode 100644
index 0000000000..064634537a
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/controlHandlers.ts
@@ -0,0 +1,97 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import { FxError, Result, ok } from "@microsoft/teamsfx-api";
+import { isValidProject } from "@microsoft/teamsfx-core";
+import * as path from "path";
+import * as vscode from "vscode";
+import { PanelType } from "../controls/PanelType";
+import { WebviewPanel } from "../controls/webviewPanel";
+import { isTeamsFxProject, workspaceUri } from "../globalVariables";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetryTriggerFrom,
+ TelemetryUpdateAppReason,
+} from "../telemetry/extTelemetryEvents";
+import { openFolderInExplorer } from "../utils/commonUtils";
+import { getWalkThroughId } from "../utils/projectStatusUtils";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+
+export async function openLifecycleTreeview(args?: any[]) {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.ClickOpenLifecycleTreeview,
+ getTriggerFromProperty(args)
+ );
+ if (isTeamsFxProject) {
+ await vscode.commands.executeCommand("teamsfx-lifecycle.focus");
+ } else {
+ await vscode.commands.executeCommand("workbench.view.extension.teamsfx");
+ }
+}
+
+export async function openWelcomeHandler(...args: unknown[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.GetStarted, getTriggerFromProperty(args));
+ const data = await vscode.commands.executeCommand(
+ "workbench.action.openWalkthrough",
+ getWalkThroughId()
+ );
+ return Promise.resolve(ok(data));
+}
+
+export async function openSamplesHandler(...args: unknown[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.Samples, getTriggerFromProperty(args));
+ WebviewPanel.createOrShow(PanelType.SampleGallery, args);
+ return Promise.resolve(ok(null));
+}
+
+export function openFolderHandler(...args: unknown[]): Promise> {
+ const scheme = "file://";
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenFolder, {
+ [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Notification,
+ });
+ if (args && args.length > 0 && args[0]) {
+ let path = args[0] as string;
+ if (path.startsWith(scheme)) {
+ path = path.substring(scheme.length);
+ }
+ const uri = vscode.Uri.file(path);
+ openFolderInExplorer(uri.fsPath);
+ }
+ return Promise.resolve(ok(null));
+}
+
+export function saveTextDocumentHandler(document: vscode.TextDocumentWillSaveEvent) {
+ if (!isValidProject(workspaceUri?.fsPath)) {
+ return;
+ }
+
+ let reason: TelemetryUpdateAppReason | undefined = undefined;
+ switch (document.reason) {
+ case vscode.TextDocumentSaveReason.Manual:
+ reason = TelemetryUpdateAppReason.Manual;
+ break;
+ case vscode.TextDocumentSaveReason.AfterDelay:
+ reason = TelemetryUpdateAppReason.AfterDelay;
+ break;
+ case vscode.TextDocumentSaveReason.FocusOut:
+ reason = TelemetryUpdateAppReason.FocusOut;
+ break;
+ }
+
+ let curDirectory = path.dirname(document.document.fileName);
+ while (curDirectory) {
+ if (isValidProject(curDirectory)) {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.UpdateTeamsApp, {
+ [TelemetryProperty.UpdateTeamsAppReason]: reason,
+ });
+ return;
+ }
+
+ if (curDirectory === path.join(curDirectory, "..")) {
+ break;
+ }
+ curDirectory = path.join(curDirectory, "..");
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/debugHandlers.ts b/packages/vscode-extension/src/handlers/debugHandlers.ts
new file mode 100644
index 0000000000..4d824cd3cd
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/debugHandlers.ts
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as vscode from "vscode";
+import { FxError, Result, err, ok } from "@microsoft/teamsfx-api";
+import { core } from "../globalVariables";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetrySuccess,
+} from "../telemetry/extTelemetryEvents";
+import { selectAndDebug } from "../debug/runIconHandler";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { processResult } from "./sharedOpts";
+import { QuestionNames, Hub, assembleError } from "@microsoft/teamsfx-core";
+import { openHubWebClient } from "../debug/launch";
+import { showError } from "../error/common";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+
+export function debugInTestToolHandler(source: "treeview" | "message") {
+ return async () => {
+ if (source === "treeview") {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewDebugInTestTool);
+ } else {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MessageDebugInTestTool);
+ }
+ await vscode.commands.executeCommand("workbench.action.quickOpen", "debug Debug in Test Tool");
+ return ok(null);
+ };
+}
+
+export async function selectAndDebugHandler(args?: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.RunIconDebugStart, getTriggerFromProperty(args));
+ const result = await selectAndDebug();
+ await processResult(TelemetryEvent.RunIconDebug, result);
+ return result;
+}
+
+export async function treeViewLocalDebugHandler(): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewLocalDebug);
+ await vscode.commands.executeCommand("workbench.action.quickOpen", "debug ");
+ return ok(null);
+}
+
+export async function treeViewPreviewHandler(...args: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.TreeViewPreviewStart,
+ getTriggerFromProperty(args)
+ );
+ const properties: { [key: string]: string } = {};
+
+ try {
+ const env = args[1]?.identifier as string;
+ const inputs = getSystemInputs();
+ inputs.env = env;
+ properties[TelemetryProperty.Env] = env;
+
+ const result = await core.previewWithManifest(inputs);
+ if (result.isErr()) {
+ throw result.error;
+ }
+
+ const hub = inputs[QuestionNames.M365Host] as Hub;
+ const url = result.value;
+ properties[TelemetryProperty.Hub] = hub;
+
+ await openHubWebClient(hub, url);
+ } catch (error) {
+ const assembledError = assembleError(error);
+ void showError(assembledError);
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.TreeViewPreview,
+ assembledError,
+ properties
+ );
+ return err(assembledError);
+ }
+
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewPreview, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ ...properties,
+ });
+ return ok(null);
+}
diff --git a/packages/vscode-extension/src/handlers/debugInTestTool.ts b/packages/vscode-extension/src/handlers/debugInTestTool.ts
deleted file mode 100644
index 47a2cd1ea1..0000000000
--- a/packages/vscode-extension/src/handlers/debugInTestTool.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-import * as vscode from "vscode";
-import { FxError, ok } from "@microsoft/teamsfx-api";
-import { ExtTelemetry } from "../telemetry/extTelemetry";
-import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
-
-export function debugInTestToolHandler(source: "treeview" | "message") {
- return async () => {
- if (source === "treeview") {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.TreeViewDebugInTestTool);
- } else {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MessageDebugInTestTool);
- }
- await vscode.commands.executeCommand("workbench.action.quickOpen", "debug Debug in Test Tool");
- return ok(null);
- };
-}
diff --git a/packages/vscode-extension/src/handlers/decryptSecret.ts b/packages/vscode-extension/src/handlers/decryptSecret.ts
new file mode 100644
index 0000000000..7e1046c943
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/decryptSecret.ts
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as vscode from "vscode";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryTriggerFrom,
+ TelemetrySuccess,
+ TelemetryEvent,
+ TelemetryProperty,
+} from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+import { core } from "../globalVariables";
+
+export async function decryptSecret(cipher: string, selection: vscode.Range): Promise {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.EditSecretStart, {
+ [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Other,
+ });
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return;
+ }
+ const inputs = getSystemInputs();
+ const result = await core.decrypt(cipher, inputs);
+ if (result.isOk()) {
+ const editedSecret = await VS_CODE_UI.inputText({
+ name: "Secret Editor",
+ title: localize("teamstoolkit.handlers.editSecretTitle"),
+ default: result.value,
+ });
+ if (editedSecret.isOk() && editedSecret.value.result) {
+ const newCiphertext = await core.encrypt(editedSecret.value.result, inputs);
+ if (newCiphertext.isOk()) {
+ await editor.edit((editBuilder) => {
+ editBuilder.replace(selection, newCiphertext.value);
+ });
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.EditSecret, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ });
+ } else {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.EditSecret, newCiphertext.error);
+ }
+ }
+ } else {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.EditSecret, result.error);
+ void vscode.window.showErrorMessage(result.error.message);
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/envHandlers.ts b/packages/vscode-extension/src/handlers/envHandlers.ts
new file mode 100644
index 0000000000..07db456150
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/envHandlers.ts
@@ -0,0 +1,162 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as vscode from "vscode";
+import * as path from "path";
+import * as util from "util";
+import * as fs from "fs-extra";
+import {
+ FxError,
+ Result,
+ SingleSelectConfig,
+ Stage,
+ SystemError,
+ UserError,
+ Void,
+ err,
+ ok,
+} from "@microsoft/teamsfx-api";
+import {
+ isValidProject,
+ InvalidProjectError,
+ environmentManager,
+ pathUtils,
+} from "@microsoft/teamsfx-core";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetrySuccess,
+} from "../telemetry/extTelemetryEvents";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { runCommand } from "./sharedOpts";
+import envTreeProviderInstance from "../treeview/environmentTreeViewProvider";
+import { workspaceUri } from "../globalVariables";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { showError } from "../error/common";
+import { ExtensionSource, ExtensionErrors } from "../error/error";
+import { localize } from "../utils/localizeUtils";
+
+export async function createNewEnvironment(args?: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.CreateNewEnvironmentStart,
+ getTriggerFromProperty(args)
+ );
+ const result = await runCommand(Stage.createEnv);
+ if (!result.isErr()) {
+ await envTreeProviderInstance.reloadEnvironments();
+ }
+ return result;
+}
+
+export async function refreshEnvironment(args?: any[]): Promise> {
+ return await envTreeProviderInstance.reloadEnvironments();
+}
+
+export async function openConfigStateFile(args: any[]): Promise {
+ let telemetryStartName = TelemetryEvent.OpenManifestConfigStateStart;
+ let telemetryName = TelemetryEvent.OpenManifestConfigState;
+
+ if (args && args.length > 0 && args[0].from === "aad") {
+ telemetryStartName = TelemetryEvent.OpenAadConfigStateStart;
+ telemetryName = TelemetryEvent.OpenAadConfigState;
+ }
+
+ ExtTelemetry.sendTelemetryEvent(telemetryStartName);
+ const workspacePath = workspaceUri?.fsPath;
+ if (!workspacePath) {
+ const noOpenWorkspaceError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.NoWorkspaceError,
+ localize("teamstoolkit.handlers.noOpenWorkspace")
+ );
+ void showError(noOpenWorkspaceError);
+ ExtTelemetry.sendTelemetryErrorEvent(telemetryName, noOpenWorkspaceError);
+ return err(noOpenWorkspaceError);
+ }
+
+ if (!isValidProject(workspacePath)) {
+ const invalidProjectError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.InvalidProject,
+ localize("teamstoolkit.handlers.invalidProject")
+ );
+ void showError(invalidProjectError);
+ ExtTelemetry.sendTelemetryErrorEvent(telemetryName, invalidProjectError);
+ return err(invalidProjectError);
+ }
+
+ let sourcePath: string | undefined = undefined;
+ let env: string | undefined = undefined;
+ if (args && args.length > 0) {
+ env = args[0].env;
+ if (!env) {
+ const envRes: Result = await askTargetEnvironment();
+ if (envRes.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(telemetryName, envRes.error);
+ return err(envRes.error);
+ }
+ env = envRes.value;
+ }
+
+ // Load env folder from yml
+ const envFolder = await pathUtils.getEnvFolderPath(workspacePath);
+ if (envFolder.isOk() && envFolder.value) {
+ sourcePath = path.resolve(`${envFolder.value}/.env.${env as string}`);
+ } else if (envFolder.isErr()) {
+ return err(envFolder.error);
+ }
+ } else {
+ const invalidArgsError = new SystemError(
+ ExtensionSource,
+ ExtensionErrors.InvalidArgs,
+ util.format(localize("teamstoolkit.handlers.invalidArgs"), args ? JSON.stringify(args) : args)
+ );
+ void showError(invalidArgsError);
+ ExtTelemetry.sendTelemetryErrorEvent(telemetryName, invalidArgsError);
+ return err(invalidArgsError);
+ }
+
+ if (sourcePath && !(await fs.pathExists(sourcePath))) {
+ const noEnvError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.EnvFileNotFoundError,
+ util.format(localize("teamstoolkit.handlers.findEnvFailed"), env)
+ );
+ void showError(noEnvError);
+ ExtTelemetry.sendTelemetryErrorEvent(telemetryName, noEnvError);
+ return err(noEnvError);
+ }
+
+ void vscode.workspace.openTextDocument(sourcePath as string).then((document) => {
+ void vscode.window.showTextDocument(document);
+ });
+ ExtTelemetry.sendTelemetryEvent(telemetryName, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ });
+}
+
+/**
+ * Ask user to select environment, local is included
+ */
+export async function askTargetEnvironment(): Promise> {
+ const projectPath = workspaceUri?.fsPath;
+ if (!isValidProject(projectPath)) {
+ return err(new InvalidProjectError(projectPath || ""));
+ }
+ const envProfilesResult = await environmentManager.listAllEnvConfigs(projectPath!);
+ if (envProfilesResult.isErr()) {
+ return err(envProfilesResult.error);
+ }
+ const config: SingleSelectConfig = {
+ name: "targetEnvName",
+ title: "Select an environment",
+ options: envProfilesResult.value,
+ };
+ const selectedEnv = await VS_CODE_UI.selectOption(config);
+ if (selectedEnv.isErr()) {
+ return err(selectedEnv.error);
+ } else {
+ return ok(selectedEnv.value.result as string);
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/lifecycleHandlers.ts b/packages/vscode-extension/src/handlers/lifecycleHandlers.ts
index 00d54aea7f..d6592ab7a4 100644
--- a/packages/vscode-extension/src/handlers/lifecycleHandlers.ts
+++ b/packages/vscode-extension/src/handlers/lifecycleHandlers.ts
@@ -1,13 +1,74 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { FxError, Result, Stage } from "@microsoft/teamsfx-api";
-import { isUserCancelError } from "@microsoft/teamsfx-core";
+import {
+ CreateProjectResult,
+ err,
+ FxError,
+ Inputs,
+ ok,
+ Result,
+ Stage,
+} from "@microsoft/teamsfx-api";
+import {
+ AppStudioScopes,
+ assembleError,
+ AuthSvcScopes,
+ CapabilityOptions,
+ isUserCancelError,
+ isValidOfficeAddInProject,
+ QuestionNames,
+ teamsDevPortalClient,
+} from "@microsoft/teamsfx-core";
+import * as vscode from "vscode";
+import M365TokenInstance from "../commonlib/m365Login";
+import { VS_CODE_UI } from "../qm/vsc_ui";
import { ExtTelemetry } from "../telemetry/extTelemetry";
-import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
+import { TelemetryEvent, TelemetryTriggerFrom } from "../telemetry/extTelemetryEvents";
import envTreeProviderInstance from "../treeview/environmentTreeViewProvider";
+import { localize } from "../utils/localizeUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { openFolder, openOfficeDevFolder } from "../utils/workspaceUtils";
+import { invokeTeamsAgent } from "./copilotChatHandlers";
import { runCommand } from "./sharedOpts";
+export async function createNewProjectHandler(...args: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.CreateProjectStart, getTriggerFromProperty(args));
+ let inputs: Inputs | undefined;
+ if (args?.length === 1) {
+ if (!!args[0].teamsAppFromTdp) {
+ inputs = getSystemInputs();
+ inputs.teamsAppFromTdp = args[0].teamsAppFromTdp;
+ }
+ } else if (args?.length === 2) {
+ // from copilot chat
+ inputs = { ...getSystemInputs(), ...args[1] };
+ }
+ const result = await runCommand(Stage.create, inputs);
+ if (result.isErr()) {
+ return err(result.error);
+ }
+
+ const res = result.value as CreateProjectResult;
+ if (res.shouldInvokeTeamsAgent) {
+ await invokeTeamsAgent([TelemetryTriggerFrom.CreateAppQuestionFlow]);
+ return result;
+ }
+ const projectPathUri = vscode.Uri.file(res.projectPath);
+ const isOfficeAddin = isValidOfficeAddInProject(projectPathUri.fsPath);
+ // If it is triggered in @office /create for code gen, then do no open the temp folder.
+ if (isOfficeAddin && inputs?.agent === "office") {
+ return result;
+ }
+ // show local debug button by default
+ if (isOfficeAddin) {
+ await openOfficeDevFolder(projectPathUri, true, res.warnings, args);
+ } else {
+ await openFolder(projectPathUri, true, res.warnings, args);
+ }
+ return result;
+}
+
export async function provisionHandler(...args: unknown[]): Promise> {
ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ProvisionStart, getTriggerFromProperty(args));
const result = await runCommand(Stage.provision);
@@ -29,3 +90,126 @@ export async function publishHandler(...args: unknown[]): Promise> {
+ if (!args || args.length < 1) {
+ // should never happen
+ return ok(null);
+ }
+
+ const appId = args[0];
+ const properties: { [p: string]: string } = {
+ teamsAppId: appId,
+ };
+
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.HandleUrlFromDeveloperProtalStart, properties);
+ const loginHint = args.length < 2 ? undefined : args[1];
+ const progressBar = VS_CODE_UI.createProgressBar(
+ localize("teamstoolkit.devPortalIntegration.checkM365Account.progressTitle"),
+ 1
+ );
+
+ await progressBar.start();
+ let token = undefined;
+ try {
+ const tokenRes = await M365TokenInstance.signInWhenInitiatedFromTdp(
+ { scopes: AppStudioScopes },
+ loginHint
+ );
+ if (tokenRes.isErr()) {
+ if ((tokenRes.error as any).displayMessage) {
+ void vscode.window.showErrorMessage((tokenRes.error as any).displayMessage);
+ } else {
+ void vscode.window.showErrorMessage(
+ localize("teamstoolkit.devPortalIntegration.generalError.message")
+ );
+ }
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.HandleUrlFromDeveloperProtal,
+ tokenRes.error,
+ properties
+ );
+ await progressBar.end(false);
+ return err(tokenRes.error);
+ }
+ token = tokenRes.value;
+
+ // set region
+ const AuthSvcTokenRes = await M365TokenInstance.getAccessToken({ scopes: AuthSvcScopes });
+ if (AuthSvcTokenRes.isOk()) {
+ await teamsDevPortalClient.setRegionEndpointByToken(AuthSvcTokenRes.value);
+ }
+
+ await progressBar.end(true);
+ } catch (e) {
+ void vscode.window.showErrorMessage(
+ localize("teamstoolkit.devPortalIntegration.generalError.message")
+ );
+ await progressBar.end(false);
+ const error = assembleError(e);
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.HandleUrlFromDeveloperProtal,
+ error,
+ properties
+ );
+ return err(error);
+ }
+
+ let appDefinition;
+ try {
+ appDefinition = await teamsDevPortalClient.getApp(token, appId);
+ } catch (error: any) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.HandleUrlFromDeveloperProtal,
+ error,
+ properties
+ );
+ void vscode.window.showErrorMessage(
+ localize("teamstoolkit.devPortalIntegration.getTeamsAppError.message")
+ );
+ return err(error);
+ }
+
+ const res = await createNewProjectHandler({ teamsAppFromTdp: appDefinition });
+
+ if (res.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.HandleUrlFromDeveloperProtal,
+ res.error,
+ properties
+ );
+ return err(res.error);
+ }
+
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.HandleUrlFromDeveloperProtal, properties);
+ return ok(null);
+}
+
+export async function copilotPluginAddAPIHandler(args: any[]) {
+ // Telemetries are handled in runCommand()
+ const inputs = getSystemInputs();
+ if (args && args.length > 0) {
+ const filePath = args[0].fsPath as string;
+ const isFromApiPlugin: boolean = args[0].isFromApiPlugin ?? false;
+ if (!isFromApiPlugin) {
+ // Codelens for API ME. Trigger from manifest.json
+ inputs[QuestionNames.ManifestPath] = filePath;
+ } else {
+ inputs[QuestionNames.Capabilities] = CapabilityOptions.copilotPluginApiSpec().id;
+ inputs[QuestionNames.DestinationApiSpecFilePath] = filePath;
+ inputs[QuestionNames.ManifestPath] = args[0].manifestPath;
+ }
+ }
+ const result = await runCommand(Stage.copilotPluginAddAPI, inputs);
+ return result;
+}
diff --git a/packages/vscode-extension/src/handlers/manifestHandlers.ts b/packages/vscode-extension/src/handlers/manifestHandlers.ts
new file mode 100644
index 0000000000..219eee101e
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/manifestHandlers.ts
@@ -0,0 +1,173 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+import {
+ AppPackageFolderName,
+ BuildFolderName,
+ err,
+ FxError,
+ ok,
+ Result,
+ SelectFileConfig,
+ SingleSelectConfig,
+ Stage,
+} from "@microsoft/teamsfx-api";
+import * as fs from "fs-extra";
+import * as path from "path";
+import { window, workspace } from "vscode";
+import { core, workspaceUri } from "../globalVariables";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { runCommand } from "./sharedOpts";
+
+export async function validateManifestHandler(args?: any[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.ValidateManifestStart,
+ getTriggerFromProperty(args)
+ );
+
+ const inputs = getSystemInputs();
+ return await runCommand(Stage.validateApplication, inputs);
+}
+
+export async function buildPackageHandler(...args: unknown[]): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.BuildStart, getTriggerFromProperty(args));
+ return await runCommand(Stage.createAppPackage);
+}
+
+let lastAppPackageFile: string | undefined;
+
+export async function publishInDeveloperPortalHandler(
+ ...args: unknown[]
+): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.PublishInDeveloperPortalStart,
+ getTriggerFromProperty(args)
+ );
+ const workspacePath = workspaceUri?.fsPath;
+ const zipDefaultFolder: string | undefined = path.join(
+ workspacePath!,
+ BuildFolderName,
+ AppPackageFolderName
+ );
+
+ let files: string[] = [];
+ if (await fs.pathExists(zipDefaultFolder)) {
+ files = await fs.readdir(zipDefaultFolder);
+ files = files
+ .filter((file) => path.extname(file).toLowerCase() === ".zip")
+ .map((file) => {
+ return path.join(zipDefaultFolder, file);
+ });
+ }
+ while (true) {
+ const selectFileConfig: SelectFileConfig = {
+ name: "appPackagePath",
+ title: localize("teamstoolkit.publishInDevPortal.selectFile.title"),
+ placeholder: localize("teamstoolkit.publishInDevPortal.selectFile.placeholder"),
+ filters: {
+ "Zip files": ["zip"],
+ },
+ };
+ if (lastAppPackageFile && fs.existsSync(lastAppPackageFile)) {
+ selectFileConfig.default = lastAppPackageFile;
+ } else {
+ selectFileConfig.possibleFiles = files.map((file) => {
+ const appPackageFilename = path.basename(file);
+ const appPackageFilepath = path.dirname(file);
+ return {
+ id: file,
+ label: `$(file) ${appPackageFilename}`,
+ description: appPackageFilepath,
+ };
+ });
+ }
+ const selectFileResult = await VS_CODE_UI.selectFile(selectFileConfig);
+ if (selectFileResult.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.PublishInDeveloperPortal,
+ selectFileResult.error,
+ getTriggerFromProperty(args)
+ );
+ return ok(null);
+ }
+ if (
+ (lastAppPackageFile && selectFileResult.value.result === lastAppPackageFile) ||
+ (!lastAppPackageFile && files.indexOf(selectFileResult.value.result!) !== -1)
+ ) {
+ // user selected file in options
+ lastAppPackageFile = selectFileResult.value.result;
+ break;
+ }
+ // final confirmation
+ lastAppPackageFile = selectFileResult.value.result!;
+ const appPackageFilename = path.basename(lastAppPackageFile);
+ const appPackageFilepath = path.dirname(lastAppPackageFile);
+ const confirmOption: SingleSelectConfig = {
+ options: [
+ {
+ id: "yes",
+ label: `$(file) ${appPackageFilename}`,
+ description: appPackageFilepath,
+ },
+ ],
+ name: "confirm",
+ title: localize("teamstoolkit.publishInDevPortal.selectFile.title"),
+ placeholder: localize("teamstoolkit.publishInDevPortal.confirmFile.placeholder"),
+ step: 2,
+ };
+ const confirm = await VS_CODE_UI.selectOption(confirmOption);
+ if (confirm.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.PublishInDeveloperPortal,
+ confirm.error,
+ getTriggerFromProperty(args)
+ );
+ return ok(null);
+ }
+ if (confirm.value.type === "success") {
+ break;
+ }
+ }
+ const inputs = getSystemInputs();
+ inputs["appPackagePath"] = lastAppPackageFile;
+ const res = await runCommand(Stage.publishInDeveloperPortal, inputs);
+ if (res.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.PublishInDeveloperPortal,
+ res.error,
+ getTriggerFromProperty(args)
+ );
+ }
+ return res;
+}
+
+export async function updatePreviewManifest(args: any[]): Promise {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.UpdatePreviewManifestStart,
+ getTriggerFromProperty(args && args.length > 1 ? [args[1]] : undefined)
+ );
+ const inputs = getSystemInputs();
+ const result = await runCommand(Stage.deployTeams, inputs);
+
+ if (!args || args.length === 0) {
+ const workspacePath = workspaceUri?.fsPath;
+ const inputs = getSystemInputs();
+ inputs.ignoreEnvInfo = true;
+ const env = await core.getSelectedEnv(inputs);
+ if (env.isErr()) {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.UpdatePreviewManifest, env.error);
+ return err(env.error);
+ }
+ const manifestPath = `${
+ workspacePath as string
+ }/${AppPackageFolderName}/${BuildFolderName}/manifest.${env.value as string}.json`;
+ void workspace.openTextDocument(manifestPath).then((document) => {
+ void window.showTextDocument(document);
+ });
+ }
+ return result;
+}
diff --git a/packages/vscode-extension/src/handlers/migrationHandler.ts b/packages/vscode-extension/src/handlers/migrationHandler.ts
new file mode 100644
index 0000000000..6d2639d51a
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/migrationHandler.ts
@@ -0,0 +1,206 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import {
+ FxError,
+ ok,
+ Result,
+ SelectFileConfig,
+ SelectFolderConfig,
+ UserError,
+} from "@microsoft/teamsfx-api";
+import * as path from "path";
+import * as util from "util";
+import VsCodeLogInstance from "../commonlib/log";
+import { showError, wrapError } from "../error/common";
+import { ExtensionErrors, ExtensionSource } from "../error/error";
+import { TeamsAppMigrationHandler } from "../migration/migrationHandler";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetrySuccess,
+} from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+
+export async function migrateTeamsTabAppHandler(): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsTabAppStart);
+ const selection = await VS_CODE_UI.showMessage(
+ "warn",
+ localize("teamstoolkit.migrateTeamsTabApp.warningMessage"),
+ true,
+ localize("teamstoolkit.migrateTeamsTabApp.upgrade")
+ );
+ const userCancelError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.UserCancel,
+ localize("teamstoolkit.common.userCancel")
+ );
+ if (
+ selection.isErr() ||
+ selection.value !== localize("teamstoolkit.migrateTeamsTabApp.upgrade")
+ ) {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, userCancelError);
+ return ok(null);
+ }
+ const selectFolderConfig: SelectFolderConfig = {
+ name: localize("teamstoolkit.migrateTeamsTabApp.selectFolderConfig.name"),
+ title: localize("teamstoolkit.migrateTeamsTabApp.selectFolderConfig.title"),
+ };
+ const selectFolderResult = await VS_CODE_UI.selectFolder(selectFolderConfig);
+ if (selectFolderResult.isErr() || selectFolderResult.value.type !== "success") {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, userCancelError);
+ return ok(null);
+ }
+ const tabAppPath = selectFolderResult.value.result as string;
+
+ const progressBar = VS_CODE_UI.createProgressBar(
+ localize("teamstoolkit.migrateTeamsTabApp.progressTitle"),
+ 2
+ );
+ await progressBar.start();
+
+ const migrationHandler = new TeamsAppMigrationHandler(tabAppPath);
+ let result: Result = ok(null);
+ let packageUpdated: Result = ok(true);
+ let updateFailedFiles: string[] = [];
+ try {
+ // Update package.json to use @microsoft/teams-js v2
+ await progressBar.next(localize("teamstoolkit.migrateTeamsTabApp.updatingPackageJson"));
+ VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsTabApp.updatingPackageJson"));
+ packageUpdated = await migrationHandler.updatePackageJson();
+ if (packageUpdated.isErr()) {
+ throw packageUpdated.error;
+ } else if (!packageUpdated.value) {
+ // no change in package.json, show warning.
+ const warningMessage = util.format(
+ localize("teamstoolkit.migrateTeamsTabApp.updatePackageJsonWarning"),
+ path.join(tabAppPath, "package.json")
+ );
+ VsCodeLogInstance.warning(warningMessage);
+ void VS_CODE_UI.showMessage("warn", warningMessage, false, "OK");
+ } else {
+ // Update codes to use @microsoft/teams-js v2
+ await progressBar.next(localize("teamstoolkit.migrateTeamsTabApp.updatingCodes"));
+ VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsTabApp.updatingCodes"));
+ const failedFiles = await migrationHandler.updateCodes();
+ if (failedFiles.isErr()) {
+ throw failedFiles.error;
+ } else {
+ updateFailedFiles = failedFiles.value;
+ if (failedFiles.value.length > 0) {
+ VsCodeLogInstance.warning(
+ util.format(
+ localize("teamstoolkit.migrateTeamsTabApp.updateCodesErrorOutput"),
+ failedFiles.value.length,
+ failedFiles.value.join(", ")
+ )
+ );
+ void VS_CODE_UI.showMessage(
+ "warn",
+ util.format(
+ localize("teamstoolkit.migrateTeamsTabApp.updateCodesErrorMessage"),
+ failedFiles.value.length,
+ failedFiles.value[0]
+ ),
+ false,
+ "OK"
+ );
+ }
+ }
+ }
+ } catch (error) {
+ result = wrapError(error as Error);
+ }
+
+ if (result.isErr()) {
+ await progressBar.end(false);
+ void showError(result.error);
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsTabApp, result.error);
+ } else {
+ await progressBar.end(true);
+ if (!packageUpdated.isErr() && packageUpdated.value) {
+ void VS_CODE_UI.showMessage(
+ "info",
+ util.format(localize("teamstoolkit.migrateTeamsTabApp.success"), tabAppPath),
+ false
+ );
+ }
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsTabApp, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ [TelemetryProperty.UpdateFailedFiles]: updateFailedFiles.length.toString(),
+ });
+ }
+ return result;
+}
+
+export async function migrateTeamsManifestHandler(): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsManifestStart);
+ const selection = await VS_CODE_UI.showMessage(
+ "warn",
+ localize("teamstoolkit.migrateTeamsManifest.warningMessage"),
+ true,
+ localize("teamstoolkit.migrateTeamsManifest.upgrade")
+ );
+ const userCancelError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.UserCancel,
+ localize("teamstoolkit.common.userCancel")
+ );
+ if (
+ selection.isErr() ||
+ selection.value !== localize("teamstoolkit.migrateTeamsManifest.upgrade")
+ ) {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, userCancelError);
+ return ok(null);
+ }
+ const selectFileConfig: SelectFileConfig = {
+ name: localize("teamstoolkit.migrateTeamsManifest.selectFileConfig.name"),
+ title: localize("teamstoolkit.migrateTeamsManifest.selectFileConfig.title"),
+ };
+ const selectFileResult = await VS_CODE_UI.selectFile(selectFileConfig);
+ if (selectFileResult.isErr() || selectFileResult.value.type !== "success") {
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, userCancelError);
+ return ok(null);
+ }
+ const manifestPath = selectFileResult.value.result as string;
+
+ const progressBar = VS_CODE_UI.createProgressBar(
+ localize("teamstoolkit.migrateTeamsManifest.progressTitle"),
+ 1
+ );
+ await progressBar.start();
+
+ const migrationHandler = new TeamsAppMigrationHandler(manifestPath);
+ let result: Result = ok(null);
+
+ try {
+ // Update Teams manifest
+ await progressBar.next(localize("teamstoolkit.migrateTeamsManifest.updateManifest"));
+ VsCodeLogInstance.info(localize("teamstoolkit.migrateTeamsManifest.updateManifest"));
+ result = await migrationHandler.updateManifest();
+ if (result.isErr()) {
+ throw result.error;
+ }
+ } catch (error) {
+ result = wrapError(error as Error);
+ }
+
+ if (result.isErr()) {
+ await progressBar.end(false);
+ void showError(result.error);
+ ExtTelemetry.sendTelemetryErrorEvent(TelemetryEvent.MigrateTeamsManifest, result.error);
+ } else {
+ await progressBar.end(true);
+ void VS_CODE_UI.showMessage(
+ "info",
+ util.format(localize("teamstoolkit.migrateTeamsManifest.success"), manifestPath),
+ false
+ );
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.MigrateTeamsManifest, {
+ [TelemetryProperty.Success]: TelemetrySuccess.Yes,
+ });
+ }
+ return result;
+}
diff --git a/packages/vscode-extension/src/handlers/officeDevHandlers.ts b/packages/vscode-extension/src/handlers/officeDevHandlers.ts
index 61769b3865..e114f31f1a 100644
--- a/packages/vscode-extension/src/handlers/officeDevHandlers.ts
+++ b/packages/vscode-extension/src/handlers/officeDevHandlers.ts
@@ -7,25 +7,12 @@
"use strict";
import { FxError, Result, ok } from "@microsoft/teamsfx-api";
-import {
- globalStateGet,
- globalStateUpdate,
- isManifestOnlyOfficeAddinProject,
-} from "@microsoft/teamsfx-core";
-import * as fs from "fs-extra";
-import * as path from "path";
+import { globalStateGet, globalStateUpdate } from "@microsoft/teamsfx-core";
import * as vscode from "vscode";
import { GlobalKey } from "../constants";
import { OfficeDevTerminal, TriggerCmdType } from "../debug/taskTerminal/officeDevTerminal";
import { VS_CODE_UI } from "../qm/vsc_ui";
import * as globalVariables from "../globalVariables";
-import {
- ShowScaffoldingWarningSummary,
- autoInstallDependencyHandler,
- openReadMeHandler,
- openSampleReadmeHandler,
- showLocalDebugMessage,
-} from "../handlers";
import {
TelemetryTriggerFrom,
TelemetryEvent,
@@ -34,6 +21,12 @@ import {
import { getTriggerFromProperty } from "../utils/telemetryUtils";
import { localize } from "../utils/localizeUtils";
import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ ShowScaffoldingWarningSummary,
+ autoInstallDependencyHandler,
+ showLocalDebugMessage,
+} from "../utils/autoOpenHelper";
+import { openReadMeHandler, openSampleReadmeHandler } from "./readmeHandlers";
export async function openOfficePartnerCenterHandler(
args?: any[]
@@ -168,26 +161,6 @@ export function installOfficeAddInDependencies(args?: any[]): Promise> {
ExtTelemetry.sendTelemetryEvent(TelemetryEvent.stopAddInDebug, getTriggerFromProperty(args));
const terminal = OfficeDevTerminal.getInstance(TriggerCmdType.triggerStopDebug);
@@ -209,7 +182,6 @@ export async function autoOpenOfficeDevProjectHandler(): Promise {
const isOpenReadMe = (await globalStateGet(GlobalKey.OpenReadMe, "")) as string;
const isOpenSampleReadMe = (await globalStateGet(GlobalKey.OpenSampleReadMe, false)) as boolean;
const createWarnings = (await globalStateGet(GlobalKey.CreateWarnings, "")) as string;
- const autoInstallDependency = (await globalStateGet(GlobalKey.AutoInstallDependency)) as boolean;
if (isOpenWalkThrough) {
// current the welcome walkthrough is not supported for wxp add in
await globalStateUpdate(GlobalKey.OpenWalkThrough, false);
@@ -226,21 +198,4 @@ export async function autoOpenOfficeDevProjectHandler(): Promise {
await openSampleReadmeHandler([TelemetryTriggerFrom.Auto]);
await globalStateUpdate(GlobalKey.OpenSampleReadMe, false);
}
- if (autoInstallDependency) {
- if (!isManifestOnlyOfficeAddinProject(globalVariables.workspaceUri?.fsPath ?? ""))
- void popupOfficeAddInDependenciesMessage();
- await globalStateUpdate(GlobalKey.AutoInstallDependency, false);
- }
- if (
- globalVariables.isOfficeAddInProject &&
- !checkOfficeAddInInstalled(globalVariables.workspaceUri?.fsPath ?? "") &&
- !isManifestOnlyOfficeAddinProject(globalVariables.workspaceUri?.fsPath ?? "")
- ) {
- void popupOfficeAddInDependenciesMessage();
- }
-}
-
-export function checkOfficeAddInInstalled(directory: string): boolean {
- const nodeModulesExists = fs.existsSync(path.join(directory, "node_modules"));
- return nodeModulesExists;
}
diff --git a/packages/vscode-extension/src/handlers/openLinkHandlers.ts b/packages/vscode-extension/src/handlers/openLinkHandlers.ts
index 035afe93be..78b1bbbe64 100644
--- a/packages/vscode-extension/src/handlers/openLinkHandlers.ts
+++ b/packages/vscode-extension/src/handlers/openLinkHandlers.ts
@@ -1,12 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import { FxError, ok, Result } from "@microsoft/teamsfx-api";
-import { AppStudioScopes, featureFlagManager, FeatureFlags } from "@microsoft/teamsfx-core";
+import {
+ err,
+ FxError,
+ ok,
+ Result,
+ SubscriptionInfo,
+ UserError,
+ Void,
+} from "@microsoft/teamsfx-api";
+import { AppStudioScopes, getHashedEnv } from "@microsoft/teamsfx-core";
import * as vscode from "vscode";
+import * as util from "util";
import { signedIn } from "../commonlib/common/constant";
import M365TokenInstance from "../commonlib/m365Login";
-import { DeveloperPortalHomeLink, PublishAppLearnMoreLink } from "../constants";
+import {
+ AzurePortalUrl,
+ DeveloperPortalHomeLink,
+ PublishAppLearnMoreLink,
+ ResourceInfo,
+} from "../constants";
import { VS_CODE_UI } from "../qm/vsc_ui";
import { ExtTelemetry } from "../telemetry/extTelemetry";
import {
@@ -16,6 +30,10 @@ import {
} from "../telemetry/extTelemetryEvents";
import { TreeViewCommand } from "../treeview/treeViewCommand";
import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { ExtensionSource, ExtensionErrors } from "../error/error";
+import { getSubscriptionInfoFromEnv, getResourceGroupNameFromEnv } from "../utils/envTreeUtils";
+import { localize } from "../utils/localizeUtils";
+import { getWalkThroughId } from "../utils/projectStatusUtils";
export async function openEnvLinkHandler(args: any[]): Promise> {
ExtTelemetry.sendTelemetryEvent(TelemetryEvent.Documentation, {
@@ -49,15 +67,6 @@ export async function openHelpFeedbackLinkHandler(args: any[]): Promise> {
- ExtTelemetry.sendTelemetryEvent(TelemetryEvent.GetStarted, getTriggerFromProperty(args));
- const data = await vscode.commands.executeCommand(
- "workbench.action.openWalkthrough",
- getWalkThroughId()
- );
- return Promise.resolve(ok(data));
-}
-
export async function openDocumentLinkHandler(args?: any[]): Promise> {
if (!args || args.length < 1) {
// should never happen
@@ -112,12 +121,6 @@ export async function openAzureAccountHandler() {
return VS_CODE_UI.openUrl("https://portal.azure.com/");
}
-export function getWalkThroughId(): string {
- return featureFlagManager.getBooleanValue(FeatureFlags.ChatParticipant)
- ? "TeamsDevApp.ms-teams-vscode-extension#teamsToolkitGetStartedWithChat"
- : "TeamsDevApp.ms-teams-vscode-extension#teamsToolkitGetStarted";
-}
-
export async function openAppManagement(...args: unknown[]): Promise> {
ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ManageTeamsApp, getTriggerFromProperty(args));
const accountRes = await M365TokenInstance.getStatus({ scopes: AppStudioScopes });
@@ -163,3 +166,101 @@ export async function openDocumentHandler(...args: unknown[]): Promise 0) {
+ const url = (args[0] as { url: string }).url;
+ return VS_CODE_UI.openUrl(url);
+ }
+ return ok(false);
+}
+
+function getSubscriptionUrl(subscriptionInfo: SubscriptionInfo): string {
+ const subscriptionId = subscriptionInfo.subscriptionId;
+ const tenantId = subscriptionInfo.tenantId;
+
+ return `${AzurePortalUrl}/#@${tenantId}/resource/subscriptions/${subscriptionId}`;
+}
+
+export async function openSubscriptionInPortal(env: string): Promise> {
+ const telemetryProperties: { [p: string]: string } = {};
+ telemetryProperties[TelemetryProperty.Env] = getHashedEnv(env);
+
+ const subscriptionInfo = await getSubscriptionInfoFromEnv(env);
+ if (subscriptionInfo) {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenSubscriptionInPortal, telemetryProperties);
+
+ const url = getSubscriptionUrl(subscriptionInfo);
+ await vscode.env.openExternal(vscode.Uri.parse(url));
+
+ return ok(Void);
+ } else {
+ const resourceInfoNotFoundError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.EnvResourceInfoNotFoundError,
+ util.format(
+ localize("teamstoolkit.handlers.resourceInfoNotFound"),
+ ResourceInfo.Subscription,
+ env
+ )
+ );
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.OpenSubscriptionInPortal,
+ resourceInfoNotFoundError,
+ telemetryProperties
+ );
+
+ return err(resourceInfoNotFoundError);
+ }
+}
+
+export async function openResourceGroupInPortal(env: string): Promise> {
+ const telemetryProperties: { [p: string]: string } = {};
+ telemetryProperties[TelemetryProperty.Env] = getHashedEnv(env);
+
+ const subscriptionInfo = await getSubscriptionInfoFromEnv(env);
+ const resourceGroupName = await getResourceGroupNameFromEnv(env);
+
+ if (subscriptionInfo && resourceGroupName) {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenResourceGroupInPortal, telemetryProperties);
+
+ const url = `${getSubscriptionUrl(subscriptionInfo)}/resourceGroups/${resourceGroupName}`;
+ await vscode.env.openExternal(vscode.Uri.parse(url));
+
+ return ok(Void);
+ } else {
+ let errorMessage = "";
+ if (subscriptionInfo) {
+ errorMessage = util.format(
+ localize("teamstoolkit.handlers.resourceInfoNotFound"),
+ ResourceInfo.ResourceGroup,
+ env
+ );
+ } else if (resourceGroupName) {
+ errorMessage = util.format(
+ localize("teamstoolkit.handlers.resourceInfoNotFound"),
+ ResourceInfo.Subscription,
+ env
+ );
+ } else {
+ errorMessage = util.format(
+ localize("teamstoolkit.handlers.resourceInfoNotFound"),
+ `${ResourceInfo.Subscription} and ${ResourceInfo.ResourceGroup}`,
+ env
+ );
+ }
+
+ const resourceInfoNotFoundError = new UserError(
+ ExtensionSource,
+ ExtensionErrors.EnvResourceInfoNotFoundError,
+ errorMessage
+ );
+ ExtTelemetry.sendTelemetryErrorEvent(
+ TelemetryEvent.OpenSubscriptionInPortal,
+ resourceInfoNotFoundError,
+ telemetryProperties
+ );
+
+ return err(resourceInfoNotFoundError);
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/prerequisiteHandlers.ts b/packages/vscode-extension/src/handlers/prerequisiteHandlers.ts
new file mode 100644
index 0000000000..94f7e7c59e
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/prerequisiteHandlers.ts
@@ -0,0 +1,148 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+/**
+ * @author Huajie Zhang
+ */
+"use strict";
+
+import { FxError, Result, ok } from "@microsoft/teamsfx-api";
+import { DepsManager, DepsType, assembleError } from "@microsoft/teamsfx-core";
+import * as path from "path";
+import * as vscode from "vscode";
+import { checkPrerequisitesForGetStarted } from "../debug/depsChecker/getStartedChecker";
+import { vscodeLogger } from "../debug/depsChecker/vscodeLogger";
+import { vscodeTelemetry } from "../debug/depsChecker/vscodeTelemetry";
+import { showError } from "../error/common";
+import { core } from "../globalVariables";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetryTriggerFrom,
+} from "../telemetry/extTelemetryEvents";
+import { acpInstalled } from "../utils/commonUtils";
+import { localize } from "../utils/localizeUtils";
+import { triggerV3Migration } from "../utils/migrationUtils";
+import { getSystemInputs } from "../utils/systemEnvUtils";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+
+/**
+ * Trigger V3 migration for deprecated projects.
+ */
+export async function triggerV3MigrationHandler(): Promise {
+ try {
+ await triggerV3Migration();
+ return undefined;
+ } catch (error: any) {
+ void showError(error as FxError);
+ return "1";
+ }
+}
+
+/**
+ * Check required prerequisites in Get Started Page.
+ */
+export async function validateGetStartedPrerequisitesHandler(
+ ...args: unknown[]
+): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.ClickValidatePrerequisites,
+ getTriggerFromProperty(args)
+ );
+ const result = await checkPrerequisitesForGetStarted();
+ if (result.isErr()) {
+ void showError(result.error);
+ // // return non-zero value to let task "exit ${command:xxx}" to exit
+ // return "1";
+ }
+ return result;
+}
+
+/**
+ * Get path delimiter
+ * Usage like ${workspaceFolder}/devTools/func${command:...}${env:PATH}
+ */
+export function getPathDelimiterHandler(): string {
+ return path.delimiter;
+}
+
+/**
+ * Get dotnet path to be referenced by task definition.
+ * Usage like ${command:...}${env:PATH} so need to include delimiter as well
+ */
+export async function getDotnetPathHandler(): Promise {
+ try {
+ const depsManager = new DepsManager(vscodeLogger, vscodeTelemetry);
+ const dotnetStatus = (await depsManager.getStatus([DepsType.Dotnet]))?.[0];
+ if (dotnetStatus?.isInstalled && dotnetStatus?.details?.binFolders !== undefined) {
+ return `${path.delimiter}${dotnetStatus.details.binFolders
+ .map((f: string) => path.dirname(f))
+ .join(path.delimiter)}${path.delimiter}`;
+ }
+ } catch (error: any) {
+ void showError(assembleError(error));
+ }
+
+ return `${path.delimiter}`;
+}
+
+export async function checkUpgrade(args?: any[]) {
+ const triggerFrom = getTriggerFromProperty(args);
+ const input = getSystemInputs();
+ if (triggerFrom?.[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.Auto) {
+ input["isNonmodalMessage"] = true;
+ // not await here to avoid blocking the UI.
+ void core.phantomMigrationV3(input).then((result) => {
+ if (result.isErr()) {
+ void showError(result.error);
+ }
+ });
+ return;
+ } else if (
+ triggerFrom[TelemetryProperty.TriggerFrom] &&
+ (triggerFrom[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.SideBar ||
+ triggerFrom[TelemetryProperty.TriggerFrom] === TelemetryTriggerFrom.CommandPalette)
+ ) {
+ input["skipUserConfirm"] = true;
+ }
+ const result = await core.phantomMigrationV3(input);
+ if (result.isErr()) {
+ void showError(result.error);
+ }
+}
+
+export async function installAdaptiveCardExt(
+ ...args: unknown[]
+): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.AdaptiveCardPreviewerInstall,
+ getTriggerFromProperty(args)
+ );
+ if (acpInstalled()) {
+ await vscode.window.showInformationMessage(
+ localize("teamstoolkit.handlers.adaptiveCardExtUsage")
+ );
+ } else {
+ const selection = await vscode.window.showInformationMessage(
+ localize("teamstoolkit.handlers.installAdaptiveCardExt"),
+ "Install",
+ "Cancel"
+ );
+ if (selection === "Install") {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.AdaptiveCardPreviewerInstallConfirm,
+ getTriggerFromProperty(args)
+ );
+ await vscode.commands.executeCommand(
+ "workbench.extensions.installExtension",
+ "TeamsDevApp.vscode-adaptive-cards"
+ );
+ } else {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.AdaptiveCardPreviewerInstallCancel,
+ getTriggerFromProperty(args)
+ );
+ }
+ }
+ return Promise.resolve(ok(null));
+}
diff --git a/packages/vscode-extension/src/handlers/readmeHandlers.ts b/packages/vscode-extension/src/handlers/readmeHandlers.ts
new file mode 100644
index 0000000000..c32d0285d3
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/readmeHandlers.ts
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import * as fs from "fs-extra";
+import * as vscode from "vscode";
+import { ok, FxError } from "@microsoft/teamsfx-api";
+import { Correlator } from "@microsoft/teamsfx-core";
+import { WebviewPanel } from "../controls/webviewPanel";
+import { TreatmentVariableValue } from "../exp/treatmentVariables";
+import { isTeamsFxProject, isOfficeAddInProject } from "../globalVariables";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ InProductGuideInteraction,
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetryTriggerFrom,
+} from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { getTriggerFromProperty, isTriggerFromWalkThrough } from "../utils/telemetryUtils";
+import { createNewProjectHandler } from "./lifecycleHandlers";
+import { PanelType } from "../controls/PanelType";
+
+export async function openReadMeHandler(...args: unknown[]) {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ClickOpenReadMe, getTriggerFromProperty(args));
+ if (!isTeamsFxProject && !isOfficeAddInProject) {
+ const createProject = {
+ title: localize("teamstoolkit.handlers.createProjectTitle"),
+ run: async (): Promise => {
+ await Correlator.run(
+ async () => await createNewProjectHandler(TelemetryTriggerFrom.Notification)
+ );
+ },
+ };
+
+ const openFolder = {
+ title: localize("teamstoolkit.handlers.openFolderTitle"),
+ run: async (): Promise => {
+ await vscode.commands.executeCommand("vscode.openFolder");
+ },
+ };
+
+ void vscode.window
+ .showInformationMessage(
+ localize("teamstoolkit.handlers.createProjectNotification"),
+ createProject,
+ openFolder
+ )
+ .then((selection) => {
+ selection?.run();
+ });
+ } else if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
+ const workspaceFolder = vscode.workspace.workspaceFolders[0];
+ const workspacePath: string = workspaceFolder.uri.fsPath;
+ // show README.md or src/README.md(SPFx) in workspace root folder
+ const rootReadmePath = `${workspacePath}/README.md`;
+ const uri = (await fs.pathExists(rootReadmePath))
+ ? vscode.Uri.file(rootReadmePath)
+ : vscode.Uri.file(`${workspacePath}/src/README.md`);
+
+ if (TreatmentVariableValue.inProductDoc) {
+ const content = await fs.readFile(uri.fsPath, "utf8");
+ if (content.includes("## Get Started with the Notification bot")) {
+ // A notification bot project.
+ if (content.includes("restify")) {
+ // Restify server notification bot.
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.InteractWithInProductDoc, {
+ [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Auto,
+ [TelemetryProperty.Interaction]: InProductGuideInteraction.Open,
+ [TelemetryProperty.Identifier]: PanelType.RestifyServerNotificationBotReadme,
+ });
+ WebviewPanel.createOrShow(PanelType.RestifyServerNotificationBotReadme);
+ } else {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.InteractWithInProductDoc, {
+ [TelemetryProperty.TriggerFrom]: TelemetryTriggerFrom.Auto,
+ [TelemetryProperty.Interaction]: InProductGuideInteraction.Open,
+ [TelemetryProperty.Identifier]: PanelType.FunctionBasedNotificationBotReadme,
+ });
+ WebviewPanel.createOrShow(PanelType.FunctionBasedNotificationBotReadme);
+ }
+ }
+ }
+
+ // Always open README.md in current panel instead of side-by-side.
+ await vscode.workspace.openTextDocument(uri);
+ const PreviewMarkdownCommand = "markdown.showPreview";
+ await vscode.commands.executeCommand(PreviewMarkdownCommand, uri);
+ }
+ return ok(null);
+}
+
+export async function openSampleReadmeHandler(args?: any) {
+ if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
+ const workspaceFolder = vscode.workspace.workspaceFolders[0];
+ const workspacePath: string = workspaceFolder.uri.fsPath;
+ const uri = vscode.Uri.file(`${workspacePath}/README.md`);
+ await vscode.workspace.openTextDocument(uri);
+ if (isTriggerFromWalkThrough(args as unknown[])) {
+ const PreviewMarkdownCommand = "markdown.showPreviewToSide";
+ await vscode.commands.executeCommand(PreviewMarkdownCommand, uri);
+ } else {
+ const PreviewMarkdownCommand = "markdown.showPreview";
+ await vscode.commands.executeCommand(PreviewMarkdownCommand, uri);
+ }
+ }
+}
diff --git a/packages/vscode-extension/src/handlers/tutorialHandlers.ts b/packages/vscode-extension/src/handlers/tutorialHandlers.ts
new file mode 100644
index 0000000000..aa01fe1b51
--- /dev/null
+++ b/packages/vscode-extension/src/handlers/tutorialHandlers.ts
@@ -0,0 +1,340 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import {
+ Result,
+ FxError,
+ SingleSelectConfig,
+ StaticOptions,
+ err,
+ OptionItem,
+ ok,
+} from "@microsoft/teamsfx-api";
+import { WebviewPanel } from "../controls/webviewPanel";
+import { TreatmentVariableValue } from "../exp/treatmentVariables";
+import { isSPFxProject } from "../globalVariables";
+import { VS_CODE_UI } from "../qm/vsc_ui";
+import { ExtTelemetry } from "../telemetry/extTelemetry";
+import {
+ TelemetryEvent,
+ TelemetryProperty,
+ TelemetryTriggerFrom,
+} from "../telemetry/extTelemetryEvents";
+import { localize } from "../utils/localizeUtils";
+import { getTriggerFromProperty } from "../utils/telemetryUtils";
+import { PanelType } from "../controls/PanelType";
+
+export async function selectTutorialsHandler(
+ ...args: unknown[]
+): Promise> {
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.ViewGuidedTutorials, getTriggerFromProperty(args));
+ const config: SingleSelectConfig = {
+ name: "tutorialName",
+ title: localize("teamstoolkit.commandsTreeViewProvider.guideTitle"),
+ options: isSPFxProject
+ ? [
+ {
+ id: "cicdPipeline",
+ label: `${localize("teamstoolkit.guides.cicdPipeline.label")}`,
+ detail: localize("teamstoolkit.guides.cicdPipeline.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-add-cicd-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ ]
+ : [
+ {
+ id: "cardActionResponse",
+ label: `${localize("teamstoolkit.guides.cardActionResponse.label")}`,
+ detail: localize("teamstoolkit.guides.cardActionResponse.detail"),
+ groupName: localize("teamstoolkit.guide.scenario"),
+ data: "https://aka.ms/teamsfx-workflow-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "sendNotification",
+ label: `${localize("teamstoolkit.guides.sendNotification.label")}`,
+ detail: localize("teamstoolkit.guides.sendNotification.detail"),
+ groupName: localize("teamstoolkit.guide.scenario"),
+ data: "https://aka.ms/teamsfx-notification-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "commandAndResponse",
+ label: `${localize("teamstoolkit.guides.commandAndResponse.label")}`,
+ detail: localize("teamstoolkit.guides.commandAndResponse.detail"),
+ groupName: localize("teamstoolkit.guide.scenario"),
+ data: "https://aka.ms/teamsfx-command-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "dashboardApp",
+ label: `${localize("teamstoolkit.guides.dashboardApp.label")}`,
+ detail: localize("teamstoolkit.guides.dashboardApp.detail"),
+ groupName: localize("teamstoolkit.guide.scenario"),
+ data: "https://aka.ms/teamsfx-dashboard-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addTab",
+ label: `${localize("teamstoolkit.guides.addTab.label")}`,
+ detail: localize("teamstoolkit.guides.addTab.detail"),
+ groupName: localize("teamstoolkit.guide.capability"),
+ data: "https://aka.ms/teamsfx-add-tab",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addBot",
+ label: `${localize("teamstoolkit.guides.addBot.label")}`,
+ detail: localize("teamstoolkit.guides.addBot.detail"),
+ groupName: localize("teamstoolkit.guide.capability"),
+ data: "https://aka.ms/teamsfx-add-bot",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addME",
+ label: `${localize("teamstoolkit.guides.addME.label")}`,
+ detail: localize("teamstoolkit.guides.addME.detail"),
+ groupName: localize("teamstoolkit.guide.capability"),
+ data: "https://aka.ms/teamsfx-add-message-extension",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ ...[
+ {
+ id: "addOutlookAddin",
+ label: `${localize("teamstoolkit.guides.addOutlookAddin.label")}`,
+ detail: localize("teamstoolkit.guides.addOutlookAddin.detail"),
+ groupName: localize("teamstoolkit.guide.capability"),
+ data: "https://aka.ms/teamsfx-add-outlook-add-in",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ ],
+ {
+ id: "addSso",
+ label: `${localize("teamstoolkit.guides.addSso.label")}`,
+ detail: localize("teamstoolkit.guides.addSso.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-add-sso-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "connectApi",
+ label: `${localize("teamstoolkit.guides.connectApi.label")}`,
+ detail: localize("teamstoolkit.guides.connectApi.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-add-api-connection-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "cicdPipeline",
+ label: `${localize("teamstoolkit.guides.cicdPipeline.label")}`,
+ detail: localize("teamstoolkit.guides.cicdPipeline.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-add-cicd-new",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "mobilePreview",
+ label: `${localize("teamstoolkit.guides.mobilePreview.label")}`,
+ detail: localize("teamstoolkit.guides.mobilePreview.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-mobile",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "multiTenant",
+ label: `${localize("teamstoolkit.guides.multiTenant.label")}`,
+ detail: localize("teamstoolkit.guides.multiTenant.detail"),
+ groupName: localize("teamstoolkit.guide.development"),
+ data: "https://aka.ms/teamsfx-multi-tenant",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addAzureFunction",
+ label: localize("teamstoolkit.guides.addAzureFunction.label"),
+ detail: localize("teamstoolkit.guides.addAzureFunction.detail"),
+ groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
+ data: "https://aka.ms/teamsfx-add-azure-function",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addAzureSql",
+ label: localize("teamstoolkit.guides.addAzureSql.label"),
+ detail: localize("teamstoolkit.guides.addAzureSql.detail"),
+ groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
+ data: "https://aka.ms/teamsfx-add-azure-sql",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addAzureAPIM",
+ label: localize("teamstoolkit.guides.addAzureAPIM.label"),
+ detail: localize("teamstoolkit.guides.addAzureAPIM.detail"),
+ groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
+ data: "https://aka.ms/teamsfx-add-azure-apim",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ {
+ id: "addAzureKeyVault",
+ label: localize("teamstoolkit.guides.addAzureKeyVault.label"),
+ detail: localize("teamstoolkit.guides.addAzureKeyVault.detail"),
+ groupName: localize("teamstoolkit.guide.cloudServiceIntegration"),
+ data: "https://aka.ms/teamsfx-add-azure-keyvault",
+ buttons: [
+ {
+ iconPath: "file-symlink-file",
+ tooltip: localize("teamstoolkit.guide.tooltip.github"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ },
+ ],
+ returnObject: true,
+ };
+ if (TreatmentVariableValue.inProductDoc && !isSPFxProject) {
+ (config.options as StaticOptions).splice(0, 1, {
+ id: "cardActionResponse",
+ label: `${localize("teamstoolkit.guides.cardActionResponse.label")}`,
+ description: localize("teamstoolkit.common.recommended"),
+ detail: localize("teamstoolkit.guides.cardActionResponse.detail"),
+ groupName: localize("teamstoolkit.guide.scenario"),
+ data: "https://aka.ms/teamsfx-card-action-response",
+ buttons: [
+ {
+ iconPath: "file-code",
+ tooltip: localize("teamstoolkit.guide.tooltip.inProduct"),
+ command: "fx-extension.openTutorial",
+ },
+ ],
+ });
+ }
+
+ const selectedTutorial = await VS_CODE_UI.selectOption(config);
+ if (selectedTutorial.isErr()) {
+ return err(selectedTutorial.error);
+ } else {
+ const tutorial = selectedTutorial.value.result as OptionItem;
+ return openTutorialHandler([TelemetryTriggerFrom.Auto, tutorial]);
+ }
+}
+
+export function openTutorialHandler(args?: any[]): Promise> {
+ if (!args || args.length !== 2) {
+ // should never happen
+ return Promise.resolve(ok(null));
+ }
+ const tutorial = args[1] as OptionItem;
+ ExtTelemetry.sendTelemetryEvent(TelemetryEvent.OpenTutorial, {
+ ...getTriggerFromProperty(args),
+ [TelemetryProperty.TutorialName]: tutorial.id,
+ });
+ if (
+ TreatmentVariableValue.inProductDoc &&
+ (tutorial.id === "cardActionResponse" || tutorial.data === "cardActionResponse")
+ ) {
+ WebviewPanel.createOrShow(PanelType.RespondToCardActions);
+ return Promise.resolve(ok(null));
+ }
+ return VS_CODE_UI.openUrl(tutorial.data as string);
+}
diff --git a/packages/vscode-extension/src/handlers/walkthrough.ts b/packages/vscode-extension/src/handlers/walkthrough.ts
index 109f3e13a6..76f692d0c1 100644
--- a/packages/vscode-extension/src/handlers/walkthrough.ts
+++ b/packages/vscode-extension/src/handlers/walkthrough.ts
@@ -1,10 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+import * as vscode from "vscode";
import { runCommand } from "../handlers/sharedOpts";
import { ExtTelemetry } from "../telemetry/extTelemetry";
import { TelemetryEvent } from "../telemetry/extTelemetryEvents";
-import { CreateProjectResult, FxError, Result, Stage } from "@microsoft/teamsfx-api";
+import { CreateProjectResult, FxError, Result, Stage, ok } from "@microsoft/teamsfx-api";
import { getSystemInputs } from "../utils/systemEnvUtils";
import { getTriggerFromProperty } from "../utils/telemetryUtils";
@@ -24,3 +25,17 @@ export async function createProjectFromWalkthroughHandler(
const result = await runCommand(Stage.create, inputs);
return result;
}
+
+export async function openBuildIntelligentAppsWalkthroughHandler(
+ ...args: unknown[]
+): Promise> {
+ ExtTelemetry.sendTelemetryEvent(
+ TelemetryEvent.WalkThroughBuildIntelligentApps,
+ getTriggerFromProperty(args)
+ );
+ const data = await vscode.commands.executeCommand(
+ "workbench.action.openWalkthrough",
+ "TeamsDevApp.ms-teams-vscode-extension#buildIntelligentApps"
+ );
+ return Promise.resolve(ok(data));
+}
diff --git a/packages/vscode-extension/src/officeChat/commands/create/helper.ts b/packages/vscode-extension/src/officeChat/commands/create/helper.ts
index 4c74c42b3e..de305c6bdc 100644
--- a/packages/vscode-extension/src/officeChat/commands/create/helper.ts
+++ b/packages/vscode-extension/src/officeChat/commands/create/helper.ts
@@ -2,11 +2,9 @@
// Licensed under the MIT license.
import * as tmp from "tmp";
-import * as crypto from "crypto";
import * as officeTemplateMeatdata from "./officeTemplateMetadata.json";
import * as fs from "fs-extra";
import * as path from "path";
-import * as vscode from "vscode";
import {
ChatRequest,
CancellationToken,
@@ -16,22 +14,23 @@ import {
LanguageModelChatMessage,
LanguageModelChatMessageRole,
} from "vscode";
-import { IChatTelemetryData } from "../../../chat/types";
import { ProjectMetadata } from "../../../chat/commands/create/types";
import { getCopilotResponseAsString } from "../../../chat/utils";
import { getOfficeProjectMatchSystemPrompt } from "../../officePrompts";
import { officeSampleProvider } from "./officeSamples";
-import { CommandKey } from "../../../constants";
-import { TelemetryTriggerFrom } from "../../../telemetry/extTelemetryEvents";
-import { CHAT_EXECUTE_COMMAND_ID } from "../../../chat/consts";
import { fileTreeAdd, buildFileTree } from "../../../chat/commands/create/helper";
-import { getOfficeSampleDownloadUrlInfo } from "../../utils";
+import { getOfficeSample } from "../../utils";
import { getSampleFileInfo } from "@microsoft/teamsfx-core/build/component/generator/utils";
+import { OfficeChatTelemetryData } from "../../telemetry";
+import { OfficeXMLAddinGenerator } from "./officeXMLAddinGenerator/generator";
+import { CreateProjectInputs } from "@microsoft/teamsfx-api";
+import { core } from "../../../globalVariables";
+import { OfficeProjectInfo } from "../../types";
export async function matchOfficeProject(
request: ChatRequest,
token: CancellationToken,
- telemetryMetadata: IChatTelemetryData
+ telemetryData: OfficeChatTelemetryData
): Promise {
const allOfficeProjectMetadata = [
...getOfficeTemplateMetadata(),
@@ -41,8 +40,12 @@ export async function matchOfficeProject(
getOfficeProjectMatchSystemPrompt(allOfficeProjectMetadata),
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
];
- telemetryMetadata.chatMessages.push(...messages);
- const response = await getCopilotResponseAsString("copilot-gpt-4", messages, token);
+ let response = "";
+ telemetryData.chatMessages.push(...messages);
+ response = await getCopilotResponseAsString("copilot-gpt-4", messages, token);
+ telemetryData.responseChatMessages.push(
+ new LanguageModelChatMessage(LanguageModelChatMessageRole.Assistant, response)
+ );
let matchedProjectId: string;
if (response) {
try {
@@ -97,23 +100,27 @@ export function getOfficeTemplateMetadata(): ProjectMetadata[] {
export async function showOfficeSampleFileTree(
projectMetadata: ProjectMetadata,
response: ChatResponseStream
-): Promise {
+): Promise {
response.markdown(
"\nWe've found a sample project that matches your description. Take a look at it below."
);
- const downloadUrlInfo = await getOfficeSampleDownloadUrlInfo(projectMetadata.id);
- const { samplePaths, fileUrlPrefix } = await getSampleFileInfo(downloadUrlInfo, 2);
+ const sample = await getOfficeSample(projectMetadata.id);
+ const { samplePaths, fileUrlPrefix } = await getSampleFileInfo(sample.downloadUrlInfo, 2);
const tempFolder = tmp.dirSync({ unsafeCleanup: true }).name;
const nodes = await buildFileTree(
fileUrlPrefix,
samplePaths,
tempFolder,
- downloadUrlInfo.dir,
+ sample.downloadUrlInfo.dir,
2,
20
);
- response.filetree(nodes, Uri.file(path.join(tempFolder, downloadUrlInfo.dir)));
- return path.join(tempFolder, downloadUrlInfo.dir);
+ response.filetree(nodes, Uri.file(path.join(tempFolder, sample.downloadUrlInfo.dir)));
+ const result: OfficeProjectInfo = {
+ path: path.join(tempFolder, sample.downloadUrlInfo.dir),
+ host: sample.types[0],
+ };
+ return result;
}
export async function showOfficeTemplateFileTree(
@@ -122,43 +129,41 @@ export async function showOfficeTemplateFileTree(
codeSnippet?: string
): Promise {
const tempFolder = tmp.dirSync({ unsafeCleanup: true }).name;
- const tempAppName = `office-addin-${crypto.randomBytes(8).toString("hex")}`;
- const nodes = await buildTemplateFileTree(data, tempFolder, tempAppName, codeSnippet);
- response.filetree(nodes, Uri.file(path.join(tempFolder, tempAppName)));
- return path.join(tempFolder, tempAppName);
+ const nodes = await buildTemplateFileTree(data, tempFolder, data.capabilities, codeSnippet);
+ response.filetree(nodes, Uri.file(path.join(tempFolder, data.capabilities)));
+ return path.join(tempFolder, data.capabilities);
}
export async function buildTemplateFileTree(
data: any,
tempFolder: string,
- tempAppName: string,
+ appName: string,
codeSnippet?: string
): Promise {
- const createInputs = {
+ const createInputs: CreateProjectInputs = {
...data,
folder: tempFolder,
- "app-name": tempAppName,
+ "app-name": appName,
};
- await vscode.commands.executeCommand(
- CHAT_EXECUTE_COMMAND_ID,
- CommandKey.Create,
- TelemetryTriggerFrom.CopilotChat,
- createInputs
- );
- const rootFolder = path.join(tempFolder, tempAppName);
+ const generator = new OfficeXMLAddinGenerator();
+ const result = await core.createProjectByCustomizedGenerator(createInputs, generator);
+ if (result.isErr()) {
+ throw new Error("Failed to generate the project.");
+ }
+ const projectPath = result.value.projectPath;
const isCustomFunction = data.capabilities.includes("excel-custom-functions");
if (!!isCustomFunction && !!codeSnippet) {
- await mergeCFCode(rootFolder, codeSnippet);
+ await mergeCFCode(projectPath, codeSnippet);
} else if (!!codeSnippet) {
- await mergeTaskpaneCode(rootFolder, codeSnippet);
+ await mergeTaskpaneCode(projectPath, codeSnippet);
}
const root: ChatResponseFileTree = {
- name: rootFolder,
+ name: projectPath,
children: [],
};
- await fs.ensureDir(rootFolder);
- traverseFiles(rootFolder, (fullPath) => {
- const relativePath = path.relative(rootFolder, fullPath);
+ await fs.ensureDir(projectPath);
+ traverseFiles(projectPath, (fullPath) => {
+ const relativePath = path.relative(projectPath, fullPath);
fileTreeAdd(root, relativePath);
});
return root.children ?? [];
diff --git a/packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts b/packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts
index 681aa489cd..c390a8c567 100644
--- a/packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts
+++ b/packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts
@@ -13,15 +13,15 @@ import {
import { OfficeChatCommand, officeChatParticipantId } from "../../consts";
import { verbatimCopilotInteraction } from "../../../chat/utils";
import { isInputHarmful } from "../../utils";
-import { ICopilotChatOfficeResult } from "../../types";
+import { ICopilotChatOfficeResult, OfficeProjectInfo } from "../../types";
import { describeOfficeProjectSystemPrompt } from "../../officePrompts";
import { TelemetryEvent } from "../../../telemetry/extTelemetryEvents";
import { ExtTelemetry } from "../../../telemetry/extTelemetry";
-import { ChatTelemetryData } from "../../../chat/telemetry";
import { matchOfficeProject, showOfficeSampleFileTree, showOfficeTemplateFileTree } from "./helper";
import { localize } from "../../../utils/localizeUtils";
import { Planner } from "../../common/planner";
import { CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID } from "../../consts";
+import { OfficeChatTelemetryBlockReasonEnum, OfficeChatTelemetryData } from "../../telemetry";
export default async function officeCreateCommandHandler(
request: ChatRequest,
@@ -29,7 +29,7 @@ export default async function officeCreateCommandHandler(
response: ChatResponseStream,
token: CancellationToken
): Promise