I am starting to investigate Azure Devops and its pipelines feature for setting up a continuous integration workflow. I have a pipeline that builds a Docker image of my application using the following dockerfile:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build-env
WORKDIR /cicd
# restore (put more volatile, changing projects later in process)
COPY src/WebApp/WebApp.csproj ./src/WebApp/
RUN dotnet restore src/WebApp/WebApp.csproj -s http://mycontainerrepo.acme.com/repository/nuget/
COPY tests/WebApp.Test/WebApp.Test.csproj ./tests/WebApp.Test/
RUN dotnet restore tests/WebApp.Test/WebApp.Test.csproj -s http://mycontainerrepo.acme.com/repository/nuget/
# copy source
COPY . .
# test (if tests fail, no final image, yay)
RUN dotnet test tests/WebApp.Test/WebApp.Test.csproj
# publish
RUN dotnet publish src/WebApp/WebApp.csproj -o /publish
# runtime stage
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS release
COPY --from=build-env /publish /publish
WORKDIR /publish
ENTRYPOINT ["dotnet", "WebApp.dll"]
The call to run dotnet test executes just fine and outputs results to the console, but I don't know of any way to make use of this result in the pipeline. In TeamCity, you could set an environment variable to sort of trick it into outputting the test results (xUnit only, I think...). But not sure if there's a similar trick here...
I saw this post on Github about making a separate test image just for testing but was hoping to avoid that route unless its my only option.
Any other CI/CD Azure Devops gurus out there?
Related
I'm having trouble getting coverlet to run in my docker container. My problems seems similar to this issue, although the problem persists, and there are some differences.
Setup
.NET 6 tests project.
References have Microsoft.NET.Test.Sdk v17.2.0 (latest), and coverlet.collector v3.1.2 (latest)
I'm running the tests in a Dockerfile, like so:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
COPY ["src/MyAPI/", "src/MyAPI/"]
COPY ["tests/MyAPI.Handlers.Tests/", "tests/MyAPI.Handlers.Tests/"]
WORKDIR "/tests/MyAPI.Handlers.Tests"
RUN dotnet restore "MyAPI.Handlers.Tests.csproj" --configfile NuGet.config
FROM build AS publish
WORKDIR /tests/MyAPI.Handlers.Tests
RUN dotnet publish "MyAPI.Handlers.Tests.csproj" -c Release -o /tests/publish --no-restore
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS final
WORKDIR /tests
COPY --from=publish /tests/publish .
ENTRYPOINT ["dotnet", "test", "MyAPI.Handlers.Tests.dll", "--collect:\"XPlat Code Coverage\""]
So i am doing a dotnet publish, and running the tests from there. That should mean that everything is there, that needs to run the tests / coverage.
When i run, i get this error:
Data collection : Unable to find a datacollector with friendly name '"XPlat Code Coverage"'.
What i've confirmed:
Command works outside docker fine (e.g if i do a dotnet publish, then dotnet test with coverage)
I've listed the files in the directory in the container, and confirmed the coverlet DLL's are there
Any suggestions would be great! Thanks in advance :)
I tried by removing \" from argument and it worked.
ENTRYPOINT ["dotnet", "test", "MyAPI.Handlers.Tests.dll", "--collect:XPlat Code Coverage"]
I have a .net solution which has 2 projects, and each project is a microservice (a server). I have a dockerfile which first installs all the dependencies which are used by both projects. Then I publish the solution:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.sln .
COPY Server/*.csproj ./Server/
COPY JobRunner/*.csproj ./JobRunner/
RUN dotnet restore ./MySolution.sln
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "Server.dll"]
When the solution is published, 2 executables are available: Server.dll and JobRunner.dll. However, I can only start only one of them in Dockerfile.
This seems to be wasteful because restoring the solution is a common step for both Server and JobRunner project. In addition this line RUN dotnet publish -c Release -o out produces both an executable for Server and JobRunner. I could write a separate Dockerfile for each project but this seems redundant as 99% of the build steps for each project is identical.
Is there a way to somehow start 2 executables from a single file without using a script (I don't want that both services will be started in a single container)? The closest I've found is the --target option in docker build but it probably won't work because I'd need multiple entrypoints.
In your Dockerfile, change ENTRYPOINT to CMD in the very last line.
Once you do this, you can override the command by just providing an alternate command after the image name in the docker run command:
docker run ... my-image \
dotnet JobRunner.dll
(In principle you can do this without changing the Dockerfile, but the docker run construction is awkward, and there's no particular benefit to using ENTRYPOINT here. If you're using Docker Compose, you can override either entrypoint: or command: on a container-by-container basis.)
I do a multistage build right now. The first stage compiles with credentials for my internal repos and I just keep the binaries as per this example: https://github.com/dotnet/dotnet-docker/blob/master/documentation/scenarios/nuget-credentials.md
But I want to run in CI server and need to provider the CI server with test and coverage reports. It would be most elegant to do this in the build layer but how do I get files out of a docker image during build?
For example:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj .
COPY ./nuget.config .
RUN dotnet restore
# Copy and publish app and libraries
COPY . .
############ Get this files out #####################
# Generate test report. copy this to external directory
RUN dotnet test --logger trx
# Generate coverage report. copy this to external directory
RUN dotCover.sh dotnet --output=myRep.html --reportType=HTML -- test
#######################################################
RUN dotnet publish -c Release -o out --no-restore
FROM mcr.microsoft.com/dotnet/core/runtime:3.1 AS runtime
WORKDIR /app/
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "dotnetapp.dll"]
So I want to be able to run docker build and have it dump a test and coverage report to the current directory where docker build command was run. Is this possible? It would make this seamless for CI because all server must do is run docker build and it get reports
docker build supports an --output flag. I think it requires BuildKit (DOCKER_BUILDKIT=1). Here's one example usage.
https://docs.docker.com/engine/reference/commandline/build/ - then find --output on the page
https://docs.docker.com/engine/reference/commandline/build/#output
I am creating a CI pipeline in Azure for a .NetCore 3.1 application and adding Docker "buildandpush" tasks. i have 2 cases, if i run only .Netcore tasks (restore, build, test, publish) my build success With out any error, if i disable above .NetCore tasks and run only docker(buildAndpublish) Tasks my build success and image pushed into my ACR, but if I enable above .NetCore tasks along with Docker tasks throw an error here.
Can any one tell me the Build definition of .netCore tasks, is i am doing the right things.
ERROR
C:\Program Files\dotnet\sdk\3.1.100\NuGet.targets(123,5): error :
Access to the path 'C:\src\RINWeb\obj\RINMVC.csproj.nuget.dgspec.json'
is denied. [C:\src\RINWeb\RINMVC.csproj]
Build FAILED.
C:\Program Files\dotnet\sdk\3.1.100\NuGet.targets(123,5): error :
Access to the path 'C:\src\RINWeb\obj\RINMVC.csproj.nuget.dgspec.json'
is denied. [C:\src\RINWeb\RINMVC.csproj]
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:01.34
The command 'cmd /S /C dotnet build "RINMVC.csproj" -c Release -o /app/build' returned a non-zero code: 1
[error]The process 'C:\Program Files\Docker\docker.exe' failed with exit code 1
My docker file is:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-nanoserver-1809 AS build
WORKDIR /src
#####COPY ["RINWeb/RINMVC.csproj", "RINWeb/"]
COPY ["RINMVC.csproj", "RINWeb/"]
RUN dotnet restore "RINWeb/RINMVC.csproj"
#####COPY . .
COPY . RINWeb/
WORKDIR "/src/RINWeb"
RUN dotnet build "RINMVC.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "RINMVC.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RINMVC.dll"]
You can use two agent jobs to run your pipeline. On agent job to run the dotnet tasks and the second to run the docker task.
If you are using classic view build pipeline. You can click on the (...) on the Pipeline to add an agent job. Please check below screenshot.
Then run docker tasks in agent job2 and configure agent job2 to depend the successful run of agent job1. Please check below screenshot.
If you are using yaml pipeline. You can define multiple jobs. You can check here for more information.
Update:
Here is an example to build and push to ACR in Microsoft. You donot need to use dotnet tasks to build and publish your project only to check if the build is successful or not, since your dockfile is just repeating the the same dotnet commands. You can only use a docker task to build the dockfile.
Or you can modify your dockerfile to only have the last copy step to copy the published files from output folder of the dotnet publish task(remove the dotnet restore, build, publish steps from dockerfile), for your dotnet tasks already did the retore build and publish tasks.
I am making a Dockerfile for a dotnet core project with some xUnit tests. I want to run the unit tests when the images are being built. However when I docker build I get the following message at the test step:
No test is available in /ciad/tests/bin/Debug/netcoreapp2.1/Tests.dll. Make sure that test discoverer & executors are registered and platform & framework version settings are appropriate and try again.
Here is the Dockerfile:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /ciad
# restore
COPY API/API.csproj ./api/
RUN dotnet restore api/API.csproj
COPY Tests/Tests.csproj ./tests/
RUN dotnet restore tests/Tests.csproj
# copy src
COPY . .
# test
RUN dotnet test tests/Tests.csproj
I'm aware that this is an incomplete dockerfile. I'm just stuck with the tests at the moment. Could anyone see what I'm missing?
Good to mention that tests run fine in VS and "dotnet test" command works too. I can also see that the Tests projects' files are copied to the container.
I run:
docker build -t testing .
I don't know what was wrong but eventually thanks to tips from omajid I changed the tests project's name and folder to tests with small t and all other capital T in Dockerfile to small t and it worked!
I hope this might help someone.
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /ciad
# restore
COPY API/API.csproj ./api/
RUN dotnet restore api/API.csproj
COPY tests/tests.csproj ./tests/
RUN dotnet restore tests/tests.csproj
# copy src
COPY . .
# test
RUN dotnet test tests/Tests.csproj