# Linting stage in CI pipeline - which to use and how?

**URL:** https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697
**Category:** General Usage
**Tags:** question, lint, ci, staticlint
**Created:** [May 8, 2022, 7:17am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697 "2022-05-08T07:17:33Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 8, 2022, 7:17am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/1 "2022-05-08T07:17:33Z")

</div>

Hello, I have a CI/CD pipeline in [GitLab](https://docs.gitlab.com/ee/ci/examples/), and I want to run a lintig stage to fail the build on detected bugs. What is the proper way to do this?

Found [Lint.jl](https://github.com/tonyhffong/Lint.jl/) but it’s abandoned (last update 2019)

Found [StaticLint.jl](https://github.com/julia-vscode/StaticLint.jl/) but the usage documentation is lacking - doesn’t say how to run linting for project and analyze results.

Found [JET.jl](https://github.com/aviatesk/JET.jl) vs [Julia in VS Code](https://www.julia-vscode.org/docs/stable/userguide/linter/) but not sure if it’s the right tool and how to integrate that into a build.

Found these posts:

> [@What is the current approach for linting in Juno](https://discourse.julialang.org/t/what-is-the-current-approach-for-linting-in-juno/32312/2):
>
> linter-julia is actually not in Juno’s ecosystem at all – its implementation is pretty old and imho I don’t recommend using it for now. We’re planning to implement our own linter based on CSTParser.jl, but it’s not our top priority and so I can’t provide an estimate. So in conclusion there is no (static-)linter in Juno for now, but with Juno’s interactive code execution feature you can easily find syntactical misses. If you really want a linter, [vscode-julia](https://www.julia-vscode.org/) extension will do that fine.

> [@Tooling for Julia command-line scripts](https://discourse.julialang.org/t/tooling-for-julia-command-line-scripts/73915):
>
> Prompted by [Jeremy Howard’s reply](https://twitter.com/jeremyphoward/status/1477213680970305537) to @viralbshah’s [question about 2022 goals for Julia](https://twitter.com/Viral_B_Shah/status/1477211793688698881), one thing I would like to figure out how to make it easier to write and deploy command-line scripts written in Julia. I think the key things to figure out are: How should such a script be packaged? The obvious answer I can think of is as a regular Julia package, with a bin subdirectory containing the necessary scripts. This pattern is already used by some packages, but there are certain conventions that s…

But neither of them mentions a way to run a command that will give a result of whether build should pass or there are serious errors detected.

---

<div class="post-metadata">

### Author: ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)
#### Post date: [May 8, 2022, 7:57am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/2 "2022-05-08T07:57:51Z")

</div>

I would suggest to use [JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) and [JET.jl](https://github.com/aviatesk/JET.jl).

In the following comment there’s a snippet for JuliaFormatter on GitLab CI (note the workaround for `JULIA_DEPOT_PATH`): [Add option to ignore files matching patterns · Issue #574 · domluna/JuliaFormatter.jl · GitHub](https://github.com/domluna/JuliaFormatter.jl/issues/574#issuecomment-1118461499)

And here is an example of running JET.jl from the command line for a project (running in the project dir.):

```julia
julia --project --eval 'using Pkg; Pkg.activate(); Pkg.add("JET"); Pkg.activate("."); using JET; @show report_package(Pkg.project().name)'

```

The `@show` is there as otherwise the output will be silenced (opposite to running in the REPL).

I am about to add JuliaFormatter and JET job templates and jobs to [IHP Systems / Julia / Julia GitLab CI templates · GitLab](https://gitlab.com/IHPSystems/julia/julia-gitlab-ci-templates)

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 8, 2022, 8:10am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/3 "2022-05-08T08:10:49Z")

</div>

> [@stemann](#):
>
> I would suggest to use [JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) and [JET.jl](https://github.com/aviatesk/JET.jl).

Hi, thanks for the answer!

I already integrated JuliaFormatter, just used it in a _separate_ step.

Tried using JET, but the output from `report_package` is very long long and complex.  
It found “possible errors” which are in an external package.

- How do I mark that package to be ignored?
- How do I generate a summary report of how many warnings/errors did I have?
- How do I stop the build when there are _critical_ errors?

---

<div class="post-metadata">

### Author: ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)
#### Post date: [May 8, 2022, 8:21am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/4 "2022-05-08T08:21:19Z")

</div>

1. Regarding dependencies: I know that dependencies with issues detected by JET.jl is a common concern with using JET.jl: In that case, it might be better run `report_file` on `test/runtests.jl`: Cf. Warning on `analyze_from_definitions` (which is the default for `report_package`) in [Configurations · JET.jl](https://aviatesk.github.io/JET.jl/dev/config/)
2. Not sure.
3. Check the result returned by `report_package`/`report_file` and call `exit(status_code)` with a non-zero `status_code`.

---

<div class="post-metadata">

### Author: ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)
#### Post date: [May 8, 2022, 8:27am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/5 "2022-05-08T08:27:46Z")

</div>

Sounds like setting `target_defined_modules = true` might also help you.

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 8, 2022, 8:30am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/6 "2022-05-08T08:30:22Z")

</div>

> [@stemann](#):
>
> 1. Check the result returned by `report_package` / `report_file` and call `exit(status_code)` with a non-zero `status_code` .

How? Is there a guide to what is returned there? Couldn’t figure out from the documentation.

> [@stemann](#):
>
> Sounds like setting `target_defined_modules = true` might also help you.

Yes, just found it myself too!  
So limiting it to my package indeed removes the external error.

However, now I have the opposite problem 😅  
All the sample errors are already caught during _package precompilation_ stage.  
What error would not be caught by compilation but will be caught by JET.jl?

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [May 8, 2022, 8:39am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/7 "2022-05-08T08:39:32Z")

</div>

You could probably adapt [this gist](https://gist.github.com/pfitzseb/22493b0214276d3b65833232aa94bf11) to your needs.

---

<div class="post-metadata">

### Author: ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)
#### Post date: [May 8, 2022, 9:02am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/8 "2022-05-08T09:02:32Z")

</div>

Regarding checking result retuned by JET: Looks like the number of reports returned (somewhere) within the JET top-level result can be used to judge if errors were found by JET: [JET.jl/print.jl at master · aviatesk/JET.jl · GitHub](https://github.com/aviatesk/JET.jl/blob/master/src/ui/print.jl#L177)

There should be plenty of errors that JET can find, which will not be found by pre-compilation - check the docs.

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 8, 2022, 12:27pm UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/9 "2022-05-08T12:27:22Z")

</div>

> [@pfitzseb](#):
>
> You could probably adapt [this gist](https://gist.github.com/pfitzseb/22493b0214276d3b65833232aa94bf11) to your needs.

Thanks!

I ran it, and getting something like this:

```julia
LanguageServer.Diagnostic(LanguageServer.Range(LanguageServer.Position(2, 0), LanguageServer.Position(2, 26)), 3, missing, "Julia", "The included file can not be found.", missing, missing)

```

1. Is this the format of the log messages?
2. Does it just means the file was loaded incorrectly?

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [May 8, 2022, 8:18pm UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/10 "2022-05-08T20:18:13Z")

</div>

That means that an `include` statement on the third line of your source file couldn’t be resolved, afaict.

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 9, 2022, 6:13am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/11 "2022-05-09T06:13:51Z")

</div>

You are correct, this line in the file has an `include("file.jl")` statement.  
I thought it was a matter of search path, but changing directory, or even _putting the absolute path in include()_ doesn’t work, still gives the same error.  
How would you go about debugging `LanguageServer` errors like this?  
Thanks!

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 13, 2022, 6:08pm UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/12 "2022-05-13T18:08:55Z")

</div>

> [@FireCrumb](#):
>
> > [@](#):
> >
> > I am about to add JuliaFormatter and JET job templates and jobs to [IHP Systems / Julia / Julia GitLab CI templates · GitLab](https://gitlab.com/IHPSystems/julia/julia-gitlab-ci-templates)

Hi @stemann, thanks for that reference!

I used the code from [IHPSystems GitLab CI templates](https://gitlab.com/IHPSystems/julia/julia-gitlab-ci-templates/-/blob/master/templates.gitlab-ci.yaml)

Specifically this:

```julia
.julia.jet_report_package:

...

  println(result)
  errors_found = !isempty(result.res.toplevel_error_reports) || !isempty(result.res.inference_error_reports)
  exit(!errors_found ? 0 : 1)

```

It reports errors in an external package which are not relevant, so I set  
`CI_JULIA_JET_TARGET_DEFINED_MODULES: 'true'`

Then:

```julia
result == "No errors detected"
result.res.toplevel_error_reports == JET.ToplevelErrorReport[]
result.res.inference_error_reports == JET.InferenceErrorReport[...errors...]

```

So it reports “No errors detected”, but then fails because `inference_error_reports` isn’t empty – it contains errors from that other package which I wanted to ignore (and not my package).

What is the proper way to fix it?

---

<div class="post-metadata">

### Author: ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)
#### Post date: [May 13, 2022, 7:21pm UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/13 "2022-05-13T19:21:05Z")

</div>

> [@FireCrumb](#):
>
> It reports errors in an external package which are not relevant

On another thought, I went to investigate the bug and fixed it instead. Now JET.jl report is clear! 🥳

---

<div class="post-metadata">

### Author: ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)
#### Post date: [May 22, 2022, 10:30am UTC](https://discourse.julialang.org/t/linting-stage-in-ci-pipeline-which-to-use-and-how/80697/14 "2022-05-22T10:30:04Z")

</div>

It seems the `get_reports` method should be called (it should take target modules into account), so this should fix it:

```yaml
.julia.jet_report_package:

...

  println(result)
  errors_found = !isempty(JET.get_reports(result))
  exit(!errors_found ? 0 : 1)

```
