@mikarinneoracle/oci-cdk-code-only-preview 0.0.5 → 0.0.7

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.
@@ -89,9 +89,13 @@ function createArchive() {
89
89
  }
90
90
 
91
91
  function jsonOci(args) {
92
- const output = runOci([...args, '--output', 'json']);
92
+ const output = runOci([...args, '--output', 'json']).trim();
93
+ const objectStart = output.indexOf('{');
94
+ const arrayStart = output.indexOf('[');
95
+ const start = objectStart !== -1 ? objectStart : arrayStart;
96
+ const end = Math.max(output.lastIndexOf('}'), output.lastIndexOf(']'));
93
97
  try {
94
- return JSON.parse(output);
98
+ return JSON.parse(start === -1 || end < start ? output : output.slice(start, end + 1));
95
99
  } catch {
96
100
  fail(`OCI CLI returned invalid JSON for: ${args.join(' ')}`);
97
101
  }
@@ -101,16 +105,6 @@ function resourceDisplayName(resource) {
101
105
  return resource.displayName || resource['display-name'] || '';
102
106
  }
103
107
 
104
- function findApplicationId(compartmentId, appName) {
105
- const result = jsonOci(['fn', 'application', 'list', '--compartment-id', compartmentId, '--all']);
106
- const matches = (result.data || []).filter((app) => resourceDisplayName(app) === appName);
107
- if (matches.length === 0) {
108
- fail(`Functions Application "${appName}" was not found. Code-only deploy requires an existing application.`);
109
- }
110
- if (matches.length > 1) fail(`multiple Functions Applications are named "${appName}"; use a unique application name.`);
111
- return matches[0].id;
112
- }
113
-
114
108
  function findFunctionId(applicationId, functionName) {
115
109
  const result = jsonOci(['fn', 'function', 'list', '--application-id', applicationId, '--all']);
116
110
  const matches = (result.data || []).filter((fn) => resourceDisplayName(fn) === functionName);
@@ -130,12 +124,10 @@ function verifyPreviewCli() {
130
124
  function main() {
131
125
  const unexpectedArgs = process.argv.slice(2).filter((arg) => arg !== '--auto-approve');
132
126
  if (unexpectedArgs.length) fail(`unsupported code-only deploy option(s): ${unexpectedArgs.join(', ')}`);
133
- const compartmentId = (process.env.OCI_COMPARTMENT_ID || process.env.OCI_COMPARTMENT_OCID || '').trim();
134
- if (!compartmentId) fail('set OCI_COMPARTMENT_ID (or OCI_COMPARTMENT_OCID).');
135
-
136
127
  verifyPreviewCli();
137
128
  const metadata = readFunctionMetadata();
138
- const applicationId = findApplicationId(compartmentId, metadata.appName);
129
+ const applicationId = (process.env.OCI_FUNCTION_APP_ID || '').trim();
130
+ if (!applicationId) fail('Terraform output OCI_FUNCTION_APP_ID is missing. Run through "ocdk deploy --code-only".');
139
131
  const archive = createArchive();
140
132
  try {
141
133
  const functionId = findFunctionId(applicationId, metadata.functionName);
@@ -24,8 +24,13 @@ function runOci(args) {
24
24
  }
25
25
 
26
26
  function jsonOci(args) {
27
+ const output = runOci([...args, '--output', 'json']).trim();
28
+ const objectStart = output.indexOf('{');
29
+ const arrayStart = output.indexOf('[');
30
+ const start = objectStart !== -1 ? objectStart : arrayStart;
31
+ const end = Math.max(output.lastIndexOf('}'), output.lastIndexOf(']'));
27
32
  try {
28
- return JSON.parse(runOci([...args, '--output', 'json']));
33
+ return JSON.parse(start === -1 || end < start ? output : output.slice(start, end + 1));
29
34
  } catch (error) {
30
35
  fail(`OCI CLI returned invalid JSON for: ${args.join(' ')} (${error.message})`);
31
36
  }
@@ -41,23 +46,17 @@ function resourceDisplayName(resource) {
41
46
  }
42
47
 
43
48
  function main() {
44
- const compartmentId = (process.env.OCI_COMPARTMENT_ID || process.env.OCI_COMPARTMENT_OCID || '').trim();
45
- if (!compartmentId) fail('set OCI_COMPARTMENT_ID (or OCI_COMPARTMENT_OCID).');
46
49
  const funcYamlPath = path.join(projectDir, 'func.yaml');
47
50
  const yaml = fs.existsSync(funcYamlPath) ? fs.readFileSync(funcYamlPath, 'utf8') : '';
48
51
  const functionName = (process.env.OCI_FUNCTION_NAME || yamlValue(yaml, 'name')).trim();
49
52
  const appName = (process.env.OCI_FUNCTION_APP_NAME || functionName).trim();
50
53
  if (!functionName) fail('set OCI_FUNCTION_NAME or add name: to func.yaml.');
51
54
  if (!appName) fail('set OCI_FUNCTION_APP_NAME.');
55
+ const applicationId = (process.env.OCI_FUNCTION_APP_ID || '').trim();
56
+ if (!applicationId) fail('Terraform output OCI_FUNCTION_APP_ID is missing. Run through "ocdk destroy --code-only".');
52
57
 
53
58
  const version = runOci(['--version']).trim();
54
- const apps = jsonOci(['fn', 'application', 'list', '--compartment-id', compartmentId, '--all']).data || [];
55
- const app = apps.find((item) => resourceDisplayName(item) === appName);
56
- if (!app) {
57
- console.log(`Functions Application ${appName} is absent; no code-only function needs deletion.`);
58
- return;
59
- }
60
- const functions = jsonOci(['fn', 'function', 'list', '--application-id', app.id, '--all']).data || [];
59
+ const functions = jsonOci(['fn', 'function', 'list', '--application-id', applicationId, '--all']).data || [];
61
60
  const matches = functions.filter((item) => resourceDisplayName(item) === functionName);
62
61
  if (matches.length === 0) {
63
62
  console.log(`Code-only function ${functionName} is absent; continuing with Terraform destroy.`);
package/bin/ocdk.js CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  const { spawnSync } = require('child_process');
8
8
  const path = require('path');
9
+ const os = require('os');
9
10
 
10
11
  const fs = require('fs');
11
12
  const root = path.join(__dirname, '..');
@@ -18,6 +19,44 @@ const codeOnlyEnabled =
18
19
  args.includes('-code-only') ||
19
20
  args.includes('--code-only');
20
21
 
22
+ function findFunctionAppId(value) {
23
+ if (!value || typeof value !== 'object') return undefined;
24
+ if (Object.prototype.hasOwnProperty.call(value, 'function_app_id')) {
25
+ const output = value.function_app_id;
26
+ if (typeof output === 'string') return output;
27
+ if (output && typeof output === 'object' && typeof output.value === 'string') return output.value;
28
+ }
29
+ for (const child of Object.values(value)) {
30
+ const found = findFunctionAppId(child);
31
+ if (found) return found;
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ function resolveCodeOnlyFunctionAppId(env) {
37
+ if (env.OCI_FUNCTION_APP_ID?.trim()) return env.OCI_FUNCTION_APP_ID.trim();
38
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ocdk-function-app-output-'));
39
+ const outputFile = path.join(tempDir, 'outputs.json');
40
+ const stackName = env.OCI_STACK_NAME || 'oci-stack';
41
+ try {
42
+ const result = spawnSync('npm', ['run', '--silent', 'cdktf', '--', 'output', stackName, '--outputs-file', outputFile], {
43
+ cwd: root,
44
+ env,
45
+ encoding: 'utf8',
46
+ shell: false,
47
+ });
48
+ if (result.status !== 0 || !fs.existsSync(outputFile)) {
49
+ const detail = (result.stderr || result.stdout || '').trim();
50
+ throw new Error(detail || 'cdktf output did not produce an output file.');
51
+ }
52
+ const appId = findFunctionAppId(JSON.parse(fs.readFileSync(outputFile, 'utf8')));
53
+ if (!appId) throw new Error('Terraform output "function_app_id" is missing.');
54
+ return appId;
55
+ } finally {
56
+ fs.rmSync(tempDir, { recursive: true, force: true });
57
+ }
58
+ }
59
+
21
60
  const npmRunCommands = ['deploy', 'diff', 'synth', 'destroy', 'list', 'get'];
22
61
 
23
62
  if (!command || command.startsWith('-')) {
@@ -112,11 +151,18 @@ if (command === 'deploy' && codeOnlyEnabled) {
112
151
  env,
113
152
  });
114
153
  if (infrastructure.status !== 0) process.exit(infrastructure.status ?? 1);
154
+ let functionAppId;
155
+ try {
156
+ functionAppId = resolveCodeOnlyFunctionAppId(env);
157
+ } catch (error) {
158
+ console.error(`Code-only deploy failed: could not read Terraform Function App output: ${error.message}`);
159
+ process.exit(1);
160
+ }
115
161
  const result = spawnSync('node', [script], {
116
162
  stdio: 'inherit',
117
163
  cwd: projectDir,
118
164
  shell: false,
119
- env,
165
+ env: { ...env, OCI_FUNCTION_APP_ID: functionAppId },
120
166
  });
121
167
  process.exit(result.status ?? 1);
122
168
  }
@@ -137,11 +183,18 @@ if (command === 'destroy' && codeOnlyEnabled) {
137
183
  OCI_STACK_ACTION: 'function-only',
138
184
  OCI_PROJECT_DIR: projectDir,
139
185
  };
186
+ let functionAppId;
187
+ try {
188
+ functionAppId = resolveCodeOnlyFunctionAppId(env);
189
+ } catch (error) {
190
+ console.error(`Code-only destroy failed: could not read Terraform Function App output: ${error.message}`);
191
+ process.exit(1);
192
+ }
140
193
  const functionDestroy = spawnSync('node', [script], {
141
194
  stdio: 'inherit',
142
195
  cwd: projectDir,
143
196
  shell: false,
144
- env,
197
+ env: { ...env, OCI_FUNCTION_APP_ID: functionAppId },
145
198
  });
146
199
  if (functionDestroy.status !== 0) process.exit(functionDestroy.status ?? 1);
147
200
  const infrastructure = spawnSync('npm', ['run', '--silent', 'destroy', '--', ...passthroughArgs], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikarinneoracle/oci-cdk-code-only-preview",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "OCI CDK stack for OCI Functions, API Gateway, and related infrastructure",
5
5
  "main": "lib/index.js",
6
6
  "bin": {