Skip to content

Commit

Permalink
chore(actions): add native validation workflow (#1075)
Browse files Browse the repository at this point in the history
Adds a new (not blocking) workflow that runs integration tests
modules against a native build.
Also fixes native builds and renames several test modules.

Fixes #968
  • Loading branch information
mcollovati authored Nov 17, 2024
1 parent 831bc47 commit bcead28
Show file tree
Hide file tree
Showing 166 changed files with 1,266 additions and 54,574 deletions.
112 changes: 112 additions & 0 deletions .github/workflows/validation-native.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Quarkus Hilla Native Validation
on:
workflow_dispatch:
schedule:
- cron: '0 2 * * 3'
# pull_request_target:
# types: [opened, synchronize, reopened, edited]
permissions:
contents: read
issues: read
checks: write
pull-requests: write
concurrency:
group: validation-native-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
check-permissions:
name: Check User Permissions
runs-on: ubuntu-latest
steps:
- run: echo "Concurrency Group = ${{ github.head_ref || github.ref_name }}"
- uses: actions-cool/check-user-permission@main
id: checkUser
with:
username: ${{github.triggering_actor}}
require: 'write'
- name: Fail on workflow triggered by external contributor
if: ${{ steps.checkUser.outputs.require-result != 'true' && github.actor != 'dependabot[bot]' && github.actor != 'quarkus-hilla-bot[bot]' }}
run: |
echo "🚫 **${{ github.actor }}** is an external contributor, a **${{ github.repository }}** team member has to review this changes and re-run this build" \
| tee -a $GITHUB_STEP_SUMMARY && exit 1
changes:
name: Compute changes
needs: [check-permissions]
runs-on: ubuntu-latest
outputs:
validation-required: ${{ steps.filter.outputs.validate }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
validate:
- '!(README.md|LICENSE|.gitignore|etc/**)'
compute-matrix:
needs: [changes]
if: ${{ needs.changes.outputs.validation-required == 'true' }}
runs-on: ubuntu-latest
outputs:
modules: ${{ steps.set-matrix.outputs.modules }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Compute matrix
id: set-matrix
run: |
test_modules=$(find integration-tests -maxdepth 1 -mindepth 1 -type d -name "*-tests")
test_modules=$(while IFS= read -r mod; do grep -q "%test-security." $mod/src/main/resources/application.properties; echo "{\"name\": \"${mod/integration-tests\//}\", \"path\": \"$mod\", \"security\": $? }"; done <<< "${test_modules}" | jq -s -c '.')
echo "modules=${test_modules}" >> "$GITHUB_OUTPUT"
build-and-test-native:
name: Native tests
needs: [compute-matrix]
if: ${{ needs.changes.outputs.validation-required == 'true' }}
strategy:
fail-fast: false
matrix:
module: ${{fromJson(needs.compute-matrix.outputs.modules)}}
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: 23
distribution: 'graalvm'
cache: maven
- uses: browser-actions/setup-chrome@latest
id: setup-chrome
if: ${{ !vars.QH_DISABLE_CHROME_INSTALL }}
with:
chrome-version: stable
- name: Build
run: |
set -x -e -o pipefail
mvn -V -e -B -ntp -DskipTests -Dmaven.javadoc.skip=false install
- name: Native Test
run: |
set -x -e -o pipefail
mvn -V -e -B -ntp verify -am -DtrimStackTrace=false -Dselenide.browserBinary=${{ steps.setup-chrome.outputs.chrome-path }} -Pit-tests,production -Dnative -pl ${{ matrix.module.path }}
- name: Native Security Test
if: ${{ matrix.module.security == 1 }}
run: |
set -x -e -o pipefail
mvn -V -e -B -ntp verify -am -DtrimStackTrace=false -Dselenide.browserBinary=${{ steps.setup-chrome.outputs.chrome-path }} -Pit-tests,production -Dnative -Dquarkus.profile=test-security -pl ${{ matrix.module.path }}
- name: Package test output files
if: ${{ failure() || success() }}
run: find . -name surefire-reports -o -name failsafe-reports -o -name selenide-reports -o -name quarkus.log | tar -czf tests-report-native.tgz -T -
- uses: actions/upload-artifact@v4
if: ${{ failure() || success() }}
with:
name: tests-output-it-native-${{ matrix.module.name }}
path: tests-report-*.tgz
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,25 @@
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.di.LookupInitializer;
import com.vaadin.flow.router.AccessDeniedException;
import com.vaadin.flow.router.HasErrorParameter;
import com.vaadin.flow.router.HasUrlParameter;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.MenuData;
import com.vaadin.flow.router.NotFoundException;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouteAlias;
import com.vaadin.flow.router.RouterLayout;
import com.vaadin.flow.server.auth.AccessDeniedErrorRouter;
import com.vaadin.flow.server.menu.AvailableViewInfo;
import com.vaadin.flow.server.menu.RouteParamType;
import com.vaadin.flow.server.startup.ServletDeployer;
import com.vaadin.hilla.BrowserCallable;
import com.vaadin.hilla.Endpoint;
import com.vaadin.hilla.EndpointExposed;
import com.vaadin.hilla.crud.filter.Filter;
import com.vaadin.hilla.endpointransfermapper.EndpointTransferMapper;
import com.vaadin.hilla.push.PushEndpoint;
import io.quarkus.arc.deployment.ExcludedTypeBuildItem;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
Expand Down Expand Up @@ -98,6 +103,7 @@
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.objectweb.asm.Opcodes;
import org.springframework.data.domain.Pageable;

import com.github.mcollovati.quarkus.hilla.graal.AtmosphereDeferredInitializerRecorder;
import com.github.mcollovati.quarkus.hilla.graal.DelayedSchedulerExecutorsFactory;
Expand Down Expand Up @@ -221,17 +227,40 @@ void hillaNativeSupport(

IndexView index = combinedIndex.getComputingIndex();
Set<ClassInfo> classes = new HashSet<>();
classes.addAll(index.getAllKnownImplementors(EndpointTransferMapper.Mapper.class));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(BrowserCallable.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(Endpoint.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(EndpointExposed.class)));
classes.add(index.getClassByName(PushEndpoint.class));
classes.add(index.getClassByName(Filter.class));
classes.add(index.getClassByName(Pageable.class));
classes.addAll(getJsonClasses(index));
classes.addAll(index.getAllKnownImplementors(EndpointTransferMapper.Mapper.class));
classes.addAll(index.getClassesInPackage("com.vaadin.hilla.mappedtypes"));
classes.addAll(index.getClassesInPackage("com.vaadin.hilla.runtime.transfertypes"));

if (capabilities.isPresent(QuarkusHillaExtensionProcessor.SPRING_DATA_SUPPORT)) {
classes.add(index.getClassByName("org.springframework.data.repository.Repository"));
classes.add(index.getClassByName("org.springframework.data.repository.CrudRepository"));
classes.add(index.getClassByName("org.springframework.data.domain.Pageable"));
classes.add(index.getClassByName("org.springframework.data.domain.Specification"));

// explicitly register classes not present in the index
reflectiveClass.produce(ReflectiveClassBuildItem.builder(
com.github.mcollovati.quarkus.hilla.crud.spring.CrudRepositoryService.class,
com.github.mcollovati.quarkus.hilla.crud.spring.ListRepositoryService.class)
.constructors()
.methods()
.build());
}

if (capabilities.isPresent(QuarkusHillaExtensionProcessor.PANACHE_SUPPORT)) {
reflectiveClass.produce(ReflectiveClassBuildItem.builder(
com.github.mcollovati.quarkus.hilla.crud.panache.CrudRepositoryService.class,
com.github.mcollovati.quarkus.hilla.crud.panache.ListRepositoryService.class)
.constructors()
.methods()
.build());
}

reflectiveClass.produce(ReflectiveClassBuildItem.builder(classes.stream()
Expand Down Expand Up @@ -283,12 +312,17 @@ void vaadinNativeSupport(
.build());

Set<ClassInfo> classes = new HashSet<>();
classes.add(index.getClassByName(AccessDeniedException.class));
classes.add(index.getClassByName(NotFoundException.class));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(Route.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(RouteAlias.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(Layout.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(Menu.class)));
classes.addAll(getAnnotatedClasses(index, DotName.createSimple(AccessDeniedErrorRouter.class)));
classes.addAll(index.getAllKnownImplementors(AppShellConfigurator.class));
classes.addAll(getCommonComponentClasses(index));
classes.addAll(index.getAllKnownSubclasses(AccessDeniedException.class));
classes.addAll(index.getAllKnownSubclasses(NotFoundException.class));
classes.addAll(index.getAllKnownSubclasses(Component.class));
classes.addAll(index.getAllKnownSubclasses(RouterLayout.class));
classes.addAll(index.getAllKnownSubclasses(HasErrorParameter.class));
Expand All @@ -299,6 +333,9 @@ void vaadinNativeSupport(
reflectiveClass.produce(ReflectiveClassBuildItem.builder(classes.stream()
.map(classInfo -> classInfo.name().toString())
.toArray(String[]::new))
.constructors()
.methods()
.fields()
.build());

registerAtmosphereClasses(reflectiveClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import com.vaadin.hilla.signals.core.registry.SecureSignalsRegistry;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.gizmo.ClassTransformer;
import io.quarkus.gizmo.MethodDescriptor;
import org.springframework.data.domain.Sort;

import com.github.mcollovati.quarkus.hilla.SpringReplacements;

Expand Down Expand Up @@ -95,6 +98,14 @@ public static void addClassVisitors(BuildProducer<BytecodeTransformerBuildItem>
producer.produce(new BytecodeTransformerBuildItem(
ConfigList.Processor.class.getName(),
(s, classVisitor) -> new NonnullPluginConfigProcessorClassVisitor(classVisitor)));
// Remove sort method that references a type that is not in the shaded deps jar
producer.produce(new BytecodeTransformerBuildItem(Sort.class.getName(), (className, classVisitor) -> {
ClassTransformer transformer = new ClassTransformer(className);
MethodDescriptor sortMethod =
MethodDescriptor.ofMethod(className, "sort", className + "$TypedSort", "java.lang.Class");
transformer.removeMethod(sortMethod);
return transformer.applyTo(classVisitor);
}));
}

@SafeVarargs
Expand Down
1 change: 1 addition & 0 deletions commons/hilla-shaded-deps/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
<include>org/springframework/data/domain/AbstractPageRequest.class</include>
<include>org/springframework/data/domain/Chunk.class</include>
<include>org/springframework/data/domain/KeysetScrollPosition.class</include>
<include>org/springframework/data/domain/Limit**.class</include>
<include>org/springframework/data/domain/OffsetScrollPosition.class</include>
<include>org/springframework/data/domain/ScrollPosition.class</include>
<include>org/springframework/data/domain/ScrollPosition$Direction.class
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {ConnectClient} from '@vaadin/hilla-frontend';
const client = new ConnectClient({prefix: 'my-prefix'});
export default client;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import java.util.UUID;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection
public class UserPOJO {

private String id;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 Marco Collovati, Dario Götze
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.application;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class AutoGridNativeIT extends AutoGridTest {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 Marco Collovati, Dario Götze
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.application;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class SignalsNativeIT extends SignalsTest {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 Marco Collovati, Dario Götze
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.application;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class SmokeNativeIT extends SmokeTest {}
Loading

0 comments on commit bcead28

Please sign in to comment.