@mikarinneoracle/oci-cdk-code-only-preview 0.0.28 → 0.0.30

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/README.md CHANGED
@@ -57,7 +57,7 @@ Only **`OCI_COMPARTMENT_ID`** (or `OCI_COMPARTMENT_OCID`) is required for deploy
57
57
  | `OCI_IMAGE_TAG` | Image tag for OCIR | func.yaml version or `latest` |
58
58
  | `OCI_CODE_ONLY` | When `1`, use the Code-only Functions ZIP deploy path | `0` |
59
59
  | `OCI_CODE_ONLY_SOURCE_DIR` | Source directory to archive for code-only deploy | current directory |
60
- | `OCI_CODE_ONLY_RUNTIME_NAME` | Required OCI Functions runtime name for code-only deploy (for example `python312.ol9`) | — |
60
+ | `OCI_CODE_ONLY_RUNTIME_NAME` | Optional explicit OCI Functions runtime name for code-only deploy (for example `python312.ol9`). OCDK resolves Python automatically from `func.yaml`. | — |
61
61
  | **API Gateway** | | |
62
62
  | `OCI_APIGATEWAY_DEPLOYMENT_JSON` | Path to deployment spec JSON | `oci_apigateway_deployment.json` in project root |
63
63
  | **Stack / networking** | | |
@@ -115,8 +115,8 @@ export OCI_CLI_PATH="/Users/MRINNE/projects/ocdk/.tools/oci-preview-bin/oci"
115
115
  # Required: OCI target
116
116
  export OCI_COMPARTMENT_ID='ocid1.compartment.oc1...'
117
117
 
118
- # Required: code-only runtime and handler
119
- export OCI_CODE_ONLY_RUNTIME_NAME='python312.ol9'
118
+ # Required: handler. OCDK resolves the latest available Python runtime.
119
+ # Optionally pin one: export OCI_CODE_ONLY_RUNTIME_NAME='python312.ol9'
120
120
  export OCI_FUNCTION_HANDLER='func.handler'
121
121
 
122
122
  # Required in func.yaml: name: my-function
@@ -157,11 +157,11 @@ mvn -DskipTests package
157
157
  # or: gradle build -x test
158
158
  ```
159
159
 
160
- OCDK also runs this build automatically when no artifact exists yet, and searches the project root, Maven `target/`, and Gradle `build/libs/`. The build must produce a fat/uber JAR: Maven projects normally use `maven-shade-plugin`, and Gradle projects use the Shadow plugin. If several JARs exist, set `OCI_FUNCTION_JAR_PATH` to the fat JAR explicitly. Java archives do not contain the project source tree or a `function/` directory.
160
+ OCDK also runs this build automatically when no artifact exists yet, and searches the project root, Maven `target/`, and Gradle `build/libs/`. The OCI service validates the JAR contents; if several non-source JARs exist, set `OCI_FUNCTION_JAR_PATH` to the one to deploy explicitly. Java archives do not contain the project source tree or a `function/` directory.
161
161
 
162
162
  #### Find the available code-only runtimes
163
163
 
164
- The exact `OCI_CODE_ONLY_RUNTIME_NAME` values are enabled per tenancy and region during this Limited Availability preview. Query the Preview CLI instead of copying a runtime name from another environment:
164
+ The exact `OCI_CODE_ONLY_RUNTIME_NAME` values are enabled per tenancy and region during this Limited Availability preview. For Python, OCDK queries this list automatically and selects the newest matching runtime when `func.yaml` contains `runtime: python` (or a versioned value such as `python3.12`). Set `OCI_CODE_ONLY_RUNTIME_NAME` to pin or override that choice. Query the Preview CLI to inspect available runtimes or when deploying another language:
165
165
 
166
166
  ```bash
167
167
  # List every runtime available to the active OCI profile
@@ -49,12 +49,45 @@ function integerValue(value, name, fallback) {
49
49
  return String(parsed);
50
50
  }
51
51
 
