@johnlwin-test/create-repro 0.1.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.
@@ -0,0 +1,268 @@
1
+ import { execSync } from "child_process";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import os from "os";
5
+
6
+ /**
7
+ * Attempts to get available operations for a service by installing and inspecting the package
8
+ * @param {string} servicePackage - The service package name (e.g., "@aws-sdk/client-s3")
9
+ * @returns {Promise<{operations: string[], clientName: string, error?: string}>} - Operations in kebab-case, actual client name, and optional error
10
+ */
11
+ export async function getServiceOperations(servicePackage) {
12
+ let tempDir = null;
13
+ try {
14
+ // Create a temporary directory
15
+ tempDir = path.join(os.tmpdir(), `aws-sdk-inspect-${Date.now()}`);
16
+ fs.mkdirSync(tempDir, { recursive: true });
17
+
18
+ // Create a minimal package.json
19
+ fs.writeFileSync(
20
+ path.join(tempDir, "package.json"),
21
+ JSON.stringify({
22
+ name: "temp-inspector",
23
+ version: "1.0.0",
24
+ type: "module"
25
+ })
26
+ );
27
+
28
+ // Install the package
29
+ console.log(` Installing ${servicePackage}...`);
30
+ try {
31
+ execSync(`npm install ${servicePackage}@latest --no-save --silent --no-audit --no-fund --loglevel=error`, {
32
+ cwd: tempDir,
33
+ stdio: "pipe",
34
+ timeout: 60000, // 60 second timeout
35
+ });
36
+ } catch (installError) {
37
+ // Check if it's a 404 (package doesn't exist)
38
+ const errorOutput = installError.stderr?.toString() || installError.message;
39
+ if (errorOutput.includes('404') || errorOutput.includes('Not Found')) {
40
+ return {
41
+ operations: [],
42
+ clientName: "",
43
+ error: `Package "${servicePackage}" not found on npm. Please verify the package name.`
44
+ };
45
+ }
46
+ throw installError; // Re-throw other errors
47
+ }
48
+
49
+ // Find the package directory
50
+ const packagePath = path.join(tempDir, "node_modules", ...servicePackage.split('/'));
51
+
52
+ if (!fs.existsSync(packagePath)) {
53
+ throw new Error(`Package not found at ${packagePath}`);
54
+ }
55
+
56
+ // Read package.json to find exports
57
+ const packageJsonPath = path.join(packagePath, "package.json");
58
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
59
+
60
+ const operations = new Set();
61
+ let clientName = "";
62
+
63
+ // Method 1: Parse exports field from package.json
64
+ if (packageJson.exports) {
65
+ for (const key of Object.keys(packageJson.exports)) {
66
+ // Look for command exports like "./commands/ListBucketsCommand"
67
+ const commandMatch = key.match(/\/commands\/([A-Z][a-zA-Z0-9]+Command)/);
68
+ if (commandMatch) {
69
+ const commandName = commandMatch[1];
70
+ const operationName = commandName
71
+ .replace(/Command$/, '')
72
+ .replace(/([A-Z])/g, (match, p1, offset) =>
73
+ offset > 0 ? `-${p1.toLowerCase()}` : p1.toLowerCase()
74
+ );
75
+ operations.add(operationName);
76
+ }
77
+
78
+ // Look for the client export (e.g., "./DynamoDBClient")
79
+ const clientMatch = key.match(/^\.\/([A-Za-z0-9]+Client)$/);
80
+ if (clientMatch && !clientName) {
81
+ clientName = clientMatch[1];
82
+ }
83
+ }
84
+ }
85
+
86
+ // Method 2: Scan the commands directory if it exists
87
+ const commandsDir = path.join(packagePath, "dist-cjs", "commands");
88
+ if (fs.existsSync(commandsDir)) {
89
+ const files = fs.readdirSync(commandsDir);
90
+ for (const file of files) {
91
+ if (file.endsWith('Command.js')) {
92
+ const commandName = file.replace('.js', '');
93
+ const operationName = commandName
94
+ .replace(/Command$/, '')
95
+ .replace(/([A-Z])/g, (match, p1, offset) =>
96
+ offset > 0 ? `-${p1.toLowerCase()}` : p1.toLowerCase()
97
+ );
98
+ operations.add(operationName);
99
+ }
100
+ }
101
+ }
102
+
103
+ // Method 3: Try dist-es directory
104
+ const commandsDirES = path.join(packagePath, "dist-es", "commands");
105
+ if (fs.existsSync(commandsDirES)) {
106
+ const files = fs.readdirSync(commandsDirES);
107
+ for (const file of files) {
108
+ if (file.endsWith('Command.js') || file.endsWith('Command.mjs')) {
109
+ const commandName = file.replace(/\.(m)?js$/, '');
110
+ const operationName = commandName
111
+ .replace(/Command$/, '')
112
+ .replace(/([A-Z])/g, (match, p1, offset) =>
113
+ offset > 0 ? `-${p1.toLowerCase()}` : p1.toLowerCase()
114
+ );
115
+ operations.add(operationName);
116
+ }
117
+ }
118
+ }
119
+
120
+ // Fallback: Find client name from dist-cjs or dist-es if not found in exports
121
+ if (!clientName) {
122
+ for (const distDir of ["dist-cjs", "dist-es"]) {
123
+ const dir = path.join(packagePath, distDir);
124
+ if (fs.existsSync(dir)) {
125
+ const files = fs.readdirSync(dir);
126
+ const clientFile = files.find(f => f.match(/^[A-Z][a-zA-Z0-9]*Client\.(js|mjs)$/));
127
+ if (clientFile) {
128
+ clientName = clientFile.replace(/\.(m)?js$/, '');
129
+ break;
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ // Cleanup
136
+ if (tempDir && fs.existsSync(tempDir)) {
137
+ fs.rmSync(tempDir, { recursive: true, force: true });
138
+ }
139
+
140
+ const result = Array.from(operations).sort();
141
+ console.log(` Found ${result.length} operations`);
142
+ if (clientName) {
143
+ console.log(` Client: ${clientName}`);
144
+ }
145
+ return { operations: result, clientName };
146
+
147
+ } catch (error) {
148
+ // Cleanup on error
149
+ if (tempDir && fs.existsSync(tempDir)) {
150
+ try {
151
+ fs.rmSync(tempDir, { recursive: true, force: true });
152
+ } catch (cleanupError) {
153
+ // Ignore cleanup errors
154
+ }
155
+ }
156
+
157
+ // Return error details for better user feedback
158
+ console.warn(` Could not fetch operations: ${error.message}`);
159
+ return {
160
+ operations: [],
161
+ clientName: "",
162
+ error: error.message
163
+ };
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Validates operation name format (kebab-case)
169
+ * @param {string} operation - Operation name to validate
170
+ * @returns {boolean} - True if valid kebab-case format
171
+ */
172
+ export function isValidOperationFormat(operation) {
173
+ // Must be kebab-case: lowercase letters, numbers, and hyphens only
174
+ // Must start with a letter
175
+ const kebabCasePattern = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
176
+ return kebabCasePattern.test(operation);
177
+ }
178
+
179
+ /**
180
+ * Validates if an operation exists for a given service
181
+ * @param {string} operation - Operation name in kebab-case
182
+ * @param {string[]} availableOperations - List of available operations
183
+ * @returns {boolean} - True if operation exists
184
+ */
185
+ export function isValidOperation(operation, availableOperations) {
186
+ if (availableOperations.length === 0) {
187
+ // If we don't have the list, just validate format
188
+ return isValidOperationFormat(operation);
189
+ }
190
+ return availableOperations.includes(operation);
191
+ }
192
+
193
+ /**
194
+ * Gets operation suggestions based on partial input
195
+ * @param {string} input - Partial operation name
196
+ * @param {string[]} availableOperations - List of available operations
197
+ * @returns {string[]} - Array of matching operation names
198
+ */
199
+ export function getOperationSuggestions(input, availableOperations) {
200
+ if (availableOperations.length === 0) return [];
201
+
202
+ const lowerInput = input.toLowerCase();
203
+ return availableOperations.filter(op =>
204
+ op.toLowerCase().includes(lowerInput)
205
+ ).slice(0, 20); // Limit to 20 suggestions
206
+ }
207
+
208
+ /**
209
+ * Provides helpful error message for invalid operations
210
+ * @param {string} operation - The invalid operation name
211
+ * @param {string[]} availableOperations - List of available operations
212
+ * @returns {string} - Error message with suggestions
213
+ */
214
+ export function getOperationErrorMessage(operation, availableOperations) {
215
+ if (!isValidOperationFormat(operation)) {
216
+ return "Operation must be in kebab-case format (e.g., list-buckets, get-object)";
217
+ }
218
+
219
+ if (availableOperations.length === 0) {
220
+ return "Could not validate operation. Please ensure the operation name is correct.";
221
+ }
222
+
223
+ // Find similar operations (Levenshtein distance or simple substring match)
224
+ const similar = availableOperations.filter(op => {
225
+ const distance = levenshteinDistance(operation, op);
226
+ return distance <= 2; // Allow up to 2 character differences
227
+ });
228
+
229
+ if (similar.length > 0) {
230
+ return `Operation not found. Did you mean: ${similar.slice(0, 3).join(", ")}?`;
231
+ }
232
+
233
+ return `Operation not found. Available operations: ${availableOperations.slice(0, 5).join(", ")}...`;
234
+ }
235
+
236
+ /**
237
+ * Calculate Levenshtein distance between two strings
238
+ * @param {string} a - First string
239
+ * @param {string} b - Second string
240
+ * @returns {number} - Edit distance
241
+ */
242
+ function levenshteinDistance(a, b) {
243
+ const matrix = [];
244
+
245
+ for (let i = 0; i <= b.length; i++) {
246
+ matrix[i] = [i];
247
+ }
248
+
249
+ for (let j = 0; j <= a.length; j++) {
250
+ matrix[0][j] = j;
251
+ }
252
+
253
+ for (let i = 1; i <= b.length; i++) {
254
+ for (let j = 1; j <= a.length; j++) {
255
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
256
+ matrix[i][j] = matrix[i - 1][j - 1];
257
+ } else {
258
+ matrix[i][j] = Math.min(
259
+ matrix[i - 1][j - 1] + 1, // substitution
260
+ matrix[i][j - 1] + 1, // insertion
261
+ matrix[i - 1][j] + 1 // deletion
262
+ );
263
+ }
264
+ }
265
+ }
266
+
267
+ return matrix[b.length][a.length];
268
+ }
package/src/regions.js ADDED
@@ -0,0 +1,235 @@
1
+ // Comprehensive list of AWS regions
2
+
3
+ export const AWS_REGIONS = [
4
+ // US Regions
5
+ "us-east-1", // US East (N. Virginia)
6
+ "us-east-2", // US East (Ohio)
7
+ "us-west-1", // US West (N. California)
8
+ "us-west-2", // US West (Oregon)
9
+
10
+ // Africa
11
+ "af-south-1", // Africa (Cape Town)
12
+
13
+ // Asia Pacific
14
+ "ap-east-1", // Asia Pacific (Hong Kong)
15
+ "ap-south-1", // Asia Pacific (Mumbai)
16
+ "ap-south-2", // Asia Pacific (Hyderabad)
17
+ "ap-northeast-1", // Asia Pacific (Tokyo)
18
+ "ap-northeast-2", // Asia Pacific (Seoul)
19
+ "ap-northeast-3", // Asia Pacific (Osaka)
20
+ "ap-southeast-1", // Asia Pacific (Singapore)
21
+ "ap-southeast-2", // Asia Pacific (Sydney)
22
+ "ap-southeast-3", // Asia Pacific (Jakarta)
23
+ "ap-southeast-4", // Asia Pacific (Melbourne)
24
+
25
+ // Canada
26
+ "ca-central-1", // Canada (Central)
27
+ "ca-west-1", // Canada (Calgary)
28
+
29
+ // Europe
30
+ "eu-central-1", // Europe (Frankfurt)
31
+ "eu-central-2", // Europe (Zurich)
32
+ "eu-west-1", // Europe (Ireland)
33
+ "eu-west-2", // Europe (London)
34
+ "eu-west-3", // Europe (Paris)
35
+ "eu-south-1", // Europe (Milan)
36
+ "eu-south-2", // Europe (Spain)
37
+ "eu-north-1", // Europe (Stockholm)
38
+
39
+ // Middle East
40
+ "me-south-1", // Middle East (Bahrain)
41
+ "me-central-1", // Middle East (UAE)
42
+
43
+ // South America
44
+ "sa-east-1", // South America (São Paulo)
45
+
46
+ // AWS GovCloud (US)
47
+ "us-gov-east-1", // AWS GovCloud (US-East)
48
+ "us-gov-west-1", // AWS GovCloud (US-West)
49
+
50
+ // China (requires separate account)
51
+ "cn-north-1", // China (Beijing)
52
+ "cn-northwest-1", // China (Ningxia)
53
+ ];
54
+
55
+ // Region display names for better UX
56
+ const REGION_NAMES = {
57
+ "us-east-1": "US East (N. Virginia)",
58
+ "us-east-2": "US East (Ohio)",
59
+ "us-west-1": "US West (N. California)",
60
+ "us-west-2": "US West (Oregon)",
61
+ "af-south-1": "Africa (Cape Town)",
62
+ "ap-east-1": "Asia Pacific (Hong Kong)",
63
+ "ap-south-1": "Asia Pacific (Mumbai)",
64
+ "ap-south-2": "Asia Pacific (Hyderabad)",
65
+ "ap-northeast-1": "Asia Pacific (Tokyo)",
66
+ "ap-northeast-2": "Asia Pacific (Seoul)",
67
+ "ap-northeast-3": "Asia Pacific (Osaka)",
68
+ "ap-southeast-1": "Asia Pacific (Singapore)",
69
+ "ap-southeast-2": "Asia Pacific (Sydney)",
70
+ "ap-southeast-3": "Asia Pacific (Jakarta)",
71
+ "ap-southeast-4": "Asia Pacific (Melbourne)",
72
+ "ca-central-1": "Canada (Central)",
73
+ "ca-west-1": "Canada (Calgary)",
74
+ "eu-central-1": "Europe (Frankfurt)",
75
+ "eu-central-2": "Europe (Zurich)",
76
+ "eu-west-1": "Europe (Ireland)",
77
+ "eu-west-2": "Europe (London)",
78
+ "eu-west-3": "Europe (Paris)",
79
+ "eu-south-1": "Europe (Milan)",
80
+ "eu-south-2": "Europe (Spain)",
81
+ "eu-north-1": "Europe (Stockholm)",
82
+ "me-south-1": "Middle East (Bahrain)",
83
+ "me-central-1": "Middle East (UAE)",
84
+ "sa-east-1": "South America (São Paulo)",
85
+ "us-gov-east-1": "AWS GovCloud (US-East)",
86
+ "us-gov-west-1": "AWS GovCloud (US-West)",
87
+ "cn-north-1": "China (Beijing)",
88
+ "cn-northwest-1": "China (Ningxia)",
89
+ };
90
+
91
+ /**
92
+ * Validates if a region code is valid
93
+ * @param {string} region - The region code (e.g., "us-west-2")
94
+ * @returns {boolean} - True if valid, false otherwise
95
+ */
96
+ export function isValidRegion(region) {
97
+ return AWS_REGIONS.includes(region.toLowerCase());
98
+ }
99
+
100
+ /**
101
+ * Gets the display name for a region
102
+ * @param {string} region - The region code
103
+ * @returns {string} - Display name or the region code if not found
104
+ */
105
+ export function getRegionDisplayName(region) {
106
+ return REGION_NAMES[region] || region;
107
+ }
108
+
109
+ /**
110
+ * Calculate Levenshtein distance between two strings
111
+ * @param {string} a - First string
112
+ * @param {string} b - Second string
113
+ * @returns {number} - Edit distance
114
+ */
115
+ function levenshteinDistance(a, b) {
116
+ const matrix = [];
117
+
118
+ for (let i = 0; i <= b.length; i++) {
119
+ matrix[i] = [i];
120
+ }
121
+
122
+ for (let j = 0; j <= a.length; j++) {
123
+ matrix[0][j] = j;
124
+ }
125
+
126
+ for (let i = 1; i <= b.length; i++) {
127
+ for (let j = 1; j <= a.length; j++) {
128
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
129
+ matrix[i][j] = matrix[i - 1][j - 1];
130
+ } else {
131
+ matrix[i][j] = Math.min(
132
+ matrix[i - 1][j - 1] + 1, // substitution
133
+ matrix[i][j - 1] + 1, // insertion
134
+ matrix[i - 1][j] + 1 // deletion
135
+ );
136
+ }
137
+ }
138
+ }
139
+
140
+ return matrix[b.length][a.length];
141
+ }
142
+
143
+ /**
144
+ * Finds similar region codes based on typos
145
+ * @param {string} region - The region code to check
146
+ * @param {number} maxDistance - Maximum edit distance (default: 2)
147
+ * @returns {string[]} - Array of similar region codes
148
+ */
149
+ export function findSimilarRegions(region, maxDistance = 2) {
150
+ const lowerRegion = region.toLowerCase();
151
+
152
+ return AWS_REGIONS.filter(validRegion => {
153
+ const distance = levenshteinDistance(lowerRegion, validRegion);
154
+ return distance > 0 && distance <= maxDistance;
155
+ }).slice(0, 5); // Limit to top 5 suggestions
156
+ }
157
+
158
+ /**
159
+ * Gets region suggestions based on partial input
160
+ * @param {string} input - Partial region code
161
+ * @returns {string[]} - Array of matching region codes
162
+ */
163
+ export function getRegionSuggestions(input) {
164
+ if (!input) return AWS_REGIONS;
165
+
166
+ const lowerInput = input.toLowerCase();
167
+ return AWS_REGIONS.filter(region =>
168
+ region.toLowerCase().includes(lowerInput)
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Validates region format (basic pattern check)
174
+ * @param {string} region - Region code to validate
175
+ * @returns {boolean} - True if format is valid
176
+ */
177
+ export function isValidRegionFormat(region) {
178
+ // AWS region format: 2-3 letter prefix, direction, number
179
+ // Examples: us-west-2, ap-southeast-1, eu-central-1
180
+ const regionPattern = /^[a-z]{2,3}-(north|south|east|west|central|northeast|northwest|southeast|southwest)-\d+$/;
181
+ const govCloudPattern = /^us-gov-(east|west)-\d+$/;
182
+ const chinaPattern = /^cn-(north|northwest)-\d+$/;
183
+
184
+ return regionPattern.test(region) || govCloudPattern.test(region) || chinaPattern.test(region);
185
+ }
186
+
187
+ /**
188
+ * Provides helpful error message for invalid regions
189
+ * @param {string} region - The invalid region code
190
+ * @returns {string} - Error message with suggestions
191
+ */
192
+ export function getRegionErrorMessage(region) {
193
+ const lowerRegion = region.toLowerCase();
194
+
195
+ // Check if it's a valid format but not in our list
196
+ if (!isValidRegionFormat(lowerRegion)) {
197
+ return `Invalid region format. AWS regions follow the pattern: prefix-direction-number (e.g., us-west-2, eu-central-1)`;
198
+ }
199
+
200
+ // Find similar regions
201
+ const similar = findSimilarRegions(lowerRegion);
202
+
203
+ if (similar.length > 0) {
204
+ const suggestions = similar.map(r => `${r} (${getRegionDisplayName(r)})`).join(", ");
205
+ return `Region not found. Did you mean: ${suggestions}?`;
206
+ }
207
+
208
+ // Check for common mistakes
209
+ if (lowerRegion.includes("_")) {
210
+ const corrected = lowerRegion.replace(/_/g, "-");
211
+ if (isValidRegion(corrected)) {
212
+ return `Invalid format. Did you mean: ${corrected}? (use hyphens, not underscores)`;
213
+ }
214
+ }
215
+
216
+ return `Region not found. Use format: prefix-direction-number (e.g., us-west-2, eu-central-1)`;
217
+ }
218
+
219
+ /**
220
+ * Converts Java-style region format to standard format
221
+ * @param {string} region - Region in Java format (e.g., "US_WEST_1")
222
+ * @returns {string} - Region in standard format (e.g., "us-west-1")
223
+ */
224
+ export function javaRegionToStandard(region) {
225
+ return region.toLowerCase().replace(/_/g, "-");
226
+ }
227
+
228
+ /**
229
+ * Converts standard region format to Java-style format
230
+ * @param {string} region - Region in standard format (e.g., "us-west-1")
231
+ * @returns {string} - Region in Java format (e.g., "US_WEST_1")
232
+ */
233
+ export function standardRegionToJava(region) {
234
+ return region.toUpperCase().replace(/-/g, "_");
235
+ }
@@ -0,0 +1,79 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ // import { generateMavenWrapper } from "./utils/maven.js";
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ // Template cache to avoid repeated file reads
9
+ const TEMPLATES = {
10
+ mainJava: fs.readFileSync(
11
+ path.join(__dirname, "templates/Main.java"),
12
+ "utf-8"
13
+ ),
14
+ pomXml: fs.readFileSync(path.join(__dirname, "templates/pom.xml"), "utf-8"),
15
+ readme: fs.readFileSync(path.join(__dirname, "templates/README.md"), "utf-8"),
16
+ };
17
+
18
+ export const generateJavaProject = (answers, projectDir) => {
19
+ // Create Maven project structure
20
+ const paths = {
21
+ mainJava: path.join(projectDir, "src/main/java/com/aws/repro"),
22
+ testJava: path.join(projectDir, "src/test/java/com/aws/repro"),
23
+ resources: path.join(projectDir, "src/main/resources"),
24
+ };
25
+
26
+ // Create directories
27
+ Object.values(paths).forEach((p) => {
28
+ fs.mkdirSync(p, { recursive: true });
29
+ });
30
+
31
+ // Process service name for Java SDK
32
+ const javaService = answers.service.toLowerCase();
33
+ const operationPascal =
34
+ answers.operation.charAt(0).toUpperCase() + answers.operation.slice(1);
35
+
36
+ // Generate Main.java
37
+ const mainJavaContent = TEMPLATES.mainJava
38
+ .replace(/{{service}}/g, javaService)
39
+ .replace(
40
+ /{{Service}}/g,
41
+ javaService.charAt(0).toUpperCase() + javaService.slice(1)
42
+ )
43
+ .replace(/{{operation}}/g, answers.operation)
44
+ .replace(/{{Operation}}/g, operationPascal)
45
+ .replace(/{{region}}/g, answers.region.toUpperCase());
46
+
47
+ // Generate pom.xml
48
+ const pomXmlContent = TEMPLATES.pomXml
49
+ .replace(/{{service}}/g, javaService)
50
+ .replace(/{{aws-sdk-version}}/g, "2.20.136");
51
+
52
+ // Generate README
53
+ const readmeContent = TEMPLATES.readme
54
+ .replace(/{{service}}/g, javaService)
55
+ .replace(/{{operation}}/g, answers.operation)
56
+ .replace(/{{region}}/g, answers.region);
57
+
58
+ // Write core files
59
+ fs.writeFileSync(path.join(paths.mainJava, "Main.java"), mainJavaContent);
60
+ fs.writeFileSync(path.join(projectDir, "pom.xml"), pomXmlContent);
61
+ fs.writeFileSync(path.join(projectDir, "README.md"), readmeContent);
62
+
63
+ // // Add Maven wrapper
64
+ // generateMavenWrapper(projectDir);
65
+
66
+ // Add .gitignore
67
+ fs.writeFileSync(
68
+ path.join(projectDir, ".gitignore"),
69
+ "target/\n.classpath\n.project\n.settings/\nbin/\n"
70
+ );
71
+ };
72
+
73
+ // Helper to render templates with replacements
74
+ function renderTemplate(template, variables) {
75
+ return Object.entries(variables).reduce(
76
+ (acc, [key, value]) => acc.replace(new RegExp(`{{${key}}}`, "g"), value),
77
+ template
78
+ );
79
+ }
File without changes
@@ -0,0 +1,24 @@
1
+ package com.aws.repro;
2
+ import software.amazon.awssdk.regions.Region;
3
+ import software.amazon.awssdk.services.{{service}}.{{Service}}Client;
4
+ import software.amazon.awssdk.services.{{service}}.model.{{Operation}}Request;
5
+ import software.amazon.awssdk.services.{{service}}.model.{{Operation}}Response;
6
+ public class Main {
7
+ public static void main(String[] args) {
8
+ {{Service}}Client client = {{Service}}Client.builder()
9
+ .region(Region.{{region}})
10
+ .build();
11
+ {{Operation}}Request request = {{Operation}}Request.builder()
12
+ // Configure request parameters here
13
+ .build();
14
+ try {
15
+ {{Operation}}Response response = client.{{operation}}(request);
16
+ System.out.println("Operation successful:");
17
+ System.out.println(response);
18
+ } catch (Exception e) {
19
+ System.err.println("Error executing operation:");
20
+ e.printStackTrace();
21
+ System.exit(1);
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,14 @@
1
+ # AWS Java SDK Repro Project
2
+
3
+ Service: {{service}}
4
+ Operation: {{operation}}
5
+ Region: {{region}}
6
+
7
+ ## Running the Project
8
+
9
+ Configure AWS credentials:
10
+
11
+ ```bash
12
+ export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
13
+ export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
14
+ ```
@@ -0,0 +1,61 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+ <modelVersion>4.0.0</modelVersion>
6
+
7
+ <groupId>com.aws.repro</groupId>
8
+ <artifactId>aws-java-repro</artifactId>
9
+ <version>1.0.0</version>
10
+ <packaging>jar</packaging>
11
+
12
+ <properties>
13
+ <maven.compiler.source>11</maven.compiler.source>
14
+ <maven.compiler.target>11</maven.compiler.target>
15
+ <aws.sdk.version>2.20.136</aws.sdk.version>
16
+ </properties>
17
+
18
+ <dependencyManagement>
19
+ <dependencies>
20
+ <dependency>
21
+ <groupId>software.amazon.awssdk</groupId>
22
+ <artifactId>bom</artifactId>
23
+ <version>${aws.sdk.version}</version>
24
+ <type>pom</type>
25
+ <scope>import</scope>
26
+ </dependency>
27
+ </dependencies>
28
+ </dependencyManagement>
29
+
30
+ <dependencies>
31
+ <dependency>
32
+ <groupId>software.amazon.awssdk</groupId>
33
+ <artifactId>{{service}}</artifactId>
34
+ </dependency>
35
+ </dependencies>
36
+
37
+ <build>
38
+ <plugins>
39
+ <plugin>
40
+ <groupId>org.apache.maven.plugins</groupId>
41
+ <artifactId>maven-shade-plugin</artifactId>
42
+ <version>3.3.0</version>
43
+ <executions>
44
+ <execution>
45
+ <phase>package</phase>
46
+ <goals>
47
+ <goal>shade</goal>
48
+ </goals>
49
+ <configuration>
50
+ <transformers>
51
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
52
+ <mainClass>com.aws.repro.Main</mainClass>
53
+ </transformer>
54
+ </transformers>
55
+ </configuration>
56
+ </execution>
57
+ </executions>
58
+ </plugin>
59
+ </plugins>
60
+ </build>
61
+ </project>