-
Install Jenkins using docker
1.1. Install Docker & Docker compose
1.2. Update docker to run without sudo permission
1.3. Logging in to your Github account (or your's company Github account)
This Github account need write permission to this repository
1.4. Clone this repo and check out branch cicd
- Jenkins will only use Jenkinsfile from this branch to trigger job
- Check function setup_environment_variables inside Jenkinsfile, update the variables value if necessary
1.5. Executing bash script to create Jenkins data folder
sudo .cicd/jenkins/scripts/host-setup.sh
1.6. Installing Jenkins
cd jenkins docker compose up -d --build
-
Allowing Jenkins to authenticate with Github using SSH keys
2.1. Add SSH keys to Jenkins instance
-
Access to Jenkins (docker) instance
2.2. Create a SSH Username with private key credential in Jenkins
- Access Jenkins Web UI
- Path: Dashboard > Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted) -> + Add Credentials
- Kind: SSH Username with private key
- ID: github-ssh-cred
- Description: Jenkins uses this key to authenticate with Github
- Username: your github username
- Private key / Enter directly/ Add: paste your private SSH key content at step 2.1 here
2.3. Add SSH public key (.pub) at step 2.1. to the Github account at step 1.3
-
-
Config Github plugin - allow trigger job in Jenkins by Github webhook
3.1. Generate Github personal access token (classic)
- Access to the Github account at step 1.3
- Select scopes:
- repo
- admin:repo_hook
3.2. Create a Secret Text credential in Jenkins
-
Access Jenkins Web UI
-
Path: Dashboard > Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted) -> + Add Credentials
-
Kind: Secret text
-
Secret: generated token at step 3.1
-
ID: github-access-token-cred
-
Description: Jenkins will use this token credentail for managing webhook, manipulate commit statuses
3.3. Config Github Server
-
Access Jenkins Web UI
-
Path: Dashboard > Manage Jenkins > System : Github / Github Servers
-
Add new Github server with following information:
- API URL: https://api.github.com
- Credentials: select the credential created at step 3.2
- Click Test connection to check your configuration
-
Click Save
-
Config remote server info
4.1. Add remote server ssh credential in Jenkins
- Access Jenkins Web UI
- Path: Dashboard > Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted) -> + Add Credentials
- Kind: SSH Username with private key
- ID: remote-server-cred
- Description: Jenkins will use this credential to connect to the remote server and execute commands, scripts.
- Username: the server's username
- Private Key / Enter directly / Add: the private key use to access the server
4.2. Allow remote server connect to Github using SSH keys
4.2.1. Add SSH keys to remote server
-
Access to remote server - the server that Jenkins will deploy code to
4.2.2. Add SSH public key (.pub) at step 4.2.1 to the Github account at step 1.3
4.3. Add privatekey credential
- Access Jenkins Web UI
- Path: Dashboard > Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted) -> + Add Credentials
- Kind: Secret file
- File: Upload the SSH private key generated at step 4.2.1
- ID: remote-server-github-privatekey-cred
- Description: Server use this private key to connect to Github and pull latest code
-
Create and config Github pipeline on Jenkins
5.1. Create new pipeline
-
Access Jenkins Web UI
-
Path: Dashboard > New Item -> Pipeline
-
Fill pipeline name. warning don't put space to pipeline name
-
Check Do not allow concurrent builds
-
Pipeline / Definition: Pipeline script from SCM
-
SCM: Git
-
Repositories / Repository URL: paste this repo's SSH url
-
Credentials: select the credential you created at step 2.4
-
Branches to build / Branch Specifier: select an apropriate branch that contains Jenkinsfile, default */cicd
-
Script Path: path to Jenkinsfile in repo, default .cicd/jenkins/Jenkinsfile
-
Select Lightweight checkout
5.2. Config Generic Webhook Trigger
-
Continue updating the pipeline at step 5.1
-
Check Build Triggers/Generic Webhook Trigger
-
Given the following Post content parameters are configured:
Variable Expression Expression Type Default value Value filter action $.action JSONPath pr_id $.number JSONPath pr_state $.pull_request.state JSONPath pr_merged $.pull_request.merged JSONPath pr_to_ref $.pull_request.base.ref JSONPath pr_to_repo_ssh_url $.pull_request.base.repo.ssh_url JSONPath pr_url $.pull_request.html_url JSONPath pr_draft $.pull_request.draft JSONPath pr_sha $.pull_request.head.sha JSONPath -
Fill the Token with a random string
-
Fill the Cause with text: Triggered from PR: $pr_url
-
Given Optional filter is configured with Text: $action#$pr_draft##$action#$pr_merged
-
Given Optional filter is configured with Expression: (reopened|opened|synchronize|ready_for_review)#(false)##|##(closed)#(true)
5.3. Add remote server information
-
Jenkins will use these variable for CD process (deploy to remote server)
-
Continue updating the pipeline at step 5.1
-
Select Prepare an environment for the run
-
Select Keep Jenkins Environment Variables
-
Select Keep Jenkins Build Variables
-
Properties Content: add below variables with appropriate value
server_host=<server ip address here> server_odoo_url=<odoo service endpoint> server_docker_compose_path=<path to folder contain odoo docker-compose.yml file> server_config_file=<path to odoo config file> server_custom_addons_path=<path to custom addons folder, also a git repo> server_odoo_db_name=<db name to backup and use in integration test> server_odoo_image_tag=<odoo image name - defined in docker compose file>
for example:
server_host=12.34.56.78 server_docker_compose_path=/opt/odoo/.deploy server_odoo_url=http://12.34.56.78:8069 server_config_file=/opt/odoo/.deploy/etc/odoo.conf server_custom_addons_path=/opt/odoo/ server_odoo_db_name=odoo-staging server_odoo_image_tag=xmars/odoo:16
-
-
6.1. If you use a local server to receive webhook, reference this guide to expose Jenkins locally to internet
6.2. Add Jenkins's hook url to repo's webhook
- Open this Github repo page
- Path: Settings / Webhooks / Add webhook
- Payload URL: <the_public_jenkins_url>/generic-webhook-trigger/invoke?token=<the_Token_at_step_5.2>
- Content type: application/json
- Which events would you like to trigger this webhook? : Let me select individual events./ Pull requests
- Click : Add webhook
-
CI/CD options for build and run test cases
If you want to ignore running Odoo test cases for some addons, update file odoo.json
Belwow is the structure and list of avaiable options:{ "addons": { "addon_name": { "ignore_test": true, ... }, "addon_2": { "ignore_demo": true, ... } } ... }
- addon_name: Odoo addon name, each addon have to stay in a different block
- ignore_test: if it's value is true, Jenkins won't run test cases for this addon
- ignore_demo: if it's value is true, Jenkins will ingore this module's demo data when running test cases
-
Integration with SonarQube
8.1. Install SonarQube
- Install SonarQube and allow Jenkins to connect to it (already done in docker compose file at step 1.6)
- Access SonarQube UI and generate a user token
8.2. Add SonarQube installer to Jenkins
- Access Jenkins Web UI
- Path: Dasboard / Manage Jenkins / Tools / SonarQube Scanner
- Click Add SonarQube Scanner
- Input Name: sonarqube-scanner
- Check: Install automatically
8.3. Add SonarQube credentail to Jenkins
- Access Jenkins Web UI
- Path: Dashboard > Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted) -> + Add Credentials
- Kind: Username with password
- Username: the SonarQube url which Jenkins can connect
- Secret: the token was obtained from step 8.1
- ID: sonar-cred
- Description: Jenkins will use this url and token to connect to SonarQube
-
Send message to Telegram from Jenkins
- Follow this link to obtain BOT token and Channel ID
- Add two secret text credentails to your Jenkins instance
- ID: telegram-bot-token Secret: BOT token
- ID: telegram-channel-id Secret: Channel ID
-
Trigger build process manually
-
You have to trigger build process first time manually before Github webhook can trigger the build process automatically
-
Path: Dashboard / Your pipeline / Build Now
-
⚡⚡Congrats✌️✌️ : now your pipeline will automatic start building when the repo received a pull request commit
-
Jenkins plugins:
-
Run Jenkins from docker-compose.yml file using a bind mount volume:
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
-> Solution:
sudo mkdir -p /var/jenkins_home && sudo chown -R 1000:1000 /var/jenkins_home/
-
Why use bind mount volume instead of volume for Jenkins' container
-
SonarQube code quality inspection -> use to scan Odoo addons
-
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
-> Solution: check Jenkins Dockerfile, line 17,18, 19 to create a new group mapped with docker group on host
-
Config Generic webhook trigger in Jenkins file
node { withCredentials([string(credentialsId: 'github-access-token-cred', variable: 'webhookToken')]) { properties([ pipelineTriggers([ [ $class: 'GenericTrigger', genericVariables: [ [key: 'action', value: '$.action', expressionType: 'JSONPath'], [key: 'pr_id', value: '$.number', expressionType: 'JSONPath'], [key: 'pr_state', value: '$.pull_request.state', expressionType: 'JSONPath'], [key: 'pr_merged', value: '$.pull_request.merged', expressionType: 'JSONPath'], [key: 'pr_to_ref', value: '$.pull_request.base.ref', expressionType: 'JSONPath'], [key: 'pr_to_repo_ssh_url', value: '$.pull_request.base.repo.ssh_url', expressionType: 'JSONPath'], [key: 'pr_url', value: '$.pull_request.html_url', expressionType: 'JSONPath'], [key: 'pr_draft', value: '$.pull_request.draft', expressionType: 'JSONPath'] ], causeString: 'Triggered from PR: $pr_url', token: webhookToken, regexpFilterText: '$action#$pr_draft##$action#$pr_merged', regexpFilterExpression: '(reopened|opened|synchronize|ready_for_review)#(false)##|##(closed)#(true)', printContributedVariables: false, printPostContent: false, ] ]) ]) } stage ... }
-
By default, before pipeline start, Jenkins will check out repo with branch specified in 'Branches to build' to get the Jenkinsfile,
so we can't ignore check out default Instead, we will perform second checkout with specific branch (from pull request)