From e872ff00a09c3394ad5676a1c136ae883c0cf042 Mon Sep 17 00:00:00 2001 From: Sanjula Ganepola Date: Wed, 20 Nov 2024 22:41:01 -0500 Subject: [PATCH 1/3] Add octokit Signed-off-by: Sanjula Ganepola --- package-lock.json | 369 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- tsconfig.json | 3 +- 3 files changed, 373 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2dc4569..a481314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "Apache-2.0", "dependencies": { "child_process": "^1.0.2", + "octokit": "^4.0.2", "sanitize-filename": "^1.6.3", "yaml": "^2.6.0" }, @@ -335,6 +336,326 @@ "node": ">= 8" } }, + "node_modules/@octokit/app": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@octokit/app/-/app-15.1.1.tgz", + "integrity": "sha512-fk8xrCSPTJGpyBdBNI+DcZ224dm0aApv4vi6X7/zTmANXlegKV2Td+dJ+fd7APPaPN7R+xttUsj2Fm+AFDSfMQ==", + "dependencies": { + "@octokit/auth-app": "^7.0.0", + "@octokit/auth-unauthenticated": "^6.0.0", + "@octokit/core": "^6.1.2", + "@octokit/oauth-app": "^7.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/types": "^13.0.0", + "@octokit/webhooks": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-app": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.3.tgz", + "integrity": "sha512-GZdkOp2kZTIy5dG9oXqvzUAZiPvDx4C/lMlN6yQjtG9d/+hYa7W8WXTJoOrXE8UdfL9A/sZMl206dmtkl9lwVQ==", + "dependencies": { + "@octokit/auth-oauth-app": "^8.1.0", + "@octokit/auth-oauth-user": "^5.1.0", + "@octokit/request": "^9.1.1", + "@octokit/request-error": "^6.1.1", + "@octokit/types": "^13.4.1", + "toad-cache": "^3.7.0", + "universal-github-app-jwt": "^2.2.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-oauth-app": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz", + "integrity": "sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg==", + "dependencies": { + "@octokit/auth-oauth-device": "^7.0.0", + "@octokit/auth-oauth-user": "^5.0.1", + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-oauth-device": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz", + "integrity": "sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg==", + "dependencies": { + "@octokit/oauth-methods": "^5.0.0", + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-oauth-user": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz", + "integrity": "sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw==", + "dependencies": { + "@octokit/auth-oauth-device": "^7.0.1", + "@octokit/oauth-methods": "^5.0.0", + "@octokit/request": "^9.0.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.1.tgz", + "integrity": "sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-unauthenticated": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-6.1.0.tgz", + "integrity": "sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ==", + "dependencies": { + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.2.tgz", + "integrity": "sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==", + "dependencies": { + "@octokit/auth-token": "^5.0.0", + "@octokit/graphql": "^8.0.0", + "@octokit/request": "^9.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^3.0.2", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", + "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", + "dependencies": { + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.1.1.tgz", + "integrity": "sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==", + "dependencies": { + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-app": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-7.1.3.tgz", + "integrity": "sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg==", + "dependencies": { + "@octokit/auth-oauth-app": "^8.0.0", + "@octokit/auth-oauth-user": "^5.0.1", + "@octokit/auth-unauthenticated": "^6.0.0-beta.1", + "@octokit/core": "^6.0.0", + "@octokit/oauth-authorization-url": "^7.0.0", + "@octokit/oauth-methods": "^5.0.0", + "@types/aws-lambda": "^8.10.83", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", + "integrity": "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz", + "integrity": "sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g==", + "dependencies": { + "@octokit/oauth-authorization-url": "^7.0.0", + "@octokit/request": "^9.1.0", + "@octokit/request-error": "^6.1.0", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "22.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", + "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==" + }, + "node_modules/@octokit/openapi-webhooks-types": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-8.5.1.tgz", + "integrity": "sha512-i3h1b5zpGSB39ffBbYdSGuAd0NhBAwPyA3QV3LYi/lx4lsbZiu7u2UHgXVUR6EpvOI8REOuVh1DZTRfHoJDvuQ==" + }, + "node_modules/@octokit/plugin-paginate-graphql": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-5.2.4.tgz", + "integrity": "sha512-pLZES1jWaOynXKHOqdnwZ5ULeVR6tVVCMm+AUbp0htdcyXDU95WbkYdU4R2ej1wKj5Tu94Mee2Ne0PjPO9cCyA==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.5.tgz", + "integrity": "sha512-cgwIRtKrpwhLoBi0CUNuY83DPGRMaWVjqVI/bGKsLJ4PzyWZNaEmhHroI2xlrVXkk6nFv0IsZpOp+ZWSWUS2AQ==", + "dependencies": { + "@octokit/types": "^13.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.2.6", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.6.tgz", + "integrity": "sha512-wMsdyHMjSfKjGINkdGKki06VEkgdEldIGstIEyGX0wbYHGByOwN/KiM+hAAlUwAtPkP3gvXtVQA9L3ITdV2tVw==", + "dependencies": { + "@octokit/types": "^13.6.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.2.tgz", + "integrity": "sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==", + "dependencies": { + "@octokit/request-error": "^6.0.0", + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.2.tgz", + "integrity": "sha512-FqpvcTpIWFpMMwIeSoypoJXysSAQ3R+ALJhXXSG1HTP3YZOIeLmcNcimKaXxTcws+Sh6yoRl13SJ5r8sXc1Fhw==", + "dependencies": { + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^6.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz", + "integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==", + "dependencies": { + "@octokit/endpoint": "^10.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.5.tgz", + "integrity": "sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==", + "dependencies": { + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.6.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz", + "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==", + "dependencies": { + "@octokit/openapi-types": "^22.2.0" + } + }, + "node_modules/@octokit/webhooks": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-13.4.1.tgz", + "integrity": "sha512-I5YPUtfWidh+OzyrlDahJsUpkpGK0kCTmDRbuqGmlCUzOtxdEkX3R4d6Cd08ijQYwkVXQJanPdbKuZBeV2NMaA==", + "dependencies": { + "@octokit/openapi-webhooks-types": "8.5.1", + "@octokit/request-error": "^6.0.1", + "@octokit/webhooks-methods": "^5.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/webhooks-methods": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-5.1.0.tgz", + "integrity": "sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.145", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.145.tgz", + "integrity": "sha512-dtByW6WiFk5W5Jfgz1VM+YPA21xMXTuSFoLYIDY0L44jDLLflVPtZkYuu3/YxpGcvjzKFBZLU+GyKjR0HOYtyw==" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -839,6 +1160,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/before-after-hook": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1867,6 +2198,26 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node_modules/octokit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/octokit/-/octokit-4.0.2.tgz", + "integrity": "sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg==", + "dependencies": { + "@octokit/app": "^15.0.0", + "@octokit/core": "^6.0.0", + "@octokit/oauth-app": "^7.0.0", + "@octokit/plugin-paginate-graphql": "^5.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/plugin-rest-endpoint-methods": "^13.0.0", + "@octokit/plugin-retry": "^7.0.0", + "@octokit/plugin-throttling": "^9.0.0", + "@octokit/request-error": "^6.0.0", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2391,6 +2742,14 @@ "node": ">=8.0" } }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "engines": { + "node": ">=12" + } + }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -2462,6 +2821,16 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, + "node_modules/universal-github-app-jwt": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz", + "integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==" + }, + "node_modules/universal-user-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", + "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", diff --git a/package.json b/package.json index e8c93ae..65ce1bf 100644 --- a/package.json +++ b/package.json @@ -539,6 +539,7 @@ }, "dependencies": { "child_process": "^1.0.2", + "octokit": "^4.0.2", "sanitize-filename": "^1.6.3", "yaml": "^2.6.0" }, @@ -553,4 +554,4 @@ "webpack": "^5.96.1", "webpack-cli": "^5.1.4" } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index c519a3d..47515fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { - "module": "Node16", + "module": "ESNext", + "moduleResolution": "bundler", "target": "ES2022", "lib": [ "ES2022" From 8330caaef9b35950886d9c3841debe5a9e5d9516 Mon Sep 17 00:00:00 2001 From: Sanjula Ganepola Date: Thu, 21 Nov 2024 19:16:03 -0500 Subject: [PATCH 2/3] Add dependency on vscode.git and add type definitions Signed-off-by: Sanjula Ganepola --- package.json | 20 ++- src/import/git.d.ts | 415 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 src/import/git.d.ts diff --git a/package.json b/package.json index 65ce1bf..36f4216 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,9 @@ "categories": [ "Other" ], + "extensionDependencies": [ + "vscode.git" + ], "engines": { "vscode": "^1.93.0" }, @@ -249,6 +252,12 @@ "title": "Hide", "icon": "$(eye-closed)" }, + { + "category": "GitHub Local Actions", + "command": "githubLocalActions.importFromGithub", + "title": "Import from GitHub", + "icon": "$(github)" + }, { "category": "GitHub Local Actions", "command": "githubLocalActions.editSetting", @@ -351,6 +360,10 @@ "command": "githubLocalActions.hide", "when": "never" }, + { + "command": "githubLocalActions.importFromGithub", + "when": "never" + }, { "command": "githubLocalActions.editSetting", "when": "never" @@ -492,6 +505,11 @@ "when": "view == settings && viewItem =~ /^githubLocalActions.secret(?!s)_show.*/", "group": "inline@0" }, + { + "command": "githubLocalActions.importFromGithub", + "when": "view == settings && viewItem =~ /^githubLocalActions.variables.*/", + "group": "inline@0" + }, { "command": "githubLocalActions.editSetting", "when": "view == settings && viewItem =~ /^githubLocalActions.(secret|variable|input|runner)(?!s).*/", @@ -554,4 +572,4 @@ "webpack": "^5.96.1", "webpack-cli": "^5.1.4" } -} +} \ No newline at end of file diff --git a/src/import/git.d.ts b/src/import/git.d.ts new file mode 100644 index 0000000..ee45e7a --- /dev/null +++ b/src/import/git.d.ts @@ -0,0 +1,415 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Uri, Event, Disposable, ProviderResult, Command, CancellationToken } from 'vscode'; +export { ProviderResult } from 'vscode'; + +export interface Git { + readonly path: string; +} + +export interface InputBox { + value: string; +} + +export const enum ForcePushMode { + Force, + ForceWithLease, + ForceWithLeaseIfIncludes, +} + +export const enum RefType { + Head, + RemoteHead, + Tag +} + +export interface Ref { + readonly type: RefType; + readonly name?: string; + readonly commit?: string; + readonly remote?: string; +} + +export interface UpstreamRef { + readonly remote: string; + readonly name: string; + readonly commit?: string; +} + +export interface Branch extends Ref { + readonly upstream?: UpstreamRef; + readonly ahead?: number; + readonly behind?: number; +} + +export interface CommitShortStat { + readonly files: number; + readonly insertions: number; + readonly deletions: number; +} + +export interface Commit { + readonly hash: string; + readonly message: string; + readonly parents: string[]; + readonly authorDate?: Date; + readonly authorName?: string; + readonly authorEmail?: string; + readonly commitDate?: Date; + readonly shortStat?: CommitShortStat; +} + +export interface Submodule { + readonly name: string; + readonly path: string; + readonly url: string; +} + +export interface Remote { + readonly name: string; + readonly fetchUrl?: string; + readonly pushUrl?: string; + readonly isReadOnly: boolean; +} + +export const enum Status { + INDEX_MODIFIED, + INDEX_ADDED, + INDEX_DELETED, + INDEX_RENAMED, + INDEX_COPIED, + + MODIFIED, + DELETED, + UNTRACKED, + IGNORED, + INTENT_TO_ADD, + INTENT_TO_RENAME, + TYPE_CHANGED, + + ADDED_BY_US, + ADDED_BY_THEM, + DELETED_BY_US, + DELETED_BY_THEM, + BOTH_ADDED, + BOTH_DELETED, + BOTH_MODIFIED +} + +export interface Change { + + /** + * Returns either `originalUri` or `renameUri`, depending + * on whether this change is a rename change. When + * in doubt always use `uri` over the other two alternatives. + */ + readonly uri: Uri; + readonly originalUri: Uri; + readonly renameUri: Uri | undefined; + readonly status: Status; +} + +export interface RepositoryState { + readonly HEAD: Branch | undefined; + readonly refs: Ref[]; + readonly remotes: Remote[]; + readonly submodules: Submodule[]; + readonly rebaseCommit: Commit | undefined; + + readonly mergeChanges: Change[]; + readonly indexChanges: Change[]; + readonly workingTreeChanges: Change[]; + readonly untrackedChanges: Change[]; + + readonly onDidChange: Event; +} + +export interface RepositoryUIState { + readonly selected: boolean; + readonly onDidChange: Event; +} + +/** + * Log options. + */ +export interface LogOptions { + /** Max number of log entries to retrieve. If not specified, the default is 32. */ + readonly maxEntries?: number; + readonly path?: string; + /** A commit range, such as "0a47c67f0fb52dd11562af48658bc1dff1d75a38..0bb4bdea78e1db44d728fd6894720071e303304f" */ + readonly range?: string; + readonly reverse?: boolean; + readonly sortByAuthorDate?: boolean; + readonly shortStats?: boolean; + readonly author?: string; + readonly refNames?: string[]; + readonly maxParents?: number; + readonly skip?: number; +} + +export interface CommitOptions { + all?: boolean | 'tracked'; + amend?: boolean; + signoff?: boolean; + signCommit?: boolean; + empty?: boolean; + noVerify?: boolean; + requireUserConfig?: boolean; + useEditor?: boolean; + verbose?: boolean; + /** + * string - execute the specified command after the commit operation + * undefined - execute the command specified in git.postCommitCommand + * after the commit operation + * null - do not execute any command after the commit operation + */ + postCommitCommand?: string | null; +} + +export interface FetchOptions { + remote?: string; + ref?: string; + all?: boolean; + prune?: boolean; + depth?: number; +} + +export interface InitOptions { + defaultBranch?: string; +} + +export interface RefQuery { + readonly contains?: string; + readonly count?: number; + readonly pattern?: string | string[]; + readonly sort?: 'alphabetically' | 'committerdate'; +} + +export interface BranchQuery extends RefQuery { + readonly remote?: boolean; +} + +export interface Repository { + + readonly rootUri: Uri; + readonly inputBox: InputBox; + readonly state: RepositoryState; + readonly ui: RepositoryUIState; + + readonly onDidCommit: Event; + + getConfigs(): Promise<{ key: string; value: string; }[]>; + getConfig(key: string): Promise; + setConfig(key: string, value: string): Promise; + getGlobalConfig(key: string): Promise; + + getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }>; + detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }>; + buffer(ref: string, path: string): Promise; + show(ref: string, path: string): Promise; + getCommit(ref: string): Promise; + + add(paths: string[]): Promise; + revert(paths: string[]): Promise; + clean(paths: string[]): Promise; + + apply(patch: string, reverse?: boolean): Promise; + diff(cached?: boolean): Promise; + diffWithHEAD(): Promise; + diffWithHEAD(path: string): Promise; + diffWith(ref: string): Promise; + diffWith(ref: string, path: string): Promise; + diffIndexWithHEAD(): Promise; + diffIndexWithHEAD(path: string): Promise; + diffIndexWith(ref: string): Promise; + diffIndexWith(ref: string, path: string): Promise; + diffBlobs(object1: string, object2: string): Promise; + diffBetween(ref1: string, ref2: string): Promise; + diffBetween(ref1: string, ref2: string, path: string): Promise; + + hashObject(data: string): Promise; + + createBranch(name: string, checkout: boolean, ref?: string): Promise; + deleteBranch(name: string, force?: boolean): Promise; + getBranch(name: string): Promise; + getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise; + getBranchBase(name: string): Promise; + setBranchUpstream(name: string, upstream: string): Promise; + + checkIgnore(paths: string[]): Promise>; + + getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise; + + getMergeBase(ref1: string, ref2: string): Promise; + + tag(name: string, upstream: string): Promise; + deleteTag(name: string): Promise; + + status(): Promise; + checkout(treeish: string): Promise; + + addRemote(name: string, url: string): Promise; + removeRemote(name: string): Promise; + renameRemote(name: string, newName: string): Promise; + + fetch(options?: FetchOptions): Promise; + fetch(remote?: string, ref?: string, depth?: number): Promise; + pull(unshallow?: boolean): Promise; + push(remoteName?: string, branchName?: string, setUpstream?: boolean, force?: ForcePushMode): Promise; + + blame(path: string): Promise; + log(options?: LogOptions): Promise; + + commit(message: string, opts?: CommitOptions): Promise; + merge(ref: string): Promise; + mergeAbort(): Promise; +} + +export interface RemoteSource { + readonly name: string; + readonly description?: string; + readonly url: string | string[]; +} + +export interface RemoteSourceProvider { + readonly name: string; + readonly icon?: string; // codicon name + readonly supportsQuery?: boolean; + getRemoteSources(query?: string): ProviderResult; + getBranches?(url: string): ProviderResult; + publishRepository?(repository: Repository): Promise; +} + +export interface RemoteSourcePublisher { + readonly name: string; + readonly icon?: string; // codicon name + publishRepository(repository: Repository): Promise; +} + +export interface Credentials { + readonly username: string; + readonly password: string; +} + +export interface CredentialsProvider { + getCredentials(host: Uri): ProviderResult; +} + +export interface PostCommitCommandsProvider { + getCommands(repository: Repository): Command[]; +} + +export interface PushErrorHandler { + handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise; +} + +export interface BranchProtection { + readonly remote: string; + readonly rules: BranchProtectionRule[]; +} + +export interface BranchProtectionRule { + readonly include?: string[]; + readonly exclude?: string[]; +} + +export interface BranchProtectionProvider { + onDidChangeBranchProtection: Event; + provideBranchProtection(): BranchProtection[]; +} + +export type APIState = 'uninitialized' | 'initialized'; + +export interface PublishEvent { + repository: Repository; + branch?: string; +} + +export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; + readonly onDidPublish: Event; + readonly git: Git; + readonly repositories: Repository[]; + readonly onDidOpenRepository: Event; + readonly onDidCloseRepository: Event; + + toGitUri(uri: Uri, ref: string): Uri; + getRepository(uri: Uri): Repository | null; + init(root: Uri, options?: InitOptions): Promise; + openRepository(root: Uri): Promise + + registerRemoteSourcePublisher(publisher: RemoteSourcePublisher): Disposable; + registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable; + registerCredentialsProvider(provider: CredentialsProvider): Disposable; + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable; + registerPushErrorHandler(handler: PushErrorHandler): Disposable; + registerBranchProtectionProvider(root: Uri, provider: BranchProtectionProvider): Disposable; +} + +export interface GitExtension { + + readonly enabled: boolean; + readonly onDidChangeEnablement: Event; + + /** + * Returns a specific API version. + * + * Throws error if git extension is disabled. You can listen to the + * [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event + * to know when the extension becomes enabled/disabled. + * + * @param version Version number. + * @returns API instance + */ + getAPI(version: 1): API; +} + +export const enum GitErrorCodes { + BadConfigFile = 'BadConfigFile', + AuthenticationFailed = 'AuthenticationFailed', + NoUserNameConfigured = 'NoUserNameConfigured', + NoUserEmailConfigured = 'NoUserEmailConfigured', + NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified', + NotAGitRepository = 'NotAGitRepository', + NotAtRepositoryRoot = 'NotAtRepositoryRoot', + Conflict = 'Conflict', + StashConflict = 'StashConflict', + UnmergedChanges = 'UnmergedChanges', + PushRejected = 'PushRejected', + ForcePushWithLeaseRejected = 'ForcePushWithLeaseRejected', + ForcePushWithLeaseIfIncludesRejected = 'ForcePushWithLeaseIfIncludesRejected', + RemoteConnectionError = 'RemoteConnectionError', + DirtyWorkTree = 'DirtyWorkTree', + CantOpenResource = 'CantOpenResource', + GitNotFound = 'GitNotFound', + CantCreatePipe = 'CantCreatePipe', + PermissionDenied = 'PermissionDenied', + CantAccessRemote = 'CantAccessRemote', + RepositoryNotFound = 'RepositoryNotFound', + RepositoryIsLocked = 'RepositoryIsLocked', + BranchNotFullyMerged = 'BranchNotFullyMerged', + NoRemoteReference = 'NoRemoteReference', + InvalidBranchName = 'InvalidBranchName', + BranchAlreadyExists = 'BranchAlreadyExists', + NoLocalChanges = 'NoLocalChanges', + NoStashFound = 'NoStashFound', + LocalChangesOverwritten = 'LocalChangesOverwritten', + NoUpstreamBranch = 'NoUpstreamBranch', + IsInSubmodule = 'IsInSubmodule', + WrongCase = 'WrongCase', + CantLockRef = 'CantLockRef', + CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', + PatchDoesNotApply = 'PatchDoesNotApply', + NoPathFound = 'NoPathFound', + UnknownPath = 'UnknownPath', + EmptyCommitMessage = 'EmptyCommitMessage', + BranchFastForwardRejected = 'BranchFastForwardRejected', + BranchNotYetBorn = 'BranchNotYetBorn', + TagConflict = 'TagConflict', + CherryPickEmpty = 'CherryPickEmpty', + CherryPickConflict = 'CherryPickConflict' +} From a0974c3d69bb43d59a9592866bb2f0cfe2f5703e Mon Sep 17 00:00:00 2001 From: Sanjula Ganepola Date: Thu, 21 Nov 2024 19:32:01 -0500 Subject: [PATCH 3/3] Add github manager with authentication and import variable support Signed-off-by: Sanjula Ganepola --- src/githubManager.ts | 155 ++++++++++++++++++ src/historyManager.ts | 2 +- src/settingsManager.ts | 38 ++++- .../settings/settingsTreeDataProvider.ts | 109 +++++++++++- 4 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 src/githubManager.ts diff --git a/src/githubManager.ts b/src/githubManager.ts new file mode 100644 index 0000000..722d302 --- /dev/null +++ b/src/githubManager.ts @@ -0,0 +1,155 @@ +import { Octokit } from "octokit"; +import * as path from "path"; +import { authentication, AuthenticationSession, commands, extensions, window, WorkspaceFolder } from "vscode"; +import { GitExtension } from "./import/git"; + +export interface Response { + data: T, + error?: string +} + +export interface GithubRepository { + owner: string, + repo: string +} + +export interface GithubEnvironment { + name: string +} + +export interface GithubVariable { + name: string, + value: string +} + +export class GitHubManager { + async getRepository(workspaceFolder: WorkspaceFolder, command: string, args: any[]): Promise { + const gitApi = extensions.getExtension('vscode.git')?.exports.getAPI(1); + if (gitApi) { + if (gitApi.state === 'initialized') { + const repository = gitApi.getRepository(workspaceFolder.uri); + + if (repository) { + const remoteOriginUrl = await repository.getConfig('remote.origin.url'); + + if (remoteOriginUrl) { + const parsedPath = path.parse(remoteOriginUrl); + const parsedParentPath = path.parse(parsedPath.dir); + + return { + owner: parsedParentPath.name, + repo: parsedPath.name + }; + } else { + window.showErrorMessage('Remote GitHub URL not found.'); + } + } else { + window.showErrorMessage(`${workspaceFolder.name} does not have a Git repository`); + } + } else { + window.showErrorMessage('Git extension is still being initialized. Please try again later.', 'Try Again').then(async value => { + if (value && value === 'Try Again') { + await commands.executeCommand(command, ...args); + } + }); + } + } else { + window.showErrorMessage('Failed to load VS Code Git API.'); + } + } + + async getEnvironments(owner: string, repo: string): Promise> { + const environments: Response = { + data: [] + }; + + try { + const response = await this.get( + owner, + repo, + '/repos/{owner}/{repo}/environments' + ); + + if (response) { + for (const environment of response.environments) { + environments.data.push({ + name: environment.name + }); + } + } + } catch (error: any) { + environments.error = error.message ? error.message : error; + } + + return environments; + } + + async getVariables(owner: string, repo: string, environment?: string): Promise> { + const variables: Response = { + data: [] + }; + + try { + const response = environment ? + await this.get( + owner, + repo, + '/repos/{owner}/{repo}/environments/{environment_name}/variables', + { + environment_name: environment + } + ) : + await this.get( + owner, + repo, + '/repos/{owner}/{repo}/actions/variables' + ); + + if (response) { + for (const variable of response.variables) { + variables.data.push({ + name: variable.name, + value: variable.value + }); + } + } + } catch (error: any) { + variables.error = error.message ? error.message : error; + } + + return variables; + } + + private async get(owner: string, repo: string, endpoint: string, additionalParams?: Record) { + const session = await this.getSession(); + if (!session) { + return; + } + + const octokit = new Octokit({ + auth: session.accessToken + }); + + const response = await octokit.request(`GET ${endpoint}`, { + owner: owner, + repo: repo, + ...additionalParams, + headers: { + 'X-GitHub-Api-Version': '2022-11-28' + } + }); + + if (response.status === 200) { + return response.data; + } + } + + private async getSession(): Promise { + try { + return await authentication.getSession('github', ['repo'], { createIfNone: true }); + } catch (error) { + window.showErrorMessage(`Failed to authenticate to GitHub. Error ${error}`); + return; + } + } +} \ No newline at end of file diff --git a/src/historyManager.ts b/src/historyManager.ts index 753cab3..cf38f5d 100644 --- a/src/historyManager.ts +++ b/src/historyManager.ts @@ -58,7 +58,7 @@ export class HistoryManager { async viewOutput(history: History) { try { - const document = await workspace.openTextDocument(history.logPath) + const document = await workspace.openTextDocument(history.logPath); await window.showTextDocument(document); } catch (error) { window.showErrorMessage(`${history.name} #${history.count} log file not found`); diff --git a/src/settingsManager.ts b/src/settingsManager.ts index fc291d1..01ae06c 100644 --- a/src/settingsManager.ts +++ b/src/settingsManager.ts @@ -1,5 +1,6 @@ import { WorkspaceFolder } from "vscode"; import { act } from "./extension"; +import { GitHubManager } from "./githubManager"; import { SecretManager } from "./secretManager"; import { StorageKey, StorageManager } from "./storageManager"; @@ -19,6 +20,7 @@ export enum Visibility { export class SettingsManager { storageManager: StorageManager; secretManager: SecretManager; + githubManager: GitHubManager; static secretsRegExp: RegExp = /\${{\s*secrets\.(.*?)\s*}}/g; static variablesRegExp: RegExp = /\${{\s*vars\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g; static inputsRegExp: RegExp = /\${{\s*(?:inputs|github\.event\.inputs)\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g; @@ -27,6 +29,7 @@ export class SettingsManager { constructor(storageManager: StorageManager, secretManager: SecretManager) { this.storageManager = storageManager; this.secretManager = secretManager; + this.githubManager = new GitHubManager(); } async getSettings(workspaceFolder: WorkspaceFolder, isUserSelected: boolean) { @@ -34,12 +37,14 @@ export class SettingsManager { const variables = (await this.getSetting(workspaceFolder, SettingsManager.variablesRegExp, StorageKey.Variables, false, Visibility.show)).filter(variable => !isUserSelected || variable.selected); const inputs = (await this.getSetting(workspaceFolder, SettingsManager.inputsRegExp, StorageKey.Inputs, false, Visibility.show)).filter(input => !isUserSelected || (input.selected && input.value)); const runners = (await this.getSetting(workspaceFolder, SettingsManager.runnersRegExp, StorageKey.Runners, false, Visibility.show)).filter(runner => !isUserSelected || (runner.selected && runner.value)); + const environments = await this.getEnvironments(workspaceFolder); return { secrets: secrets, variables: variables, inputs: inputs, - runners: runners + runners: runners, + environments: environments }; } @@ -89,6 +94,37 @@ export class SettingsManager { return settings; } + async getEnvironments(workspaceFolder: WorkspaceFolder): Promise { + const environments: Setting[] = []; + + const workflows = await act.workflowsManager.getWorkflows(workspaceFolder); + for (const workflow of workflows) { + if (!workflow.yaml) { + continue; + } + + const jobs = workflow.yaml?.jobs; + if (jobs) { + for (const details of Object.values(jobs)) { + if (details.environment) { + const existingEnvironment = environments.find(environment => environment.key === details.environment); + if (!existingEnvironment) { + environments.push({ + key: details.environment, + value: '', + password: false, + selected: false, + visible: Visibility.show + }); + } + } + } + } + } + + return environments; + } + async editSetting(workspaceFolder: WorkspaceFolder, newSetting: Setting, storageKey: StorageKey) { const value = newSetting.value; if (storageKey === StorageKey.Secrets) { diff --git a/src/views/settings/settingsTreeDataProvider.ts b/src/views/settings/settingsTreeDataProvider.ts index 65ac2ed..4e4beaf 100644 --- a/src/views/settings/settingsTreeDataProvider.ts +++ b/src/views/settings/settingsTreeDataProvider.ts @@ -1,6 +1,7 @@ -import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeCheckboxChangeEvent, TreeDataProvider, TreeItem, TreeItemCheckboxState, window, workspace } from "vscode"; +import { CancellationToken, commands, EventEmitter, ExtensionContext, QuickPickItem, QuickPickItemKind, ThemeIcon, TreeCheckboxChangeEvent, TreeDataProvider, TreeItem, TreeItemCheckboxState, window, workspace } from "vscode"; import { act } from "../../extension"; import { Visibility } from "../../settingsManager"; +import { StorageKey } from "../../storageManager"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import SettingTreeItem from "./setting"; import WorkspaceFolderSettingsTreeItem from "./workspaceFolderSettings"; @@ -27,6 +28,112 @@ export default class SettingsTreeDataProvider implements TreeDataProvider { + const settings = await act.settingsManager.getSettings(settingTreeItem.workspaceFolder, false); + const variableNames = settings.variables.map(variable => variable.key); + if (variableNames.length > 0) { + const repository = await act.settingsManager.githubManager.getRepository(settingTreeItem.workspaceFolder, 'githubLocalActions.importFromGithub', [settingTreeItem]); + if (repository) { + const variableOptions: QuickPickItem[] = []; + const errors: string[] = []; + + await window.withProgress({ location: { viewId: SettingsTreeDataProvider.VIEW_ID } }, async () => { + // Get repository variables + const repositoryVariables = await act.settingsManager.githubManager.getVariables(repository.owner, repository.repo); + if (repositoryVariables.error) { + errors.push(repositoryVariables.error); + } else { + const matchingVariables = repositoryVariables.data.filter(variable => variableNames.includes(variable.name)); + if (matchingVariables.length > 0) { + variableOptions.push({ + label: 'Repository Variables', + kind: QuickPickItemKind.Separator + }); + + variableOptions.push( + ...matchingVariables.map(variable => { + return { + label: variable.name, + description: variable.value, + iconPath: new ThemeIcon('symbol-variable') + }; + }) + ); + } + } + + // Get environment variables + const environments = await act.settingsManager.githubManager.getEnvironments(repository.owner, repository.repo); + if (environments.error) { + errors.push(environments.error); + } else { + for (const environment of environments.data) { + const environmentVariables = await act.settingsManager.githubManager.getVariables(repository.owner, repository.repo, environment.name); + if (environmentVariables.error) { + errors.push(environmentVariables.error); + } else { + const matchingVariables = environmentVariables.data.filter(variable => variableNames.includes(variable.name)); + if (matchingVariables.length > 0) { + variableOptions.push({ + label: environment.name, + kind: QuickPickItemKind.Separator + }); + + variableOptions.push( + ...matchingVariables.map(variable => { + return { + label: variable.name, + description: variable.value, + iconPath: new ThemeIcon('symbol-variable') + }; + }) + ); + } + } + } + } + }); + + if (errors.length > 0) { + window.showErrorMessage(`Error(s) encountered retrieving variables from GitHub. Errors: ${[...new Set(errors)].join(' ')}`); + } + + if (variableOptions.length > 0) { + const selectedVariables = await window.showQuickPick(variableOptions, { + title: 'Select the variables to import from GitHub', + placeHolder: 'Variables', + matchOnDescription: true, + canPickMany: true + }); + + if (selectedVariables) { + const seen = new Set(); + const hasDuplicates = selectedVariables.some(variable => { + return seen.size === seen.add(variable.label).size; + }); + + if (hasDuplicates) { + window.showErrorMessage('Duplicate variables selected'); + } else { + for await (const variable of selectedVariables) { + const newSetting = settings.variables.find(existingVariable => existingVariable.key === variable.label); + if (newSetting && variable.description) { + newSetting.value = variable.description; + await act.settingsManager.editSetting(settingTreeItem.workspaceFolder, newSetting, StorageKey.Variables); + } + } + + this.refresh(); + } + } + } else if (errors.length === 0) { + window.showErrorMessage('No matching variables defined in Github'); + } + } + } else { + window.showErrorMessage('No variables found in workflow(s)'); + } + }), commands.registerCommand('githubLocalActions.editSetting', async (settingTreeItem: SettingTreeItem) => { const newValue = await window.showInputBox({ prompt: `Enter the value for ${settingTreeItem.setting.value}`,