I want to build and run coverage test and publish to sonar. Here's the Dockerfile:
FROM node:12.22.12-buster-slim as base
RUN apt update &&\
apt install --yes --no-install-recommends \
python2 \
make \
g++
WORKDIR /code
COPY .npmrc package.json package-lock.json ./
RUN npm install
ARG PUBLIC_URL="/web-frontend/"
FROM base as dev
RUN npm install --also=dev
COPY ./ ./
CMD ["npm", "start"]
FROM base as builder
COPY ./ ./
RUN PUBLIC_URL=${PUBLIC_URL} npm run build
FROM nginx:1.25-alpine3.18 AS dist
RUN apk add --no-cache \
# CVE-2023-43787
'libx11>=1.8.7-r0'
WORKDIR /app
COPY --from=builder /code/build/ ./
COPY st/nginx.conf /etc/nginx/nginx.conf
COPY st/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
and pipeline yaml:
trigger:
- none
pr:
- none
pool:
vmImage: 'ubuntu-latest'
variables:
acr_repository_name: 'webui'
pkg_version: '0.0.1'
sprint_number: '0001'
branch_type: '$(Build.SourceBranchName)'
build_version: '$(pkg_version)-d$(sprint_number).$(Build.BuildId)'
sonar_project_key: 'com.my_domain:$(acr_repository_name)-$(branch_type)'
jobs:
- job: Build
displayName: 'Build'
steps:
- checkout: self
- script: |
echo "Build id: $(Build.BuildId)"
echo "Branch name: $(Build.SourceBranchName)"
echo "Branch type: $(branch_type)"
echo "Build version: $(build_version)"
echo "Souce directory: '$(Build.SourcesDirectory)"
echo "Tag name: "my_domain.azurecr.io/dir/$(acr_repository_name):$(build_version)""
displayName: 'Variables info'
- task: Docker@2
displayName: 'Build dev image'
inputs:
containerRegistry: 'my_domain Container Registry'
repository: 'dir/$(acr_repository_name)'
command: 'build'
Dockerfile: '**/Dockerfile'
target: 'dev'
tags: '$(build_version)'
- task: Docker@2
displayName: 'Push dev image'
inputs:
containerRegistry: 'my_domain Container Registry'
repository: 'dir/$(acr_repository_name)'
command: 'push'
tags: '$(build_version)'
- script: |
docker images
displayName: 'List Docker Images'
- script: |
docker run --rm -v $(Build.SourcesDirectory)/coverage:/code/coverage dir/insightui:$(build_version) npm run test:coverage
displayName: 'Run unit tests'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.SourcesDirectory)/coverage'
artifact: 'coverage'
Output from build step is:
#20 writing image sha256:2aab8942b077ded98d19adc30af6591d0c20c21f930ef4caef3a2fb5158f4abb done
#20 naming to ***/dir/web-ui:0.0.1-d001.001 done
Output from unit test step is:
Script contents:
docker run --rm -v /home/vsts/work/1/s/coverage:/code/coverage /dir/web-ui:0.0.1-d0001.001 npm run test:coverage
========================== Starting Command Output ===========================
/usr/bin/bash --noprofile --norc /home/vsts/work/_temp/4e631df5-e77e-4617-bdd3-8685a8f2a0a8.sh
Unable to find image '/dir/web-ui:0.0.1-d0001.001' locally
docker: Error response from daemon: pull access denied for dir/web-ui, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
See 'docker run --help'.
Output from docker images step is:
REPOSITORY TAG IMAGE ID CREATED SIZE
***/dir/web-ui 0.0.1-d0001.001 2393648ffe25 5 seconds ago 63.9MB
I can't understand what's the issue here. The goal is to build image, do unit test and push to sonarcloud report. I can see some report in sonar for each run, but coverage is empty because there are no unit tests ran locally. Can I even run the npm run test:coverage
against locally built image. Tried to change things plenty of times, but without any luck. Any help is appreciated.
// Answer to @Bright Ran-MSFT
Replaced in Dockerfile From base as builder
to From builder as test
and added these 2 lines:
FROM builder as test
ARG BuildId
LABEL test=$BuildId
RUN npm run test:coverage > coverage/lcov.info
Azure pipelines edit:
- task: Docker@2
displayName: 'Build dev image'
inputs:
containerRegistry: 'my_domain Container Registry'
repository: 'dor/$(acr_repository_name)'
command: 'build'
Dockerfile: '**/Dockerfile'
target: 'dev'
tags: '$(build_version)'
arguments: '--build-arg BuildId=$(Build.BuildId)'
# - script: |
# npm run test:coverage > coverage/lcov.info
# displayName: 'Run tests and generate coverage'
- task: PowerShell@2
displayName: 'Copy test results'
inputs:
pwsh: true
targetType: inline
script: |
$images = docker images
echo "images" $images
$id=docker images --filter "label=test=$(Build.BuildId)" -q | Select-Object -First 1
echo "image id:" $id
docker create --name copytestresult $id
docker cp copytestresult:/testresults ./testresults
docker rm copytestresult
# - task: PublishCodeCoverageResults@1
# displayName: 'Publish code coverage results'
# inputs:
# codeCoverageTool: 'lcov'
# summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage/lcov.info'
- script: |
echo ">> Running SonarQube analysis"
docker run --rm --volume $(System.DefaultWorkingDirectory):/code --workdir /code --env SONAR_SCANNER_OPTS=-Xmx512m sonarsource/sonar-scanner-cli:4.8 \
sonar-scanner \
-Dsonar.host.url=https://global-sonar.my-domain.com \
-Dsonar.projectKey=$(sonar_project_key) \
-Dsonar.projectVersion=$(build_version) \
-Dsonar.sources=src
echo ">> Waiting for SonarQube analysis to complete"
displayName: 'Run SonarQube analysis'
continueOnError: true
Adding package.json scripts block also:
"scripts": {
"start": "npm run lint && react-scripts start ",
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
"build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
"test": "jest",
"test:coverage": "jest --collectCoverage --coverageReporters=lcov",
"coverage": "jest --collectCoverage",
"eject": "react-scripts eject",
"build": "react-scripts build",
"lint": "eslint src/**/*.js src/**/*.jsx"
In your pipeline, the step 'Run unit tests
' just starts the container in a separate session might get cleaned when this step is completed. The subsequent steps (include PublishPipelineArtifact@1
) will be still running on the agent machine instead of in the container started by above steps.
- script: |
docker run --rm -v $(Build.SourcesDirectory)/coverage:/code/coverage dir/insightui:$(build_version) npm run test:coverage
displayName: 'Run unit tests'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.SourcesDirectory)/coverage'
artifact: 'coverage'
For your case, I recommend you configure the Dockerfile to execute both build and test process when build the Docker image, and generate the report file of test result. Then copy the generated report file to outside of the built Docker image.
To publish the code coverage results, you can use the PublishTestResults@2
or PublishCodeCoverageResults@2
task. If you want to publish the test result to Sonar, you need to use tasks provided by the "SonarCloud" or "SonarQube" extension.
Dockerfile
.FROM node:12.22.12-buster-slim as base
. . .
FROM base as dev
. . .
FROM dev as builder
. . .
FROM builder as test
ARG BuildId
LABEL test=$BuildId
// Commands to run test and generate the test result to a specified path.
FROM nginx:1.25-alpine3.18 AS dist
. . .
variables:
DOCKER_BUILDKIT: 0
. . .
jobs:
- job: Build
displayName: 'Build'
steps:
. . .
- task: Docker@2
displayName: 'Build dev image'
inputs:
containerRegistry: 'my_domain Container Registry'
repository: 'dir/$(acr_repository_name)'
command: 'build'
Dockerfile: '**/Dockerfile'
target: 'dev'
tags: '$(build_version)'
arguments: '--build-arg BuildId=$(Build.BuildId)'
. . .
- task: PowerShell@2
displayName: 'Copy test results'
inputs:
pwsh: true
targetType: inline
script: |
$images = docker images
echo "images" $images
$id=docker images --filter "label=test=$(Build.BuildId)" -q | Select-Object -First 1
echo "image id:" $id
docker create --name copytestresult $id
docker cp copytestresult:/testresults ./testresults
docker rm copytestresult
- task: PublishTestResults@2
displayName: 'Pusblish test results'
. . .
EDIT:
For the error "unknown flag: --build-arg BuildId", try to check the whitespaces in the following lines. Ensure they are using the normal whitespace of and not containing other types of whitespaces:
Dockerfile
.. . .
FROM builder as test
ARG BuildId
LABEL test=$BuildId
. . .
Docker@2
task in pipeline.arguments: '--build-arg BuildId=$(Build.BuildId)'
You can try to delete and re-enter the whitespaces in these lines.