Skip to content

Commit 4dca6cb

Browse files
Update KubeloginInstaller task to handle GitHub API rate limit errors (#21527)
* Enhance error handling in KubeloginInstallerV0 - Update error messages for GitHub API rate limits and version validation in resources. - Add new tests for GitHub API rate limit and HTTP error handling. - Increment task version to 267. * Update Tasks/KubeloginInstallerV0/Strings/resources.resjson/en-US/resources.resjson Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Tasks/KubeloginInstallerV0/task.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Refactor GitHub API rate limit error messages for clarity and consistency * Improve error handling tests in KubeloginInstallerV0 to validate GitHub API responses * Enhance error handling in KubeloginInstallerV0 to include latest tag retrieval errors and improve test coverage for GitHub API rate limits * Remove error messages for GitHub API rate limits and specific HTTP errors from TestStrings in KubeloginInstallerV0 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 8b7abd5 commit 4dca6cb

File tree

6 files changed

+196
-41
lines changed

6 files changed

+196
-41
lines changed

Tasks/KubeloginInstallerV0/Strings/resources.resjson/en-US/resources.resjson

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,22 @@
77
"loc.input.help.kubeloginVersion": "The version of kubelogin to use",
88
"loc.input.label.gitHubConnection": "GitHub Connection",
99
"loc.input.help.gitHubConnection": "A GitHub connection is needed to prevent anonymous requests limits to the Github API for [Azure/kubelogin](https://github.com/azure/kubelogin) from impacting the installation. Leaving this empty may cause failures if the request limit is reached. This connection does not require ANY permissions.",
10-
"loc.messages.Info_VerifyKubeloginInstallation": "Verifying kubelogin installation...",
11-
"loc.messages.Info_ResolvedToolFromCache": "Resolved from tool cache: %s",
12-
"loc.messages.Info_UsingToolPath": "Using tool path: %s",
13-
"loc.messages.Info_UsingVersion": "Using version: %s",
10+
"loc.messages.Err_ExtractionFailed": "Failed to extract package with error %s",
11+
"loc.messages.Err_GithubApiRateLimitExceeded": "GitHub API rate limit exceeded. To increase the rate limit, provide a GitHub connection via the gitHubConnection input and set the USE_AUTHORIZATION_FOR_API_CALL variable.",
12+
"loc.messages.Err_LatestTagNotFound": "Could not retrieve the latest kubelogin version tag from GitHub",
13+
"loc.messages.Err_NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.",
14+
"loc.messages.Err_VersionNotFound": "Kubelogin version %s was not found",
1415
"loc.messages.Info_CachingTool": "Caching kubelog version: %s",
15-
"loc.messages.Info_ToolDownloaded": "Release successfully downloaded to %s",
16-
"loc.messages.Info_KubeloginRelease": "Kubelogin release: %s",
16+
"loc.messages.Info_DownloadingFailed": "Failed to download kubelogin, exception %s",
17+
"loc.messages.Info_KubeloginDownloading": "Downloading kubelogin",
1718
"loc.messages.Info_KubeloginPlatform": "Kubelogin platform: %s",
18-
"loc.messages.Info_KubeloginVersion": "Kubelogin version: %s",
19+
"loc.messages.Info_KubeloginRelease": "Kubelogin release: %s",
1920
"loc.messages.Info_KubeloginReleaseURL": "Kubelogin release URL: %s",
20-
"loc.messages.Info_DownloadingFailed": "Failed to download kubelogin, exception %s",
21-
"loc.messages.Err_ExtractionFailed": "Failed to extract package with error %s",
22-
"loc.messages.Err_VersionNotFound": "Kubelogin version %s was not found",
23-
"loc.messages.Err_NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.",
24-
"loc.messages.SucceedMsg": "Kubelogin has been successfully installed",
25-
"loc.messages.Info_KubeloginDownloading": "Downloading kubelogin"
21+
"loc.messages.Info_KubeloginVersion": "Kubelogin version: %s",
22+
"loc.messages.Info_ResolvedToolFromCache": "Resolved from tool cache: %s",
23+
"loc.messages.Info_ToolDownloaded": "Release successfully downloaded to %s",
24+
"loc.messages.Info_UsingToolPath": "Using tool path: %s",
25+
"loc.messages.Info_UsingVersion": "Using version: %s",
26+
"loc.messages.Info_VerifyKubeloginInstallation": "Verifying kubelogin installation...",
27+
"loc.messages.SucceedMsg": "Kubelogin has been successfully installed"
2628
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import * as assert from 'assert';
2+
import path = require('path');
3+
4+
import tmrm = require('azure-pipelines-task-lib/mock-run');
5+
import webClient = require('azure-pipelines-tasks-azure-arm-rest/webClient');
6+
7+
const tr = new tmrm.TaskMockRunner(path.join(__dirname, '..', 'kubelogin.js'));
8+
9+
export class GetKubeloginReleaseErrorHandlingL0Tests {
10+
static tagVersion = 'v0.0.29';
11+
12+
public static startTests() {
13+
this.validateGithubApiRateLimitErrorForLatestTag();
14+
this.validateLatestTagNotFoundError();
15+
this.validateGithubApiRateLimitErrorDownloadSpecificRelease();
16+
this.validateGithubApiDownloadSpecificReleaseNotFoundError();
17+
}
18+
19+
public static validateGithubApiRateLimitErrorForLatestTag() {
20+
tr.setInput('kubeloginVersion', 'latest');
21+
22+
tr.registerMock('azure-pipelines-tasks-azure-arm-rest/webClient', {
23+
WebRequest: webClient.WebRequest,
24+
sendRequest: (request) => {
25+
if (request.uri.endsWith('/releases/latest')) {
26+
return {
27+
statusCode: 403,
28+
headers: {
29+
'x-ratelimit-remaining': '0'
30+
}
31+
};
32+
}
33+
}
34+
});
35+
36+
try {
37+
tr.run();
38+
} catch (error) {
39+
assert(error.includes("##vso[task.complete result=Failed;]loc_mock_Err_GithubApiRateLimitExceeded"), 'Should have contained rate limit error message');
40+
}
41+
}
42+
43+
public static validateLatestTagNotFoundError() {
44+
tr.setInput('kubeloginVersion', 'latest');
45+
46+
tr.registerMock('azure-pipelines-tasks-azure-arm-rest/webClient', {
47+
WebRequest: webClient.WebRequest,
48+
sendRequest: (request) => {
49+
if (request.uri.endsWith('/releases/latest')) {
50+
return {
51+
statusCode: 404
52+
};
53+
}
54+
}
55+
});
56+
57+
try {
58+
tr.run();
59+
} catch (error) {
60+
assert(error.includes("##vso[task.complete result=Failed;]loc_mock_Err_LatestTagNotFound"), 'Should have contained latest tag not found error message');
61+
}
62+
}
63+
64+
public static validateGithubApiRateLimitErrorDownloadSpecificRelease() {
65+
tr.setInput('kubeloginVersion', 'latest');
66+
67+
tr.registerMock('azure-pipelines-tasks-azure-arm-rest/webClient', {
68+
WebRequest: webClient.WebRequest,
69+
sendRequest: (request) => {
70+
if (request.uri.endsWith('/releases/latest')) {
71+
return {
72+
body: {
73+
tag_name: this.tagVersion
74+
}
75+
};
76+
}
77+
78+
return {
79+
statusCode: 403,
80+
headers: {
81+
'x-ratelimit-remaining': '0'
82+
}
83+
};
84+
}
85+
});
86+
87+
try {
88+
tr.run();
89+
} catch (error) {
90+
assert(error.includes("##vso[task.complete result=Failed;]loc_mock_Err_GithubApiRateLimitExceeded"), 'Should have contained rate limit error message');
91+
}
92+
}
93+
94+
public static validateGithubApiDownloadSpecificReleaseNotFoundError() {
95+
tr.setInput('kubeloginVersion', 'latest');
96+
97+
tr.registerMock('azure-pipelines-tasks-azure-arm-rest/webClient', {
98+
WebRequest: webClient.WebRequest,
99+
sendRequest: (request) => {
100+
if (request.uri.endsWith('/releases/latest')) {
101+
return {
102+
body: {
103+
tag_name: this.tagVersion
104+
}
105+
};
106+
}
107+
108+
if (request.uri.includes(`/releases/tags/${this.tagVersion}`)) {
109+
return {
110+
statusCode: 404,
111+
statusMessage: 'Not Found'
112+
};
113+
}
114+
}
115+
});
116+
117+
try {
118+
tr.run();
119+
} catch (error) {
120+
assert(error.includes("##vso[task.complete result=Failed;]loc_mock_Err_VersionNotFound"), 'Should have contained version not found error message');
121+
}
122+
}
123+
}
124+
125+
GetKubeloginReleaseErrorHandlingL0Tests.startTests();

Tasks/KubeloginInstallerV0/Tests/L0.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path = require('path');
22
import * as assert from 'assert';
33

44
import * as ttm from 'azure-pipelines-task-lib/mock-test';
5+
56
import { TestString } from './TestStrings';
67

78
describe('TestUtils', function () {
@@ -41,6 +42,11 @@ describe('TestUtils', function () {
4142
done();
4243
}).timeout(20000);
4344

45+
it('should handle HTTP errors correctly', (done: Mocha.Done) => {
46+
new ttm.MockTestRunner(path.join(__dirname, 'GetKubeloginReleaseErrorHandlingL0Tests.js')).run();
47+
done();
48+
}).timeout(20000);
49+
4450
it('should resolve a platform', (done: Mocha.Done) => {
4551
const taskPath = path.join(__dirname, 'ResolvePlatformL0Tests.js');
4652
const tr: ttm.MockTestRunner = new ttm.MockTestRunner(taskPath);

Tasks/KubeloginInstallerV0/task.json

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"author": "Microsoft Corporation",
1616
"version": {
1717
"Major": 0,
18-
"Minor": 264,
18+
"Minor": 267,
1919
"Patch": 0
2020
},
2121
"demands": [],
@@ -53,21 +53,23 @@
5353
}
5454
},
5555
"messages": {
56-
"Info_VerifyKubeloginInstallation": "Verifying kubelogin installation...",
57-
"Info_ResolvedToolFromCache": "Resolved from tool cache: %s",
58-
"Info_UsingToolPath": "Using tool path: %s",
59-
"Info_UsingVersion": "Using version: %s",
56+
"Err_ExtractionFailed": "Failed to extract package with error %s",
57+
"Err_GithubApiRateLimitExceeded": "GitHub API rate limit exceeded. To increase the rate limit, provide a GitHub connection via the gitHubConnection input and set the USE_AUTHORIZATION_FOR_API_CALL variable.",
58+
"Err_LatestTagNotFound": "Could not retrieve the latest kubelogin version tag from GitHub",
59+
"Err_NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.",
60+
"Err_VersionNotFound": "Kubelogin version %s was not found",
6061
"Info_CachingTool": "Caching kubelog version: %s",
61-
"Info_ToolDownloaded": "Release successfully downloaded to %s",
62-
"Info_KubeloginRelease": "Kubelogin release: %s",
62+
"Info_DownloadingFailed": "Failed to download kubelogin, exception %s",
63+
"Info_KubeloginDownloading": "Downloading kubelogin",
6364
"Info_KubeloginPlatform": "Kubelogin platform: %s",
64-
"Info_KubeloginVersion": "Kubelogin version: %s",
65+
"Info_KubeloginRelease": "Kubelogin release: %s",
6566
"Info_KubeloginReleaseURL": "Kubelogin release URL: %s",
66-
"Info_DownloadingFailed": "Failed to download kubelogin, exception %s",
67-
"Err_ExtractionFailed": "Failed to extract package with error %s",
68-
"Err_VersionNotFound": "Kubelogin version %s was not found",
69-
"Err_NotAValidSemverVersion": "Version not specified in correct format. E.g: 1.8.2, v1.8.2, 2.8.2, v2.8.2.",
70-
"SucceedMsg": "Kubelogin has been successfully installed",
71-
"Info_KubeloginDownloading": "Downloading kubelogin"
67+
"Info_KubeloginVersion": "Kubelogin version: %s",
68+
"Info_ResolvedToolFromCache": "Resolved from tool cache: %s",
69+
"Info_ToolDownloaded": "Release successfully downloaded to %s",
70+
"Info_UsingToolPath": "Using tool path: %s",
71+
"Info_UsingVersion": "Using version: %s",
72+
"Info_VerifyKubeloginInstallation": "Verifying kubelogin installation...",
73+
"SucceedMsg": "Kubelogin has been successfully installed"
7274
}
7375
}

Tasks/KubeloginInstallerV0/task.loc.json

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"author": "Microsoft Corporation",
1616
"version": {
1717
"Major": 0,
18-
"Minor": 264,
18+
"Minor": 267,
1919
"Patch": 0
2020
},
2121
"demands": [],
@@ -53,21 +53,23 @@
5353
}
5454
},
5555
"messages": {
56-
"Info_VerifyKubeloginInstallation": "ms-resource:loc.messages.Info_VerifyKubeloginInstallation",
57-
"Info_ResolvedToolFromCache": "ms-resource:loc.messages.Info_ResolvedToolFromCache",
58-
"Info_UsingToolPath": "ms-resource:loc.messages.Info_UsingToolPath",
59-
"Info_UsingVersion": "ms-resource:loc.messages.Info_UsingVersion",
56+
"Err_ExtractionFailed": "ms-resource:loc.messages.Err_ExtractionFailed",
57+
"Err_GithubApiRateLimitExceeded": "ms-resource:loc.messages.Err_GithubApiRateLimitExceeded",
58+
"Err_LatestTagNotFound": "ms-resource:loc.messages.Err_LatestTagNotFound",
59+
"Err_NotAValidSemverVersion": "ms-resource:loc.messages.Err_NotAValidSemverVersion",
60+
"Err_VersionNotFound": "ms-resource:loc.messages.Err_VersionNotFound",
6061
"Info_CachingTool": "ms-resource:loc.messages.Info_CachingTool",
61-
"Info_ToolDownloaded": "ms-resource:loc.messages.Info_ToolDownloaded",
62-
"Info_KubeloginRelease": "ms-resource:loc.messages.Info_KubeloginRelease",
62+
"Info_DownloadingFailed": "ms-resource:loc.messages.Info_DownloadingFailed",
63+
"Info_KubeloginDownloading": "ms-resource:loc.messages.Info_KubeloginDownloading",
6364
"Info_KubeloginPlatform": "ms-resource:loc.messages.Info_KubeloginPlatform",
64-
"Info_KubeloginVersion": "ms-resource:loc.messages.Info_KubeloginVersion",
65+
"Info_KubeloginRelease": "ms-resource:loc.messages.Info_KubeloginRelease",
6566
"Info_KubeloginReleaseURL": "ms-resource:loc.messages.Info_KubeloginReleaseURL",
66-
"Info_DownloadingFailed": "ms-resource:loc.messages.Info_DownloadingFailed",
67-
"Err_ExtractionFailed": "ms-resource:loc.messages.Err_ExtractionFailed",
68-
"Err_VersionNotFound": "ms-resource:loc.messages.Err_VersionNotFound",
69-
"Err_NotAValidSemverVersion": "ms-resource:loc.messages.Err_NotAValidSemverVersion",
70-
"SucceedMsg": "ms-resource:loc.messages.SucceedMsg",
71-
"Info_KubeloginDownloading": "ms-resource:loc.messages.Info_KubeloginDownloading"
67+
"Info_KubeloginVersion": "ms-resource:loc.messages.Info_KubeloginVersion",
68+
"Info_ResolvedToolFromCache": "ms-resource:loc.messages.Info_ResolvedToolFromCache",
69+
"Info_ToolDownloaded": "ms-resource:loc.messages.Info_ToolDownloaded",
70+
"Info_UsingToolPath": "ms-resource:loc.messages.Info_UsingToolPath",
71+
"Info_UsingVersion": "ms-resource:loc.messages.Info_UsingVersion",
72+
"Info_VerifyKubeloginInstallation": "ms-resource:loc.messages.Info_VerifyKubeloginInstallation",
73+
"SucceedMsg": "ms-resource:loc.messages.SucceedMsg"
7274
}
7375
}

