From df19c46efe90bbd80784ef9b06f066496cc505eb Mon Sep 17 00:00:00 2001 From: shripad621git Date: Fri, 1 Dec 2023 12:40:44 +0530 Subject: [PATCH] tools/jenkins: Added the the support of jenkins in esp_matter - Added the jenkins related code for building esp-matter examples in Jenkins environment. - Added few config options to the sdkconfig to build the firware with those config options. - Generated the required artefacts and the tools required for automation purpose. --- tools/jenkins/Jenkinsfile.esp_matter.firmware | 156 +++++++++++ tools/jenkins/esp_matter.groovy | 253 ++++++++++++++++++ 2 files changed, 409 insertions(+) create mode 100644 tools/jenkins/Jenkinsfile.esp_matter.firmware create mode 100644 tools/jenkins/esp_matter.groovy diff --git a/tools/jenkins/Jenkinsfile.esp_matter.firmware b/tools/jenkins/Jenkinsfile.esp_matter.firmware new file mode 100644 index 000000000..d5941942b --- /dev/null +++ b/tools/jenkins/Jenkinsfile.esp_matter.firmware @@ -0,0 +1,156 @@ +node('master') { + stage('Choose Docker') { + script { + checkout scm + product_choices = sh (script: 'for product in ${WORKSPACE}/examples/*/main; do echo $product | sed "s="${WORKSPACE}"/examples/==" | sed "s=/main==" ; done;', returnStdout:true).trim() + echo "Product Choices: ${product_choices}" + } + } +} +pipeline { + agent { + docker { + image 'registry.hub.docker.com/shripad97/esp_matter_jenkins:latest' + alwaysPull true + } + } + options { + timeout(time: 2, unit: 'HOURS') + } + parameters { + choice(name: 'product', choices: "${product_choices}", description: 'Product choices') + choice(name: 'chip', choices:['esp32c3', 'esp32', 'esp32h2', 'esp32c2','esp32c6'], description: 'Chips') + string(name: 'esp_matter_branch', defaultValue: 'main', description: 'Branch to be used for esp-matter') + } + environment { + REPOS_PATH="/opt/espressif" + IDF_PATH="${REPOS_PATH}/esp-idf" + ESP_MATTER_PATH="${REPOS_PATH}/esp-matter" + PROJECT_VER_SUFFIX="${BUILD_NUMBER}" + } + stages { + stage('Setup') { + steps { + script { + currentBuild.displayName = "${BUILD_TAG}" + currentBuild.description = "esp-matter Setup" + } + println('Running esp-matter Setup...') + catchError() { + script { + package_name = "esp_matter_firmware_${product}_${chip}" + package_name = package_name + "_${BUILD_NUMBER}" + env.PACKAGE_NAME = package_name + env.PACKAGE_PATH = "${REPOS_PATH}/${PACKAGE_NAME}" + echo "Package name: ${PACKAGE_NAME}" + + def esp_matter = load "${WORKSPACE}/tools/jenkins/esp_matter.groovy" + esp_matter.setup_directories_firmware() + esp_matter.setup_directories_script() + esp_matter.setup_directories_tools() + esp_matter.setup_environment() + } + } + } + post { + success { + echo 'Success for setup' + } + failure { + echo 'Failure for setup' + error('Failure for setup. Abort.') + } + } + } + stage("Build product") { + steps { + println('Build ${product} product binary for ${chip}.') + catchError() { + script { + def esp_matter = load "${WORKSPACE}/tools/jenkins/esp_matter.groovy" + + env.FIRMWARE_TYPE = "Evaluation" + esp_matter.firmware_build() + esp_matter.firmware_build_save() + + } + } + } + post { + success { + echo 'Success for build product' + } + failure { + echo 'Failure for build product' + error('Failure for build product. Abort.') + } + } + } + stage("Support package") { + steps { + println('Create Support package.') + catchError() { + script { + def esp_matter = load "${WORKSPACE}/tools/jenkins/esp_matter.groovy" + esp_matter.script_artifacts_create() + esp_matter.tools_artifacts_create() + } + } + } + post { + success { + echo 'Success for script package' + } + failure { + echo 'Failure for script package' + error('Failure for script package. Abort.') + } + } + } + stage('Artifacts') { + steps { + println('Generating artifacts.') + catchError() { + script { + def esp_matter = load "${WORKSPACE}/tools/jenkins/esp_matter.groovy" + esp_matter.artifacts_save() + } + } + } + post { + success { + archiveArtifacts artifacts: 'artifacts/*.tar.gz, artifacts/*.txt', fingerprint: true + echo 'Success for artifacts' + } + failure { + echo 'Failure for artifacts' + error('Failure for artifacts. Abort.') + } + } + } + stage('Cleanup') { + steps { + echo 'Build Clean up.' + } + post { + always { + cleanWs() + } + success { + echo 'Success for cleanup' + } + failure { + echo 'Failure for cleanup' + error('Failure for cleanup. Abort.') + } + } + } + } + post { + always { + echo 'Cleanup post' + cleanWs() + } + } +} + diff --git a/tools/jenkins/esp_matter.groovy b/tools/jenkins/esp_matter.groovy new file mode 100644 index 000000000..c599f9ac6 --- /dev/null +++ b/tools/jenkins/esp_matter.groovy @@ -0,0 +1,253 @@ +def setup_directories_firmware() { + sh ''' + echo "repos path: ${REPOS_PATH}" + ls -l ${REPOS_PATH} + cd ${REPOS_PATH} + cd .. + ls -l + mkdir -p ${PACKAGE_PATH} + mkdir -p ${PACKAGE_PATH}/Firmware + mkdir -p ${PACKAGE_PATH}/Firmware/Evaluation + ''' +} + +def setup_directories_script() { + sh ''' + cd ${REPOS_PATH} + mkdir -p ${PACKAGE_PATH} + mkdir -p ${PACKAGE_PATH}/Script + ''' +} + +def setup_directories_tools() { + sh ''' + cd ${REPOS_PATH} + mkdir -p ${PACKAGE_PATH} + mkdir -p ${PACKAGE_PATH}/Tools + ''' +} + +def setup_environment() { + sh ''' + cd ${REPOS_PATH}/esp-idf + . ./export.sh + cd .. + + cd ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip + scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug chip_config_network_layer_ble=false + + IDF_BRANCH=`cd ${REPOS_PATH}/esp-idf && git rev-parse --abbrev-ref HEAD` + IDF_COMMIT_ID=`cd ${REPOS_PATH}/esp-idf && git rev-parse --verify HEAD` + ESP_MATTER_BRANCH=`cd ${REPOS_PATH}/esp-matter && git rev-parse --abbrev-ref HEAD` + ESP_MATTER_COMMIT_ID=`cd ${REPOS_PATH}/esp-matter && git rev-parse --verify HEAD` + + echo "esp-idf: ${IDF_BRANCH}: ${IDF_COMMIT_ID}" >> ${REPOS_PATH}/build_details.txt + echo "esp-matter: ${ESP_MATTER_BRANCH}: ${ESP_MATTER_COMMIT_ID}" >> ${REPOS_PATH}/build_details.txt + printf "\n\n" >> ${REPOS_PATH}/build_details.txt + + echo "product: ${product}" >> ${REPOS_PATH}/build_details.txt + echo "chip: ${chip}" >> ${REPOS_PATH}/build_details.txt + echo "flash_size: 4MB" >> ${REPOS_PATH}/build_details.txt + echo "secure_boot: enabled" >> ${REPOS_PATH}/build_details.txt + + printf "\n\n" >> ${REPOS_PATH}/build_details.txt + ''' +} + +def firmware_build() { + sh ''' + printf "\n\n" >> ${REPOS_PATH}/build_details.txt + echo "firmware_type: ${FIRMWARE_TYPE}" >> ${REPOS_PATH}/build_details.txt + + echo "product :${product} " + cd ${ESP_MATTER_PATH}/examples/${product} + SDKCONFIG_FILE=${ESP_MATTER_PATH}/examples/${product}/sdkconfig.defaults + + . ${IDF_PATH}/export.sh + . ${ESP_MATTER_PATH}/export.sh; + + idf.py fullclean + + config_option1="CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER=y" + config_option2="CONFIG_ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER=y" + config_option3="CONFIG_SEC_CERT_DAC_PROVIDER=y" + config_option4="CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n" + config_option5="CONFIG_ENABLE_OTA_REQUESTOR=y" + config_option6="CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y" + config_option7="CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y" + + if [ -e "sdkconfig.defaults.${chip}" ]; then + if ! grep -q "^${config_option1%%=*}=" "sdkconfig.defaults.${chip}"; then + echo "${config_option1}" >> "sdkconfig.defaults.${chip}" + fi + + if ! grep -q "^${config_option2%%=*}=" "sdkconfig.defaults.${chip}"; then + echo "${config_option2}" >> "sdkconfig.defaults.${chip}" + fi + + if ! grep -q "^${config_option3%%=*}=" "sdkconfig.defaults.${chip}"; then + echo "${config_option3}" >> "sdkconfig.defaults.${chip}" + fi + + if [ "${chip}" != "esp32h2" ] && ! grep -q "^${config_option4%%=*}=" "sdkconfig.defaults.${chip}"; then + echo "${config_option4}" >> "sdkconfig.defaults.${chip}" + fi + + if ! grep -q "${config_option5}" "sdkconfig.defaults.${chip}"; then + echo "${config_option5}" >> "sdkconfig.defaults.${chip}" + fi + + echo "${config_option6}" >> "sdkconfig.defaults.${chip}" + + if ! grep -q "${config_option7}" "sdkconfig.defaults.${chip}"; then + echo "${config_option7}" >> "sdkconfig.defaults.${chip}" + fi + + else + if ! grep -q "^${config_option1%%=*}=" sdkconfig.defaults; then + echo "${config_option1}" >> "sdkconfig.defaults" + fi + + if ! grep -q "^${config_option2%%=*}=" sdkconfig.defaults; then + echo "${config_option2}" >> "sdkconfig.defaults" + fi + + if ! grep -q "^${config_option3%%=*}=" sdkconfig.defaults; then + echo "${config_option3}" >> "sdkconfig.defaults" + fi + + if ! grep -q "^${config_option4%%=*}=" sdkconfig.defaults; then + echo "${config_option4}" >> "sdkconfig.defaults" + fi + + if ! grep -q "${config_option5}" "sdkconfig.defaults"; then + echo "${config_option5}" >> "sdkconfig.defaults" + fi + + echo "${config_option6}" >> "sdkconfig.defaults" + + if ! grep -q "${config_option7}" "sdkconfig.defaults"; then + echo "${config_option7}" >> "sdkconfig.defaults" + fi + fi + + idf.py set-target ${chip} + + cat sdkconfig + idf.py build + ''' +} + +def firmware_build_save() { + sh ''' + PACKAGE_FIRMWARE_PATH=${PACKAGE_PATH}/Firmware/${FIRMWARE_TYPE} + cd ${ESP_MATTER_PATH}/examples/${product} + + mkdir -p ${PACKAGE_FIRMWARE_PATH}/build + mkdir -p ${PACKAGE_FIRMWARE_PATH}/build/bootloader + mkdir -p ${PACKAGE_FIRMWARE_PATH}/build/partition_table + + cp build/${product}.bin ${PACKAGE_FIRMWARE_PATH}/build/${product}.bin + cp build/bootloader/bootloader.bin ${PACKAGE_FIRMWARE_PATH}/build/bootloader/bootloader.bin + cp build/partition_table/partition-table.bin ${PACKAGE_FIRMWARE_PATH}/build/partition_table/partition-table.bin + cp build/ota_data_initial.bin ${PACKAGE_FIRMWARE_PATH}/build/ota_data_initial.bin + + cp build/${product}.elf ${PACKAGE_FIRMWARE_PATH}/build/${product}.elf + cp build/${product}.map ${PACKAGE_FIRMWARE_PATH}/build/${product}.map + + # Helper files + echo -n "${FILE_PREFIX}" >> ${PACKAGE_FIRMWARE_PATH}/file_prefix_ota_0.txt + echo -n "${FILE_PREFIX}" >> ${PACKAGE_FIRMWARE_PATH}/file_prefix_bootloader.txt + + # json + cp build/project_description.json ${PACKAGE_FIRMWARE_PATH}/build/project_description.json + cp build/flasher_args.json ${PACKAGE_FIRMWARE_PATH}/build/flasher_args.json + + ''' +} + +def script_artifacts_create() { + sh ''' + PACKAGE_SCRIPT_PATH=${PACKAGE_PATH}/Script + SCRIPTS_DIRECTORY_NAME=manufacturing_scripts + SCRIPTS_PATH=${PACKAGE_SCRIPT_PATH}/${SCRIPTS_DIRECTORY_NAME} + mkdir -p ${SCRIPTS_PATH} + + # esp-idf + mkdir -p ${SCRIPTS_PATH}/esp-idf + mkdir -p ${SCRIPTS_PATH}/esp-idf/components + mkdir -p ${SCRIPTS_PATH}/esp-idf/components/nvs_flash + cp -r ${IDF_PATH}/components/nvs_flash/nvs_partition_generator ${SCRIPTS_PATH}/esp-idf/components/nvs_flash/ + + mkdir -p ${SCRIPTS_PATH}/esp-idf/tools + cp -r ${IDF_PATH}/tools/mass_mfg ${SCRIPTS_PATH}/esp-idf/tools/ + + # esp-matter + mkdir -p ${SCRIPTS_PATH}/esp-matter + mkdir -p ${SCRIPTS_PATH}/esp-matter/tools + cp -r ${ESP_MATTER_PATH}/tools/mfg_tool ${SCRIPTS_PATH}/esp-matter/tools/ + + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/scripts + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/scripts/tools + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/scripts/tools/spake2p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/scripts/tools + + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/src + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/setup_payload + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/src/setup_payload/python ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/setup_payload + + mkdir -p ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/credentials + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/credentials/test ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/credentials + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/credentials/production ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/credentials + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/credentials/development ${SCRIPTS_PATH}/esp-matter/connectedhomeip/connectedhomeip/credentials + + # script_description + mkdir -p ${SCRIPTS_PATH}/script_description + cp ${SCRIPTS_PATH}/esp-matter/tools/mfg_tool/requirements.txt ${SCRIPTS_PATH}/script_description/ + cp ${SCRIPTS_PATH}/esp-matter/tools/mfg_tool/README.md ${SCRIPTS_PATH}/script_description/ + ''' +} + +def tools_artifacts_create() { + sh ''' + PACKAGE_TOOLS_PATH=${PACKAGE_PATH}/Tools + TOOL_DIRECTORY_NAME=chip-tool + TOOL_PATH=${PACKAGE_TOOLS_PATH}/${TOOL_DIRECTORY_NAME} + mkdir -p ${TOOL_PATH} + + cp ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/out/host/chip-tool ${TOOL_PATH}/ + + TOOL_DIRECTORY_NAME=chip-cert + TOOL_PATH=${PACKAGE_TOOLS_PATH}/${TOOL_DIRECTORY_NAME} + mkdir -p ${TOOL_PATH} + + cp ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/out/host/chip-cert ${TOOL_PATH}/ + + TOOL_DIRECTORY_NAME=chip-ota-provider-app + TOOL_PATH=${PACKAGE_TOOLS_PATH}/${TOOL_DIRECTORY_NAME} + mkdir -p ${TOOL_PATH} + + cp ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/out/debug/chip-ota-provider-app ${TOOL_PATH}/ + + # esp-matter + mkdir -p ${TOOL_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/app + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/src/app/ota_image_tool.py ${TOOL_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/app + + mkdir -p ${TOOL_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/controller + cp -r ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip/src/controller/python ${TOOL_PATH}/esp-matter/connectedhomeip/connectedhomeip/src/controller + ''' +} + +def artifacts_save() { + sh ''' + cd ${REPOS_PATH} + cp build_details.txt ${PACKAGE_NAME}/ + + mkdir ${WORKSPACE}/artifacts + cp build_details.txt ${WORKSPACE}/artifacts/ + tar -zcvf ${WORKSPACE}/artifacts/${PACKAGE_NAME}.tar.gz ${PACKAGE_NAME} + ''' +} + +return this