vaadin / vaadin-gradle-plugin

Gradle plugin for Vaadin 14 applications. Takes care of front-end build, helps to configure repositories and to create various project and file templates.
Apache License 2.0
31 stars 9 forks source link

Task vaadinBuildFrontend fails with dependency error #54

Closed straurob closed 4 years ago

straurob commented 4 years ago

Desktop (please complete the following information):

Describe the bug When building my app with Jenkins the build fails with a "missing dependency error". The app stack is Spring boot 2.2.5 with Vaadin 14.

To Reproduce

  1. Using the below artifact run a CI pipeline job in Jenkins.

Expected behavior The build should finish successfully.

Additional context

Jenkins Console Output

Welcome to Gradle 5.6.4!

Here are the highlights of this release:
 - Incremental Groovy compilation
 - Groovy compile avoidance
 - Test fixtures for Java projects
 - Manage plugin versions via settings script

For more details see https://docs.gradle.org/5.6.4/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)
> Task :clean
> Task :nodeSetup
> Task :vaadinPrepareNode
> Task :compileJava
> Task :vaadinPrepareFrontend
> Task :processResources
> Task :classes

> Task :vaadinBuildFrontend FAILED
Command `/var/lib/jenkins/workspace/build-mokka-app/gradle/node/node /var/lib/jenkins/workspace/build-mokka-app/gradle/node/node_modules/npm/bin/npm-cli.js --no-update-notifier install` failed:

>>> Dependency ERROR. Check that all required dependencies are deployed in npm repositories.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':vaadinBuildFrontend'.
> com.vaadin.flow.server.ExecutionFailedException: Npm install has exited with non zero status. Some dependencies are not installed. Check npm command output

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

build.gradle

plugins {
    id 'org.springframework.boot' version '2.2.5.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'org.siouan.frontend' version '1.3.1'
    id 'com.vaadin' version '0.6.0'
    id 'java'
}

group = 'mygroup'
version = '1.4.0-rc.1'

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

ext {
    commonsLangVersion = '3.9'
    vaadinVersion = '14.1.18'
}

repositories {
    mavenCentral()
    maven { url 'https://maven.vaadin.com/vaadin-addons' }
}

dependencyManagement {
    imports {
        mavenBom "com.vaadin:vaadin-bom:${vaadinVersion}"
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.vaadin:vaadin-spring-boot-starter'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    compile "org.apache.commons:commons-lang3:${commonsLangVersion}"
}

test {
    useJUnitPlatform()
}

Jenkinsfile


pipeline {
    agent any

    triggers { pollSCM('H/5 * * * *') }

    environment {
        APP_NAME = 'MyApp'

        // Gradle settings
        GRADLE_DOCKER_IMAGE = 'gradle:5.6.4-jdk8'
        GRADLE_DOCKER_ARGS = '-v ${HOME}/.m2:/maven/.m2'
        GRADLE_DEPENDENCY_PATH = 'build/dependency'    
    }

    stages {
        stage('Compile') {
            steps {
                script {
                    docker.image(GRADLE_DOCKER_IMAGE).inside("${GRADLE_DOCKER_ARGS}") {
                        sh './gradlew clean vaadinPrepareNode build -Pvaadin.productionMode'
                        sh "mkdir -p ${GRADLE_DEPENDENCY_PATH} && (cd ${GRADLE_DEPENDENCY_PATH}; jar -xf ../libs/*.jar)"
                    }
                }
            }
        }
    }
}   
straurob commented 4 years ago

Update 1

For further debugging I ran the following commands inside the Gradle Dokcer container on the Jenkins host:

sh './gradlew clean vaadinPrepareNode build'
sh '/var/lib/jenkins/workspace/build-mokka-app/gradle/node/node /var/lib/jenkins/workspace/build-mokka-app/gradle/node/node_modules/npm/bin/npm-cli.js --no-update-notifier install'

This gives me the following error message:

npm WARN no-name@ No repository field.
npm ERR! path /.npm
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall mkdir
npm ERR! Error: EACCES: permission denied, mkdir '/.npm'
npm ERR!  { [Error: EACCES: permission denied, mkdir '/.npm']
npm ERR!   stack: 'Error: EACCES: permission denied, mkdir \'/.npm\'',
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'mkdir',
npm ERR!   path: '/.npm' }
npm ERR! 

As you can see, the npm directory to be used is /.npm whereas the build expects the path to be /var/lib/jenkins/workspace/build-mokka-app/gradle/node/node_modules/npm.

mvysny commented 4 years ago

Hi! Thank you so much for debugging of the issue. In my case the .npm folder is created in $HOME. Could you please check what is value of $HOME in the docker image? My guess is that it's empty, but it's good to have it confirmed first.

straurob commented 4 years ago

Could you please check what is value of $HOME in the docker image? My guess is that it's empty, but it's good to have it confirmed first.

When running echo $HOME in the docker.image command then $HOME points to /.

If i change the args to -u root -v ${HOME}/.m2:/maven/.m2, i.e. the container is started as root, then $HOME points to /root.

Here's a screenshot of the Jenkins workspace. As you can see there are several folders owned by root. I guess that might be a problem.

grafik

mvysny commented 4 years ago

Hi, yeah, it also sounds like a permission/user problem to me. It seems that the files are checked out by the jenkins user, however gradle seem to be running under the root user? :thinking: However that can't be right, since root user would definitely be able to create the /.npm folder... Could it be that the Vaadin plugin launches npm not as root, but as some other user perhaps?

Could you perhaps run gradle with --debug --stacktrace, perhaps we can learn more about why the npm failed?

Regardless, the Vaadin Gradle plugin should definitely dump stderr of the npm subprocess if it crashes, instead of just printing that it exited with non-zero exit code. I'll try to play with this a bit.

straurob commented 4 years ago

After having searched for similiar issues I stumbled across this workaround. This works for me at the moment :slightly_smiling_face:

docker.image(gradleDockerImage).inside("${gradleDockerArgs}") {     
    withEnv([
        /* Override the npm cache directory to avoid: EACCES: permission denied, mkdir '/.npm' */
        'npm_config_cache=npm-cache',
        /* set home to our current directory because other bower
         * nonsense breaks with HOME=/, e.g.:
         * EACCES: permission denied, mkdir '/.config'
         */
        'HOME=.',
        ]) {
            sh 'gradle clean vaadinPrepareNode build -Pvaadin.productionMode'
            sh "mkdir -p ${gradleDependencyPath} && (cd ${gradleDependencyPath}; jar -xf ../libs/*.jar)"
        }       
    }
mvysny commented 4 years ago

Thank you for letting us know and for posting of the workaround. This looks like a permission issue. The plugin 0.14.3.7 and 0.17.x should now correctly dump stderr, closing as fixed.