Merge pull request #62 from SanjulaGanepola/feature/github-manager

Add `Import from GitHub` action to import repository/environment variables
This commit is contained in:
Sanjula Ganepola
2024-11-21 19:39:24 -05:00
committed by GitHub
8 changed files with 1106 additions and 4 deletions

369
package-lock.json generated
View File

@@ -10,6 +10,7 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"child_process": "^1.0.2", "child_process": "^1.0.2",
"octokit": "^4.0.2",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"yaml": "^2.6.0" "yaml": "^2.6.0"
}, },
@@ -335,6 +336,326 @@
"node": ">= 8" "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": { "node_modules/@types/eslint": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@@ -839,6 +1160,16 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "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": { "node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -1867,6 +2198,26 @@
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
"dev": true "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": { "node_modules/optionator": {
"version": "0.9.4", "version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -2391,6 +2742,14 @@
"node": ">=8.0" "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": { "node_modules/truncate-utf8-bytes": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
@@ -2462,6 +2821,16 @@
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true "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": { "node_modules/update-browserslist-db": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",

View File

@@ -25,6 +25,9 @@
"categories": [ "categories": [
"Other" "Other"
], ],
"extensionDependencies": [
"vscode.git"
],
"engines": { "engines": {
"vscode": "^1.93.0" "vscode": "^1.93.0"
}, },
@@ -249,6 +252,12 @@
"title": "Hide", "title": "Hide",
"icon": "$(eye-closed)" "icon": "$(eye-closed)"
}, },
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.importFromGithub",
"title": "Import from GitHub",
"icon": "$(github)"
},
{ {
"category": "GitHub Local Actions", "category": "GitHub Local Actions",
"command": "githubLocalActions.editSetting", "command": "githubLocalActions.editSetting",
@@ -351,6 +360,10 @@
"command": "githubLocalActions.hide", "command": "githubLocalActions.hide",
"when": "never" "when": "never"
}, },
{
"command": "githubLocalActions.importFromGithub",
"when": "never"
},
{ {
"command": "githubLocalActions.editSetting", "command": "githubLocalActions.editSetting",
"when": "never" "when": "never"
@@ -492,6 +505,11 @@
"when": "view == settings && viewItem =~ /^githubLocalActions.secret(?!s)_show.*/", "when": "view == settings && viewItem =~ /^githubLocalActions.secret(?!s)_show.*/",
"group": "inline@0" "group": "inline@0"
}, },
{
"command": "githubLocalActions.importFromGithub",
"when": "view == settings && viewItem =~ /^githubLocalActions.variables.*/",
"group": "inline@0"
},
{ {
"command": "githubLocalActions.editSetting", "command": "githubLocalActions.editSetting",
"when": "view == settings && viewItem =~ /^githubLocalActions.(secret|variable|input|runner)(?!s).*/", "when": "view == settings && viewItem =~ /^githubLocalActions.(secret|variable|input|runner)(?!s).*/",
@@ -551,6 +569,7 @@
}, },
"dependencies": { "dependencies": {
"child_process": "^1.0.2", "child_process": "^1.0.2",
"octokit": "^4.0.2",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"yaml": "^2.6.0" "yaml": "^2.6.0"
}, },

155
src/githubManager.ts Normal file
View File

@@ -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<T> {
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<GithubRepository | undefined> {
const gitApi = extensions.getExtension<GitExtension>('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<Response<GithubEnvironment[]>> {
const environments: Response<GithubEnvironment[]> = {
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<Response<GithubVariable[]>> {
const variables: Response<GithubVariable[]> = {
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<string, any>) {
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<AuthenticationSession | undefined> {
try {
return await authentication.getSession('github', ['repo'], { createIfNone: true });
} catch (error) {
window.showErrorMessage(`Failed to authenticate to GitHub. Error ${error}`);
return;
}
}
}

View File

@@ -58,7 +58,7 @@ export class HistoryManager {
async viewOutput(history: History) { async viewOutput(history: History) {
try { try {
const document = await workspace.openTextDocument(history.logPath) const document = await workspace.openTextDocument(history.logPath);
await window.showTextDocument(document); await window.showTextDocument(document);
} catch (error) { } catch (error) {
window.showErrorMessage(`${history.name} #${history.count} log file not found`); window.showErrorMessage(`${history.name} #${history.count} log file not found`);

415
src/import/git.d.ts vendored Normal file
View File

@@ -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<void>;
}
export interface RepositoryUIState {
readonly selected: boolean;
readonly onDidChange: Event<void>;
}
/**
* 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<void>;
getConfigs(): Promise<{ key: string; value: string; }[]>;
getConfig(key: string): Promise<string>;
setConfig(key: string, value: string): Promise<string>;
getGlobalConfig(key: string): Promise<string>;
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<Buffer>;
show(ref: string, path: string): Promise<string>;
getCommit(ref: string): Promise<Commit>;
add(paths: string[]): Promise<void>;
revert(paths: string[]): Promise<void>;
clean(paths: string[]): Promise<void>;
apply(patch: string, reverse?: boolean): Promise<void>;
diff(cached?: boolean): Promise<string>;
diffWithHEAD(): Promise<Change[]>;
diffWithHEAD(path: string): Promise<string>;
diffWith(ref: string): Promise<Change[]>;
diffWith(ref: string, path: string): Promise<string>;
diffIndexWithHEAD(): Promise<Change[]>;
diffIndexWithHEAD(path: string): Promise<string>;
diffIndexWith(ref: string): Promise<Change[]>;
diffIndexWith(ref: string, path: string): Promise<string>;
diffBlobs(object1: string, object2: string): Promise<string>;
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
hashObject(data: string): Promise<string>;
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
getBranchBase(name: string): Promise<Branch | undefined>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
checkIgnore(paths: string[]): Promise<Set<string>>;
getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
getMergeBase(ref1: string, ref2: string): Promise<string | undefined>;
tag(name: string, upstream: string): Promise<void>;
deleteTag(name: string): Promise<void>;
status(): Promise<void>;
checkout(treeish: string): Promise<void>;
addRemote(name: string, url: string): Promise<void>;
removeRemote(name: string): Promise<void>;
renameRemote(name: string, newName: string): Promise<void>;
fetch(options?: FetchOptions): Promise<void>;
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
pull(unshallow?: boolean): Promise<void>;
push(remoteName?: string, branchName?: string, setUpstream?: boolean, force?: ForcePushMode): Promise<void>;
blame(path: string): Promise<string>;
log(options?: LogOptions): Promise<Commit[]>;
commit(message: string, opts?: CommitOptions): Promise<void>;
merge(ref: string): Promise<void>;
mergeAbort(): Promise<void>;
}
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<RemoteSource[]>;
getBranches?(url: string): ProviderResult<string[]>;
publishRepository?(repository: Repository): Promise<void>;
}
export interface RemoteSourcePublisher {
readonly name: string;
readonly icon?: string; // codicon name
publishRepository(repository: Repository): Promise<void>;
}
export interface Credentials {
readonly username: string;
readonly password: string;
}
export interface CredentialsProvider {
getCredentials(host: Uri): ProviderResult<Credentials>;
}
export interface PostCommitCommandsProvider {
getCommands(repository: Repository): Command[];
}
export interface PushErrorHandler {
handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise<boolean>;
}
export interface BranchProtection {
readonly remote: string;
readonly rules: BranchProtectionRule[];
}
export interface BranchProtectionRule {
readonly include?: string[];
readonly exclude?: string[];
}
export interface BranchProtectionProvider {
onDidChangeBranchProtection: Event<Uri>;
provideBranchProtection(): BranchProtection[];
}
export type APIState = 'uninitialized' | 'initialized';
export interface PublishEvent {
repository: Repository;
branch?: string;
}
export interface API {
readonly state: APIState;
readonly onDidChangeState: Event<APIState>;
readonly onDidPublish: Event<PublishEvent>;
readonly git: Git;
readonly repositories: Repository[];
readonly onDidOpenRepository: Event<Repository>;
readonly onDidCloseRepository: Event<Repository>;
toGitUri(uri: Uri, ref: string): Uri;
getRepository(uri: Uri): Repository | null;
init(root: Uri, options?: InitOptions): Promise<Repository | null>;
openRepository(root: Uri): Promise<Repository | null>
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<boolean>;
/**
* 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'
}

View File

@@ -1,5 +1,6 @@
import { WorkspaceFolder } from "vscode"; import { WorkspaceFolder } from "vscode";
import { act } from "./extension"; import { act } from "./extension";
import { GitHubManager } from "./githubManager";
import { SecretManager } from "./secretManager"; import { SecretManager } from "./secretManager";
import { StorageKey, StorageManager } from "./storageManager"; import { StorageKey, StorageManager } from "./storageManager";
@@ -19,6 +20,7 @@ export enum Visibility {
export class SettingsManager { export class SettingsManager {
storageManager: StorageManager; storageManager: StorageManager;
secretManager: SecretManager; secretManager: SecretManager;
githubManager: GitHubManager;
static secretsRegExp: RegExp = /\${{\s*secrets\.(.*?)\s*}}/g; static secretsRegExp: RegExp = /\${{\s*secrets\.(.*?)\s*}}/g;
static variablesRegExp: RegExp = /\${{\s*vars\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g; static variablesRegExp: RegExp = /\${{\s*vars\.(.*?)(?:\s*==\s*(.*?))?\s*}}/g;
static inputsRegExp: RegExp = /\${{\s*(?:inputs|github\.event\.inputs)\.(.*?)(?:\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) { constructor(storageManager: StorageManager, secretManager: SecretManager) {
this.storageManager = storageManager; this.storageManager = storageManager;
this.secretManager = secretManager; this.secretManager = secretManager;
this.githubManager = new GitHubManager();
} }
async getSettings(workspaceFolder: WorkspaceFolder, isUserSelected: boolean) { 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 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 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 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 { return {
secrets: secrets, secrets: secrets,
variables: variables, variables: variables,
inputs: inputs, inputs: inputs,
runners: runners runners: runners,
environments: environments
}; };
} }
@@ -89,6 +94,37 @@ export class SettingsManager {
return settings; return settings;
} }
async getEnvironments(workspaceFolder: WorkspaceFolder): Promise<Setting[]> {
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<any>(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) { async editSetting(workspaceFolder: WorkspaceFolder, newSetting: Setting, storageKey: StorageKey) {
const value = newSetting.value; const value = newSetting.value;
if (storageKey === StorageKey.Secrets) { if (storageKey === StorageKey.Secrets) {

View File

@@ -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 { act } from "../../extension";
import { Visibility } from "../../settingsManager"; import { Visibility } from "../../settingsManager";
import { StorageKey } from "../../storageManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem"; import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import SettingTreeItem from "./setting"; import SettingTreeItem from "./setting";
import WorkspaceFolderSettingsTreeItem from "./workspaceFolderSettings"; import WorkspaceFolderSettingsTreeItem from "./workspaceFolderSettings";
@@ -27,6 +28,112 @@ export default class SettingsTreeDataProvider implements TreeDataProvider<Github
await act.settingsManager.editSetting(settingTreeItem.workspaceFolder, newSetting, settingTreeItem.storageKey); await act.settingsManager.editSetting(settingTreeItem.workspaceFolder, newSetting, settingTreeItem.storageKey);
this.refresh(); this.refresh();
}), }),
commands.registerCommand('githubLocalActions.importFromGithub', async (settingTreeItem: SettingTreeItem) => {
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) => { commands.registerCommand('githubLocalActions.editSetting', async (settingTreeItem: SettingTreeItem) => {
const newValue = await window.showInputBox({ const newValue = await window.showInputBox({
prompt: `Enter the value for ${settingTreeItem.setting.value}`, prompt: `Enter the value for ${settingTreeItem.setting.value}`,

View File

@@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "Node16", "module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2022", "target": "ES2022",
"lib": [ "lib": [
"ES2022" "ES2022"