52
+ function runtimeResourceName(runtime) {
53
+ return runtime.name || runtime['runtime-name'] || runtime.runtimeName || runtime['runtimeName'] || '';
54
+ }
55
+
56
+ function pythonRuntimeSortKey(runtimeName) {
57
+ const match = runtimeName.toLowerCase().match(/^python(\d+)/);
58
+ return match ? Number.parseInt(match[1], 10) : -1;
59
+ }
60
+
61
+ function resolvePythonRuntime(runtime) {
62
+ // OCI's preview runtime names omit separators from the Python version:
63
+ // func.yaml's "python3.12" therefore maps to the runtime-list prefix
64
+ // "python312". A plain "python" selects the newest available version.
65
+ const normalizedRuntime = runtime.toLowerCase().replace(/[^a-z0-9]/g, '');
66
+ const namePrefix = normalizedRuntime === 'python' ? 'python' : normalizedRuntime;
67
+ const result = jsonOci(['fn', 'runtime', 'list', '--all', '--name-starts-with', namePrefix]);
68
+ const candidates = (result.data || [])
69
+ .map(runtimeResourceName)
70
+ .filter((name) => name.toLowerCase().startsWith(namePrefix));
71
+ if (!candidates.length) {
72
+ fail(`no available code-only runtime matches ${runtime}. Set OCI_CODE_ONLY_RUNTIME_NAME to a runtime returned by "oci fn runtime list --all".`);
73
+ }
74
+ candidates.sort((left, right) => {
75
+ const versionDifference = pythonRuntimeSortKey(right) - pythonRuntimeSortKey(left);
76
+ return versionDifference || right.localeCompare(left);
77
+ });
78
+ const selected = candidates[0];
79
+ console.log(`Selected OCI code-only runtime ${selected} for func.yaml runtime ${runtime}. Set OCI_CODE_ONLY_RUNTIME_NAME to pin a different runtime.`);
80
+ return selected;
81
+ }
82
+
52
83
  function readFunctionMetadata() {
53
84
  const funcYamlPath = path.join(projectDir, 'func.yaml');
54
85
  const yaml = fs.existsSync(funcYamlPath) ? fs.readFileSync(funcYamlPath, 'utf8') : '';
55
86
  const functionName = (process.env.OCI_FUNCTION_NAME || yamlValue(yaml, 'name')).trim();
56
87
  const appName = (process.env.OCI_FUNCTION_APP_NAME || functionName).trim();
57
- const runtimeName = (process.env.OCI_CODE_ONLY_RUNTIME_NAME || '').trim();
88
+ const configuredRuntime = yamlValue(yaml, 'runtime');
89
+ const runtimeName = (process.env.OCI_CODE_ONLY_RUNTIME_NAME || '').trim()
90
+ || (configuredRuntime.toLowerCase().startsWith('python') ? resolvePythonRuntime(configuredRuntime) : '');
58
91
  const configuredHandler = (process.env.OCI_FUNCTION_HANDLER || yamlValue(yaml, 'cmd') || yamlValue(yaml, 'entrypoint')).trim();
59
92
  // The managed Node runtime already invokes `node`; its handler is the script
60
93
  // path, whereas a conventional func.yaml entrypoint is `node func.js`.
@@ -66,7 +99,7 @@ function readFunctionMetadata() {
66
99
 
67
100
  if (!functionName) fail('set OCI_FUNCTION_NAME or add name: to func.yaml.');
68
101
  if (!appName) fail('set OCI_FUNCTION_APP_NAME.');
69
- if (!runtimeName) fail('set OCI_CODE_ONLY_RUNTIME_NAME (for example python312.ol9).');
102
+ if (!runtimeName) fail('set OCI_CODE_ONLY_RUNTIME_NAME (for example python312.ol9). Automatic runtime resolution currently supports Python functions with runtime: python in func.yaml.');
70
103
  if (!handler) fail('set OCI_FUNCTION_HANDLER or add cmd: to func.yaml.');
71
104
 
72
105
  return { functionName, appName, handler, runtimeName, memory, timeout };
@@ -123,12 +156,6 @@ function buildJavaProject() {
123
156
  }
124
157
  }
125
158
 
126
- function isFatJavaJar(jarPath) {
127
- const result = spawnSync('jar', ['tf', jarPath], { encoding: 'utf8', shell: false });
128
- if (result.error || result.status !== 0) return false;
129
- return /(^|\n)com\/fnproject\/fn\/(api|runtime)\//.test(result.stdout || '');
130
- }
131
-
132
159
  function resolveJavaJar() {
133
160
  const configuredPath = (process.env.OCI_CODE_ONLY_JAR_PATH || process.env.OCI_FUNCTION_JAR_PATH || '').trim();
134
161
  if (configuredPath) {
@@ -136,9 +163,6 @@ function resolveJavaJar() {
136
163
  if (!fs.existsSync(jarPath) || !fs.statSync(jarPath).isFile() || !jarPath.endsWith('.jar')) {
137
164
  fail(`OCI_FUNCTION_JAR_PATH must point to an existing .jar file: ${jarPath}`);
138
165
  }
139
- if (!isFatJavaJar(jarPath)) {
140
- fail(`Java archive is not a fat/uber JAR: ${jarPath}. Configure your Maven Shade or Gradle Shadow build, then point OCI_FUNCTION_JAR_PATH to its output.`);
141
- }
142
166
  return jarPath;
143
167
  }
144
168
  let candidates = listJavaJarCandidates();
@@ -148,14 +172,11 @@ function resolveJavaJar() {
148
172
  }
149
173
  const uniqueCandidates = [...new Set(candidates)];
150
174
  if (uniqueCandidates.length === 1) {
151
- if (!isFatJavaJar(uniqueCandidates[0])) {
152
- fail(`Java build produced a non-fat JAR: ${uniqueCandidates[0]}. Configure your Maven Shade or Gradle Shadow build, then set OCI_FUNCTION_JAR_PATH to its fat/uber JAR.`);
153
- }
154
175
  return uniqueCandidates[0];
155
176
  }
156
177
  const found = uniqueCandidates.length ? ` Found: ${uniqueCandidates.join(', ')}` : '';
157
- const guidance = ' Run `mvn -DskipTests package` (or `gradle build -x test`) to produce a fat/uber JAR using Maven Shade or Gradle Shadow, then set OCI_FUNCTION_JAR_PATH (for example target/my-function-all.jar).';
158
- fail(`Java code-only deploy requires exactly one fat/uber JAR.${guidance}${found}`);
178
+ const guidance = ' Run `mvn -DskipTests package` (or `gradle build -x test`) to produce the function JAR, then set OCI_FUNCTION_JAR_PATH (for example target/my-function.jar).';
179
+ fail(`Java code-only deploy requires exactly one JAR.${guidance}${found}`);
159
180
  }
160
181
 
161
182
  function createArchive(functionName, runtimeName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikarinneoracle/oci-cdk-code-only-preview",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "description": "OCI CDK stack for OCI Functions, API Gateway, and related infrastructure",
5
5
  "main": "lib/index.js",
6
6
  "bin": {