diff --git a/.gitea/workflows/kibot.yml b/.gitea/workflows/kibot.yml index c13f3b8..59eebd8 100644 --- a/.gitea/workflows/kibot.yml +++ b/.gitea/workflows/kibot.yml @@ -1,36 +1,33 @@ -# Reusable Gitea Actions workflow — the Gitea-flavoured equivalent -# of /kibot-ci.yml. Same fab outputs, same Astable upload contract. +# KiCad CI — reusable Gitea Actions workflow. # -# Both files live in the same kicad-ci repo on the same branch; they -# don't collide because GitLab CI looks at /kibot-ci.yml and Gitea -# Actions looks at /.gitea/workflows/*.yml. Maintain in lockstep — -# any change that affects the upload contract should land in both. +# Ported from cookietronics/keeb@dev, which is where this design was +# actually debugged into working. Callers should be a ten-line stub: # -# How a PCB project on Gitea uses this: -# -# # In the PCB project's .gitea/workflows/ci.yml -# name: KiCad CI -# on: -# push: -# branches: [dev, main] -# pull_request: -# branches: [dev, main] # jobs: # kicad: -# uses: Micromelon/kicad-ci/.gitea/workflows/kibot.yml@main +# uses: public/kicad-ci/.gitea/workflows/kibot.yml@main # with: -# project_name: m100301-dengus_cab_tablet_mainboard +# project_name: m120101-honey_harvester_mainboard # secrets: # ASTABLE_URL: ${{ secrets.ASTABLE_URL }} # ASTABLE_API_TOKEN: ${{ secrets.ASTABLE_API_TOKEN }} # -# Gitea Actions secrets are configured under Repo → Settings → Actions -# → Secrets (or at the org level for inheritance, same idea as -# GitLab's group-level CI variables). +# Architecture note (different from the GitLab side, on purpose): +# We do NOT use `container:` on jobs. Gitea Actions runs every step +# (including actions/checkout's Node-based post step) inside the job +# container — but the inti-cmnb/kicad*_auto images don't ship Node, +# so checkout's cleanup dies with exit 127 and the whole job fails +# regardless of what kibot did. Workaround: jobs run on the regular +# act-latest runner image (which has Node) and shell out to +# `docker run` for each kibot invocation. KiBot still runs in the +# pinned image; only the wrapper plumbing lives on the host. # -# Required secrets: -# ASTABLE_URL e.g. https://astable.timhadwen.com +# Required secrets, passed by the caller (set them at org level): +# ASTABLE_URL e.g. https://astable.micromelon.dev # ASTABLE_API_TOKEN minted at /manage/api-tokens (ast_…) +# +# Boards predating KiCad 10 may fail to parse under the default image; +# pin an older one via the kibot_image input if a board needs it. name: KiBot CI (reusable) @@ -38,13 +35,14 @@ on: workflow_call: inputs: project_name: + description: "Project directory name — also the partIpn for Astable" required: true type: string - description: "Project directory name — also used as the partIpn for Astable" kibot_image: + description: "KiBot container image to run KiCad tooling in" required: false type: string - default: "ghcr.io/inti-cmnb/kicad9_auto:1.8.4" + default: "ghcr.io/inti-cmnb/kicad10_auto:latest" secrets: ASTABLE_URL: required: true @@ -53,11 +51,12 @@ on: env: PROJECT_NAME: ${{ inputs.project_name }} + KIBOT_IMAGE: ${{ inputs.kibot_image }} jobs: # ─── Preflight ────────────────────────────────────────────────────── extract_version: - runs-on: ubuntu-latest + runs-on: docker-host outputs: version: ${{ steps.derive.outputs.version }} steps: @@ -73,9 +72,6 @@ jobs: PR_TITLE: ${{ github.event.pull_request.title }} GIT_SHA: ${{ github.sha }} run: | - # Dev branch: VERSION=dev. Main branch: parse VX.Y from commit - # message (matches the GitLab-side rule). MR-to-main uses the - # MR title's V-token, falling back to dev. if [ "${{ github.ref }}" = "refs/heads/main" ]; then VERSION=$(printf '%s' "$COMMIT_MESSAGE" | grep -oE 'V[0-9]+(\.[0-9]+)*' | head -1 || true) [ -z "$VERSION" ] && VERSION="${GIT_SHA:0:8}" @@ -89,17 +85,16 @@ jobs: echo "Resolved VERSION=$VERSION" run_erc: - runs-on: ubuntu-latest + runs-on: docker-host needs: extract_version - container: - image: ${{ inputs.kibot_image }} steps: - uses: actions/checkout@v4 with: submodules: recursive - - run: | - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ]; then - cat > /tmp/erc.kibot.yaml << 'EOF' + - name: KiBot ERC + run: | + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ] || exit 0 + cat > erc.kibot.yaml << 'EOF' kibot: version: 1 preflight: @@ -107,11 +102,12 @@ jobs: enabled: true warnings_as_errors: false EOF + mkdir -p Validation + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c /tmp/erc.kibot.yaml \ - -d Validation/ - fi - - uses: actions/upload-artifact@v4 + -c erc.kibot.yaml -d Validation/ + - uses: actions/upload-artifact@v3 if: always() with: name: Validation @@ -119,24 +115,23 @@ jobs: retention-days: 7 run_drc: - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} steps: - uses: actions/checkout@v4 with: submodules: recursive - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v3 with: name: Validation path: Validation/ - - run: | - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ]; then - PART_NUM=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - cat > /tmp/drc.kibot.yaml << EOF + - name: KiBot DRC + run: | + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ] || exit 0 + PART_NUM=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) + cat > drc.kibot.yaml << EOF kibot: version: 1 preflight: @@ -151,12 +146,12 @@ jobs: enabled: true warnings_as_errors: false EOF + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ -b "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" \ - -c /tmp/drc.kibot.yaml \ - -d Validation/ - fi - - uses: actions/upload-artifact@v4 + -c drc.kibot.yaml -d Validation/ + - uses: actions/upload-artifact@v3 if: always() with: name: Validation @@ -165,15 +160,9 @@ jobs: retention-days: 7 # ─── Fabrication ──────────────────────────────────────────────────── - # Reusable step block via a small composite isn't worth it — each - # generate_* job is small enough to inline its own checkout + - # kibot invocation. Common KIBOT_VAR_* env is set per-job. - generate_schematic: - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} KIBOT_VAR_rev: ${{ needs.extract_version.outputs.version }} @@ -181,25 +170,33 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot schematic PDF + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ]; then + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ] || exit 0 + mkdir -p "Fabrication/${PROJECT_NAME}" + # default.kibot.yaml imports user.kibot.yaml, which each project + # must supply. Mirrors the GitLab pipeline's "Setup user config": + # use the project's own kibot.yaml if present, else blank fallback. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/sch.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/${PROJECT_NAME}" - mv "Fabrication/${PROJECT_NAME}"/*.pdf Fabrication/ 2>/dev/null || true - fi - - uses: actions/upload-artifact@v4 + -c ".gitlab/configs/sch.kibot.yaml" \ + -d "Fabrication/${PROJECT_NAME}" + mv "Fabrication/${PROJECT_NAME}"/*.pdf Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication path: Fabrication/ retention-days: 7 generate_bom: - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} KIBOT_VAR_rev: ${{ needs.extract_version.outputs.version }} @@ -207,26 +204,34 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot BOM + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ]; then + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" ] || exit 0 + mkdir -p "Fabrication/${PROJECT_NAME}" + # default.kibot.yaml imports user.kibot.yaml, which each project + # must supply. Mirrors the GitLab pipeline's "Setup user config": + # use the project's own kibot.yaml if present, else blank fallback. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/sch.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/${PROJECT_NAME}" - mv "Fabrication/${PROJECT_NAME}"/*.csv Fabrication/ 2>/dev/null || true - mv "Fabrication/${PROJECT_NAME}"/*.xlsx Fabrication/ 2>/dev/null || true - fi - - uses: actions/upload-artifact@v4 + -c ".gitlab/configs/sch.kibot.yaml" \ + -d "Fabrication/${PROJECT_NAME}" + mv "Fabrication/${PROJECT_NAME}"/*.csv Fabrication/ 2>/dev/null || true + mv "Fabrication/${PROJECT_NAME}"/*.xlsx Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication-bom path: Fabrication/ retention-days: 7 generate_3d: - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} KIBOT_VAR_rev: ${{ needs.extract_version.outputs.version }} @@ -234,15 +239,25 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot 3D (STEP) + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ]; then + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ] || exit 0 + mkdir -p "Fabrication/${PROJECT_NAME}" + # default.kibot.yaml imports user.kibot.yaml, which each project + # must supply. Mirrors the GitLab pipeline's "Setup user config": + # use the project's own kibot.yaml if present, else blank fallback. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/mech.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/${PROJECT_NAME}" - mv "Fabrication/${PROJECT_NAME}"/*.step Fabrication/ 2>/dev/null || true - fi - - uses: actions/upload-artifact@v4 + -c ".gitlab/configs/mech.kibot.yaml" \ + -d "Fabrication/${PROJECT_NAME}" + mv "Fabrication/${PROJECT_NAME}"/*.step Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication-3d path: Fabrication/ @@ -250,11 +265,9 @@ jobs: # Main-only jobs — gated by the `if:` so dev branches skip them. generate_gerbers: - if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.base_ref == 'main') - runs-on: ubuntu-latest + # Runs on dev and main — dev uploads gerbers to Astable too. + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} KIBOT_VAR_rev: ${{ needs.extract_version.outputs.version }} @@ -262,26 +275,33 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot gerbers + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ]; then + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ] || exit 0 + mkdir -p "Fabrication/${PROJECT_NAME}" + # default.kibot.yaml imports user.kibot.yaml, which each project + # must supply. Mirrors the GitLab pipeline's "Setup user config": + # use the project's own kibot.yaml if present, else blank fallback. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/pcb_main.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/${PROJECT_NAME}" - mv "Fabrication/${PROJECT_NAME}"/*.zip Fabrication/ 2>/dev/null || true - fi - - uses: actions/upload-artifact@v4 + -c ".gitlab/configs/pcb_main.kibot.yaml" \ + -d "Fabrication/${PROJECT_NAME}" + mv "Fabrication/${PROJECT_NAME}"/*.zip Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication-gerbers path: Fabrication/ retention-days: 7 generate_position: - if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.base_ref == 'main') - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} env: VERSION: ${{ needs.extract_version.outputs.version }} KIBOT_VAR_rev: ${{ needs.extract_version.outputs.version }} @@ -289,26 +309,33 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot CPL + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) - if [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ]; then + [ -f "${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" ] || exit 0 + mkdir -p "Fabrication/${PROJECT_NAME}" + # default.kibot.yaml imports user.kibot.yaml, which each project + # must supply. Mirrors the GitLab pipeline's "Setup user config": + # use the project's own kibot.yaml if present, else blank fallback. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + "$KIBOT_IMAGE" \ kibot -e "${PROJECT_NAME}/${PROJECT_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/pos.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/${PROJECT_NAME}" - mv "Fabrication/${PROJECT_NAME}"/*cpl*.csv Fabrication/ 2>/dev/null || true - fi - - uses: actions/upload-artifact@v4 + -c ".gitlab/configs/pos.kibot.yaml" \ + -d "Fabrication/${PROJECT_NAME}" + mv "Fabrication/${PROJECT_NAME}"/*cpl*.csv Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication-position path: Fabrication/ retention-days: 7 generate_panel: - if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.base_ref == 'main') - runs-on: ubuntu-latest + runs-on: docker-host needs: [extract_version, run_erc, run_drc] - container: - image: ${{ inputs.kibot_image }} continue-on-error: true # optional per the GitLab side env: VERSION: ${{ needs.extract_version.outputs.version }} @@ -317,29 +344,36 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: | + - name: KiBot panel + run: | export KIBOT_VAR_name=$(echo "${PROJECT_NAME}" | cut -d"-" -f1) PANEL_JSON=$(find "${PROJECT_NAME}" -name "*_panel.json" 2>/dev/null | head -1) - if [ -n "$PANEL_JSON" ] && [ -f "$PANEL_JSON" ]; then - PANEL_NAME=$(basename "${PANEL_JSON%.json}") - mkdir -p "panels/${PANEL_NAME}" - PCB_FILE="${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb" - [ -f ".gitlab/.scripts/pre_panel.py" ] && python3 .gitlab/.scripts/pre_panel.py "$PCB_FILE" "$PANEL_JSON" - kikit panelize -p "$PANEL_JSON" "$PCB_FILE" "panels/${PANEL_NAME}/${PANEL_NAME}.kicad_pcb" - cp .gitlab/templates/micromelon_default/micromelon_default.kicad_sch "panels/${PANEL_NAME}/${PANEL_NAME}.kicad_sch" 2>/dev/null || true - cp "${PROJECT_NAME}/fp-lib-table" "panels/${PANEL_NAME}/" 2>/dev/null || true - cp -r "${PROJECT_NAME}/libs" "panels/${PANEL_NAME}/" 2>/dev/null || true - [ -f ".gitlab/.scripts/post_panel.py" ] && python3 .gitlab/.scripts/post_panel.py "panels/${PANEL_NAME}/${PANEL_NAME}.kicad_pro" "$PCB_FILE" - cd panels - kibot -e "${PANEL_NAME}/${PANEL_NAME}.kicad_sch" \ - -c "$GITHUB_WORKSPACE/.gitlab/configs/panel.kibot.yaml" \ - -d "$GITHUB_WORKSPACE/Fabrication/panels" - cd "$GITHUB_WORKSPACE" - mv Fabrication/panels/*.zip Fabrication/ 2>/dev/null || true - else + if [ -z "$PANEL_JSON" ] || [ ! -f "$PANEL_JSON" ]; then echo "No panel config — skipping" + exit 0 fi - - uses: actions/upload-artifact@v4 + PANEL_NAME=$(basename "${PANEL_JSON%.json}") + mkdir -p "panels/${PANEL_NAME}" + # See note in the other jobs: supply user.kibot.yaml for the import. + USER_FILE=".gitlab/configs/blank.kibot.yaml" + [ -f "${PROJECT_NAME}/kibot.yaml" ] && USER_FILE="${PROJECT_NAME}/kibot.yaml" + cp "$USER_FILE" .gitlab/configs/user.kibot.yaml + docker run --rm --volumes-from "$(hostname)" -w "$PWD" \ + -e KIBOT_VAR_name -e KIBOT_VAR_rev -e KIBOT_VAR_rev_pcb \ + -e WORKDIR="$PWD" \ + "$KIBOT_IMAGE" \ + bash -c " + PCB_FILE='${PROJECT_NAME}/${PROJECT_NAME}.kicad_pcb' + [ -f .gitlab/.scripts/pre_panel.py ] && python3 .gitlab/.scripts/pre_panel.py \"\$PCB_FILE\" '${PANEL_JSON}' + kikit panelize -p '${PANEL_JSON}' \"\$PCB_FILE\" 'panels/${PANEL_NAME}/${PANEL_NAME}.kicad_pcb' + cp .gitlab/templates/micromelon_default/micromelon_default.kicad_sch 'panels/${PANEL_NAME}/${PANEL_NAME}.kicad_sch' 2>/dev/null || true + cp '${PROJECT_NAME}/fp-lib-table' 'panels/${PANEL_NAME}/' 2>/dev/null || true + cp -r '${PROJECT_NAME}/libs' 'panels/${PANEL_NAME}/' 2>/dev/null || true + [ -f .gitlab/.scripts/post_panel.py ] && python3 .gitlab/.scripts/post_panel.py 'panels/${PANEL_NAME}/${PANEL_NAME}.kicad_pro' \"\$PCB_FILE\" + cd panels && kibot -e '${PANEL_NAME}/${PANEL_NAME}.kicad_sch' -c \"\$WORKDIR/.gitlab/configs/panel.kibot.yaml\" -d \"\$WORKDIR/Fabrication/panels\" + " + mv Fabrication/panels/*.zip Fabrication/ 2>/dev/null || true + - uses: actions/upload-artifact@v3 with: name: Fabrication-panel path: Fabrication/ @@ -349,13 +383,10 @@ jobs: # Mirrors astable_dev / astable_main on the GitLab side. The fab # artifacts above are downloaded into a shared Fabrication/ tree; # upload-bom.sh handles the POST + polling. - astable_dev: if: github.ref == 'refs/heads/dev' || (github.event_name == 'pull_request' && github.base_ref == 'dev') - runs-on: ubuntu-latest - needs: [extract_version, generate_schematic, generate_bom, generate_3d] - container: - image: alpine:3.20 + runs-on: docker-host + needs: [extract_version, generate_schematic, generate_bom, generate_3d, generate_gerbers, generate_position, generate_panel] env: VERSION: ${{ needs.extract_version.outputs.version }} ASTABLE_URL: ${{ secrets.ASTABLE_URL }} @@ -363,56 +394,50 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: apk add --no-cache bash curl jq - # Pull each fab job's artifact into a unified Fabrication/ tree. - - uses: actions/download-artifact@v4 - with: { name: Fabrication, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-bom, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-3d, path: Fabrication/ } - - name: Upload to Astable (dev rev) - run: | - install -m 0755 "$GITHUB_WORKSPACE/.gitlab/scripts/upload-bom.sh" /usr/local/bin/upload-bom.sh - bash -s <<'BASH_SCRIPT' - set -euo pipefail - FAB="$GITHUB_WORKSPACE/Fabrication" - SUB="$FAB/${PROJECT_NAME}" - VAL="$GITHUB_WORKSPACE/Validation" - ARGS=( - --file "$FAB/${PROJECT_NAME}_dev_bom.csv" - --part-ipn "$PROJECT_NAME" - --branch dev - --commit-sha "$GITHUB_SHA" - --commit-message "${COMMIT_MESSAGE:-}" - ) - [ -f "$FAB/${PROJECT_NAME}_dev_cpl.csv" ] && ARGS+=(--cpl "$FAB/${PROJECT_NAME}_dev_cpl.csv") - [ -f "$FAB/${PROJECT_NAME}_dev.step" ] && ARGS+=(--step "$FAB/${PROJECT_NAME}_dev.step") - [ -f "$FAB/${PROJECT_NAME}_dev_schematic.pdf" ] && ARGS+=(--schematic-pdf "$FAB/${PROJECT_NAME}_dev_schematic.pdf") - [ -f "$SUB/${PROJECT_NAME}_dev_ibom.html" ] && ARGS+=(--ibom-html "$SUB/${PROJECT_NAME}_dev_ibom.html") - [ -f "$SUB/${PROJECT_NAME}_dev_bom.xlsx" ] && ARGS+=(--bom-xlsx "$SUB/${PROJECT_NAME}_dev_bom.xlsx") - [ -f "$SUB/PCBA_${PROJECT_NAME}_dev.png" ] && ARGS+=(--pcba-image "$SUB/PCBA_${PROJECT_NAME}_dev.png") - [ -f "$SUB/PCB_${PROJECT_NAME}_dev.png" ] && ARGS+=(--pcb-image "$SUB/PCB_${PROJECT_NAME}_dev.png") - [ -f "$VAL/${PROJECT_NAME}-erc.html" ] && ARGS+=(--erc-report "$VAL/${PROJECT_NAME}-erc.html") - [ -f "$VAL/${PROJECT_NAME}-drc.html" ] && ARGS+=(--drc-report "$VAL/${PROJECT_NAME}-drc.html") - upload-bom.sh "${ARGS[@]}" - BASH_SCRIPT + - uses: actions/download-artifact@v3 + with: { name: Fabrication, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-bom, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-3d, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-gerbers, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-position, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-panel, path: Fabrication } + continue-on-error: true + - name: Astable dev upload env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + run: | + # Wrapped in bash heredoc so commit-message metachars don't + # leak. upload-bom.sh lives in the kicad-ci submodule. + install -m 0755 .gitlab/scripts/upload-bom.sh /tmp/upload-bom.sh + FAB="$PWD/Fabrication" + SUB="$FAB/${PROJECT_NAME}" + shopt -s nullglob + # KiBot names outputs __.. The segment is + # empty when the schematic has no ${rev} revision field, so match it + # with a glob (`_*_`) rather than hard-coding the pipeline version. + add() { local flag="$1"; shift; local m=( "$@" ); if [ ${#m[@]} -gt 0 ]; then ARGS+=("$flag" "${m[0]}"); fi; } + ARGS=( --part-ipn "$PROJECT_NAME" --branch dev --commit-sha "${{ github.sha }}" --commit-message "$COMMIT_MESSAGE" ) + add --file "$FAB"/${PROJECT_NAME}_*_bom.csv + add --schematic-pdf "$FAB"/${PROJECT_NAME}_*_schematic.pdf + add --step "$FAB"/${PROJECT_NAME}_*.step + add --gerbers "$FAB"/${PROJECT_NAME}_*_JLC.zip + add --panel-gerbers "$FAB"/${PROJECT_NAME}_panel_*_JLC.zip + add --cpl "$FAB"/${PROJECT_NAME}_*_cpl.csv + add --ibom-html "$SUB"/${PROJECT_NAME}_*_ibom.html + add --bom-xlsx "$SUB"/${PROJECT_NAME}_*_bom.xlsx + add --pcba-image "$SUB"/PCBA_${PROJECT_NAME}_*.png + add --pcb-image "$SUB"/PCB_${PROJECT_NAME}_*.png + /tmp/upload-bom.sh "${ARGS[@]}" astable_main: - if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.base_ref == 'main') - runs-on: ubuntu-latest - needs: - - extract_version - - generate_schematic - - generate_bom - - generate_3d - - generate_gerbers - - generate_position - - generate_panel - container: - image: alpine:3.20 + if: github.ref == 'refs/heads/main' + runs-on: docker-host + needs: [extract_version, generate_schematic, generate_bom, generate_3d, generate_gerbers, generate_position, generate_panel] env: VERSION: ${{ needs.extract_version.outputs.version }} ASTABLE_URL: ${{ secrets.ASTABLE_URL }} @@ -420,59 +445,46 @@ jobs: steps: - uses: actions/checkout@v4 with: { submodules: recursive } - - run: apk add --no-cache bash curl jq - - uses: actions/download-artifact@v4 - with: { name: Fabrication, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-bom, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-3d, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-gerbers, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-position, path: Fabrication/ } - - uses: actions/download-artifact@v4 - with: { name: Fabrication-panel, path: Fabrication/ } + - uses: actions/download-artifact@v3 + with: { name: Fabrication, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-bom, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-3d, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-gerbers, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-position, path: Fabrication } + - uses: actions/download-artifact@v3 + with: { name: Fabrication-panel, path: Fabrication } continue-on-error: true - - name: Upload to Astable (main rev) - run: | - install -m 0755 "$GITHUB_WORKSPACE/.gitlab/scripts/upload-bom.sh" /usr/local/bin/upload-bom.sh - bash -s <<'BASH_SCRIPT' - set -euo pipefail - FAB="$GITHUB_WORKSPACE/Fabrication" - SUB="$FAB/${PROJECT_NAME}" - VAL="$GITHUB_WORKSPACE/Validation" - # MR-to-main → upload to dev rev (pre-ordering window). - # Actual main pushes → released rev. - if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then - BRANCH=dev - else - BRANCH=main - fi - ARGS=( - --file "$FAB/${PROJECT_NAME}_${VERSION}_bom.csv" - --part-ipn "$PROJECT_NAME" - --branch "$BRANCH" - --commit-sha "$GITHUB_SHA" - --commit-message "${COMMIT_MESSAGE:-}" - ) - [ -f "$FAB/${PROJECT_NAME}_${VERSION}_cpl.csv" ] && ARGS+=(--cpl "$FAB/${PROJECT_NAME}_${VERSION}_cpl.csv") - [ -f "$FAB/${PROJECT_NAME}_${VERSION}_JLC.zip" ] && ARGS+=(--gerbers "$FAB/${PROJECT_NAME}_${VERSION}_JLC.zip") - [ -f "$FAB/${PROJECT_NAME}_panel_${VERSION}_JLC.zip" ] && ARGS+=(--panel-gerbers "$FAB/${PROJECT_NAME}_panel_${VERSION}_JLC.zip") - [ -f "$FAB/${PROJECT_NAME}_${VERSION}.step" ] && ARGS+=(--step "$FAB/${PROJECT_NAME}_${VERSION}.step") - [ -f "$FAB/${PROJECT_NAME}_${VERSION}_schematic.pdf" ] && ARGS+=(--schematic-pdf "$FAB/${PROJECT_NAME}_${VERSION}_schematic.pdf") - [ -f "$SUB/${PROJECT_NAME}_${VERSION}_PCB.pdf" ] && ARGS+=(--pcb-pdf "$SUB/${PROJECT_NAME}_${VERSION}_PCB.pdf") - [ -f "$SUB/${PROJECT_NAME}_${VERSION}_ibom.html" ] && ARGS+=(--ibom-html "$SUB/${PROJECT_NAME}_${VERSION}_ibom.html") - [ -f "$SUB/${PROJECT_NAME}_${VERSION}_bom.xlsx" ] && ARGS+=(--bom-xlsx "$SUB/${PROJECT_NAME}_${VERSION}_bom.xlsx") - [ -f "$SUB/PCBA_${PROJECT_NAME}_${VERSION}.png" ] && ARGS+=(--pcba-image "$SUB/PCBA_${PROJECT_NAME}_${VERSION}.png") - [ -f "$SUB/PCB_${PROJECT_NAME}_${VERSION}.png" ] && ARGS+=(--pcb-image "$SUB/PCB_${PROJECT_NAME}_${VERSION}.png") - [ -f "$VAL/${PROJECT_NAME}-erc.html" ] && ARGS+=(--erc-report "$VAL/${PROJECT_NAME}-erc.html") - [ -f "$VAL/${PROJECT_NAME}-drc.html" ] && ARGS+=(--drc-report "$VAL/${PROJECT_NAME}-drc.html") - upload-bom.sh "${ARGS[@]}" - BASH_SCRIPT + - name: Astable main upload env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - - uses: actions/upload-artifact@v4 + run: | + install -m 0755 .gitlab/scripts/upload-bom.sh /tmp/upload-bom.sh + FAB="$PWD/Fabrication" + SUB="$FAB/${PROJECT_NAME}" + VAL="$PWD/Validation" + shopt -s nullglob + # See astable_dev: match KiBot's __ outputs by glob. + add() { local flag="$1"; shift; local m=( "$@" ); if [ ${#m[@]} -gt 0 ]; then ARGS+=("$flag" "${m[0]}"); fi; } + ARGS=( --part-ipn "$PROJECT_NAME" --branch main --commit-sha "${{ github.sha }}" --commit-message "$COMMIT_MESSAGE" ) + add --file "$FAB"/${PROJECT_NAME}_*_bom.csv + add --cpl "$FAB"/${PROJECT_NAME}_*_cpl.csv + add --gerbers "$FAB"/${PROJECT_NAME}_*_JLC.zip + add --panel-gerbers "$FAB"/${PROJECT_NAME}_panel_*_JLC.zip + add --step "$FAB"/${PROJECT_NAME}_*.step + add --schematic-pdf "$FAB"/${PROJECT_NAME}_*_schematic.pdf + add --pcb-pdf "$SUB"/${PROJECT_NAME}_*_PCB.pdf + add --ibom-html "$SUB"/${PROJECT_NAME}_*_ibom.html + add --bom-xlsx "$SUB"/${PROJECT_NAME}_*_bom.xlsx + add --pcba-image "$SUB"/PCBA_${PROJECT_NAME}_*.png + add --pcb-image "$SUB"/PCB_${PROJECT_NAME}_*.png + add --erc-report "$VAL"/${PROJECT_NAME}-erc.html + add --drc-report "$VAL"/${PROJECT_NAME}-drc.html + /tmp/upload-bom.sh "${ARGS[@]}" + - uses: actions/upload-artifact@v3 if: always() with: name: Fabrication-release