7

This is how I would do it using Github:

jobs:
  run-tests:

    runs-on: ubuntu-latest
    
    defaults:
      run:
        working-directory: ./MyApp

    steps:
    - uses: actions/checkout@v2
    
    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 5.0.x

    - name: Restore dependencies
      run: dotnet restore
      
    - name: Build project
      run: dotnet build --no-restore
      
    - name: Run tests
      run: dotnet test --no-build

This time on Gitlab my project solution file is in the root directory of the repository. I created a .gitlab-ci.yml file and started with

image: mcr.microsoft.com/dotnet/sdk:5.0

stages:
  - restore-dependencies
  - build-solution
  - run-tests

restore-dependencies:
  stage: restore-dependencies
  script:
    - dotnet restore --packages packages
  artifacts:
    paths:
      - packages

build-solution:
  stage: build-solution
  script:
    - dotnet build --no-restore --source packages --output build
  artifacts:
    paths:
      - build
  dependencies:
    - restore-dependencies

run-tests:
  stage: run-tests
  script:
    - dotnet test --no-build --output build
  dependencies:
    - build-solution

The first job passes but the second one fails because it can't find the restored files from the first job. So my solution has a TestProject1 and the second job is not able to find a resource file in ...\TestProject1\obj\project.assets.json

How can I fix the pipeline configuration?

2 Answers2

4

You are using separate jobs to run each command. Gitlab runs each job in a new container, destroying any context from the previous command except for explicitly specified artifacts. To run sequential commands like you have configured in Github actions, you can just add multiple steps which will run sequentially in the same image, preserving the context between commands.

stages:
 - build-solution

run-tests:
  image: mcr.microsoft.com/dotnet/sdk:5.0
  stage: build-solution
  script:
    - dotnet restore
    - dotnet build --no-restore
    - dotnet test --no-build

Alternatively, you could use artifacts and flags to transfer the output of each command between jobs:

I believe artifacts have to be relative paths to your $CI_PROJECT_DIR (source), and according to the dotnet restore documentation the default write location is in the home directory.

You could try specifying the write location as packages/ with dotnet restore --packages packages (source)

and the read location as packages/ with dotnet build --source packages (source)

Then you would need to specify this artifact like:

artifacts:
  paths:
    - packages

You would need a similar usage of the --output flag to save your build artifact in the build-solution stage.

This is more complicated, but may be desired in some cases.

William Edmisten
  • 693
  • 5
  • 12
  • hey there! thanks for your help. I updated my question with your suggested solution –  Jun 26 '21 at 05:22
  • unfortunately that didn't help ... am I missing something? –  Jun 26 '21 at 05:22
  • @OlafSvenson don't forget to use the artifact in the tests stage `--output build` I think ... – Question3r Jun 26 '21 at 05:52
  • @OlafSvenson sorry if my answer was confusing, you can probably disregard the second part of my answer, after "Alternatively". Your gitlab yaml is defining 3 separate jobs, whereas your github yaml only uses one. This is why artifacts are required to transfer files between jobs. Try simplifying your approach to only define one job. The first yaml section I provided defines a single job "run-tests" which runs 3 commands, just like your github actions yaml does. You should be able to use that and avoid artifacts altogether. – William Edmisten Jun 26 '21 at 15:04
  • 1
    @wedm yeah, thanks for the first approach. But there will be a lot more jobs to handle so I am highly interested in fixing the artifacts so that I can add more conditional jobs :) –  Jun 26 '21 at 16:15
  • that's why I updated my question but that didn't help unfortunately –  Jun 26 '21 at 16:16
  • If `dotnet restore` is writing the `\TestProject1\obj` directory, then it won't be transferred to the build job unless added as an artifact. You could try copying that directory to an artifact and copying it back in the next job before running `dotnet build`. The Gitlab CI example for dotnet seems to run `dotnet restore` in the same job as `dotnet build` so if that's acceptable, you could also try that. Examples: https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml https://github.com/forrestab/dotnet-gitlab-ci/blob/master/.gitlab-ci.yml – William Edmisten Jun 26 '21 at 16:39
  • thanks for your help. The example on Gitlab looks very complex and outdated to me... and the Github sample tries to specify every single project in the solution. That would be bad with 20 different projects in the solution file ... There must be a simpler way ... as I would do it in Github –  Jun 27 '21 at 05:44
  • @wedm I dont think that one should create only one CI Job, as the tasks that should be done actually are related to different parts of a project development process. there are three tasks given: **restore**, **build**, **test** which are clearly three separable things, and so the CI should separate it, too, since e.g. one might always run tests on software but the build should only execute after a feature is ready, not with every commit. Maybe my answer [below](https://stackoverflow.com/a/68215701/10046524) is helpful for you and guides you into the right direction. – SPMSE Jul 02 '21 at 06:58
  • 1
    @SuicideS3ason I definitely agree, the second part of my answer after "Alternatively" hinted at a similar approach, thanks for providing a standalone example. The first approach I provided was simpler and matched the original Github Actions, so I provided it as a starting off point. It appears that the restore command modifies the project directory, even when the --packages flag is provided, so I would suggest omitting the --no-restore flag and following this [solution](https://stackoverflow.com/questions/68132456/how-to-setup-gitlab-ci-job-artifacts-for-a-c-sharp-project/68188539#68188539) – William Edmisten Jul 02 '21 at 12:56
0

Maybe it might me worth a try to define the pipeline as a Directed Acyclic Graph (DAG), so instead of defining dependencies in your step, you could define needs. When a Job is defined with the needs keyword it will only start if all dependent previous jobs succeeded (except they are allowed to fail). The advantage of the needs keyword here would be that you can explicitly configure the step to download the artifacts from the previous jobs

image: mcr.microsoft.com/dotnet/sdk:5.0

stages:
  - restore-dependencies
  - build-solution
  - run-tests

restore-dependencies:
  stage: restore-dependencies
  script:
    - dotnet restore --packages packages
  artifacts:
    paths:
      - packages

build-solution:
  stage: build-solution
  script:
    - dotnet build --no-restore --source packages --output build
  artifacts:
    paths:
      - build
  needs:
    - job: restore-dependencies
      artifacts: true

run-tests:
  stage: run-tests
  script:
    - dotnet test --no-build --output build
  needs:
    - job: build-solution
      artifacts: true
SPMSE
  • 478
  • 3
  • 14