diff --git a/.gitea/workflows/kibot.yml b/.gitea/workflows/kibot.yml new file mode 100644 index 0000000..84ddadc --- /dev/null +++ b/.gitea/workflows/kibot.yml @@ -0,0 +1,541 @@ +name: "KiBot PCB Generation" + +# Controls when the action will run +on: + push: + paths: + - '**/*.kicad_sch' + - '**/*.kicad_pcb' + - '**/*.kicad_pro' + - 'kibot.yaml' + - '.gitea/workflows/*.yml' + pull_request: + paths: + - '**/*.kicad_sch' + - '**/*.kicad_pcb' + - '**/*.kicad_pro' + - 'kibot.yaml' + - '.gitea/workflows/*.yml' + repository_dispatch: + types: [run_qs] + workflow_dispatch: + inputs: + board_layers: + description: 'Number of PCB layers' + required: false + default: '4' + type: choice + options: + - '2' + - '4' + - '6' + diff_old: + description: 'Old revision for diff (e.g., HEAD~1, commit hash, tag)' + required: false + default: 'HEAD~1' + type: string + diff_new: + description: 'New revision for diff (e.g., HEAD, commit hash, tag)' + required: false + default: 'HEAD' + type: string + enable_interactive_diff: + description: 'Generate interactive HTML diff' + required: false + default: false + type: boolean + +# 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: + # Fetch full history for diff generation + 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: Set layer count + id: layers + run: | + # Use workflow input or default to 4 layers + LAYERS="${{ github.event.inputs.board_layers }}" + if [ -z "$LAYERS" ]; then + LAYERS="4" + fi + echo "layers=$LAYERS" >> $GITHUB_OUTPUT + echo "Using $LAYERS layer configuration" + + - name: Check for KiBot config + id: config_check + run: | + # Check if kibot.yaml exists in repository root + if [ -f "kibot.yaml" ]; then + echo "found=true" >> $GITHUB_OUTPUT + echo "Using kibot.yaml configuration from repository root" + else + echo "found=false" >> $GITHUB_OUTPUT + echo "No kibot.yaml found in repository root - will use --quick-start mode" + fi + + - name: Generate schematic diff + id: generate_diff + if: github.event_name == 'push' || github.event_name == 'pull_request' + run: | + PROJECT_DIR="${{ steps.find_project.outputs.project_dir }}" + PROJECT_NAME="${{ steps.find_project.outputs.project_name }}" + + # Create DIFF output directory + mkdir -p "${GITHUB_WORKSPACE}/Generated/DIFF" + cd "$PROJECT_DIR" + + # Get the previous commit hash + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE_SHA="${{ github.event.pull_request.base.sha }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + else + # For push events, compare with previous commit + HEAD_SHA="${{ github.sha }}" + BASE_SHA=$(git rev-parse HEAD~1 2>/dev/null || echo "") + fi + + if [ -z "$BASE_SHA" ]; then + echo "No previous commit found for comparison" + echo "has_diff=false" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "Comparing commits: $BASE_SHA...$HEAD_SHA" + + # Find all schematic files + SCH_FILES=$(find . -name "*.kicad_sch" -o -name "*.sch" | head -10) + + if [ -z "$SCH_FILES" ]; then + echo "No schematic files found" + echo "has_diff=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # Generate diff for each schematic + DIFF_GENERATED=false + for SCH_FILE in $SCH_FILES; do + SCH_NAME=$(basename "$SCH_FILE" | sed 's/\.[^.]*$//') + + # Check if file changed between commits + if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -q "$SCH_FILE"; then + echo "Generating diff for $SCH_FILE" + + # Create temp directory for processing + TEMP_DIR=$(mktemp -d) + + # Export old version + git show "$BASE_SHA:$SCH_FILE" > "$TEMP_DIR/${SCH_NAME}_old.kicad_sch" 2>/dev/null || continue + + # Copy current version + cp "$SCH_FILE" "$TEMP_DIR/${SCH_NAME}_new.kicad_sch" + + # Try to use kidiff if available (better visual diff tool for KiCad) + if command -v kidiff &> /dev/null; then + kidiff -o "${GITHUB_WORKSPACE}/Generated/DIFF/${SCH_NAME}_diff.pdf" \ + "$TEMP_DIR/${SCH_NAME}_old.kicad_sch" \ + "$TEMP_DIR/${SCH_NAME}_new.kicad_sch" || true + fi + + # Also generate text diff + git diff "$BASE_SHA" "$HEAD_SHA" -- "$SCH_FILE" > "${GITHUB_WORKSPACE}/Generated/DIFF/${SCH_NAME}_changes.txt" + + # Generate a simple HTML diff for easy viewing + cat > "${GITHUB_WORKSPACE}/Generated/DIFF/${SCH_NAME}_diff.html" << EOF + + + + Schematic Diff: ${SCH_NAME} + + + +

