diff --git a/kibot.yaml b/kibot.yaml index 09d298d..dc13e53 100644 --- a/kibot.yaml +++ b/kibot.yaml @@ -1,480 +1,297 @@ -# KiBot configuration for 2/4/6 layer boards -# Works with Gitea CI/CD pipeline +- name: Download component datasheets + if: steps.config_check.outputs.found == 'true' + continue-on-error: true + run: | + echo "Datasheets will be downloaded by KiBot's download_datasheets output" + echo "They will be saved in Generated/BoM/Datasheets/" + + # Create a README for the datasheets folder if KiBot creates it + if [ -d "${GITHUB_WORKSPACE}/Generated/BoM/Datasheets" ]; then + cat > "${GITHUB_WORKSPACE}/Generated/BoM/Datasheets/README.md" << EOF + # Component Datasheets + + This folder contains downloaded datasheets for components used in the project. + + - Datasheets are downloaded automatically from URLs in the schematic + - Files are named based on the component reference and original filename + - Only unique datasheets are downloaded (duplicates are linked) + + Generated on: $(date) + Project: ${{ steps.find_project.outputs.project_name }} + EOF + + echo "Datasheet folder contents:" + ls -la "${GITHUB_WORKSPACE}/Generated/BoM/Datasheets/" || true + else + echo "Note: Datasheet folder not created yet - will be created by KiBot" + finame: "KiBot PCB Generation" -kibot: - version: 1 +# 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: '2' + type: choice + options: + - '2' + - '4' + - '6' -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' +# 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 -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 + steps: + - uses: actions/checkout@v3 + with: + # So we can run a diff between last 2 changes + fetch-depth: '0' -outputs: - # Schematic outputs - - name: 'print_sch' - comment: "Schematic PDF" - type: pdf_sch_print - dir: Schematic - options: - output: '%f-schematic.%x' + - 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: 'print_sch_svg' - comment: "Schematic SVG" - type: svg_sch_print - dir: Schematic - options: - output: '%f-schematic.%x' + - 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" # Change this default if needed + fi + echo "layers=$LAYERS" >> $GITHUB_OUTPUT + echo "Using $LAYERS layer configuration" - # 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: 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: '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 + - name: Run ERC + if: steps.config_check.outputs.found == 'true' + run: | + cd "${{ steps.find_project.outputs.project_dir }}" + + if [ -n "${{ steps.find_project.outputs.sch_file }}" ]; then + echo "Running ERC on schematic files..." + # Use absolute path to config file in repo root + kibot -c "${GITHUB_WORKSPACE}/kibot.yaml" -s run_erc -v || true + else + echo "No schematic files found, skipping ERC" + fi + continue-on-error: true - # 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 + - 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 + kibot -c "${GITHUB_WORKSPACE}/kibot.yaml" -s run_drc -v || true + continue-on-error: 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 + - 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" + + # Run KiBot with the configuration from repo root + # Skip ERC/DRC preflight checks to avoid stopping on errors + kibot -c "${GITHUB_WORKSPACE}/kibot.yaml" -s run_erc,run_drc -d Fabrication -v + + # Move outputs to root Generated folder + mkdir -p "${GITHUB_WORKSPACE}/Generated" + if [ -d "Fabrication" ]; then + cp -r Fabrication/* "${GITHUB_WORKSPACE}/Generated/" + fi - # 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 + - 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 - # Drill map - - name: 'drill_map' - comment: "Drill map" - type: gerb_drill - dir: Gerbers - options: - output: '%f-drill_map.%x' + - 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 - # 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 + - name: Fix file permissions + run: | + chmod -R a+rw Generated || true - # 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 + - name: Retrieve results - All outputs + uses: actions/upload-artifact@v3 + with: + name: Automatic_outputs + path: Generated - # 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' + - 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 - # 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' + - 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 - # 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' + - 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 - # Download datasheets - - name: 'download_datasheets' - comment: "Download component datasheets" - type: download_datasheets - dir: BoM/Datasheets - run_by_default: true # Changed to run by default - options: - output: '%f_datasheets.csv' # CSV list of downloaded files - field: 'Datasheet' # Field containing datasheet URLs - dnf: false # Don't download for DNF parts - repeated: false # Don't download the same datasheet twice + - name: Retrieve results - 3D Model + if: steps.config_check.outputs.found == 'true' + uses: actions/upload-artifact@v3 + with: + name: 3D-Model + path: Generated/3D - # 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 + - 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 - # Board characteristics report - - name: 'report' - comment: "Board report" - type: report - dir: . - options: - output: '%f-report.%x' - do_convert: true + - 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 - # Schematic diff - - name: 'sch_diff' - comment: "Schematic diff PDF" - type: diff - dir: DIFF - run_by_default: false # Only run when explicitly requested - options: - output: '%f-schematic-diff.%x' - format: PDF - diff_mode: 'red_green' - old: 'HEAD~1' - new: 'HEAD' - cache_dir: '.cache' - add_link_id: true - only_different: true - - # PCB diff - - name: 'pcb_diff' - comment: "PCB diff PDF" - type: diff - dir: DIFF - run_by_default: false # Only run when explicitly requested - options: - output: '%f-pcb-diff.%x' - format: PDF - diff_mode: 'red_green' - old: 'HEAD~1' - new: 'HEAD' - cache_dir: '.cache' - pcb: true - only_different: true + - 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 - # 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 + # Deploy to documentation branch + deploy: + runs-on: kicad-kibot-runner + needs: generate - # 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: / + steps: + - uses: actions/checkout@v4 - # 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 + - name: Retrieve results + uses: actions/download-artifact@v3 + with: + name: Automatic_outputs + path: Generated -# 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 + - 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