diff --git a/.gitea/workflows/kibot.yml b/.gitea/workflows/kibot.yml new file mode 100644 index 0000000..8242652 --- /dev/null +++ b/.gitea/workflows/kibot.yml @@ -0,0 +1,241 @@ +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/c64psu/*.kicad_sch' + - 'kicad/c64psu/*.kicad_pcb' + - 'kicad/c64psu/*.kicad_pro' + - '.gitea/workflows/kibot_quick_start.yml' + - 'kibot.yaml' + pull_request: + paths: + - 'kicad/c64psu/*.kicad_sch' + - 'kicad/c64psu/*.kicad_pcb' + - 'kicad/c64psu/*.kicad_pro' + - '.gitea/workflows/kibot_quick_start.yml' + - 'kibot.yaml' + 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: Detect layer count + id: layers + working-directory: kicad/c64psu + run: | + 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 + # Auto-detect layers from PCB file + LAYERS=$(python3 -c " + import re + import sys + import glob + + try: + pcb_files = glob.glob('*.kicad_pcb') + if not pcb_files: + print(2) + sys.exit(0) + + with open(pcb_files[0], '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(f'Error: {e}', file=sys.stderr) + print(2) # Default to 2 layers + ") + echo "layers=$LAYERS" >> $GITHUB_OUTPUT + echo "Auto-detected $LAYERS layer board" + fi + + - name: Check for KiBot config + id: config_check + run: | + if [ -f "kibot.yaml" ]; then + echo "found=true" >> $GITHUB_OUTPUT + echo "Using custom kibot.yaml configuration" + elif [ -f "kicad/c64psu/kibot.yaml" ]; then + echo "found=true" >> $GITHUB_OUTPUT + echo "config_path=kicad/c64psu/kibot.yaml" >> $GITHUB_OUTPUT + echo "Using project-specific kibot.yaml configuration" + else + echo "found=false" >> $GITHUB_OUTPUT + echo "Using --quick-start mode (no custom config found)" + fi + + - name: Run ERC + working-directory: kicad/c64psu + run: | + if [ "${{ steps.config_check.outputs.found }}" == "true" ]; then + CONFIG_PATH="${{ steps.config_check.outputs.config_path }}" + [ -z "$CONFIG_PATH" ] && CONFIG_PATH="../../kibot.yaml" + [ -f *.kicad_sch ] && kibot -c "$CONFIG_PATH" -s run_erc -v || true + fi + continue-on-error: true + + - name: Run DRC + working-directory: kicad/c64psu + run: | + if [ "${{ steps.config_check.outputs.found }}" == "true" ]; then + CONFIG_PATH="${{ steps.config_check.outputs.config_path }}" + [ -z "$CONFIG_PATH" ] && CONFIG_PATH="../../kibot.yaml" + [ -f *.kicad_pcb ] && kibot -c "$CONFIG_PATH" -s run_drc -v || true + fi + continue-on-error: true + + - name: Generate outputs with custom config + if: steps.config_check.outputs.found == 'true' + working-directory: kicad/c64psu + run: | + echo "Generating outputs for ${{ steps.layers.outputs.layers }} layer board" + CONFIG_PATH="${{ steps.config_check.outputs.config_path }}" + [ -z "$CONFIG_PATH" ] && CONFIG_PATH="../../kibot.yaml" + + # Run KiBot with the configuration + kibot -c "$CONFIG_PATH" -d Fabrication -v + + # Move outputs to match the original structure + mkdir -p ../../Generated + if [ -d "Fabrication" ]; then + cp -r Fabrication/* ../../Generated/ + fi + + - name: Quick Start fallback + if: steps.config_check.outputs.found == 'false' + working-directory: kicad/c64psu + run: | + echo "Running KiBot in quick-start mode" + kibot --quick-start + + # Move outputs to expected location + if [ -d "Generated" ]; then + mv Generated ../../ + fi + + - 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 \ 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..8931096 --- /dev/null +++ b/kibot.yaml @@ -0,0 +1,257 @@ +# 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 + output: 'Fabrication' + + # 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 + +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.%x' + 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 + + # 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 + + # 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 + +# 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