Schematic Changes: ${SCH_NAME}

+
Commit: ${BASE_SHA:0:8} → ${HEAD_SHA:0:8}
+
+        EOF
+            
+            # Add the diff content with HTML escaping
+            git diff "$BASE_SHA" "$HEAD_SHA" -- "$SCH_FILE" | \
+              sed 's/&/\&/g; s//\>/g' | \
+              sed 's/^+[^+].*/&<\/span>/g' | \
+              sed 's/^-[^-].*/&<\/span>/g' >> "${GITHUB_WORKSPACE}/Generated/DIFF/${SCH_NAME}_diff.html"
+            
+            echo "
" >> "${GITHUB_WORKSPACE}/Generated/DIFF/${SCH_NAME}_diff.html" + + rm -rf "$TEMP_DIR" + DIFF_GENERATED=true + fi + done + + # Generate PCB diff if PCB file changed + PCB_FILE="${{ steps.find_project.outputs.pcb_file }}" + if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -q "$PCB_FILE"; then + echo "Generating PCB diff" + PCB_NAME=$(basename "$PCB_FILE" | sed 's/\.[^.]*$//') + + # Generate text diff for PCB + git diff "$BASE_SHA" "$HEAD_SHA" -- "$PCB_FILE" > "${GITHUB_WORKSPACE}/Generated/DIFF/${PCB_NAME}_pcb_changes.txt" + + # Summary of changes + git diff --stat "$BASE_SHA" "$HEAD_SHA" -- "$PCB_FILE" > "${GITHUB_WORKSPACE}/Generated/DIFF/${PCB_NAME}_pcb_summary.txt" + + DIFF_GENERATED=true + fi + + # Create a summary file + cat > "${GITHUB_WORKSPACE}/Generated/DIFF/README.md" << EOF + # KiCad Project Diff Report + + **Base Commit:** ${BASE_SHA:0:8} + **Head Commit:** ${HEAD_SHA:0:8} + **Date:** $(date) + + ## Changed Files: + $(git diff --name-status "$BASE_SHA" "$HEAD_SHA" -- "*.kicad_sch" "*.sch" "*.kicad_pcb" "*.pcb") + + ## Summary: + $(git diff --stat "$BASE_SHA" "$HEAD_SHA" -- "*.kicad_sch" "*.sch" "*.kicad_pcb" "*.pcb") + + ## Commit Messages: + $(git log --oneline "$BASE_SHA".."$HEAD_SHA") + EOF + + if [ "$DIFF_GENERATED" = true ]; then + echo "has_diff=true" >> $GITHUB_OUTPUT + else + echo "No schematic or PCB changes detected" + echo "has_diff=false" >> $GITHUB_OUTPUT + fi + + - name: Run ERC + if: steps.config_check.outputs.found == 'true' + run: | + cd "${{ steps.find_project.outputs.project_dir }}" + + # Clean up any existing output directories + rm -rf Fabrication Generated Output + + if [ -n "${{ steps.find_project.outputs.sch_file }}" ]; then + echo "Running ERC on schematic files..." + # Use absolute path to config file in repo root + # Skip ERC step in preflight to avoid stopping on errors + kibot -c "${GITHUB_WORKSPACE}/kibot.yaml" -s run_erc,run_drc -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 }}" + + echo "Running DRC on PCB..." + # Use absolute path to config file in repo root + # Skip both ERC and DRC in preflight to avoid stopping on errors + kibot -c "${GITHUB_WORKSPACE}/kibot.yaml" -s run_erc,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 }}" + + echo "Generating outputs for ${{ steps.layers.outputs.layers }} layer board" + echo "Project: ${{ steps.find_project.outputs.project_name }}" + echo "Using config: ${GITHUB_WORKSPACE}/kibot.yaml" + + # First, let's check what's in the current directory + echo "Current directory contents:" + ls -la + + # Check if Fabrication exists and what it is + if [ -e "Fabrication" ]; then + echo "Fabrication exists as:" + file Fabrication + echo "Removing it..." + rm -rf Fabrication + fi + + # Create a temporary modified config without the global output setting + cp "${GITHUB_WORKSPACE}/kibot.yaml" /tmp/kibot_temp.yaml + + # Remove or comment out the global output line if it exists + sed -i 's/^ output:.*$/ # output: commented out for workflow/' /tmp/kibot_temp.yaml + + # Update diff revisions if specified + if [ -n "${{ github.event.inputs.diff_old }}" ]; then + sed -i "s/old: 'HEAD~1'/old: '${{ github.event.inputs.diff_old }}'/" /tmp/kibot_temp.yaml + fi + if [ -n "${{ github.event.inputs.diff_new }}" ]; then + sed -i "s/new: 'HEAD'/new: '${{ github.event.inputs.diff_new }}'/" /tmp/kibot_temp.yaml + fi + + # Use a timestamp-based directory to ensure uniqueness + OUTPUT_DIR="kibot_output_$(date +%s)" + + # Determine which outputs to run + EXTRA_OUTPUTS="" + if [ "${{ github.event.inputs.enable_interactive_diff }}" = "true" ]; then + EXTRA_OUTPUTS="interactive_diff svg_diff" + fi + + # Run KiBot with the modified configuration + # Skip ERC/DRC preflight checks to avoid stopping on errors + echo "Running KiBot with output directory: $OUTPUT_DIR" + + # Run all outputs (KiBot will run all by default when no specific outputs are listed) + # Only add extra outputs if interactive diff is enabled + if [ "${{ github.event.inputs.enable_interactive_diff }}" = "true" ]; then + # Run with interactive diff outputs explicitly enabled + kibot -c /tmp/kibot_temp.yaml -s run_erc,run_drc -d "$OUTPUT_DIR" -v interactive_diff svg_diff + else + # Run all default outputs (everything with run_by_default: true) + kibot -c /tmp/kibot_temp.yaml -s run_erc,run_drc -d "$OUTPUT_DIR" -v + fi + + # Move outputs to root Generated folder + mkdir -p "${GITHUB_WORKSPACE}/Generated" + if [ -d "$OUTPUT_DIR" ]; then + echo "Copying outputs from $OUTPUT_DIR to Generated/" + cp -r "$OUTPUT_DIR"/* "${GITHUB_WORKSPACE}/Generated/" + rm -rf "$OUTPUT_DIR" + elif [ -d "Fabrication" ]; then + echo "KiBot used default Fabrication directory, copying from there" + cp -r Fabrication/* "${GITHUB_WORKSPACE}/Generated/" + rm -rf Fabrication + else + echo "Warning: No output directory was created" + fi + + - name: Check downloaded datasheets + if: steps.config_check.outputs.found == 'true' + continue-on-error: true + run: | + echo "Checking for downloaded datasheets..." + + # KiBot should download datasheets to the configured directory + # Check if datasheets were downloaded + if [ -d "${GITHUB_WORKSPACE}/Generated/Datasheets" ]; then + echo "Datasheets folder found in Generated/" + + # Create README + cat > "${GITHUB_WORKSPACE}/Generated/Datasheets/README.md" << EOF + # Component Datasheets + + This folder contains downloaded datasheets for all components in the project. + + Organized by component type: + - **ICs/** - Integrated circuits (U references) + - **Capacitors/** - Capacitors (C references) + - **Resistors/** - Resistors (R references) + - **Transistors/** - Transistors (Q references) + - **Diodes/** - Diodes (D references) + - **Connectors/** - Connectors (J, P references) + - **Inductors/** - Inductors (L references) + - And more... + + Files are named: REFERENCE_VALUE.pdf (e.g., U1_LM7805.pdf) + + Generated on: $(date) + Project: ${{ steps.find_project.outputs.project_name }} + EOF + + echo "Datasheet folder structure:" + find "${GITHUB_WORKSPACE}/Generated/Datasheets" -type f -name "*.pdf" | head -20 + + # Count PDFs + PDF_COUNT=$(find "${GITHUB_WORKSPACE}/Generated/Datasheets" -type f -name "*.pdf" | wc -l) + echo "Total PDFs downloaded: $PDF_COUNT" + else + echo "No Datasheets folder found - KiBot may not have downloaded any datasheets" + echo "Check that components have valid Datasheet URLs in the schematic" + fi + + - 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 + mkdir -p "${GITHUB_WORKSPACE}/Generated" + if [ -d "Generated" ]; then + cp -r Generated/* "${GITHUB_WORKSPACE}/Generated/" + fi + + - name: Add board 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 - BOM + if: steps.config_check.outputs.found == 'true' + uses: actions/upload-artifact@v3 + with: + name: BOM-${{ steps.layers.outputs.layers }}layer + path: Generated/BoM + + - name: Retrieve results - Datasheets + if: steps.config_check.outputs.found == 'true' + uses: actions/upload-artifact@v3 + with: + name: Datasheets + path: Generated/Datasheets + + - 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 + + - name: Retrieve results - JLCPCB Package + if: steps.config_check.outputs.found == 'true' + uses: actions/upload-artifact@v3 + with: + name: JLCPCB-${{ steps.layers.outputs.layers }}layer + path: Generated/*_JLCPCB_compress.zip + + - name: Retrieve results - Interactive Viewers + if: steps.config_check.outputs.found == 'true' + uses: actions/upload-artifact@v3 + with: + name: Interactive-Viewers + path: Generated/Interactive + + - name: Retrieve results - Diff Report + if: steps.generate_diff.outputs.has_diff == 'true' + uses: actions/upload-artifact@v3 + with: + name: Schematic-PCB-Diff + path: Generated/DIFF + + # Deploy to documentation branch + 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" + git push --force "$AUTHED_URL" docu + else + echo "No changes to deploy" + fi \ No newline at end of file diff --git a/.gitea/workflows/kibot_quick_start.yml b/.gitea/workflows/kibot_quick_start.yml deleted file mode 100644 index 0e3a562..0000000 --- a/.gitea/workflows/kibot_quick_start.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: "Variants demo using --quick-start" - -# 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/c64psu/*.kicad_sch' - - 'kicad/c64psu/*.kicad_pcb' - - '.gitea/workflows/kibot_quick_start.yml' - pull_request: - paths: - - 'kicad/c64psu/*.kicad_sch' - - 'kicad/c64psu/*.kicad_pcb' - - '.gitea/workflows/kibot_quick_start.yml' - repository_dispatch: - types: [run_qs] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - quick-start: - 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: Quick Start - run: | - kibot --quick-start - - - name: Retrieve results - uses: actions/upload-artifact@v3 - with: - name: Automatic_outputs - path: Generated - - # This step is to upload the results to another repo (web pages) - deploy: - runs-on: kicad-kibot-runner - needs: quick-start - - 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" - git push --force "$AUTHED_URL" docu - else - echo "No changes to deploy" - fi \ No newline at end of file diff --git a/kibot.yaml b/kibot.yaml new file mode 100644 index 0000000..3997525 --- /dev/null +++ b/kibot.yaml @@ -0,0 +1,622 @@ +# KiBot configuration for 2/4/6 layer boards +# Works with Gitea CI/CD pipeline + +kibot: + version: 1 + +global: + # Filters for ERC/DRC warnings + filters: + - number: 1007 + - number: 1015 + - number: 58 + - number: 61 + + # Default output directory - will be overridden by command line + # output: 'Fabrication' # Commented out to use command line option + + # Variant for assembly if needed + variant: '' + + # Date format for filenames + date_format: '%Y-%m-%d_%H-%M-%S' + +preflight: + run_erc: true + run_drc: true + check_zone_fills: true + ignore_unconnected: false + update_xml: true + erc: + warnings_as_errors: false + # Continue even if ERC fails + dont_stop: true + drc: + warnings_as_errors: false + # Continue even if DRC fails + dont_stop: true + +outputs: + # Schematic outputs + - name: 'print_sch' + comment: "Schematic PDF" + type: pdf_sch_print + dir: Schematic + options: + output: '%f-schematic.%x' + + - name: 'print_sch_svg' + comment: "Schematic SVG" + type: svg_sch_print + dir: Schematic + options: + output: '%f-schematic.%x' + + # PCB 2D renders + - name: 'pcb_top' + comment: "PCB render top" + type: pcbdraw + dir: PCB/2D_render + options: + output: '%f-top.%x' + format: svg + show_components: all + dpi: 300 + + - name: 'pcb_bottom' + comment: "PCB render bottom" + type: pcbdraw + dir: PCB/2D_render + options: + output: '%f-bottom.%x' + format: svg + bottom: true + show_components: all + dpi: 300 + + # PCB PDF documentation + - name: 'print_pcb' + comment: "PCB PDF" + type: pdf_pcb_print + dir: PCB/PDF + options: + output: '%f-pcb.%x' + plot_sheet_reference: true + monochrome: false + pages: + - layers: + - F.Cu + - F.Paste + - F.Silkscreen + - Edge.Cuts + sheet: 'Front copper' + - layers: + - B.Cu + - B.Paste + - B.Silkscreen + - Edge.Cuts + mirror: true + sheet: 'Bottom copper' + - layers: + - In1.Cu + - Edge.Cuts + sheet: 'Inner layer 1' + skip_if_no_layer: true + - layers: + - In2.Cu + - Edge.Cuts + sheet: 'Inner layer 2' + skip_if_no_layer: true + - layers: + - In3.Cu + - Edge.Cuts + sheet: 'Inner layer 3' + skip_if_no_layer: true + - layers: + - In4.Cu + - Edge.Cuts + sheet: 'Inner layer 4' + skip_if_no_layer: true + + # Gerber files - automatically handles 2/4/6 layers + - name: 'gerbers' + comment: "Gerber files" + type: gerber + dir: Gerbers + options: + output: '%f%i.%x' + exclude_edge_layer: true + exclude_pads_from_silkscreen: true + plot_sheet_reference: false + plot_footprint_refs: true + plot_footprint_values: false + force_plot_invisible_refs_vals: false + tent_vias: true + use_protel_extensions: false + create_gerber_job_file: true + disable_aperture_macros: true + gerber_precision: 4.6 + use_gerber_x2_attributes: false + use_gerber_net_attributes: false + line_width: 0.1 + subtract_mask_from_silk: true + layers: + # Copper layers - automatically included if present + - F.Cu + - B.Cu + - In1.Cu + - In2.Cu + - In3.Cu + - In4.Cu + # Technical layers + - F.Paste + - B.Paste + - F.Silkscreen + - B.Silkscreen + - F.Mask + - B.Mask + - Edge.Cuts + - User.Comments + - F.Fab + - B.Fab + + # Excellon drill files + - name: 'drill' + comment: "Drill files" + type: excellon + dir: Gerbers + options: + output: '%f%i.%x' + metric_units: true + minimal_header: false + mirror_y_axis: false + report: + filename: '%f-drill_report.txt' + pth_and_npth_single_file: false + + # Drill map + - name: 'drill_map' + comment: "Drill map" + type: gerb_drill + dir: Gerbers + options: + output: '%f-drill_map.%x' + + # Pick and place files + - name: 'position' + comment: "Pick and place file" + type: position + dir: Assembly + options: + output: '%f-position-%i.%x' # Added %i to differentiate front/back files + format: CSV + units: millimeters + separate_files_for_front_and_back: true + only_smd: false + + # Interactive BOM + - name: 'ibom' + comment: "Interactive BOM" + type: ibom + dir: Assembly + options: + output: '%f-ibom.%x' + dark_mode: false + hide_pads: false + show_fabrication: false + hide_silkscreen: false + highlight_pin1: true + no_redraw_on_drag: false + board_rotation: 0 + check_extra_fields: false + include_tracks: false + include_nets: false + + # Generic BOM in CSV format + - name: 'bom_csv' + comment: "Bill of Materials in CSV format" + type: bom + dir: BoM/Generic + options: + output: '%f_bom.%x' + format: CSV + separator: ',' + ref_separator: ',' + group_fields: ['Value', 'Footprint', 'Tolerance', 'Voltage'] + columns: + - field: 'References' + name: 'Reference' + - field: 'Value' + name: 'Value' + - field: 'Quantity Per PCB' + name: 'Qty' + - field: 'Footprint' + name: 'Package' + - field: 'Description' + name: 'Description' + - field: 'Manufacturer' + name: 'Manufacturer' + - field: 'MPN' + name: 'Part Number' + - field: 'LCSC' + name: 'LCSC Part' + - field: 'Digikey' + name: 'Digikey Part' + - field: 'Mouser' + name: 'Mouser Part' + + # Generic BOM in HTML format + - name: 'bom_html' + comment: "Bill of Materials in HTML format" + type: bom + dir: BoM/Generic + options: + output: '%f_bom.%x' + format: HTML + html: + style: 'modern-blue' # Style for HTML output + datasheet_as_link: 'Datasheet' # Column name for datasheet links + generate_dnf: true + logo: false + title: 'Bill of Materials - %f' + group_fields: ['Value', 'Footprint', 'Tolerance', 'Voltage'] + columns: + - field: 'References' + name: 'Reference' + - field: 'Value' + name: 'Value' + - field: 'Quantity Per PCB' + name: 'Qty' + - field: 'Footprint' + name: 'Package' + - field: 'Description' + name: 'Description' + - field: 'Manufacturer' + name: 'Manufacturer' + - field: 'MPN' + name: 'Part Number' + - field: 'LCSC' + name: 'LCSC Part' + - field: 'Digikey' + name: 'Digikey Part' + - field: 'Mouser' + name: 'Mouser Part' + + # Generic BOM in XLSX format + - name: 'bom_xlsx' + comment: "Bill of Materials in Excel format" + type: bom + dir: BoM/Generic + options: + output: '%f_bom.%x' + format: XLSX + xlsx: + datasheet_as_link: 'Datasheet' # Column name for datasheet links + generate_dnf: true + logo: false + title: 'Bill of Materials' + max_col_width: 50 + highlight_empty: true + group_fields: ['Value', 'Footprint', 'Tolerance', 'Voltage'] + columns: + - field: 'References' + name: 'Reference' + - field: 'Value' + name: 'Value' + - field: 'Quantity Per PCB' + name: 'Qty' + - field: 'Footprint' + name: 'Package' + - field: 'Description' + name: 'Description' + - field: 'Manufacturer' + name: 'Manufacturer' + - field: 'MPN' + name: 'Part Number' + - field: 'LCSC' + name: 'LCSC Part' + - field: 'Digikey' + name: 'Digikey Part' + - field: 'Mouser' + name: 'Mouser Part' + - field: 'Datasheet' + name: 'Datasheet' + + # Download datasheets + - name: 'download_datasheets' + comment: "Download component datasheets as PDFs" + type: download_datasheets + dir: Datasheets # Put in root Datasheets folder + run_by_default: true + priority: 60 + category: 'Schematic/docs' + options: + field: 'Datasheet' # Field containing the datasheet URLs + output: '${REFERENCE}_${VALUE}.pdf' # Name pattern for downloaded files + dnf: false # Don't include DNF components + dnf_filter: '_none' # No DNF filtering + link_repeated: true # Use symlinks for repeated datasheets + repeated: false # Don't re-download same URL + classify: true # Organize by component type (Capacitors/, Resistors/, etc.) + classify_extra: # Additional classification rules + 'U': 'ICs' + 'Q': 'Transistors' + 'D': 'Diodes' + 'L': 'Inductors' + 'F': 'Fuses' + 'J': 'Connectors' + 'P': 'Connectors' + 'SW': 'Switches' + 'Y': 'Crystals' + 'T': 'Transformers' + 'RV': 'Varistors' + 'FB': 'Ferrite_Beads' + + # 3D model + - name: 'step' + comment: "3D STEP model" + type: step + dir: 3D + options: + output: '%f-3D.%x' + metric_units: true + origin: grid + no_virtual: true + + # Board characteristics report + - name: 'report' + comment: "Board report" + type: report + dir: . + options: + output: '%f-report.%x' + do_convert: true + + # Schematic diff + - name: 'sch_diff' + comment: "Schematic diff PDF" + type: diff + dir: DIFF + category: 'Schematic/docs' + run_by_default: true + priority: 50 + layers: [] # Empty for schematic (not PCB) + options: + output: '%f-schematic-diff.%x' + format: 'pdf' # Output format: pdf, svg, ps, or png + pcb: false # This is for schematic + old: 'HEAD~1' # Old version to compare (previous commit) + new: 'HEAD' # New version (current) + cache_dir: '.cache' + add_link_id: true # Add link IDs to the generated diff + only_different: true # Only include pages that changed + threshold: 0 # Difference threshold (0 = any difference) + fuzz: 5 # Fuzzy matching tolerance in pixels + diff_mode: 'red_green' # How to show differences + old_color: '#FF0000' # Color for old/removed items + new_color: '#00FF00' # Color for new/added items + + # PCB diff + - name: 'pcb_diff' + comment: "PCB diff PDF" + type: diff + dir: DIFF + category: 'PCB/docs' + run_by_default: true + priority: 50 + layers: 'selected' # Use selected layers below + options: + output: '%f-pcb-diff.%x' + format: 'pdf' # Output format + pcb: true # This is for PCB + old: 'HEAD~1' # Old version to compare + new: 'HEAD' # New version + cache_dir: '.cache' + add_link_id: false # Not used for PCB + only_different: true # Only include layers that changed + threshold: 0 # Difference threshold + fuzz: 5 # Fuzzy matching tolerance + diff_mode: 'red_green' # Visual diff mode + old_color: '#FF0000' # Color for removed items + new_color: '#00FF00' # Color for added items + layers: # Which PCB layers to include in diff + - 'F.Cu' + - 'B.Cu' + - 'In1.Cu' + - 'In2.Cu' + - 'In3.Cu' + - 'In4.Cu' + - 'F.Silkscreen' + - 'B.Silkscreen' + - 'F.Mask' + - 'B.Mask' + - 'Edge.Cuts' + - 'F.Courtyard' + - 'B.Courtyard' + - 'F.Fab' + - 'B.Fab' + + # Interactive diff using KiRi (HTML output) + - name: 'interactive_diff' + comment: "Interactive HTML diff" + type: diff + dir: DIFF + category: 'PCB/docs' + run_by_default: false # Optional - can be slow + priority: 40 + layers: 'all' # Include all layers for interactive view + options: + output: '%f-interactive-diff.%x' + format: 'html' # HTML format for interactive viewing + pcb: true + old: 'HEAD~1' + new: 'HEAD' + cache_dir: '.cache' + only_different: true + diff_mode: 'stats' # Show statistics in HTML + + # SVG diff for web viewing + - name: 'svg_diff' + comment: "SVG diff for web" + type: diff + dir: DIFF + category: 'PCB/docs' + run_by_default: false + priority: 40 + layers: 'copper' # Only copper layers for web view + options: + output: '%f-diff.%x' + format: 'svg' # SVG format for web embedding + pcb: true + old: 'HEAD~1' + new: 'HEAD' + cache_dir: '.cache' + only_different: true + diff_mode: 'red_green' + old_color: '#FF0000' + new_color: '#00FF00' + zones: 'fill' # How to handle zones: fill, outline, or none + + # JLCPCB fabrication package + - name: 'jlcpcb_gerbers' + comment: "Gerbers for JLCPCB" + type: gerber + dir: JLCPCB + options: + output: '%f%i.%x' + exclude_edge_layer: false + exclude_pads_from_silkscreen: true + plot_sheet_reference: false + plot_footprint_refs: true + plot_footprint_values: false + force_plot_invisible_refs_vals: false + tent_vias: true + use_protel_extensions: true # JLCPCB prefers Protel extensions + create_gerber_job_file: false # JLCPCB doesn't need this + disable_aperture_macros: true + gerber_precision: 4.6 + use_gerber_x2_attributes: false + use_gerber_net_attributes: false + line_width: 0.1 + subtract_mask_from_silk: true + layers: + - F.Cu + - B.Cu + - In1.Cu + - In2.Cu + - In3.Cu + - In4.Cu + - F.Paste + - B.Paste + - F.Silkscreen + - B.Silkscreen + - F.Mask + - B.Mask + - Edge.Cuts + + # JLCPCB drill files + - name: 'jlcpcb_drill' + comment: "Drill files for JLCPCB" + type: excellon + dir: JLCPCB + options: + output: '%f%i.%x' + metric_units: true + minimal_header: false + mirror_y_axis: false + pth_and_npth_single_file: false # JLCPCB prefers separate files + + # JLCPCB ZIP file + - name: 'jlcpcb_zip' + comment: "JLCPCB fabrication ZIP" + type: compress + dir: . + options: + output: '%f_JLCPCB_compress.%x' + format: ZIP + files: + - source: JLCPCB/* + dest: / + + # Fabrication package (ZIP) + - name: 'fabrication' + comment: "Fabrication package" + type: compress + dir: . + options: + output: '%f-fabrication.%x' + format: ZIP + files: + - source: Gerbers/* + dest: / + - source: PCB/PDF/* + dest: /Documentation + - source: Assembly/* + dest: /Assembly + - source: 3D/* + dest: /3D + + # KiCanvas interactive viewer - Schematic + - name: 'kicanvas_schematic' + comment: "Interactive schematic viewer" + type: kicanvas + dir: Interactive + output: '%f-schematic-viewer.%x' + category: 'Schematic/docs' + run_by_default: true + priority: 45 + options: + source: 'schematic' + local_script: true # Download and use local copy of script + controls: 'full' # Full controls for navigation + download: true # Show download button + overlay: true # Show click overlay + title: '%f Schematic - Interactive Viewer' + + # KiCanvas interactive viewer - PCB + - name: 'kicanvas_pcb' + comment: "Interactive PCB viewer" + type: kicanvas + dir: Interactive + output: '%f-pcb-viewer.%x' + category: 'PCB/docs' + run_by_default: true + priority: 45 + options: + source: 'pcb' + local_script: true # Download and use local copy of script + controls: 'full' # Full controls for navigation + download: true # Show download button + overlay: true # Show click overlay + title: '%f PCB - Interactive Viewer' + + # KiCanvas interactive viewer - Full Project + - name: 'kicanvas_project' + comment: "Interactive project viewer (both schematic and PCB)" + type: kicanvas + dir: Interactive + output: '%f-project-viewer.%x' + category: ['Schematic/docs', 'PCB/docs'] + run_by_default: true + priority: 45 + options: + source: 'project' # Show both schematic and PCB + local_script: true # Download and use local copy of script + controls: 'full' # Full controls for navigation + download: true # Show download button + overlay: true # Show click overlay + title: '%f Project - Interactive Viewer' + +# Variants for different layer counts (optional) +variants: + - name: 2layer + comment: "2 layer board variant" + type: kibom + + - name: 4layer + comment: "4 layer board variant" + type: kibom + + - name: 6layer + comment: "6 layer board variant" + type: kibom \ No newline at end of file