feat(conventional_commits): Added conventional commit job
Migrated conventional commits from:
url: https://gitlab.com/nofusscomputing/infrastructure/ansible-roles
commit: 037774e1e44f8e1e065718f805688b8b2f64735f
updated logic so that it works on it's home repo and remote repo including private repositories.
Changes to be committed:
new file: conventional_commits/.gitlab-ci.yml
new file: conventional_commits/README.md
new file: conventional_commits/requirements.txt
new file: conventional_commits/scripts/commit.py
new file: conventional_commits/scripts/cz_junit.sh
issue #1
This commit is contained in:
73
conventional_commits/.gitlab-ci.yml
Normal file
73
conventional_commits/.gitlab-ci.yml
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
.conventional_commit:
|
||||
variables:
|
||||
DEFAULT_ROOT_DIR: './gitlab-ci'
|
||||
image: python:3.6-slim
|
||||
stage: validation
|
||||
before_script:
|
||||
- mkdir -p "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/$CI_JOB_NAME"
|
||||
- mkdir -p "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/tests"
|
||||
- if [ "0$MR_ACCESS_TOKEN" == "0" ]; then MR_ACCESS_TOKEN=$CI_JOB_TOKEN; fi
|
||||
- echo "[DEBUG] MR_ACCESS_TOKEN[$MR_ACCESS_TOKEN]"
|
||||
- if [ "0$JOB_ROOT_DIR" == "0" ]; then ROOT_DIR=$DEFAULT_ROOT_DIR; else ROOT_DIR=$JOB_ROOT_DIR ; fi
|
||||
- echo "[DEBUG] ROOT_DIR[$ROOT_DIR]"
|
||||
- if [ "0$MY_PROJECT_ID" == "0" ]; then PROJECT_ID=$CI_PROJECT_ID; else PROJECT_ID=$MY_PROJECT_ID ; fi
|
||||
- echo "[DEBUG] PROJECT_ID[$PROJECT_ID]"
|
||||
- export PYTHON_VERSION=`python -c 'import sys; version=sys.version_info[:3]; print("{0}.{1}.{2}".format(*version))'`
|
||||
- apt update
|
||||
- apt install --no-install-recommends -y git
|
||||
- python3 -m venv env
|
||||
- . env/bin/activate
|
||||
- pip install --upgrade pip
|
||||
- pip install -r $ROOT_DIR/conventional_commits/requirements.txt
|
||||
- echo "[DEBUG] CI_PROJECT_ID[$CI_PROJECT_ID]"
|
||||
- echo "[DEBUG] CI_COMMIT_BRANCH[$CI_COMMIT_BRANCH]"
|
||||
- $ROOT_DIR/conventional_commits/scripts/commit.py --token "$MR_ACCESS_TOKEN" --project $PROJECT_ID --branch $CI_COMMIT_BRANCH --target-branch
|
||||
- target_branch=$($ROOT_DIR/conventional_commits/scripts/commit.py --token "$MR_ACCESS_TOKEN" --project $PROJECT_ID --branch $CI_COMMIT_BRANCH --target-branch)
|
||||
|
||||
- echo "[DEBUG] Target Branch[$target_branch]"
|
||||
- git clone --depth 150 -b $target_branch $CI_REPOSITORY_URL check
|
||||
- cd check
|
||||
- git remote rm origin
|
||||
- git remote add origin $CI_REPOSITORY_URL
|
||||
- git fetch --all
|
||||
- git checkout --track origin/$CI_COMMIT_BRANCH
|
||||
- git submodule update --init
|
||||
- if [ -d "gitlab-ci" ]; then ls -la gitlab-ci; fi
|
||||
- first_sha1=$(git log $target_branch..$CI_COMMIT_BRANCH --format=format:%H | tail -1)
|
||||
- echo "[DEBUG] First Commit SHA[$first_sha1]"
|
||||
- echo "[DEBUG] artifacts directory [$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/$CI_JOB_NAME]"
|
||||
after_script:
|
||||
- ls -lR "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE"
|
||||
- cd ..
|
||||
- rm -Rf check
|
||||
artifacts:
|
||||
expire_in: 3 days
|
||||
when: always
|
||||
paths:
|
||||
- "$CI_PROJECT_DIR/artifacts/*"
|
||||
reports:
|
||||
junit:
|
||||
- "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/tests/*.junit.xml"
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||
when: never
|
||||
- if: '$CI_COMMIT_BRANCH'
|
||||
when: always
|
||||
- when: never
|
||||
|
||||
|
||||
MR Title:
|
||||
extends:
|
||||
- .conventional_commit
|
||||
script:
|
||||
- cz_exit=0 && cz check --message "$($ROOT_DIR/conventional_commits/scripts/commit.py --token "$MR_ACCESS_TOKEN" --project $PROJECT_ID --title --branch $CI_COMMIT_BRANCH)" > "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/$CI_JOB_NAME/cz_output.log" 2>&1 || cz_exit=$?
|
||||
- . $ROOT_DIR/conventional_commits/scripts/cz_junit.sh > "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/tests/$CI_JOB_NAME-cz.junit.xml"
|
||||
|
||||
|
||||
Commit Messages:
|
||||
extends:
|
||||
- .conventional_commit
|
||||
script:
|
||||
- cz_exit=0 && cz check --rev-range $first_sha1..HEAD > "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/$CI_JOB_NAME/cz_output.log" 2>&1 || cz_exit=$?
|
||||
- . $ROOT_DIR/conventional_commits/scripts/cz_junit.sh > "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/tests/$CI_JOB_NAME-cz.junit.xml"
|
||||
94
conventional_commits/README.md
Normal file
94
conventional_commits/README.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Conventional Commits User Manual
|
||||
Commitizen is used to validate the format of commit messages. we use [Conventional Commit Messages](https://www.conventionalcommits.org/en/v1.0.0/) format for our validation jobs.
|
||||
|
||||
This repository may have two CI jobs to do with commitizen:
|
||||
- **MR Title** *Checks the Merge Request Title*
|
||||
- **Commit Messages** *Checks all commit messages*
|
||||
|
||||
These CI Jobs output a test report that can be viewed inside of the merge request and contain the error(s), if any.
|
||||
|
||||
To fix an error please refer to the titled sections below.
|
||||
|
||||
## MR Title
|
||||
Ensure that the merge request title is in the [conventional message](https://www.conventionalcommits.org/en/v1.0.0/) format. NOTE: the title is case sensitive.
|
||||
|
||||
|
||||
## Commit Messages
|
||||
All commit messages that form part of your merge request must be in [conventional message](https://www.conventionalcommits.org/en/v1.0.0/) format.
|
||||
|
||||
To fix them go back and edit your commit messages.
|
||||
|
||||
|
||||
### fixing commit messages (suggestion)
|
||||
|
||||
If only the last commit is the commit with an error just use `git commit --amend` and edit your commit message to be in the correct format and save. now push your changes.
|
||||
|
||||
|
||||
You will require the following information if the commit message with the error is further down the commit tree:
|
||||
- Commit message SHA1 of your first commit message to the branch `{original_commit}`
|
||||
- Commit message SHA1 prior to your first commit `{source_commit}`
|
||||
|
||||
Run these commands once you have the information above.
|
||||
``` bash
|
||||
git format-patch {original_commit}..HEAD -o diff-patches
|
||||
|
||||
git reset {source_commit} --hard
|
||||
```
|
||||
|
||||
Now, navigate to the `diff-patches` folder, open up the offending patch (commit) and edit the `subject` or message body as appropriate and save. Once all the edits have been done, re-apply the patches to your tree with:
|
||||
|
||||
``` bash
|
||||
git am diff-patches/*.patch
|
||||
```
|
||||
Now push your changes upstream.
|
||||
|
||||
| :notebook_with_decorative_cover: Note |
|
||||
|:-----:|
|
||||
| *As you have changed the commit SHA1(s), when you next push your changes upstream, you must force push. `git push --force`* |
|
||||
|
||||
| :octagonal_sign: **WARNING** |
|
||||
|:-----:|
|
||||
| *Ensure that all of your commits were exported prior to reseting the branch and when re-applying, that all of your commits were applied correctly* |
|
||||
|
||||
|
||||
# Conventional Commits Admin Manual Manual
|
||||
This job checks commit messages on a branch and the merge request title for validity against the [conventional commit format](https://www.conventionalcommits.org/en/v1.0.0/)
|
||||
|
||||
This job provides the following badge:
|
||||
|
||||
- None
|
||||
|
||||
## Dependencies
|
||||
|
||||
- None
|
||||
|
||||
## your .gitlab-ci.yml changes
|
||||
To use this job add the following to your `.gitlab-ci.yml` file
|
||||
|
||||
``` yaml
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
MY_PROJECT_ID: "{yourproject id number}"
|
||||
|
||||
stages:
|
||||
- validation
|
||||
|
||||
include:
|
||||
- remote: https://gitlab.com/nofusscomputing/projects/gitlab-ci/-/raw/development/conventional_commits/.gitlab-ci.yml
|
||||
```
|
||||
|
||||
## CI/CD Variables required
|
||||
|
||||
| var name | Description |
|
||||
|:----:|:----|
|
||||
| MR_ACCESS_TOKEN | *only required if you are accessing a private repository.* <br>This token is a user access token that as a minimum requires read-only access to the api to fetch the projects merg requests. |
|
||||
|
||||
|
||||
## Job Workflow
|
||||
|
||||
|
||||
## Artifacts
|
||||
|
||||
|
||||
## License
|
||||
To view the license for this folder and any sub-folders, refer [here](https://gitlab.com/nofusscomputing/projects/gitlab-ci)
|
||||
3
conventional_commits/requirements.txt
Normal file
3
conventional_commits/requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
python-gitlab
|
||||
requests
|
||||
commitizen
|
||||
100
conventional_commits/scripts/commit.py
Executable file
100
conventional_commits/scripts/commit.py
Executable file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
|
||||
#import gitlab
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
import json
|
||||
import requests
|
||||
|
||||
get_first_commit = False
|
||||
get_mr_title = False
|
||||
get_target_branch = False
|
||||
project_id = ''
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:],"hic:t:ti:p:b:o",["commit","token=", "title", "project=", "branch=", "target-branch"])
|
||||
|
||||
except getopt.GetoptError:
|
||||
print('test.py [-c | --commit] [-t | --token {token}]')
|
||||
sys.exit(2)
|
||||
|
||||
for opt, arg in opts:
|
||||
|
||||
#print('[DEBUG] {0} {1}'.format(opt, arg))
|
||||
if opt == '-h':
|
||||
print('[commit.py] -i <inputfile> -o <outputfile>')
|
||||
sys.exit()
|
||||
elif opt in ("-c", "--commit"):
|
||||
get_first_commit = True
|
||||
elif opt in ("-t", "--token"):
|
||||
ci_job_token = arg
|
||||
elif opt in ("-ti", "--title"):
|
||||
get_mr_title = True
|
||||
elif opt in ("-p", "--project"):
|
||||
project_id = str(arg)
|
||||
elif opt in ("-b", "--branch"):
|
||||
git_branch = arg
|
||||
elif opt in ("-o", "--target-branch"):
|
||||
get_target_branch = True
|
||||
|
||||
# private token or personal token authentication
|
||||
#gl = gitlab.Gitlab('https://gitlab.com', private_token=ci_job_token)
|
||||
|
||||
|
||||
url = 'https://gitlab.com/api/v4/projects/' + project_id + '/merge_requests'
|
||||
headers = {'PRIVATE-TOKEN': ci_job_token}
|
||||
|
||||
try:
|
||||
if os.environ['CI_JOB_TOKEN'] == ci_job_token:
|
||||
|
||||
headers = {'JOB_TOKEN': os.environ['CI_JOB_TOKEN']}
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
#print('[DEBUG] headers[{0}]'.format(headers))
|
||||
|
||||
merge_requests = requests.get(url, headers=headers, data='')
|
||||
|
||||
merge_requests = merge_requests.json()
|
||||
|
||||
|
||||
#print('\n\nmerge_requests=[-{0}-][]\n\n\n\n\n'.format(merge_requests))
|
||||
|
||||
|
||||
#project_mrs = project.mergerequests.list()
|
||||
#mrs = gl.mergerequests.list()
|
||||
|
||||
|
||||
mr_title = ''
|
||||
mr_first_commit = ''
|
||||
target_branch = ''
|
||||
|
||||
for mr in merge_requests:
|
||||
|
||||
# print('\n\nMR=[-{0}-]'.format(mr))
|
||||
|
||||
if mr['source_branch'] == git_branch and str(mr['target_project_id']) == str(project_id) and str(mr['state']) == 'opened':
|
||||
mr_title = mr['title']
|
||||
mr_first_commit = mr['sha']
|
||||
target_branch = mr['target_branch']
|
||||
|
||||
|
||||
|
||||
|
||||
if get_target_branch:
|
||||
print('{0}'.format(target_branch))
|
||||
|
||||
|
||||
if get_first_commit:
|
||||
|
||||
print('{0}'.format(mr_first_commit))
|
||||
|
||||
|
||||
if get_mr_title:
|
||||
|
||||
print('{0}'.format(mr_title))
|
||||
|
||||
58
conventional_commits/scripts/cz_junit.sh
Executable file
58
conventional_commits/scripts/cz_junit.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
# to use ensure cz_exit=0 is set prior to the cz command so that if the command is successfull, this script works
|
||||
# this script must be run with '. {script-name}' so that vars set in cli are available
|
||||
|
||||
cz_command=$(cat "$CI_PROJECT_DIR/artifacts/$CI_JOB_STAGE/$CI_JOB_NAME/cz_output.log")
|
||||
|
||||
|
||||
if [ "f${cz_exit}" == "f" ]; then
|
||||
echo "[DEBUG] environmental variable cz_exit must be set"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
if [ "${cz_exit}" == "0" ]; then
|
||||
error_count=0
|
||||
system_err=''
|
||||
|
||||
cat <<EOF
|
||||
<testsuite errors="0" name="Conventional Commits Messages Check" tests="0">
|
||||
<testcase classname="Conventional Commits" file="CI/commitizen/README.md" name="Using Conventional Commits Message Format"/>
|
||||
</testsuite>
|
||||
EOF
|
||||
|
||||
else
|
||||
error_count=1
|
||||
system_err="ERROR: $cz_command"
|
||||
|
||||
|
||||
cat <<EOF
|
||||
<testsuites id="Conventional Commits Messages Check" name="CI Validation test" tests="1" errors="$error_count" time="0">
|
||||
<testsuite id="conventional commit" name="testing" tests="1" failures="$error_count" time="0">
|
||||
<testcase classname="Conventional Commits" file="CI/commitizen/README.md" line="0" name="Using Conventional Commits Message Format" time="0" timestamp="$(date '+%Y-%m-%d %H:%M:%S')">
|
||||
|
||||
<failure message="Conventional commits not used" type="validation">$cz_command
|
||||
</failure>
|
||||
<system-out>
|
||||
<![CDATA[ $cz_command ]]>
|
||||
</system-out>
|
||||
<system-err>
|
||||
<![CDATA[ $system_err ]]>
|
||||
</system-err>
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
#echo boo;
|
||||
|
||||
#echo "output:[$cz_command]"
|
||||
#echo "[DEBUG] cz_exit[$cz_exit]"
|
||||
|
||||
|
||||
|
||||
|
||||
exit $cz_exit
|
||||
Reference in New Issue
Block a user