I’m writing a script in YAML for building ASP.NET Core 2.2 project using GitLab Continuous Integration. In all YAML samples I could find (and there are not many) for building .NET Core based applications using GitLab CI I could see something like this:
before_script: - 'dotnet restore'
before_script is running a dependency restore before every job. It makes sense because if you use free GitLab runners (like I do) every job is executed on a different machine. There is no possibility to preserve state from previous jobs (with exception on cache and artifacts, but I’ll get to that later). What that means is that on the next job, all previously restored packages will be gone, and they need to be restored again. And on the next job once again. And again on every job in the pipeline which needs the packages. I noticed a redundancy there. A redundancy that takes precious time, because a huge project with a lot of third-party packages takes a while for a full restore.
Using job artifacts
I found a way to preserve those packages and then pass them to the next job via GitLab artifacts:
restore: stage: restore script: - 'dotnet restore --packages .nuget/' artifacts: paths: - 'src/**/obj/*' - '.nuget/'
Let’s break it down. With
dotnet restore --packages .nuget/ I explicitly specify a custom directory for packages to be restored. Then I specify two paths which GitLab CI will be interested in when creating a job artifacts.
dotnet restore creates a few files with metadata about packages inside a
obj/ directory, so these will be needed as well. I include them in
src/**/obj/*. Finally, I include the
.nuget/ directory which after
dotnet restore should contain all restored dependencies.
Note: A dependency restore saves the path where the packages will be kept inside
<PROJECT_NAME>/obj/project.assets.json file. After that, there is no need for explicitly specifying where the restored packages are e.g. when building the project.
Eventually, in the next job I use previously created job artifacts by specifying a job dependecy. In that way, GitLab CI knows that it should download job artifacts from the dependant job.
build: stage: build script: - 'dotnet build --no-restore' dependencies: - restore
Whole YAML script:
image: microsoft/dotnet:2.2-sdk variables: SOURCE_CODE_DIRECTORY: 'src' BINARIES_DIRECTORY: 'bin' OBJECTS_DIRECTORY: 'obj' NUGET_PACKAGES_DIRECTORY: '.nuget' stages: - restore - build restore: stage: restore script: - 'dotnet restore --packages="$ NUGET_PACKAGES_DIRECTORY"' artifacts: paths: - '$ SOURCE_CODE_DIRECTORY/**/$ OBJECTS_DIRECTORY/*' - '$ NUGET_PACKAGES_DIRECTORY/' build: stage: build script: - 'dotnet build --no-restore' dependencies: - restore
Please tell me what you think, any weaknesses of my approach, code smells, or maybe a better solution. All kind of constructive feedback appreciated.