Gitlab has functionality to generade badges about build status and coverage percentage.
Is it possible to create custom badge to display Pylint results?
Or just display this results in README.md?
I already have CI job for Pylint
I have written a python badge generation package that produces badges very visually similar to the main badge services. It is highly flexible, you can import and use in your python code, or run from the command line.
I use this in GitLab CI to display pylint and coverage scores.
There are other ways to do this using shields.io (see other answer from kubouch), but this approach can be used in situations where you may not have external internet access, such as in a corporate / enterprise setting where firewalls or proxies are blocking internet access.
GitLab CI Setup
1. Generate the badge
My CI pipeline has a step that runs pylint, and I used sed to extract the score from the output text. I then use anybadge (details below) to generate a pylint score badge, and save it as public/pylint.svg.
pylint:
stage: test
script:
- pylint --rcfile=.pylintrc --output-format=text <LIST-OF-FILES-TO-RUN-PYLINT-AGAINST> | tee pylint.txt
- score=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' pylint.txt)
- echo "Pylint score was $score"
- anybadge --value=$score --file=public/pylint.svg pylint
If pylint generates a non-zero rc then GitLab will see that as a command error and the job will fail, meaning no badge is generated, and missing image will show where the badge is used.
NOTE: pylint WILL OFTEN generate non-zero return codes since it uses the exit code to communicate the status of the lint check. I suggest using something like pylint-exit to handle pylint return codes in CI pipelines.
2. Register badge as pipeline artifact
I register the generated badge file as an artifact in the CI job by including this in the .gitlab-ci.yml:
pylint:
...
- echo "Pylint score was $score"
- anybadge --value=$score --file=public/pylint.svg pylint
artifacts:
paths:
- public/pylint.svg
3. Publish badge to GitLab Pages
I include a pages publish step, which deploys everything in the public directory to GitLab pages:
pages:
stage: deploy
artifacts:
paths:
- public
only:
- master
4. Include badge in README.md
When the master pipeline runs for the project, the pylint.svg file is published to GitLab Pages, and I can then reference the image from my project README.md so that the latest pylint badge is displayed.
If you are using https://gitlab.com for your project then the URL for the svg artifact will usually be something like this (replace NAMESPACE with your username, or group name if your project is under a group - more details here):
https://NAMESPACE.gitlab.io/pyling.svg
In your README.md you can include an image with:
![pylint](https://NAMESPACE.gitlab.io/pyling.svg)
If you want to make the image into a link you can use:
[![pylint](https://NAMESPACE.gitlab.io/pyling.svg)](LINKTARGET)
Let me know if you need more information on any of the setup.
Anybadge Python Package
Here's some more info on the anybadge Python package:
You can set the badge label and value, and you can set the color based on thresholds. There are pre-built settings for pylint, coverage, and pipeline success, but you can create any badge you like.
Here is a link to the github project with more detailed documentation: https://github.com/jongracecox/anybadge
Install with pip install anybadge
Example python code:
import anybadge
# Define thresholds: <2=red, <4=orange <8=yellow <10=green
thresholds = {2: 'red',
4: 'orange',
6: 'yellow',
10: 'green'}
badge = anybadge.Badge('pylint', 2.22, thresholds=thresholds)
badge.write_badge('pylint.svg')
Example command line use:
anybadge --label pylint --value 2.22 --file pylint.svg 2=red 4=orange 8=yellow 10=green
Update 2019
Using GitLab Pages is no longer required
It is now possible to directly access to the latest articfact, which simplify the workaround.
Use a dedicated pylint artifact instead of public, and remove the unnecessary deploy step (or edit it if already used):
pylint:
stage: test
before_script:
- pip install pylint pylint-exit anybadge
script:
- mkdir ./pylint
- pylint --output-format=text . | tee ./pylint/pylint.log || pylint-exit $?
- PYLINT_SCORE=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' ./pylint/pylint.log)
- anybadge --label=Pylint --file=pylint/pylint.svg --value=$PYLINT_SCORE 2=red 4=orange 8=yellow 10=green
- echo "Pylint score is $PYLINT_SCORE"
artifacts:
paths:
- ./pylint/
Note that here I copy the Pylint log file in the folder artifact, in this way it will be accessible without looking at the pipeline logs.
The badge image will then be available at https://gitlab.example.com/john-doe/foo/-/jobs/artifacts/master/raw/pylint/pylint.svg?job=pylint, and the Pylint log at https://gitlab.example.com/john-doe/foo/-/jobs/artifacts/master/raw/pylint/pylint.log?job=pylint.
2. You can use GitLab's builtin badges instead of images in README
GitLab can now include badges in a projet or group, that will be displayed in the project header.
Got to Settings / General / Badges, then create a new badge by setting its link and image link, as described above:
If you don't want to use the README, gitlab pages, anybadge or dropbox you can use https://img.shields.io/badge/lint%20score-$score-blue.svg to 'create' a badge (which is just an URL) and change the badge image URL via the gitlab API.
Details and the lint stage of my .gitlab-ci.yml
I developed a workaround solution to real-time per-job badges.
It is not Pylint specific but the approach is general and you can easily modify it into what you need.
This example repo (branch badges) creates a custom badge for each CI job. There is also a complete walkthrough so I won't copy-paste it here.
The core idea is (assuming you're now inside a running CI job):
Create a badge (e.g. fetch it from shields.io into a file).
Upload the badge file to some real-time storage from where it can be linked (e.g. Dropbox).
Dropbox supports calling its API via HTTP requests (see this).
Thus, all the above can be done using e.g. curl or Python requests - basic tools.
You just need to pass the Dropbox access token as secret variable and save the file under the same name to overwrite the old badge.
Then, you can then directly link the Dropbox badge wherever you need.
There are some tricks to it so be sure to check my example repo if you want to use it.
For me it works quite well and seems to be fast.
The advantage of this method is that you don't have to mess with GitLab Pages.
Instead of publishing on Pages you put it to Dropbox.
That is a simple file transfer called by HTTP request.
No more to that.
Tutorial
Add the below file - .gitlab-ci.yml to your GitLab repository:
pylint:
stage: test
image: python:3.7-slim
before_script:
- mkdir -p public/badges public/lint
- echo undefined > public/badges/$CI_JOB_NAME.score
- pip install pylint-gitlab
script:
- pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**") | tee /tmp/pylint.txt
- sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
- pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > codeclimate.json
- pylint --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > public/lint/index.html
after_script:
- anybadge --overwrite --label $CI_JOB_NAME --value=$(cat public/badges/$CI_JOB_NAME.score) --file=public/badges/$CI_JOB_NAME.svg 4=red 6=orange 8=yellow 10=green
- |
echo "Your score is: $(cat public/badges/$CI_JOB_NAME.score)"
artifacts:
paths:
- public
reports:
codequality: codeclimate.json
when: always
pages:
stage: deploy
image: alpine:latest
script:
- echo
artifacts:
paths:
- public
only:
refs:
- master
Substitute the below variables accordingly depending upon your project structure. For example, if your repository is located at company_intern/john/robot_code and you added the .gitlab-ci.yml file to your main branch, then:
$GROUP = company_intern
$SUBGROUP = john
$PROJECT_NAME = robot_code
$BRANCH = main
# Substitute the above variables in the badge
[![pylint](https://gitlab.com/$GROUP/$SUBGROUP/$PROJECT_NAME/-/jobs/artifacts/$BRANCH/raw/public/badges/pylint.svg?job=pylint)](https://gitlab.com/$GROUP/$SUBGROUP/$PROJECT_NAME/-/jobs/artifacts/$BRANCH/browse/public/lint?job=pylint)
Your badge has now been integrated! To verify the lining process locally before committing it directly:
# To lint all the python files in the directory:
pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**")
# To lint a specific file, say foo.py:
pylint --exit-zero --output-format=text foo.py
References:
pylint-gitlab ยท PyPI
If you use flake8 to run pylint, then an easy way to generate a badge is to use genbadge. This simple commandline tool provides capabilities to generate badges for tests, coverage, and flake8.
Simply run
genbadge flake8 -i flake8stats.txt
to generate the badge from a flake8 statistics file, such as this one: . You can then use the badge to provide a quick link to the HTML report generated by flake8-html. See documentation for details (I'm the author by the way !).
Related
I have an OpenAPI yaml file that I have built in the Swagger Editor tool. I would now like to build a static site that looks exactly the same as that.
I would like to incorporate this into a Gitlab CI/CD pipeline so that any changes are automatically updated.
Currently, I am using the redoc-cli and I really don't like the way it looks. Also, there is no "Try it out" functionality.
I have been searching all day for the necessary components to build that static site, but there do not seem to be any concrete answers.
I am currently build my GitLab Pages site like this:
pages:
stage: deploy
script:
- mkdir ~/.npm-global
- npm config set prefix '~/.npm-global'
- echo "export PATH=~/.npm-global/bin:$PATH" > ~/.profile
- source ~/.profile
- npm install -g redoc-cli --verbose
- redoc-cli bundle -o public/index.html swagger.yaml
artifacts:
paths:
- public
only:
- master
Help, please. I have problems when using the CI tool.
Here's my .gitlab-ci.yaml
stages:
- test
test:
stage: test
environment:
name: test
url: https://word.mymusise.com/env_test.txt
script: echo "Running tests TEST=$TEST"
And I've define the test environment in EnvDocker > Pipelines > Environments
But it didn't export the environment from https://word.mymusise.com/env_test.txt in the CI job.
Running with gitlab-runner 11.4.2 (cf91d5e1)
on gitlab-ci runner a0e18516
Using Docker executor with image ubuntu:16.04 ...
Pulling docker image ubuntu:16.04 ...
Using docker image sha256:2a697363a8709093834e852b26bedb1d85b316c613120720fea9524f0e98e4a2 for ubuntu:16.04 ...
Running on runner-a0e18516-project-123-concurrent-0 via gitlab...
Fetching changes...
HEAD is now at d12c05b Update .gitlab-ci.yml
From https://gitlab.kingdomai.com/mymusise/envdocker
d12c05b..1a3954f master -> origin/master
Checking out 1a3954f8 as master...
Skipping Git submodules setup
$ echo "Running tests TEST=$TEST"
Running tests TEST=
Job succeeded
I define export TEST="test" in https://word.mymusise.com/env_test.txt, but it seems not working.
What should I do... Orz
Gitlab version: 11.4.0-ee
You want to run commands that are inside the text file that is accessible via http protocol.
With curl you can download the file and print it on curl's standard output. With command substitution $() you can grab the standard output. Then you can execute the commands itself (very unsafe, there might be multiple escaping issues).
script:
- $(curl "$url")
- echo "Running tests TEST=$TEST"
A safer alternative would be to just download the file and execute/source it.
script:
- curl "$url" > ./run_this.sh
# don't forget to add executable right to the file ;)
- chmod +x ./run_this.sh
- source ./run_this.sh
# pick out the trash
- rm ./run_this.sh
# rest of your script.
- echo "Running tests TEST=$TEST"
Downloading a shell script and executing it is a popular way of automating tasks, usually with curl url | bash. It is not supported "natively" by gitlab and I don't think it should be.
I want to deploy a static page using GitLab repos with plain HTML/CSS (actually SCSS). As far as I learnt, a static page needs at least .gitlab-ci.yml and /public folder. The file .gitlab-ci.yml will have a minimum requirement like this: (an example from official doc)
pages:
stage: deploy
script:
- mkdir .public
- cp -r * .public
- mv .public public
artifacts:
paths:
- public
only:
- master
And my question is lying in the script line.
(I assume the script below will create a hidden folder name .public and copy all the file in it then move it from .public to public folder. Please correct me if I'm wrong.)
script:
- mkdir .public
- cp -r * .public
- mv .public public
To me, it's similar to shell-script of Linux. It's also confirmed in GitLab doc that it's run by the Runner. But the problem is, how do I know how many shell-scripts are installed in GitLab? And is it possible to make one?
I would like to make 2 folders: src and public. The GitLab CI will run the script and compile SCSS from src then move it to public.
I'm using gitlab.com by the way.
So a few things to consider. Each job in gitlab is run in a container. Generally you specify which one you want to use. Pages is a special case though so you don't have to care about the image for the container.
The pages job will populate your public folder. But you can alter the gitlab-ci.yml file and add steps.
This would build an app using node:
build_stuff:
stage: build
image: node:11
before_script:
- npm install
script:
- npm run build
artifacts:
paths:
- build
pages:
stage: deploy
script:
- mkdir .public
- cp -r build/ .public
- mv .public public
artifacts:
paths:
- public
only:
- master
Formatting is off
Things to note. The first step is running the build steps to generate all the assets for your output folder. It is then storing anything declared in the artifacts block, in this case the build folder, and passing it on to the next job. Adjust this step accordingly to what you need to build your app.
The only thing I altered in the second step is that you copy the contents of the build folder instead of the entire repo into the .public folder. Adjust this to your needs as well.
As for shell scripts, there are none present except for the ones you bring to the repository. The default runner supports Bash so you can execute bash commands just as you would in your terminal.
If you create the file foo.sh in your repo and do bash foo.sh it will execute the script, if it's executable. Remember to chmod it before pushing it.
There are no "shell-scripts installed in Gitlab". Gitlab supports several shells and the script part in your example are just pure bash commands. Since you are most probably using the default docker runner you can execute bash commands from the script part, run scripts in other languages that are in your repo, install packages on the docker container and even prepare and run your own docker images.
My goal is to show badges (ex : ) based on pipeline results.
I have a private gitlab ce omnibus instance with the following .gitlab-ci.yml :
image: python:3.6
stages:
- lint
- test
before_script:
- python -V
- pip install pipenv
- pipenv install --dev
lint:
stage: lint
script:
- pipenv run pylint --output-format=text --load-plugins pylint_django project/ | tee pylint.txt
- score=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' pylint.txt)
- echo "Pylint score was $score"
- ls
- pwd
- pipenv run anybadge --value=$score --file=pylint.svg pylint
artifacts:
paths:
- pylint.svg
test:
stage: test
script:
- pipenv run python manage.py test
So I thought that I would store the image in the artifacts of the lint job and display it via the badge feature.
But I encounter the following issue : when I browse https://example.com/[group]/[project]/-/jobs/[ID]/artifacts/file/pylint.svg, instead of seeing the badge I have the following message :
The image could not be displayed because it is stored as a job artifact. You can download it instead.
And anyways, I feel like this is the wrong way, because even if I could get the image, there don't seems to be a way to get the image from the last job since gitlab URL for badges images only supports %{project_path}, %{project_id}, %{default_branch}, %{commit_sha}
So how one would add badge to a gitlab project based on a svg generated from results in a gitlab pipeline ?
My guess is that I could push to a .badge folder but that doesn't sound like a clean solution.
You can indeed get the artifact(s) for the latest job (see documentation here), but the trick is that you need to use a slightly different URL:
https://example.com/[group]/[project]/-/jobs/artifacts/[ref]/raw/pylint.svg?job=lint
where [ref] is the reference to your branch/commit/tag.
Speaking of badge placeholders available in Gitlab, you can potentially put %{default_branch} or %{commit_sha} into [ref]. This won't allow you to get the correct badge for every branch, but at least your default branch will get one.
Please also note that ?job=lint query parameter is required, without it the URL won't work.
I use gitlab-ci to test, compile and deploy a small golang application but the problem is that the stages take longer than necessary because they have to fetch all of the dependencies every time.
How can I keep the golang dependencies between two stages (test and build)?
This is part of my current gitlab-ci config:
test:
stage: test
script:
# get dependencies
- go get github.com/foobar/...
- go get github.com/foobar2/...
# ...
- go tool vet -composites=false -shadow=true *.go
- go test -race $(go list ./... | grep -v /vendor/)
compile:
stage: build
script:
# getting the same dependencies again
- go get github.com/foobar/...
- go get github.com/foobar2/...
# ...
- go build -race -ldflags "-extldflags '-static'" -o foobar
artifacts:
paths:
- foobar
As mentioned by Yan Foto, you can only use paths that are within the project workspace. But you can move the $GOPATH to be inside your project, as suggested by extrawurst blog.
test:
image: golang:1.11
cache:
paths:
- .cache
script:
- mkdir -p .cache
- export GOPATH="$CI_PROJECT_DIR/.cache"
- make test
This is a pretty tricky task, as GitLab does not allow caching outside the project directory. A quick and dirty task would be to copy the contents of $GOPATH under some directory inside the project (say _GO), cache it and copy it upon each stage start back to $GOPATH:
after_script:
- cp -R $GOPATH ./_GO || :
before_script:
- cp -R _GO $GOPATH
cache:
untracked: true
key: "$CI_BUILD_REF_NAME"
paths:
- _GO/
WARNING: This is just a (rather ugly) workaround and I haven't tested it myself. It should only exhibit a possible solution.