@friggframework/devtools 2.0.0--canary.454.726ab78.0 → 2.0.0--canary.454.15f637e.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.
|
@@ -191,11 +191,11 @@ async function runPrismaMigrate(command = 'dev', verbose = false) {
|
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
193
|
* Runs Prisma db push for MongoDB
|
|
194
|
-
* Interactive - will prompt user if data loss detected
|
|
195
194
|
* @param {boolean} verbose - Enable verbose output
|
|
195
|
+
* @param {boolean} nonInteractive - Run in non-interactive mode (accepts data loss, for Lambda/CI)
|
|
196
196
|
* @returns {Promise<Object>} { success: boolean, output?: string, error?: string }
|
|
197
197
|
*/
|
|
198
|
-
async function runPrismaDbPush(verbose = false) {
|
|
198
|
+
async function runPrismaDbPush(verbose = false, nonInteractive = false) {
|
|
199
199
|
return new Promise((resolve) => {
|
|
200
200
|
try {
|
|
201
201
|
const schemaPath = getPrismaSchemaPath('mongodb');
|
|
@@ -209,20 +209,52 @@ async function runPrismaDbPush(verbose = false) {
|
|
|
209
209
|
'--skip-generate' // We generate separately
|
|
210
210
|
];
|
|
211
211
|
|
|
212
|
+
// Add non-interactive flag for Lambda/CI environments
|
|
213
|
+
if (nonInteractive) {
|
|
214
|
+
args.push('--accept-data-loss');
|
|
215
|
+
}
|
|
216
|
+
|
|
212
217
|
if (verbose) {
|
|
213
218
|
console.log(chalk.gray(`Running: npx ${args.join(' ')}`));
|
|
214
219
|
}
|
|
215
220
|
|
|
216
|
-
|
|
221
|
+
if (nonInteractive) {
|
|
222
|
+
console.log(chalk.yellow('⚠️ Non-interactive mode: Data loss will be automatically accepted'));
|
|
223
|
+
} else {
|
|
224
|
+
console.log(chalk.yellow('⚠️ Interactive mode: You may be prompted if schema changes cause data loss'));
|
|
225
|
+
}
|
|
217
226
|
|
|
218
227
|
const proc = spawn('npx', args, {
|
|
219
|
-
stdio: 'inherit', //
|
|
228
|
+
stdio: nonInteractive ? 'pipe' : 'inherit', // Use pipe for non-interactive to capture output
|
|
220
229
|
env: {
|
|
221
230
|
...process.env,
|
|
222
231
|
PRISMA_HIDE_UPDATE_MESSAGE: '1'
|
|
223
232
|
}
|
|
224
233
|
});
|
|
225
234
|
|
|
235
|
+
let stdout = '';
|
|
236
|
+
let stderr = '';
|
|
237
|
+
|
|
238
|
+
// Capture output in non-interactive mode
|
|
239
|
+
if (nonInteractive) {
|
|
240
|
+
if (proc.stdout) {
|
|
241
|
+
proc.stdout.on('data', (data) => {
|
|
242
|
+
stdout += data.toString();
|
|
243
|
+
if (verbose) {
|
|
244
|
+
process.stdout.write(data);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
if (proc.stderr) {
|
|
249
|
+
proc.stderr.on('data', (data) => {
|
|
250
|
+
stderr += data.toString();
|
|
251
|
+
if (verbose) {
|
|
252
|
+
process.stderr.write(data);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
226
258
|
proc.on('error', (error) => {
|
|
227
259
|
resolve({
|
|
228
260
|
success: false,
|
|
@@ -234,12 +266,13 @@ async function runPrismaDbPush(verbose = false) {
|
|
|
234
266
|
if (code === 0) {
|
|
235
267
|
resolve({
|
|
236
268
|
success: true,
|
|
237
|
-
output: 'Database push completed successfully'
|
|
269
|
+
output: nonInteractive ? stdout || 'Database push completed successfully' : 'Database push completed successfully'
|
|
238
270
|
});
|
|
239
271
|
} else {
|
|
240
272
|
resolve({
|
|
241
273
|
success: false,
|
|
242
|
-
error: `Database push process exited with code ${code}
|
|
274
|
+
error: `Database push process exited with code ${code}`,
|
|
275
|
+
output: stderr || stdout
|
|
243
276
|
});
|
|
244
277
|
}
|
|
245
278
|
});
|
|
@@ -613,6 +613,20 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
|
|
|
613
613
|
{ httpApi: { path: '/health/{proxy+}', method: 'GET' } },
|
|
614
614
|
],
|
|
615
615
|
},
|
|
616
|
+
dbMigrate: {
|
|
617
|
+
handler: 'node_modules/@friggframework/core/handlers/workers/db-migration.handler',
|
|
618
|
+
timeout: 300, // 5 minutes for long-running migrations
|
|
619
|
+
memorySize: 512, // Extra memory for Prisma CLI operations
|
|
620
|
+
reservedConcurrency: 1, // Prevent concurrent migrations
|
|
621
|
+
description: 'Runs database migrations via Prisma (invoke manually from CI/CD)',
|
|
622
|
+
// No events - this function is invoked manually via AWS CLI
|
|
623
|
+
maximumEventAge: 60, // Don't retry old migration requests (60 seconds)
|
|
624
|
+
maximumRetryAttempts: 0, // Don't auto-retry failed migrations
|
|
625
|
+
tags: {
|
|
626
|
+
Purpose: 'DatabaseMigration',
|
|
627
|
+
ManagedBy: 'Frigg',
|
|
628
|
+
},
|
|
629
|
+
},
|
|
616
630
|
},
|
|
617
631
|
resources: {
|
|
618
632
|
Resources: {
|
|
@@ -1762,6 +1762,97 @@ describe('composeServerlessDefinition', () => {
|
|
|
1762
1762
|
});
|
|
1763
1763
|
});
|
|
1764
1764
|
|
|
1765
|
+
describe('Database Migration Lambda', () => {
|
|
1766
|
+
it('should include dbMigrate function in all deployments', async () => {
|
|
1767
|
+
const appDefinition = {
|
|
1768
|
+
name: 'test-app',
|
|
1769
|
+
integrations: []
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1773
|
+
|
|
1774
|
+
// Check dbMigrate function exists
|
|
1775
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1776
|
+
expect(result.functions.dbMigrate.handler).toBe(
|
|
1777
|
+
'node_modules/@friggframework/core/handlers/workers/db-migration.handler'
|
|
1778
|
+
);
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
it('should configure dbMigrate with correct settings', async () => {
|
|
1782
|
+
const appDefinition = {
|
|
1783
|
+
integrations: []
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1787
|
+
|
|
1788
|
+
const dbMigrate = result.functions.dbMigrate;
|
|
1789
|
+
|
|
1790
|
+
// Check timeout (5 minutes for long migrations)
|
|
1791
|
+
expect(dbMigrate.timeout).toBe(300);
|
|
1792
|
+
|
|
1793
|
+
// Check memory allocation (extra for Prisma CLI)
|
|
1794
|
+
expect(dbMigrate.memorySize).toBe(512);
|
|
1795
|
+
|
|
1796
|
+
// Check description
|
|
1797
|
+
expect(dbMigrate.description).toContain('database migrations');
|
|
1798
|
+
expect(dbMigrate.description).toContain('Prisma');
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
it('should not have HTTP events (manual invocation only)', async () => {
|
|
1802
|
+
const appDefinition = {
|
|
1803
|
+
integrations: []
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1807
|
+
|
|
1808
|
+
const dbMigrate = result.functions.dbMigrate;
|
|
1809
|
+
|
|
1810
|
+
// Should have no events (manually invoked via AWS CLI)
|
|
1811
|
+
expect(dbMigrate.events).toBeUndefined();
|
|
1812
|
+
});
|
|
1813
|
+
|
|
1814
|
+
it('should include dbMigrate even with VPC enabled', async () => {
|
|
1815
|
+
const appDefinition = {
|
|
1816
|
+
vpc: {
|
|
1817
|
+
enable: true,
|
|
1818
|
+
management: 'discover'
|
|
1819
|
+
},
|
|
1820
|
+
integrations: []
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1824
|
+
|
|
1825
|
+
// dbMigrate should exist with VPC configuration
|
|
1826
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1827
|
+
|
|
1828
|
+
// Should have same VPC access as other functions
|
|
1829
|
+
expect(result.provider.vpc).toBeDefined();
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1832
|
+
it('should include dbMigrate with database configuration', async () => {
|
|
1833
|
+
const appDefinition = {
|
|
1834
|
+
vpc: {
|
|
1835
|
+
enable: true,
|
|
1836
|
+
management: 'discover'
|
|
1837
|
+
},
|
|
1838
|
+
database: {
|
|
1839
|
+
postgres: {
|
|
1840
|
+
enable: true,
|
|
1841
|
+
management: 'discover'
|
|
1842
|
+
}
|
|
1843
|
+
},
|
|
1844
|
+
integrations: []
|
|
1845
|
+
};
|
|
1846
|
+
|
|
1847
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1848
|
+
|
|
1849
|
+
// dbMigrate should exist alongside database configuration
|
|
1850
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1851
|
+
expect(result.provider.environment.DB_TYPE).toBe('postgresql');
|
|
1852
|
+
expect(result.provider.environment.DATABASE_URL).toBeDefined();
|
|
1853
|
+
});
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1765
1856
|
describe('Edge Cases', () => {
|
|
1766
1857
|
it('should handle empty app definition', async () => {
|
|
1767
1858
|
const appDefinition = {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.454.
|
|
4
|
+
"version": "2.0.0--canary.454.15f637e.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.454.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.454.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.454.15f637e.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.454.15f637e.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.454.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.454.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.454.15f637e.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.454.15f637e.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "15f637ef408869244080cab68677013d159d8e1b"
|
|
74
74
|
}
|