Tasks/KubeloginInstallerV0/utils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ export async function getLatestVersionTag(): Promise<string> {
6868

6969
addAuthorizationHeaderIfEnabled(request);
7070
const response = await webClient.sendRequest(request);
71+
72+
if (response.statusCode >= 400) {
73+
if ((response.statusCode === 403 || response.statusCode === 429) && response.headers['x-ratelimit-remaining'] <= 0) {
74+
throw new Error(taskLib.loc('Err_GithubApiRateLimitExceeded'));
75+
}
76+
77+
taskLib.debug(response.statusMessage);
78+
throw Error(taskLib.loc('Err_LatestTagNotFound'));
79+
}
80+
7181
return response.body['tag_name'];
7282
}
7383

@@ -101,6 +111,14 @@ export async function getKubeloginRelease(version: string = 'latest', platform?:
101111
addAuthorizationHeaderIfEnabled(request);
102112
const response = await webClient.sendRequest(request);
103113

114+
if (response.statusCode >= 400) {
115+
if ((response.statusCode === 403 || response.statusCode === 429) && response.headers['x-ratelimit-remaining'] <= 0) {
116+
throw new Error(taskLib.loc('Err_GithubApiRateLimitExceeded'));
117+
}
118+
taskLib.debug(response.statusMessage);
119+
throw Error(taskLib.loc('Err_VersionNotFound', origVersion));
120+
}
121+
104122
const releaseUrl: string =
105123
response.body['assets'].find(asset => {
106124
return asset.name.includes(releaseName);

0 commit comments

Comments
 (0)