Skip to content

Commit 5b86130

Browse files
committed
Add layer building GitHub action
1 parent a7cae01 commit 5b86130

File tree

4 files changed

+3477
-0
lines changed

4 files changed

+3477
-0
lines changed

.github/workflows/ni-layers.yml

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#
2+
# Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
#
5+
# The Universal Permissive License (UPL), Version 1.0
6+
#
7+
# Subject to the condition set forth below, permission is hereby granted to any
8+
# person obtaining a copy of this software, associated documentation and/or
9+
# data (collectively the "Software"), free of charge and under any and all
10+
# copyright rights in the Software, and any and all patent rights owned or
11+
# freely licensable by each licensor hereunder covering either (i) the
12+
# unmodified Software as contributed to or provided by such licensor, or (ii)
13+
# the Larger Works (as defined below), to deal in both
14+
#
15+
# (a) the Software, and
16+
#
17+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
# one is included with the Software each a "Larger Work" to which the Software
19+
# is contributed by such licensors),
20+
#
21+
# without restriction, including without limitation the rights to copy, create
22+
# derivative works of, display, perform, and distribute the Software and make,
23+
# use, sell, offer for sale, import, export, have made, and have sold the
24+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
# either these or other terms.
26+
#
27+
# This license is subject to the following condition:
28+
#
29+
# The above copyright notice and either this complete permission notice or at a
30+
# minimum a reference to the UPL must be included in all copies or substantial
31+
# portions of the Software.
32+
#
33+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
# SOFTWARE.
40+
#
41+
name: Weekly Native Image Layer Building Tests
42+
43+
on:
44+
schedule:
45+
- cron: "0 0 * * 1" # Once a week at midnight on Monday
46+
push:
47+
paths:
48+
- '.github/workflows/reachability-metadata.yml'
49+
pull_request:
50+
paths:
51+
- '.github/workflows/reachability-metadata.yml'
52+
53+
env:
54+
LIBRARY_METADATA_PATH: ${{github.workspace}}/vm/tests/gh_workflows/NILayerTests
55+
JAVA_VERSION: 21
56+
PYTHON_VERSION: 3.12.3
57+
58+
jobs:
59+
build-graalvm-and-populate-matrix:
60+
name: Build GraalVM and populate matrix
61+
runs-on: ubuntu-latest
62+
if: (github.repository=='oracle/graal')
63+
outputs:
64+
matrix: ${{ steps.set-matrix.outputs.matrix }}
65+
steps:
66+
- name: Checkout oracle/graal
67+
uses: actions/checkout@v4
68+
- name: Build GraalVM JDK
69+
uses: ./.github/actions/build-graalvm
70+
with:
71+
native-images: 'native-image,native-image-configure,lib:native-image-agent'
72+
components: 'Native Image,Native Image Configure Tool'
73+
java-version: ${{ env.JAVA_VERSION }}
74+
- name: Tar GraalVM JDK
75+
shell: bash
76+
run: tar -czvhf graalvm.tgz -C $(dirname ${GRAALVM_HOME}) $(basename ${GRAALVM_HOME})
77+
- name: Persist GraalVM JDK build
78+
uses: actions/upload-artifact@v4
79+
with:
80+
name: graalvm
81+
path: graalvm.tgz
82+
- name: Setup python
83+
uses: actions/setup-python@v5
84+
with:
85+
python-version: '${{env.PYTHON_VERSION}}'
86+
- name: Populate matrix
87+
id: set-matrix
88+
run: python3 -c 'import vm.tests.gh_workflows.NILayerTests.build_layer; vm.tests.gh_workflows.NILayerTests.build_layer.generate_matrix("${{env.LIBRARY_METADATA_PATH}}");'
89+
90+
test-native-image-layer-build:
91+
name: ${{matrix.coordinates}}
92+
runs-on: ubuntu-latest
93+
env:
94+
GRAALVM_HOME: ${{ github.workspace }}/graalvm
95+
timeout-minutes: 20
96+
needs: build-graalvm-and-populate-matrix
97+
strategy:
98+
fail-fast: false
99+
matrix:
100+
coordinates: ${{ fromJson(needs. build-graalvm-and-populate-matrix.outputs.matrix).coordinates}}
101+
steps:
102+
- name: Checkout oracle/graal
103+
uses: actions/checkout@v4
104+
- name: Download GraalVM JDK build
105+
uses: actions/download-artifact@v4
106+
with:
107+
name: graalvm
108+
path: .
109+
- name: Extract GraalVM JDK build
110+
run: tar -xzvf graalvm.tgz -C $(dirname ${GRAALVM_HOME})
111+
- name: "Setup JAVA_HOME"
112+
uses: actions/setup-java@v4
113+
with:
114+
distribution: 'oracle'
115+
java-version: ${{ env.JAVA_VERSION }}
116+
- name: Setup python
117+
uses: actions/setup-python@v5
118+
with:
119+
python-version: '${{env.PYTHON_VERSION}}'
120+
- name: Build layer
121+
run: |
122+
python3 -c 'import vm.tests.gh_workflows.NILayerTests.build_layer; vm.tests.gh_workflows.NILayerTests.build_layer.build_layer("${{matrix.coordinates}}".split("|")[0], "${{env.GRAALVM_HOME}}/bin/native-image");'
123+
python3 -c 'import vm.tests.gh_workflows.NILayerTests.build_layer; vm.tests.gh_workflows.NILayerTests.build_layer.build_layer("${{matrix.coordinates}}".split("|")[1], "${{env.GRAALVM_HOME}}/bin/native-image");'
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import json
2+
import os
3+
import subprocess
4+
import sys
5+
from pathlib import Path
6+
7+
def generate_matrix(path_to_data):
8+
'''
9+
Generates a matrix in the format of GAV coordinate pairs for GitHub actions.
10+
'''
11+
with open(os.path.join(path_to_data,'popular-maven-libraries.json'), 'r') as f:
12+
data = json.load(f)
13+
with open(os.path.join(path_to_data, 'excluded-libraries.json'), 'r') as f:
14+
exclude_data = json.load(f)
15+
matrix = {'coordinates': []}
16+
found_first = False
17+
for lib in data:
18+
skip = False
19+
for excluded_lib in exclude_data:
20+
if excluded_lib['group_id'] == lib['group_id'] and excluded_lib['artifact_id'] == lib['artifact_id']:
21+
skip = True
22+
break
23+
if not skip:
24+
if not found_first:
25+
first = f'{lib['group_id']}:{lib['artifact_id']}:{lib['version']}'
26+
found_first = True
27+
else:
28+
matrix['coordinates'].append(f'{first}|{lib['group_id']}:{lib['artifact_id']}:{lib['version']}')
29+
found_first = False
30+
if found_first:
31+
matrix['coordinates'].append(f'{first}|NONE')
32+
33+
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
34+
print(f"matrix={json.dumps(matrix)}", file=f)
35+
36+
def build_layer(gav, native_image_path):
37+
'''
38+
Builds a native-image layer out of the library, given its GAV coordinates and native-image path.
39+
40+
Firstly, the function invokes a maven command to download the library jar with all it's transitive dependencies, given its GAV coordinates.
41+
After that, it invokes a maven command to get the full classpath of the given library.
42+
Finally, it runs a native-image command to build the native-image layer and prints out the used command for local testing in case of issues.
43+
'''
44+
if gav == 'NONE':
45+
exit(0)
46+
currDir = os.getcwd()
47+
splitted = gav.split(':')
48+
group_id, artifact_id, version = splitted[0], splitted[1], splitted[2]
49+
50+
subprocess.call(f'mvn dependency:get -Dartifact={gav} -Dtransitive=true', shell=True)
51+
52+
home_path = str(Path.home())
53+
library_path = os.path.join(home_path, '.m2', 'repository', group_id.replace('.','/'), artifact_id, version)
54+
jar_path = os.path.join(library_path, f'{artifact_id}-{version}.jar')
55+
subprocess.call(f'cp {os.path.join(library_path, f'{artifact_id}-{version}.pom')} {os.path.join(library_path, 'pom.xml')}', shell=True)
56+
if Path(library_path).exists():
57+
subprocess.call(f'mkdir {gav}', shell=True)
58+
os.chdir(gav)
59+
image_path = os.getcwd()
60+
os.chdir(library_path)
61+
dependency_path = os.popen('mvn -q exec:exec -Dexec.executable=echo -Dexec.args="%classpath"').read().rstrip()
62+
os.chdir(image_path)
63+
command = f'{native_image_path} -H:+UnlockExperimentalVMOptions -cp {jar_path}:{dependency_path} -H:LayerCreate=layer.nil,package={jar_path} -H:+ReportExceptionStackTraces --no-fallback -o {artifact_id}-{version}'
64+
r = subprocess.call(command, shell=True)
65+
print(f'Command: {command}') # For debugging purposes
66+
os.chdir('..')
67+
os.chdir(currDir)
68+
sys.exit(r)

0 commit comments

Comments
 (0)