bitbucket-gemini-action 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +8 -0
- package/.prettierrc +8 -0
- package/CLAUDE.md +150 -0
- package/README.md +375 -0
- package/bitbucket-pipelines.yml +95 -0
- package/bun.lock +227 -0
- package/dist/prepare.js +7111 -0
- package/examples/bitbucket-pipelines-full.yml +157 -0
- package/examples/bitbucket-pipelines-minimal.yml +22 -0
- package/package.json +33 -0
- package/src/bitbucket/api/client.ts +406 -0
- package/src/bitbucket/context.ts +196 -0
- package/src/bitbucket/data/fetcher.ts +195 -0
- package/src/bitbucket/data/formatter.ts +221 -0
- package/src/bitbucket/operations/comments.ts +236 -0
- package/src/bitbucket/types.ts +262 -0
- package/src/bitbucket/validation/permissions.ts +154 -0
- package/src/bitbucket/validation/trigger.ts +175 -0
- package/src/entrypoints/execute.ts +349 -0
- package/src/entrypoints/prepare.ts +216 -0
- package/src/gemini/client.ts +263 -0
- package/src/gemini/presets.ts +2130 -0
- package/src/gemini/prompts.ts +331 -0
- package/src/gemini/tools.ts +226 -0
- package/src/index.ts +71 -0
- package/src/modes/agent/index.ts +119 -0
- package/src/modes/registry.ts +118 -0
- package/src/modes/tag/index.ts +172 -0
- package/src/modes/types.ts +95 -0
- package/src/utils/env.ts +190 -0
- package/src/utils/retry.ts +149 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Utilities
|
|
3
|
+
* Handles retry logic for API operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface RetryOptions {
|
|
7
|
+
maxAttempts: number;
|
|
8
|
+
baseDelayMs: number;
|
|
9
|
+
maxDelayMs: number;
|
|
10
|
+
shouldRetry?: (error: unknown) => boolean;
|
|
11
|
+
onRetry?: (attempt: number, error: unknown) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const DEFAULT_RETRY_OPTIONS: RetryOptions = {
|
|
15
|
+
maxAttempts: 3,
|
|
16
|
+
baseDelayMs: 1000,
|
|
17
|
+
maxDelayMs: 10000,
|
|
18
|
+
shouldRetry: (error: unknown) => {
|
|
19
|
+
// Retry on network errors and 5xx status codes
|
|
20
|
+
if (error instanceof Error) {
|
|
21
|
+
const message = error.message.toLowerCase();
|
|
22
|
+
if (
|
|
23
|
+
message.includes("network") ||
|
|
24
|
+
message.includes("timeout") ||
|
|
25
|
+
message.includes("econnrefused") ||
|
|
26
|
+
message.includes("socket")
|
|
27
|
+
) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Retry on rate limiting
|
|
33
|
+
if (isRateLimitError(error)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Retry on server errors
|
|
38
|
+
if (isServerError(error)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return false;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Execute a function with retry logic
|
|
48
|
+
*/
|
|
49
|
+
export async function withRetry<T>(
|
|
50
|
+
fn: () => Promise<T>,
|
|
51
|
+
options: Partial<RetryOptions> = {}
|
|
52
|
+
): Promise<T> {
|
|
53
|
+
const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
|
|
54
|
+
let lastError: unknown;
|
|
55
|
+
|
|
56
|
+
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
|
|
57
|
+
try {
|
|
58
|
+
return await fn();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
lastError = error;
|
|
61
|
+
|
|
62
|
+
if (attempt === opts.maxAttempts) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!opts.shouldRetry?.(error)) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
opts.onRetry?.(attempt, error);
|
|
71
|
+
|
|
72
|
+
const delay = calculateDelay(attempt, opts.baseDelayMs, opts.maxDelayMs);
|
|
73
|
+
await sleep(delay);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
throw lastError;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Calculate exponential backoff delay with jitter
|
|
82
|
+
*/
|
|
83
|
+
function calculateDelay(
|
|
84
|
+
attempt: number,
|
|
85
|
+
baseDelayMs: number,
|
|
86
|
+
maxDelayMs: number
|
|
87
|
+
): number {
|
|
88
|
+
const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
89
|
+
const jitter = Math.random() * baseDelayMs;
|
|
90
|
+
return Math.min(exponentialDelay + jitter, maxDelayMs);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Sleep for specified milliseconds
|
|
95
|
+
*/
|
|
96
|
+
function sleep(ms: number): Promise<void> {
|
|
97
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if error is a rate limit error
|
|
102
|
+
*/
|
|
103
|
+
function isRateLimitError(error: unknown): boolean {
|
|
104
|
+
if (error && typeof error === "object") {
|
|
105
|
+
const err = error as { statusCode?: number; status?: number };
|
|
106
|
+
return err.statusCode === 429 || err.status === 429;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if error is a server error (5xx)
|
|
113
|
+
*/
|
|
114
|
+
function isServerError(error: unknown): boolean {
|
|
115
|
+
if (error && typeof error === "object") {
|
|
116
|
+
const err = error as { statusCode?: number; status?: number };
|
|
117
|
+
const status = err.statusCode || err.status;
|
|
118
|
+
return status !== undefined && status >= 500 && status < 600;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Retry options for Bitbucket API
|
|
125
|
+
*/
|
|
126
|
+
export const BITBUCKET_RETRY_OPTIONS: Partial<RetryOptions> = {
|
|
127
|
+
maxAttempts: 3,
|
|
128
|
+
baseDelayMs: 1000,
|
|
129
|
+
maxDelayMs: 10000,
|
|
130
|
+
onRetry: (attempt, error) => {
|
|
131
|
+
console.warn(
|
|
132
|
+
`Bitbucket API retry attempt ${attempt}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Retry options for Gemini API
|
|
139
|
+
*/
|
|
140
|
+
export const GEMINI_RETRY_OPTIONS: Partial<RetryOptions> = {
|
|
141
|
+
maxAttempts: 2,
|
|
142
|
+
baseDelayMs: 2000,
|
|
143
|
+
maxDelayMs: 15000,
|
|
144
|
+
onRetry: (attempt, error) => {
|
|
145
|
+
console.warn(
|
|
146
|
+
`Gemini API retry attempt ${attempt}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
147
|
+
);
|
|
148
|
+
},
|
|
149
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"rootDir": "./src",
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"noImplicitReturns": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true,
|
|
20
|
+
"types": ["bun-types", "node"]
|
|
21
|
+
},
|
|
22
|
+
"include": ["src/**/*"],
|
|
23
|
+
"exclude": ["node_modules", "dist", "test"]
|
|
24
|
+
}
|