298 lines
10 KiB
YAML
298 lines
10 KiB
YAML
name: "KiBot PCB Generation with Multi-layer Support"
|
|
|
|
# Controls when the action will run. Triggers the workflow on push or pull request
|
|
# events but only for the master branch
|
|
on:
|
|
push:
|
|
paths:
|
|
- '**/*.kicad_sch'
|
|
- '**/*.kicad_pcb'
|
|
- '**/*.kicad_pro'
|
|
- '**/*.kibot.yaml'
|
|
- '**/kibot.yaml'
|
|
- '.gitea/workflows/*.yml'
|
|
pull_request:
|
|
paths:
|
|
- '**/*.kicad_sch'
|
|
- '**/*.kicad_pcb'
|
|
- '**/*.kicad_pro'
|
|
- '**/*.kibot.yaml'
|
|
- '**/kibot.yaml'
|
|
- '.gitea/workflows/*.yml'
|
|
repository_dispatch:
|
|
types: [run_qs]
|
|
workflow_dispatch:
|
|
inputs:
|
|
board_layers:
|
|
description: 'Number of PCB layers (auto-detect if not specified)'
|
|
required: false
|
|
default: 'auto'
|
|
type: choice
|
|
options:
|
|
- auto
|
|
- 2
|
|
- 4
|
|
- 6
|
|
|
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
jobs:
|
|
generate:
|
|
runs-on: kicad-kibot-runner
|
|
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
with:
|
|
# So we can run a diff between last 2 changes
|
|
fetch-depth: '0'
|
|
|
|
- name: Find KiCad project
|
|
id: find_project
|
|
run: |
|
|
# Find all .kicad_pcb files in the repository
|
|
PCB_FILES=$(find . -name "*.kicad_pcb" -type f | grep -v -E '/(backups?|backup|old|archive|deprecated)/' | head -5)
|
|
|
|
if [ -z "$PCB_FILES" ]; then
|
|
echo "Error: No KiCad PCB files found"
|
|
exit 1
|
|
fi
|
|
|
|
# Use the first PCB file found
|
|
PCB_FILE=$(echo "$PCB_FILES" | head -1)
|
|
PROJECT_DIR=$(dirname "$PCB_FILE")
|
|
PROJECT_NAME=$(basename "$PCB_FILE" .kicad_pcb)
|
|
|
|
echo "Found KiCad project: $PROJECT_NAME"
|
|
echo "Project directory: $PROJECT_DIR"
|
|
echo "PCB file: $PCB_FILE"
|
|
|
|
# Find schematic file
|
|
SCH_FILE=$(find "$PROJECT_DIR" -name "*.kicad_sch" -o -name "*.sch" | head -1)
|
|
|
|
echo "pcb_file=$PCB_FILE" >> $GITHUB_OUTPUT
|
|
echo "project_dir=$PROJECT_DIR" >> $GITHUB_OUTPUT
|
|
echo "project_name=$PROJECT_NAME" >> $GITHUB_OUTPUT
|
|
echo "sch_file=$SCH_FILE" >> $GITHUB_OUTPUT
|
|
|
|
# List all found projects for debugging
|
|
echo "All PCB files found:"
|
|
echo "$PCB_FILES"
|
|
|
|
- name: Detect layer count
|
|
id: layers
|
|
run: |
|
|
PCB_FILE="${{ steps.find_project.outputs.pcb_file }}"
|
|
if [ "${{ github.event.inputs.board_layers }}" != "" ] && [ "${{ github.event.inputs.board_layers }}" != "auto" ]; then
|
|
echo "layers=${{ github.event.inputs.board_layers }}" >> $GITHUB_OUTPUT
|
|
echo "Using manually specified ${{ github.event.inputs.board_layers }} layer configuration"
|
|
else
|
|
# Create Python script to detect layers
|
|
cat > /tmp/detect_layers.py << 'PYTHON_SCRIPT'
|
|
#!/usr/bin/env python3
|
|
import re
|
|
import sys
|
|
|
|
try:
|
|
pcb_file = sys.argv[1]
|
|
with open(pcb_file, 'r') as f:
|
|
content = f.read()
|
|
# Find all copper layers
|
|
copper_layers = re.findall(r'\(layer\s+"([^"]+)".*?\(type\s+"?copper"?\)', content, re.DOTALL)
|
|
# Count inner layers (In1.Cu, In2.Cu, etc)
|
|
inner_layers = [l for l in copper_layers if 'In' in l and '.Cu' in l]
|
|
total = 2 + len(inner_layers) # F.Cu + B.Cu + inner layers
|
|
print(total)
|
|
except Exception as e:
|
|
print(2) # Default to 2 layers
|
|
PYTHON_SCRIPT
|
|
|
|
chmod +x /tmp/detect_layers.py
|
|
LAYERS=$(/tmp/detect_layers.py "$PCB_FILE")
|
|
echo "layers=$LAYERS" >> $GITHUB_OUTPUT
|
|
echo "Auto-detected $LAYERS layer board"
|
|
fi
|
|
|
|
- name: Check for KiBot config
|
|
id: config_check
|
|
run: |
|
|
PROJECT_DIR="${{ steps.find_project.outputs.project_dir }}"
|
|
|
|
# Search for kibot config in multiple locations
|
|
if [ -f "$PROJECT_DIR/kibot.yaml" ]; then
|
|
echo "found=true" >> $GITHUB_OUTPUT
|
|
echo "config_path=$PROJECT_DIR/kibot.yaml" >> $GITHUB_OUTPUT
|
|
echo "Using project-specific kibot.yaml"
|
|
elif [ -f "$PROJECT_DIR/../kibot.yaml" ]; then
|
|
echo "found=true" >> $GITHUB_OUTPUT
|
|
echo "config_path=$PROJECT_DIR/../kibot.yaml" >> $GITHUB_OUTPUT
|
|
echo "Using parent directory kibot.yaml"
|
|
elif [ -f "kibot.yaml" ]; then
|
|
echo "found=true" >> $GITHUB_OUTPUT
|
|
echo "config_path=kibot.yaml" >> $GITHUB_OUTPUT
|
|
echo "Using root kibot.yaml"
|
|
elif [ -f ".kibot/config.yaml" ]; then
|
|
echo "found=true" >> $GITHUB_OUTPUT
|
|
echo "config_path=.kibot/config.yaml" >> $GITHUB_OUTPUT
|
|
echo "Using .kibot/config.yaml"
|
|
else
|
|
echo "found=false" >> $GITHUB_OUTPUT
|
|
echo "Using --quick-start mode (no custom config found)"
|
|
fi
|
|
|
|
- name: Run ERC
|
|
if: steps.config_check.outputs.found == 'true'
|
|
run: |
|
|
cd "${{ steps.find_project.outputs.project_dir }}"
|
|
CONFIG_PATH="../${{ steps.config_check.outputs.config_path }}"
|
|
CONFIG_PATH=$(realpath "$CONFIG_PATH")
|
|
|
|
if [ -n "${{ steps.find_project.outputs.sch_file }}" ]; then
|
|
echo "Running ERC on schematic files..."
|
|
kibot -c "$CONFIG_PATH" -s run_erc -v || true
|
|
else
|
|
echo "No schematic files found, skipping ERC"
|
|
fi
|
|
continue-on-error: true
|
|
|
|
- name: Run DRC
|
|
if: steps.config_check.outputs.found == 'true'
|
|
run: |
|
|
cd "${{ steps.find_project.outputs.project_dir }}"
|
|
CONFIG_PATH="../${{ steps.config_check.outputs.config_path }}"
|
|
CONFIG_PATH=$(realpath "$CONFIG_PATH")
|
|
|
|
echo "Running DRC on PCB..."
|
|
kibot -c "$CONFIG_PATH" -s run_drc -v || true
|
|
continue-on-error: true
|
|
|
|
- name: Generate outputs with custom config
|
|
if: steps.config_check.outputs.found == 'true'
|
|
run: |
|
|
cd "${{ steps.find_project.outputs.project_dir }}"
|
|
CONFIG_PATH="../${{ steps.config_check.outputs.config_path }}"
|
|
CONFIG_PATH=$(realpath "$CONFIG_PATH")
|
|
|
|
echo "Generating outputs for ${{ steps.layers.outputs.layers }} layer board"
|
|
echo "Project: ${{ steps.find_project.outputs.project_name }}"
|
|
|
|
# Run KiBot with the configuration
|
|
kibot -c "$CONFIG_PATH" -d Fabrication -v
|
|
|
|
# Move outputs to root Generated folder
|
|
mkdir -p ../Generated
|
|
if [ -d "Fabrication" ]; then
|
|
cp -r Fabrication/* ../Generated/
|
|
fi
|
|
cd ..
|
|
|
|
- name: Quick Start fallback
|
|
if: steps.config_check.outputs.found == 'false'
|
|
run: |
|
|
cd "${{ steps.find_project.outputs.project_dir }}"
|
|
echo "Running KiBot in quick-start mode"
|
|
kibot --quick-start
|
|
|
|
# Move outputs to root Generated folder
|
|
if [ -d "Generated" ]; then
|
|
mv Generated ../
|
|
else
|
|
mkdir -p ../Generated
|
|
echo "No Generated folder found after quick-start"
|
|
fi
|
|
cd ..
|
|
|
|
- name: Add layer information to outputs
|
|
run: |
|
|
echo "Board configuration: ${{ steps.layers.outputs.layers }} layers" > Generated/board_info.txt
|
|
echo "Project: ${{ steps.find_project.outputs.project_name }}" >> Generated/board_info.txt
|
|
echo "Project path: ${{ steps.find_project.outputs.project_dir }}" >> Generated/board_info.txt
|
|
echo "Generated on: $(date)" >> Generated/board_info.txt
|
|
echo "Commit: ${{ github.sha }}" >> Generated/board_info.txt
|
|
|
|
- name: Fix file permissions
|
|
run: |
|
|
chmod -R a+rw Generated || true
|
|
|
|
- name: Retrieve results - All outputs
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: Automatic_outputs
|
|
path: Generated
|
|
|
|
- name: Retrieve results - Gerbers
|
|
if: steps.config_check.outputs.found == 'true'
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: Gerbers-${{ steps.layers.outputs.layers }}layer
|
|
path: Generated/Gerbers
|
|
|
|
- name: Retrieve results - Assembly
|
|
if: steps.config_check.outputs.found == 'true'
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: Assembly-${{ steps.layers.outputs.layers }}layer
|
|
path: Generated/Assembly
|
|
|
|
- name: Retrieve results - 3D Model
|
|
if: steps.config_check.outputs.found == 'true'
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: 3D-Model
|
|
path: Generated/3D
|
|
|
|
- name: Retrieve results - Fabrication Package
|
|
if: steps.config_check.outputs.found == 'true'
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: Fabrication-Package-${{ steps.layers.outputs.layers }}layer
|
|
path: Generated/*.zip
|
|
|
|
# This step is to upload the results to another repo (web pages)
|
|
deploy:
|
|
runs-on: kicad-kibot-runner
|
|
needs: generate
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Retrieve results
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: Automatic_outputs
|
|
path: Generated
|
|
|
|
- name: Disable Jekyll
|
|
# Jekyll will filter the KiRi folders
|
|
run: |
|
|
touch Generated/.nojekyll
|
|
|
|
- name: Push to docu branch
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
# Set up git identity
|
|
git config --global user.email "${{ gitea.actor }}@noreply.localhost"
|
|
git config --global user.name "${{ gitea.actor }}"
|
|
|
|
# Get the repository URL and add authentication
|
|
REPO_URL=$(git config --get remote.origin.url)
|
|
AUTHED_URL=${REPO_URL/https:\/\//https:\/\/${GITEA_TOKEN}@}
|
|
|
|
# Clone the docu branch into a separate folder
|
|
git clone --depth 1 --branch docu "$AUTHED_URL" docu-branch || \
|
|
git clone --depth 1 "$AUTHED_URL" docu-branch
|
|
|
|
cd docu-branch
|
|
git checkout -B docu
|
|
|
|
# Clean old contents and copy new files
|
|
rm -rf ./*
|
|
cp -r ../Generated/* ./
|
|
|
|
# Commit and push if there are changes
|
|
git add .
|
|
if ! git diff --cached --quiet; then
|
|
git commit -m "chore: update deployed documentation for ${{ needs.generate.outputs.layers }}-layer board"
|
|
git push --force "$AUTHED_URL" docu
|
|
else
|
|
echo "No changes to deploy"
|
|
fi |