CI/CD Integration Patterns

This guide covers common patterns for integrating the HardFOC ESP-IDF Project Tools into your CI/CD workflows, including GitHub Actions, GitLab CI, and other automation platforms.

📋 Directory Structure Concepts

Project Directory (project_dir)

  • Purpose: Points to your ESP-IDF project directory (contains CMakeLists.txt, app_config.yml)
  • Examples: examples/esp32, firmware/esp32-project, src/esp32-app

Tools Directory (project_tools_dir)

  • Purpose: Points to directory containing the build scripts (build_app.sh, generate_matrix.py, etc.)
  • Auto-detection: If not specified, looks for hf-espidf-project-tools subdirectory in project directory
  • Multi-Project Support: Can be shared across multiple projects since all scripts accept --project-path argument
  • Examples: examples/esp32/scripts, examples/esp32/hf-espidf-project-tools, tools/esp32-build-scripts, shared-tools

🏗️ Common Integration Patterns

Repository structure:

1
2
3
4
5
6
7
8
9
10
your-repo/
├── .github/workflows/          # CI workflows (at repo root)
│   └── build.yml
├── examples/esp32/             # ESP-IDF project
│   ├── CMakeLists.txt
│   ├── app_config.yml
│   └── hf-espidf-project-tools/  # Submodule containing project tools
│       ├── build_app.sh
│       └── generate_matrix.py
└── README.md

GitHub Actions workflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name: Build ESP-IDF Applications

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    uses: N3b3x/hf-espidf-ci-tools/.github/workflows/build.yml@v1
    with:
      project_dir: examples/esp32
      project_tools_dir: examples/esp32/hf-espidf-project-tools  # Points to submodule
      # auto_clone_tools not needed - workflow respects explicit project_tools_dir

✅ Benefits:

  • Automatic behavior when project_tools_dir is specified
  • No auto-cloning occurs when explicit path is provided
  • Submodule detection and validation happens automatically

Pattern 2: Direct Clone Setup

Repository structure:

1
2
3
4
5
6
7
8
9
10
your-repo/
├── .github/workflows/
│   └── build.yml
├── examples/esp32/             # ESP-IDF project
│   ├── CMakeLists.txt
│   ├── app_config.yml
│   └── hf-espidf-project-tools/  # Cloned directly
│       ├── build_app.sh
│       └── generate_matrix.py
└── README.md

GitHub Actions workflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name: Build ESP-IDF Applications

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    uses: N3b3x/hf-espidf-ci-tools/.github/workflows/build.yml@v1
    with:
      project_dir: examples/esp32
      # project_tools_dir not needed - auto-detects hf-espidf-project-tools

Pattern 3: Custom Tools Location

Repository structure:

1
2
3
4
5
6
7
8
9
your-repo/
├── .github/workflows/
│   └── build.yml
├── firmware/esp32/             # ESP-IDF project
│   ├── CMakeLists.txt
│   └── app_config.yml
└── build-tools/                # Custom tools location
    ├── build_app.sh
    └── generate_matrix.py

GitHub Actions workflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name: Build ESP-IDF Applications

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    uses: N3b3x/hf-espidf-ci-tools/.github/workflows/build.yml@v1
    with:
      project_dir: firmware/esp32
      project_tools_dir: build-tools

Pattern 4: Shared Tools for Multiple Projects

Repository structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
your-repo/
├── .github/workflows/
│   └── build.yml
├── projects/
│   ├── project-a/              # ESP-IDF project A
│   │   ├── CMakeLists.txt
│   │   └── app_config.yml
│   └── project-b/              # ESP-IDF project B
│       ├── CMakeLists.txt
│       └── app_config.yml
└── shared-tools/               # Shared tools directory
    ├── build_app.sh
    └── generate_matrix.py

GitHub Actions workflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: Build ESP-IDF Applications

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-project-a:
    uses: N3b3x/hf-espidf-ci-tools/.github/workflows/build.yml@v1
    with:
      project_dir: projects/project-a
      project_tools_dir: shared-tools  # Shared across all projects
      
  build-project-b:
    uses: N3b3x/hf-espidf-ci-tools/.github/workflows/build.yml@v1
    with:
      project_dir: projects/project-b
      project_tools_dir: shared-tools  # Same shared tools directory

🔧 Advanced Configuration

Environment Variables

1
2
3
4
env:
  ESP32_PROJECT_PATH: "examples/esp32"
  CONFIG_DEFAULT_APP: "main_app"
  CONFIG_DEFAULT_BUILD_TYPE: "Release"

Matrix Builds

1
2
3
4
5
strategy:
  matrix:
    app: ["main_app", "test_app", "demo_app"]
    build_type: ["Debug", "Release"]
    idf_version: ["release/v5.5", "release/v5.4"]

Custom Build Steps

1
2
3
4
5
6
7
8
9
10
11
- name: Setup ESP-IDF
  uses: espressif/esp-idf-ci-action@v1
  with:
    esp_idf_version: $
    target: esp32c6
    path: $

- name: Build Application
  run: |
    cd $
    ./scripts/build_app.sh $ $

🚀 Best Practices

1. Directory Structure

  • Keep ESP-IDF projects in dedicated directories (examples/, firmware/, projects/)
  • Use consistent naming conventions for tools directories
  • Document your project structure in README files

2. Version Control

  • Use submodules for production projects
  • Pin specific versions of the tools repository
  • Keep tools and project code in separate commits

3. CI/CD Optimization

  • Use matrix builds for multiple configurations
  • Cache build artifacts and dependencies
  • Run tests in parallel when possible

4. Error Handling

  • Validate project structure before building
  • Use proper error codes and exit conditions
  • Provide clear error messages for debugging

Need help with a specific pattern? Check our Examples or Troubleshooting sections for more detailed guidance.