mirror of
https://github.com/mysensors/MySensors.git
synced 2026-02-20 01:21:27 +01:00
Implement Jenkins pipelines as code (#948)
Jenkins has been updated with new jobs that scan and execute
Jenkinsfiles. These Jenkinsfiles encapsulates all logic for building
and validating the commits in both pull requests and merged pull
requests.
Filestructure is as follows:
.ci/Jenkinsfile - This is the main Jenkinsfile that handles normal
pull request builds as well as merged pull request
post-validation.
Any repository in the MySensors GitHub organization
can implement this file and Jenkins will pick up
and execute it automatically.
.ci/Jenkinsfile-nightly - This perform merged pull request
post-validation using the nightly builds of
the Arduino IDE to provide early compliancy
status of the MySensors library for
upcoming releases of the Arduino IDE
.ci/ - This folder contain all the auxiliary scripts executed by the
Jenkinsfiles as well
Fixes #934
This commit is contained in:
18
.ci/Jenkinsfile
vendored
Normal file
18
.ci/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#!groovy
|
||||
node {
|
||||
deleteDir() // Purge workspace
|
||||
// Checkout the repo to get the necessary groovy scripts (and place it in the required subdirectory)
|
||||
dir('MySensors') {
|
||||
checkout scm
|
||||
}
|
||||
def pipeline = load('MySensors/.ci/pipeline.groovy')
|
||||
|
||||
// Invoke the main pipeline
|
||||
pipeline {
|
||||
library_root = 'MySensors/' // Location of the MySensors library
|
||||
repository_root = 'MySensors/' // Location of the repository root
|
||||
github_organization = 'mysensors' // Name of the GitHub Organization
|
||||
repository_name = 'MySensors' // Name of the repository on GitHub
|
||||
nightly_arduino_ide = false // Pick Arduino IDE variant to use
|
||||
}
|
||||
}
|
||||
18
.ci/Jenkinsfile-nightly
Normal file
18
.ci/Jenkinsfile-nightly
Normal file
@@ -0,0 +1,18 @@
|
||||
#!groovy
|
||||
node {
|
||||
deleteDir() // Purge workspace
|
||||
// Checkout the repo to get the necessary groovy scripts (and place it in the required subdirectory)
|
||||
dir('MySensors') {
|
||||
checkout scm
|
||||
}
|
||||
def pipeline = load('MySensors/.ci/pipeline.groovy')
|
||||
|
||||
// Invoke the main pipeline
|
||||
pipeline {
|
||||
library_root = 'MySensors/' // Location of the MySensors library
|
||||
repository_root = 'MySensors/' // Location of the repository root
|
||||
github_organization = 'mysensors' // Name of the GitHub Organization
|
||||
repository_name = 'MySensors' // Name of the repository on GitHub
|
||||
nightly_arduino_ide = true // Pick Arduino IDE variant to use
|
||||
}
|
||||
}
|
||||
351
.ci/arduino.groovy
Normal file
351
.ci/arduino.groovy
Normal file
@@ -0,0 +1,351 @@
|
||||
#!groovy
|
||||
def buildArduino(config, String buildFlags, String sketch, String key) {
|
||||
def root = '/opt/arduino-1.8.2/'
|
||||
if (config.nightly_arduino_ide)
|
||||
{
|
||||
root = '/opt/arduino-nightly/'
|
||||
}
|
||||
def esp8266_tools = '/opt/arduino-nightly/hardware/esp8266com/esp8266/tools'
|
||||
def jenkins_root = '/var/lib/jenkins/'
|
||||
def builder = root+'arduino-builder'
|
||||
def standard_args = ' -warnings="all"' //-verbose=true
|
||||
def builder_specifics = ' -hardware '+root+'hardware -tools '+root+'hardware/tools/avr -tools '+
|
||||
root+'tools-builder -tools '+esp8266_tools+' -built-in-libraries '+root+'libraries'
|
||||
def jenkins_packages = jenkins_root+'.arduino15/packages'
|
||||
def site_specifics = ' -hardware '+jenkins_packages+' -tools '+jenkins_packages
|
||||
def repo_specifics = ' -hardware hardware -libraries . '
|
||||
def build_cmd = builder+standard_args+builder_specifics+site_specifics+repo_specifics+buildFlags
|
||||
sh """#!/bin/bash
|
||||
printf "\\e[1m\\e[32mBuilding \\e[34m${sketch} \\e[0musing \\e[1m\\e[36m${build_cmd}\\e[0m\\n"
|
||||
${build_cmd} ${sketch} 2>> compiler_${key}.log"""
|
||||
}
|
||||
|
||||
def parseWarnings(String key) {
|
||||
warnings canResolveRelativePaths: false, canRunOnFailed: true, categoriesPattern: '',
|
||||
defaultEncoding: '',
|
||||
excludePattern: '''.*/EEPROM\\.h,.*/Dns\\.cpp,.*/socket\\.cpp,.*/util\\.h,.*/Servo\\.cpp,
|
||||
.*/Adafruit_NeoPixel\\.cpp,.*/UIPEthernet.*,.*/SoftwareSerial\\.cpp,
|
||||
.*/pins_arduino\\.h,.*/Stream\\.cpp,.*/USBCore\\.cpp,.*/Wire\\.cpp,
|
||||
.*/hardware/esp8266.*,.*/libraries/SD/.*''',
|
||||
healthy: '', includePattern: '', messagesPattern: '',
|
||||
parserConfigurations: [[parserName: 'Arduino/AVR', pattern: 'compiler_'+key+'.log']],
|
||||
unHealthy: '', unstableNewAll: '0', unstableTotalAll: '0'
|
||||
sh """#!/bin/bash
|
||||
echo "Compiler warnings/errors:"
|
||||
printf "\\e[101m"
|
||||
cat compiler_${key}.log
|
||||
printf "\\e[0m"
|
||||
rm compiler_${key}.log"""
|
||||
}
|
||||
|
||||
def buildMySensorsMicro(config, sketches, String key) {
|
||||
def fqbn = '-fqbn MySensors:avr:MysensorsMicro -prefs build.f_cpu=1000000 -prefs build.mcu=atmega328p'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsMicro')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsMicro - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_MySensorsMicro')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsMicro - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsMicro - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (MySensorsMicro - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildMySensorsGw(config, sketches, String key) {
|
||||
def fqbn = '-fqbn MySensors:samd:mysensors_gw_native -prefs build.f_cpu=48000000 -prefs build.mcu=cortex-m0plus'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/BatteryPoweredSensor/BatteryPoweredSensor.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGw')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_MySensorsGw')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsGW - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (MySensorsGW - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildArduinoNano(config, sketches, String key) {
|
||||
def fqbn = '-fqbn arduino:avr:nano -prefs build.f_cpu=16000000 -prefs build.mcu=atmega328p'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Nano - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoNano')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Nano - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_ArduinoNano')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Arduino Nano - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Nano - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Arduino Nano - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildArduinoUno(config, sketches, String key) {
|
||||
def fqbn = '-fqbn arduino:avr:uno -prefs build.f_cpu=16000000 -prefs build.mcu=atmega328p'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoUno')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Uno - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_ArduinoUno')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Arduino Uno - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Uno - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Arduino Uno - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildArduinoPro(config, sketches, String key) {
|
||||
def fqbn = '-fqbn arduino:avr:pro -prefs build.f_cpu=8000000 -prefs build.mcu=atmega328p'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Pro/Mini - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoPro')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Pro/Mini - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_ArduinoPro')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, config, 'ERROR', 'Toll gate (Arduino Pro/Mini - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Pro/Mini - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Arduino Pro/Mini - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildArduinoMega(config, sketches, String key) {
|
||||
def fqbn = '-fqbn arduino:avr:mega -prefs build.f_cpu=16000000 -prefs build.mcu=atmega2560'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoMega')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Mega - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_ArduinoMega')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, config, 'ERROR', 'Toll gate (Arduino Mega - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Mega - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Arduino Mega - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildEsp8266(config, sketches, String key) {
|
||||
def fqbn = '-fqbn esp8266:esp8266:generic -prefs build.f_cpu=80000000 -prefs build.mcu=esp8266'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/BatteryPoweredSensor/BatteryPoweredSensor.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/CO2Sensor/CO2Sensor.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') {
|
||||
buildArduino(config, '-prefs build.flash_ld=eagle.flash.512k0.ld -prefs build.flash_freq=40 -prefs build.flash_size=512K '+fqbn, sketches[sketch].path, key+'_Esp8266')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_Esp8266')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP8266 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (ESP8266 - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildnRF5(config, sketches, String key) {
|
||||
def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832 -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
for (sketch = 0; sketch < sketches.size(); sketch++) {
|
||||
if (sketches[sketch].path != config.library_root+'examples/BatteryPoweredSensor/BatteryPoweredSensor.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/CO2Sensor/CO2Sensor.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' &&
|
||||
sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') {
|
||||
buildArduino(config, fqbn, sketches[sketch].path, key+'_nRF5')
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF5 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_nRF5')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF5 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF5 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (nRF5 - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildnRF52832(config, sketches, String key) {
|
||||
def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF52832:bootcode=none,lfclk=lfxo,reset=notenable -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyNRF5Board/examples/MyNRF5Board/MyNRF5Board.ino', key+'_nRF52832')
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF52832 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_nRF52832')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF52832 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF52832 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (nRF52832 - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildnRF51822(config, sketches, String key) {
|
||||
def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF51822:chip=xxaa,bootcode=none,lfclk=lfxo -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m0'
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
try {
|
||||
buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyNRF5Board/examples/MyNRF5Board/MyNRF5Board.ino', key+'_nRF51822')
|
||||
} catch (ex) {
|
||||
echo "Build failed with: "+ ex.toString()
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF51822 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
throw ex
|
||||
} finally {
|
||||
parseWarnings(key+'_nRF51822')
|
||||
}
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF51822 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new')
|
||||
if (config.is_pull_request) {
|
||||
error 'Termiated due to warnings found'
|
||||
}
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF51822 - '+key+')', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (nRF51822 - '+key+')', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
47
.ci/doxygen.groovy
Normal file
47
.ci/doxygen.groovy
Normal file
@@ -0,0 +1,47 @@
|
||||
#!groovy
|
||||
def call(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Documentation)', 'Generating...', '${BUILD_URL}flowGraphTable/')
|
||||
sh """#!/bin/bash +x
|
||||
cd ${config.repository_root}
|
||||
export PROJECTNUMBER=\$(
|
||||
if [[ \$(git rev-parse --abbrev-ref HEAD) == "master" ]]; then
|
||||
git describe --tags ;
|
||||
else
|
||||
git rev-parse --short HEAD ;
|
||||
fi
|
||||
)
|
||||
echo 'WARN_LOGFILE=doxygen.log' >> Doxyfile && doxygen"""
|
||||
warnings canComputeNew: false, canResolveRelativePaths: false,
|
||||
defaultEncoding: '',
|
||||
excludePattern: '''.*/sha204_library\\.h,.*/drivers/Linux/.*,.*/cores/esp8266/.*,hardware/.*''',
|
||||
failedTotalAll: '', healthy: '', includePattern: '', messagesPattern: '',
|
||||
parserConfigurations: [[parserName: 'Doxygen', pattern: config.repository_root+'doxygen.log']],
|
||||
unHealthy: '', unstableTotalAll: '0'
|
||||
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true,
|
||||
reportDir: config.repository_root+'Documentation/html',
|
||||
reportFiles: 'index.html', reportName: 'Doxygen HTML', reportTitles: ''])
|
||||
|
||||
if (!config.is_pull_request)
|
||||
{
|
||||
// Publish docs to API server
|
||||
if (env.BRANCH_NAME == 'master') {
|
||||
sh """#!/bin/bash
|
||||
scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io"""
|
||||
} else if (env.BRANCH_NAME == 'development') {
|
||||
sh """#!/bin/bash
|
||||
scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io:beta"""
|
||||
}
|
||||
} else {
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Documentation)', 'Warnings found', '${BUILD_URL}warnings16Result/new')
|
||||
error 'Terminating due to doxygen error'
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Documentation)', 'Error generating documentation', '${BUILD_URL}flowGraphTable/')
|
||||
error 'Terminating due to doxygen error'
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Documentation)', 'Pass', '${BUILD_URL}Doxygen_HTML/index.html')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
105
.ci/gitler.groovy
Normal file
105
.ci/gitler.groovy
Normal file
@@ -0,0 +1,105 @@
|
||||
#!groovy
|
||||
def call(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Gitler)', 'Checking...', '${BUILD_URL}flowGraphTable/')
|
||||
if (env.CHANGE_TARGET == 'master' &&
|
||||
(env.CHANGE_AUTHOR != 'bblacey' || env.CHANGE_AUTHOR != 'd00616' ||
|
||||
env.CHANGE_AUTHOR != 'fallberg' || env.CHANGE_AUTHOR != 'henrikekblad' ||
|
||||
env.CHANGE_AUTHOR != 'marceloaqno' || env.CHANGE_AUTHOR != 'mfalkvidd' ||
|
||||
env.CHANGE_AUTHOR != 'scalz' || env.CHANGE_AUTHOR != 'tbowmo' ||
|
||||
env.CHANGE_AUTHOR != 'tekka007' || env.CHANGE_AUTHOR != 'user2684' ||
|
||||
env.CHANGE_AUTHOR != 'Yveaux'))
|
||||
{
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'This pull request targets master. That is not permitted!', '')
|
||||
error "This pull request targets master. That is not permitted!"
|
||||
}
|
||||
|
||||
dir(config.repository_root) {
|
||||
step([$class: 'GitChangelogRecorder', config: [configFile: 'git-changelog-settings.json',
|
||||
createFileTemplateContent: '''
|
||||
{{#commits}}
|
||||
{{{messageTitle}}}
|
||||
{{/commits}}
|
||||
''',
|
||||
createFileTemplateFile: '', createFileUseTemplateContent: true,
|
||||
createFileUseTemplateFile: false, customIssues: [[link: '', name: '', pattern: '', title: ''],
|
||||
[link: '', name: '', pattern: '', title: '']], dateFormat: 'YYYY-MM-dd HH:mm:ss',
|
||||
file: 'subjects.txt', fromReference: env.CHANGE_TARGET, fromType: 'ref', gitHubApi: '',
|
||||
gitHubApiTokenCredentialsId: '', gitHubIssuePattern: '#([0-9]+)', gitHubToken: '',
|
||||
gitLabApiTokenCredentialsId: '', gitLabProjectName: '', gitLabServer: '', gitLabToken: '',
|
||||
ignoreCommitsIfMessageMatches: '^Merge.*',
|
||||
ignoreCommitsWithoutIssue: false, ignoreTagsIfNameMatches: '',
|
||||
jiraIssuePattern: '\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b', jiraPassword: '', jiraServer: '',
|
||||
jiraUsername: '', jiraUsernamePasswordCredentialsId: '', mediaWikiPassword: '',
|
||||
mediaWikiTemplateContent: '', mediaWikiTemplateFile: '', mediaWikiTitle: '', mediaWikiUrl: '',
|
||||
mediaWikiUseTemplateContent: false, mediaWikiUseTemplateFile: false, mediaWikiUsername: '',
|
||||
noIssueName: 'No issue', readableTagName: '/([^/]+?)$', showSummary: false,
|
||||
showSummaryTemplateContent: '', showSummaryTemplateFile: '', showSummaryUseTemplateContent: false,
|
||||
showSummaryUseTemplateFile: false, subDirectory: '', timeZone: 'UTC',
|
||||
toReference: config.git_sha, toType: 'commit', untaggedName: 'Unreleased',
|
||||
useConfigFile: false, useFile: true, useGitHub: false, useGitHubApiTokenCredentials: false,
|
||||
useGitLab: false, useGitLabApiTokenCredentials: false, useIgnoreTagsIfNameMatches: false,
|
||||
useJira: false, useJiraUsernamePasswordCredentialsId: false, useMediaWiki: false,
|
||||
useReadableTagName: false, useSubDirectory: false]
|
||||
])
|
||||
step([$class: 'GitChangelogRecorder', config: [configFile: 'git-changelog-settings.json',
|
||||
createFileTemplateContent: '''
|
||||
{{#commits}}
|
||||
{{#messageBodyItems}}
|
||||
{{.}}
|
||||
{{/messageBodyItems}}
|
||||
{{/commits}}
|
||||
''',
|
||||
createFileTemplateFile: '', createFileUseTemplateContent: true,
|
||||
createFileUseTemplateFile: false, customIssues: [[link: '', name: '', pattern: '', title: ''],
|
||||
[link: '', name: '', pattern: '', title: '']], dateFormat: 'YYYY-MM-dd HH:mm:ss',
|
||||
file: 'bodies.txt', fromReference: env.CHANGE_TARGET, fromType: 'ref', gitHubApi: '',
|
||||
gitHubApiTokenCredentialsId: '', gitHubIssuePattern: '#([0-9]+)', gitHubToken: '',
|
||||
gitLabApiTokenCredentialsId: '', gitLabProjectName: '', gitLabServer: '', gitLabToken: '',
|
||||
ignoreCommitsIfMessageMatches: '^Merge.*',
|
||||
ignoreCommitsWithoutIssue: false, ignoreTagsIfNameMatches: '',
|
||||
jiraIssuePattern: '\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b', jiraPassword: '', jiraServer: '',
|
||||
jiraUsername: '', jiraUsernamePasswordCredentialsId: '', mediaWikiPassword: '',
|
||||
mediaWikiTemplateContent: '', mediaWikiTemplateFile: '', mediaWikiTitle: '', mediaWikiUrl: '',
|
||||
mediaWikiUseTemplateContent: false, mediaWikiUseTemplateFile: false, mediaWikiUsername: '',
|
||||
noIssueName: 'No issue', readableTagName: '/([^/]+?)$', showSummary: false,
|
||||
showSummaryTemplateContent: '', showSummaryTemplateFile: '', showSummaryUseTemplateContent: false,
|
||||
showSummaryUseTemplateFile: false, subDirectory: '', timeZone: 'UTC',
|
||||
toReference: config.git_sha, toType: 'commit', untaggedName: 'Unreleased',
|
||||
useConfigFile: false, useFile: true, useGitHub: false, useGitHubApiTokenCredentials: false,
|
||||
useGitLab: false, useGitLabApiTokenCredentials: false, useIgnoreTagsIfNameMatches: false,
|
||||
useJira: false, useJiraUsernamePasswordCredentialsId: false, useMediaWiki: false,
|
||||
useReadableTagName: false, useSubDirectory: false]
|
||||
])
|
||||
}
|
||||
|
||||
ret = sh(returnStatus: true,
|
||||
script:"""#!/bin/bash
|
||||
cd ${config.repository_root}/.ci
|
||||
./gitler.sh""")
|
||||
|
||||
if (fileExists(config.repository_root+'restyling.patch')) {
|
||||
emailext (
|
||||
subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} [PR#${env.CHANGE_ID}]' failed due to bad code styling",
|
||||
body: """<p>Job '${env.JOB_NAME} [<a href="${env.CHANGE_URL}">PR#${env.CHANGE_ID}</a> - ${env.CHANGE_TITLE}]' failed because code style does not follow the standards.</p>
|
||||
A patch to rectify the errors is attached. You apply the patch using:<br>
|
||||
git apply restyling.patch<p>
|
||||
If you disagree to this, please discuss it <a href="${env.CHANGE_URL}">here</a>.<p>
|
||||
Yours sincerely, Gitler, on behalf of Jenkins""",
|
||||
mimeType: 'text/html', to: '${env.CHANGE_AUTHOR_EMAIL}',
|
||||
attachLog: false, compressLog: false, attachmentsPattern: config.repository_root+'restyling.patch'
|
||||
)
|
||||
}
|
||||
publishHTML([allowMissing: true, alwaysLinkToLastBuild: false, keepAll: true,
|
||||
reportDir: config.repository_root,
|
||||
reportFiles: 'gitler.html', reportName: 'Gitler report', reportTitles: ''])
|
||||
if (ret == 1) {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'Commit(s) does not meet coding standards', '${BUILD_URL}Gitler_report/gitler.html')
|
||||
currentBuild.currentResult == 'FAILURE'
|
||||
echo "Termiated due to Gitler assert" // For BFA
|
||||
error 'Termiated due to Gitler assert'
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
93
.ci/gitler.sh
Executable file
93
.ci/gitler.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
# Yes, this script can be improved immensly...
|
||||
cd ..
|
||||
|
||||
result=0
|
||||
|
||||
echo "No subjects are of invalid size<br>" > too_long_subjects.txt
|
||||
echo "No subjects with leading lower case characters<br>" > leading_lowercases.txt
|
||||
echo "No subjects with trailing periods<br>" > trailing_periods.txt
|
||||
echo "No body lines are too wide<br>" > too_long_body_lines.txt
|
||||
|
||||
too_long_subjects=`awk 'length > 50' subjects.txt`
|
||||
if [ -n "$too_long_subjects" ]; then
|
||||
echo "<b>Commit subjects that are too wide (>50 characters):</b>" > too_long_subjects.txt
|
||||
echo "$too_long_subjects" >> too_long_subjects.txt
|
||||
sed -i -e 's/$/<br>/' too_long_subjects.txt
|
||||
result=1
|
||||
fi
|
||||
leading_lowercases=`awk '/^[[:lower:][:punct:]]/' subjects.txt`
|
||||
if [ -n "$leading_lowercases" ]; then
|
||||
echo "<b>Commit subjects with leading lowercase characters:</b>" > leading_lowercases.txt
|
||||
echo "$leading_lowercases" >> leading_lowercases.txt
|
||||
sed -i -e 's/$/<br>/' leading_lowercases.txt
|
||||
result=1
|
||||
fi
|
||||
trailing_periods=`awk '/(\.)$/' subjects.txt`
|
||||
if [ -n "$trailing_periods" ]; then
|
||||
echo "<b>Commit subjects with trailing periods:</b>" > trailing_periods.txt
|
||||
echo "$trailing_periods" >> trailing_periods.txt
|
||||
sed -i -e 's/$/<br>/' trailing_periods.txt
|
||||
result=1
|
||||
fi
|
||||
|
||||
too_long_body_lines=`awk 'length > 72' bodies.txt`
|
||||
if [ -n "$too_long_body_lines" ]; then
|
||||
echo "<b>Body lines that are too wide (>72 characters):</b>" > too_long_body_lines.txt
|
||||
echo "$too_long_body_lines" >> too_long_body_lines.txt
|
||||
sed -i -e 's/$/<br>/' too_long_body_lines.txt
|
||||
result=1
|
||||
fi
|
||||
|
||||
printf "%s" "<html>" > gitler.html
|
||||
awk 'FNR==1{print "<br>"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
if [ $result -ne 0 ]; then
|
||||
echo "You should follow <a href="http://chris.beams.io/posts/git-commit">this guide</a> when writing your commit messages.<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
echo "To change the commit message for a single-commit pull request:<br>" >> gitler.html
|
||||
echo "git checkout <your_branch><br>" >> gitler.html
|
||||
echo "git commit --amend<br>" >> gitler.html
|
||||
echo "git push origin HEAD:<your_branch_on_github> -f<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
echo "To change the commit messages for a multiple-commit pull request:<br>" >> gitler.html
|
||||
echo "git checkout <your_branch><br>" >> gitler.html
|
||||
echo "git rebase -i <sha_of_parent_to_the_earliest_commit_you_want_to_change><br>" >> gitler.html
|
||||
echo "Replace \"pick\" with \"r\" or \"reword\" on the commits you need to change message for<br>" >> gitler.html
|
||||
echo "git push origin HEAD:<your_branch_on_github> -f<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
fi
|
||||
|
||||
# Evaluate coding style
|
||||
astyle --options=.mystools/astyle/config/style.cfg -nq --recursive "*.h" "*.c" "*.cpp"
|
||||
git diff > restyling.patch
|
||||
if [ -s restyling.patch ]; then
|
||||
echo "<b>This commit is not meeting the coding standards, a mail with a patch has been sent to you that if applied to your PR, will make it meet the coding standards.</b><br>" >> gitler.html
|
||||
echo "You apply the patch using:<br>" >> gitler.html
|
||||
echo "git apply restyling.patch<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
result=1
|
||||
else
|
||||
echo "This commit is meeting the coding standards, congratulations!<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
rm restyling.patch
|
||||
fi
|
||||
|
||||
# Evaluate if there exists booleans in the code tree (not counting this file)
|
||||
if git grep -q boolean -- `git ls-files | grep -v gitler.sh`
|
||||
then
|
||||
echo "<b>This repository currently contain the boolean keyword. This should be avoided.</b><br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
result=1
|
||||
else
|
||||
echo "This repository does not contain any boolean keywords. This is good.<br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
fi
|
||||
|
||||
if [ $result -ne 0 ]; then
|
||||
echo "<b>If you disagree to this, please discuss it in the GitHub pull request thread.</b><br>" >> gitler.html
|
||||
echo "<br>" >> gitler.html
|
||||
fi
|
||||
echo "Yours sincerely, Gitler, on behalf of Jenkins<br>" >> gitler.html
|
||||
printf "%s" "</html>" >> gitler.html
|
||||
exit $result
|
||||
71
.ci/linux.groovy
Normal file
71
.ci/linux.groovy
Normal file
@@ -0,0 +1,71 @@
|
||||
#!groovy
|
||||
def buildLinux(config, String configuration, String key) {
|
||||
def linux_configurer = './configure '
|
||||
def linux_configure_standard_args = '--my-rs485-serial-port=/dev/ttyS0 --my-controller-ip-address=1.2.3.4 '+
|
||||
'--my-mqtt-subscribe-topic-prefix=dummy --my-mqtt-publish-topic-prefix==dummy --my-mqtt-client-id=0 '
|
||||
def linux_builder = 'make '
|
||||
def linux_builder_standard_args = '-j1'
|
||||
def linux_build_cmd = linux_builder + linux_builder_standard_args
|
||||
def linux_configure_cmd = linux_configurer + linux_configure_standard_args + configuration
|
||||
sh """#!/bin/bash
|
||||
printf "\\e[1m\\e[32mBuilding \\e[0musing \\e[1m\\e[36m${linux_build_cmd} \\e[0mwith \\e[1m\\e[34m${linux_configure_standard_args} ${configuration}\\e[0m\\n"
|
||||
cd ${config.library_root}
|
||||
${linux_configure_cmd}
|
||||
${linux_build_cmd} 2>> compiler_${key}.log"""
|
||||
warnings canComputeNew: false, canResolveRelativePaths: false,
|
||||
defaultEncoding: '',
|
||||
excludePattern: '''.*/EEPROM\\.h,.*/Dns\\.cpp,.*/socket\\.cpp,.*/util\\.h,.*/Servo\\.cpp,
|
||||
.*/Adafruit_NeoPixel\\.cpp,.*/UIPEthernet.*,.*/SoftwareSerial\\.cpp,
|
||||
.*/pins_arduino\\.h,.*/Stream\\.cpp,.*/USBCore\\.cpp,.*/Wire\\.cpp,
|
||||
.*/hardware/esp8266.*,.*/libraries/SD/.*''',
|
||||
failedTotalAll: '', healthy: '', includePattern: '', messagesPattern: '',
|
||||
parserConfigurations: [[parserName: 'GNU Make + GNU C Compiler (gcc)', pattern: config.library_root+'compiler_'+key+'.log']],
|
||||
unHealthy: '', unstableTotalAll: '0'
|
||||
sh """#!/bin/bash
|
||||
echo "Compiler warnings/errors:"
|
||||
printf "\\e[101m"
|
||||
cat ${config.library_root}compiler_${key}.log
|
||||
printf "\\e[0m"
|
||||
rm ${config.library_root}compiler_${key}.log"""
|
||||
}
|
||||
|
||||
def buildSerial(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Serial GW)', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=serial', 'Serial')
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Serial GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
|
||||
error 'Termiated due to warnings found'
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Serial GW)', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Linux builds - Serial GW)', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildEthernet(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Ethernet GW)', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
buildLinux(config, '--my-debug=enable --my-transport=rs485 --my-gateway=ethernet', 'Ethernet')
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Ethernet GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
|
||||
error 'Termiated due to warnings found'
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Ethernet GW)', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Linux builds - Ethernet GW)', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
def buildMQTT(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - MQTT GW)', 'Building...', '${BUILD_URL}flowGraphTable/')
|
||||
buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=mqtt', 'MQTT')
|
||||
if (currentBuild.currentResult == 'UNSTABLE') {
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - MQTT GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new')
|
||||
error 'Termiated due to warnings found'
|
||||
} else if (currentBuild.currentResult == 'FAILURE') {
|
||||
config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - MQTT GW)', 'Build error', '${BUILD_URL}')
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Linux builds - MQTT GW)', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
196
.ci/pipeline.groovy
Normal file
196
.ci/pipeline.groovy
Normal file
@@ -0,0 +1,196 @@
|
||||
#!groovy
|
||||
|
||||
def call(Closure body) {
|
||||
def config = [:]
|
||||
body.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
body.delegate = config
|
||||
body()
|
||||
|
||||
config.pr = load(config.repository_root+'.ci/pr-toolbox.groovy')
|
||||
def linux = load(config.repository_root+'.ci/linux.groovy')
|
||||
def arduino = load(config.repository_root+'.ci/arduino.groovy')
|
||||
|
||||
if (env.CHANGE_ID) {
|
||||
config.is_pull_request = true
|
||||
echo "Building pull request: #"+env.CHANGE_ID+"\nTarget branch: "+env.CHANGE_TARGET
|
||||
config.git_sha = sh(returnStdout: true,
|
||||
script: """#!/bin/bash
|
||||
cd ${config.repository_root}
|
||||
git log -n 1 --pretty=format:'%H' refs/remotes/origin/PR-${env.CHANGE_ID}""").trim()
|
||||
} else {
|
||||
config.is_pull_request = false
|
||||
echo "Building branch: "+env.BRANCH_NAME
|
||||
config.git_sha = sh(returnStdout: true,
|
||||
script: """#!/bin/bash
|
||||
cd ${config.repository_root}
|
||||
git log -n 1 --pretty=format:'%H' refs/remotes/origin/${env.BRANCH_NAME}""").trim()
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate', 'Validating...', '${BUILD_URL}flowGraphTable/')
|
||||
}
|
||||
|
||||
try {
|
||||
ansiColor('xterm') {
|
||||
if (config.is_pull_request) {
|
||||
def gitler = load(config.repository_root+'.ci/gitler.groovy')
|
||||
stage('Gitler') {
|
||||
gitler(config)
|
||||
}
|
||||
}
|
||||
|
||||
stage('Preparation') {
|
||||
checkout(changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/master']],
|
||||
extensions: [
|
||||
[$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: true],
|
||||
[$class: 'RelativeTargetDirectory', relativeTargetDir: 'hardware/MySensors/avr']
|
||||
],
|
||||
userRemoteConfigs: [[url: 'https://github.com/mysensors/ArduinoHwAVR.git']]])
|
||||
checkout(changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/master']],
|
||||
extensions: [
|
||||
[$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: true],
|
||||
[$class: 'RelativeTargetDirectory', relativeTargetDir: 'hardware/MySensors/samd']
|
||||
],
|
||||
userRemoteConfigs: [[url: 'https://github.com/mysensors/ArduinoHwSAMD.git']]])
|
||||
checkout(changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/master']],
|
||||
extensions: [
|
||||
[$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: true],
|
||||
[$class: 'RelativeTargetDirectory', relativeTargetDir: 'hardware/MySensors/nRF5']
|
||||
],
|
||||
userRemoteConfigs: [[url: 'https://github.com/mysensors/ArduinoHwNRF5.git']]])
|
||||
|
||||
config.tests = findFiles(glob: config.library_root+'tests/**/*.ino')
|
||||
config.examples = findFiles(glob: config.library_root+'examples/**/*.ino')
|
||||
|
||||
}
|
||||
|
||||
parallel Doxygen: {
|
||||
if (!config.nightly_arduino_ide) {
|
||||
stage('Doxygen') {
|
||||
def doxygen = load(config.repository_root+'.ci/doxygen.groovy')
|
||||
doxygen(config)
|
||||
}
|
||||
}
|
||||
}, CodeAnalysis: {
|
||||
if (!config.nightly_arduino_ide) {
|
||||
if (config.is_pull_request) {
|
||||
def analysis = load(config.repository_root+'.ci/static_analysis.groovy')
|
||||
stage('Cppcheck') {
|
||||
analysis.cppCheck(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, LinuxBuilds: {
|
||||
if (!config.nightly_arduino_ide) {
|
||||
stage('LinuxGwSerial') {
|
||||
linux.buildSerial(config)
|
||||
}
|
||||
stage('LinuxGwEthernet') {
|
||||
linux.buildEthernet(config)
|
||||
}
|
||||
stage('LinuxGwMQTT') {
|
||||
linux.buildMQTT(config)
|
||||
}
|
||||
}
|
||||
}, ArduinoBuilds: {
|
||||
lock(quantity: 1, resource: 'arduinoEnv') {
|
||||
stage('MySensorsMicro (tests)') {
|
||||
arduino.buildMySensorsMicro(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('MySensorsGW (tests)') {
|
||||
arduino.buildMySensorsGw(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('nRF52832 (tests)') {
|
||||
arduino.buildnRF52832(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('nRF51822 (tests)') {
|
||||
arduino.buildnRF51822(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('nRF5 (tests)') {
|
||||
arduino.buildnRF5(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('ESP8266 (tests)') {
|
||||
arduino.buildEsp8266(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('ArduinoNano (tests)') {
|
||||
arduino.buildArduinoNano(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('ArduinoUno (tests)') {
|
||||
arduino.buildArduinoUno(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('ArduinoProMini (tests)') {
|
||||
arduino.buildArduinoPro(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('ArduinoMega (tests)') {
|
||||
arduino.buildArduinoMega(config, config.tests, 'Tests')
|
||||
}
|
||||
stage('MySensorsMicro (examples)') {
|
||||
arduino.buildMySensorsMicro(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('MySensorsGW (examples)') {
|
||||
arduino.buildMySensorsGw(config, config.examples, 'Examples')
|
||||
}
|
||||
// No point in building examples for nRF52832 yet
|
||||
/*
|
||||
stage('nRF52832 (examples)') {
|
||||
arduino.buildnRF52832(config, config.examples, 'Examples')
|
||||
}
|
||||
*/
|
||||
// No point in building examples for nRF51822 yet
|
||||
/*
|
||||
stage('nRF51822 (examples)') {
|
||||
arduino.buildnRF51822(config, config.examples, 'Examples')
|
||||
}
|
||||
*/
|
||||
stage('nRF5 (examples)') {
|
||||
arduino.buildnRF5(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('ESP8266 (examples)') {
|
||||
arduino.buildEsp8266(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('ArduinoNano (examples)') {
|
||||
arduino.buildArduinoNano(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('ArduinoUno (examples)') {
|
||||
arduino.buildArduinoUno(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('ArduinoProMini (examples)') {
|
||||
arduino.buildArduinoPro(config, config.examples, 'Examples')
|
||||
}
|
||||
stage('ArduinoMega (examples)') {
|
||||
arduino.buildArduinoMega(config, config.examples, 'Examples')
|
||||
}
|
||||
}
|
||||
}, failFast: true
|
||||
}
|
||||
} catch(ex) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw ex
|
||||
} finally {
|
||||
if (currentBuild.result != 'SUCCESS')
|
||||
{
|
||||
config.pr.setBuildStatus(config, 'ERROR', 'Toll gate', 'Failed', '${BUILD_URL}flowGraphTable/')
|
||||
if (config.is_pull_request) {
|
||||
slackSend color: 'danger',
|
||||
message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>' failed with result ${currentBuild.result}."
|
||||
emailext (
|
||||
subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER}' failed",
|
||||
body: """Job '${env.JOB_NAME} <a href="${env.BUILD_URL}">#${env.BUILD_NUMBER}</a> (<a href="${env.CHANGE_URL}">PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}</a>)' ended with result ${currentBuild.result}.
|
||||
<br>Check attached console output or <a href="${env.BUILD_URL}">here</a> for a hint on what the problem might be.""",
|
||||
mimeType: 'text/html', to: env.CHANGE_AUTHOR_EMAIL, attachLog: true, compressLog: false
|
||||
)
|
||||
} else {
|
||||
slackSend color: 'danger',
|
||||
message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> ${env.BRANCH_NAME}]' failed with result ${currentBuild.result}."
|
||||
emailext (
|
||||
subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} ${env.BRANCH_NAME}' failed",
|
||||
body: """Job '${env.JOB_NAME} <a href="${env.BUILD_URL}">#${env.BUILD_NUMBER}</a> (${env.BRANCH_NAME})' ended with result ${currentBuild.result}.
|
||||
<br>Check attached console output or <a href="${env.BUILD_URL}">here</a> for a hint on what the problem might be.""",
|
||||
mimeType: 'text/html', to: 'builds@mysensors.org', attachLog: true, compressLog: false
|
||||
)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate', 'Pass', '')
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
16
.ci/pr-toolbox.groovy
Normal file
16
.ci/pr-toolbox.groovy
Normal file
@@ -0,0 +1,16 @@
|
||||
#!groovy
|
||||
def setBuildStatus(config, String state, String context, String message, String backref) {
|
||||
if (config.is_pull_request) {
|
||||
step([$class: 'GitHubCommitStatusSetter',
|
||||
reposSource: [$class: 'ManuallyEnteredRepositorySource', url: "https://github.com/${config.github_organization}/${config.repository_name}"],
|
||||
errorHandlers: [[$class: 'ShallowAnyErrorHandler']],
|
||||
contextSource: [$class: 'ManuallyEnteredCommitContextSource', context: context],
|
||||
commitShaSource: [$class: "ManuallyEnteredShaSource", sha: config.git_sha],
|
||||
statusBackrefSource: [$class: 'ManuallyEnteredBackrefSource', backref: backref],
|
||||
statusResultSource: [$class: 'ConditionalStatusResultSource',
|
||||
results: [[$class: 'AnyBuildResult', message: message, state: state]]]]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
40
.ci/static_analysis.groovy
Normal file
40
.ci/static_analysis.groovy
Normal file
@@ -0,0 +1,40 @@
|
||||
#!groovy
|
||||
def cppCheck(config) {
|
||||
config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Code analysis - Cppcheck)', 'Running...', '${BUILD_URL}flowGraphTable/')
|
||||
// We could consider running Cppcheck for GNU as well, but to avoid so many duplicates, we stick to AVR
|
||||
sh """#!/bin/bash +x
|
||||
cd ${config.repository_root}
|
||||
echo "Doing cppcheck for AVR..."
|
||||
git diff --name-only origin/${env.CHANGE_TARGET}..${config.git_sha} | sed '/.ci\\/gitler.sh/d' | sed '/README.md/d' | cppcheck -j 4 --file-list=- --enable=style,information --platform=.mystools/cppcheck/config/avr.xml --suppressions-list=.mystools/cppcheck/config/suppressions.cfg --includes-file=.mystools/cppcheck/config/includes.cfg --language=c++ --xml --xml-version=2 2> cppcheck-avr.xml
|
||||
cppcheck-htmlreport --file="cppcheck-avr.xml" --title="cppcheck-avr" --report-dir=cppcheck-avr_cppcheck_reports --source-dir=."""
|
||||
|
||||
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true,
|
||||
reportDir: config.repository_root+'cppcheck-avr_cppcheck_reports',
|
||||
reportFiles: 'index.html', reportName: 'CppCheck AVR', reportTitles: ''])
|
||||
|
||||
step([$class: 'ViolationsToGitHubRecorder',
|
||||
config: [
|
||||
repositoryName: config.repository_name,
|
||||
pullRequestId: env.CHANGE_ID,
|
||||
createCommentWithAllSingleFileComments: true,
|
||||
createSingleFileComments: true,
|
||||
commentOnlyChangedContent: true,
|
||||
keepOldComments: false,
|
||||
violationConfigs: [[pattern: '.*/cppcheck-avr\\.xml$', parser: 'CPPCHECK', reporter: 'Cppcheck'],]
|
||||
]
|
||||
])
|
||||
ret = sh(returnStatus: true,
|
||||
script: "#!/bin/bash +e\n"+
|
||||
"cd ${config.repository_root}\n"+
|
||||
"grep -q \"<td>0</td><td>total</td>\" cppcheck-avr_cppcheck_reports/index.html || exit_code=\$?\n"+
|
||||
"exit \$((exit_code == 0 ? 0 : 1))")
|
||||
if (ret == 1) {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Code analysis - Cppcheck)', 'Issues found (but are not considered critical)', '${BUILD_URL}CppCheck_AVR/index.html')
|
||||
//currentBuild.result = 'UNSTABLE'
|
||||
//error 'Terminating due to Cppcheck error'
|
||||
} else {
|
||||
config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Code analysis - Cppcheck)', 'Pass', '')
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
@@ -4,14 +4,14 @@ Please visit www.mysensors.org for more information
|
||||
|
||||
Doxygen
|
||||
-------
|
||||
[master](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/development/Doxygen_HTML/index.html)
|
||||
[master](https://www.mysensors.org/apidocs/index.html) [development](https://www.mysensors.org/apidocs-beta/index.html)
|
||||
|
||||
CI statuses
|
||||
-----------
|
||||
Current build status of master branch: [](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/master/)
|
||||
|
||||
Current build status of development branch: [](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/development/)
|
||||
Current build status of development branch: [](https://ci.mysensors.org/job/MySensors/job/MySensors/job/development/)
|
||||
|
||||
Current build status of master branch (nightly build of Arduino IDE): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/master/)
|
||||
|
||||
Current build status of development branch (nightly build of Arduino IDE): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/development/)
|
||||
Current build status of development branch (nightly build of Arduino IDE): [](https://ci.mysensors.org/job/MySensors-nightly-IDE/job/MySensors/job/development/)
|
||||
@@ -26,6 +26,10 @@
|
||||
#ifndef MyHw_h
|
||||
#define MyHw_h
|
||||
|
||||
/**
|
||||
* @def MY_HWID_PADDING_BYTE
|
||||
* @brief HwID padding byte
|
||||
*/
|
||||
#define MY_HWID_PADDING_BYTE (0xAAu)
|
||||
|
||||
// Implement these as functions or macros
|
||||
|
||||
Reference in New Issue
Block a user