Run final OpenRGB integration verification #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Fetch and build layout | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| layout_id: | |
| description: "Layout id available in URL https://configure.zsa.io/voyager/layouts/[ID_IS_HERE]/latest" | |
| required: true | |
| default: "emVdK" | |
| layout_geometry: | |
| description: "Keyboard type" | |
| type: choice | |
| options: | |
| - voyager | |
| - moonlander/reva | |
| - moonlander/revb | |
| - ergodox_ez | |
| - ergodox_ez/m32u4/glow | |
| - ergodox_ez/m32u4/shine | |
| - ergodox_ez/stm32 | |
| - ergodox_ez/stm32/glow | |
| - ergodox_ez/stm32/shine | |
| - planck_ez | |
| - planck_ez/glow | |
| default: voyager | |
| # Temporary self-test trigger; removed after this verification run. | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - .github/workflows/fetch-and-build-layout.yml | |
| env: | |
| QMK_OPENRGB_REF: module_revD | |
| LAYOUT_ID: ${{ github.event.inputs.layout_id || 'emVdK' }} | |
| LAYOUT_GEOMETRY: ${{ github.event.inputs.layout_geometry || 'voyager' }} | |
| permissions: | |
| contents: write | |
| jobs: | |
| fetch-and-build-layout: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Oryx source branch | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: oryx | |
| fetch-depth: 0 | |
| - name: Download latest Oryx layout source | |
| id: download-layout-source | |
| run: | | |
| response=$(curl --fail --silent --show-error --location 'https://oryx.zsa.io/graphql' \ | |
| --header 'Content-Type: application/json' \ | |
| --data '{"query":"query getLayout($hashId: String!, $revisionId: String!, $geometry: String) {layout(hashId: $hashId, geometry: $geometry, revisionId: $revisionId) { revision { hashId, qmkVersion, title }}}","variables":{"hashId":"'"${LAYOUT_ID}"'","geometry":"'"${LAYOUT_GEOMETRY}"'","revisionId":"latest"}}') | |
| hash_id=$(echo "${response}" | jq -r '.data.layout.revision.hashId') | |
| firmware_version=$(printf '%.0f' "$(echo "${response}" | jq -r '.data.layout.revision.qmkVersion')") | |
| change_description=$(echo "${response}" | jq -r '.data.layout.revision.title') | |
| test -n "${hash_id}" | |
| test "${hash_id}" != "null" | |
| test -n "${firmware_version}" | |
| if [[ -z "${change_description}" || "${change_description}" == "null" ]]; then | |
| change_description="latest layout modification made with Oryx" | |
| fi | |
| echo "Oryx revision: ${hash_id}" | |
| echo "Oryx QMK firmware: firmware${firmware_version}" | |
| echo "Oryx title: ${change_description}" | |
| curl --fail --silent --show-error --location \ | |
| "https://oryx.zsa.io/source/${hash_id}" \ | |
| -o source.zip | |
| rm -rf "${LAYOUT_ID}" | |
| mkdir -p "${LAYOUT_ID}" | |
| unzip -oj source.zip '*_source/*' -d "${LAYOUT_ID}" | |
| rm source.zip | |
| echo "hash_id=${hash_id}" >> "$GITHUB_OUTPUT" | |
| echo "firmware_version=${firmware_version}" >> "$GITHUB_OUTPUT" | |
| echo "change_description=${change_description}" >> "$GITHUB_OUTPUT" | |
| - name: Validate official dual Navigator configuration | |
| if: ${{ env.LAYOUT_GEOMETRY == 'voyager' }} | |
| run: | | |
| # Dual Navigator support is now official ZSA/Oryx behavior. Do not | |
| # synthesize either module here: the Oryx layout must own this config. | |
| grep -q '"zsa/navigator_trackball"' "${LAYOUT_ID}/keymap.json" | |
| grep -q '"zsa/navigator_trackpad"' "${LAYOUT_ID}/keymap.json" | |
| - name: Save pristine Oryx source | |
| env: | |
| CHANGE_DESCRIPTION: ${{ steps.download-layout-source.outputs.change_description }} | |
| run: | | |
| git config --local user.name "github-actions" | |
| git config --local user.email "github-actions@github.com" | |
| git add "${LAYOUT_ID}" | |
| if ! git diff --cached --quiet; then | |
| printf "✨(oryx): %s\n" "$CHANGE_DESCRIPTION" | git commit -F - | |
| git push origin HEAD:oryx | |
| else | |
| echo "Oryx source unchanged" | |
| fi | |
| - name: Replace main layout with latest Oryx source | |
| run: | | |
| git fetch origin main | |
| git checkout -B main origin/main | |
| rm -rf "${LAYOUT_ID}" | |
| git checkout oryx -- "${LAYOUT_ID}" | |
| - name: Apply OpenRGB integration | |
| if: ${{ env.LAYOUT_GEOMETRY == 'voyager' }} | |
| run: | | |
| python3 - <<'PY' | |
| import json | |
| import os | |
| import re | |
| from pathlib import Path | |
| layout = Path(os.environ["LAYOUT_ID"]) | |
| # Oryx owns all Navigator modules and settings. Our only keymap-level | |
| # module addition is QMK-OpenRGB. | |
| keymap_json = layout / "keymap.json" | |
| data = json.loads(keymap_json.read_text()) | |
| modules = data.setdefault("modules", []) | |
| if "openrgb" not in modules: | |
| modules.append("openrgb") | |
| keymap_json.write_text(json.dumps(data, indent=4) + "\n") | |
| # OpenRGB plus the dedicated Oryx/Keymapp HID interface consumes one | |
| # extra USB endpoint. Sharing QMK's mouse HID endpoint reclaims it. | |
| rules = layout / "rules.mk" | |
| text = rules.read_text() | |
| pattern = r"^MOUSE_SHARED_EP\s*=.*$" | |
| if re.search(pattern, text, flags=re.MULTILINE): | |
| text = re.sub(pattern, "MOUSE_SHARED_EP = yes", text, flags=re.MULTILINE) | |
| else: | |
| if text and not text.endswith("\n"): | |
| text += "\n" | |
| text += "MOUSE_SHARED_EP = yes\n" | |
| rules.write_text(text) | |
| PY | |
| - name: Save customized layout on main | |
| run: | | |
| git config --local user.name "github-actions" | |
| git config --local user.email "github-actions@github.com" | |
| git add "${LAYOUT_ID}" | |
| git commit -m "✨(layout): Refresh from Oryx with OpenRGB integration" || echo "No customized layout change" | |
| git push origin HEAD:main | |
| - name: Update QMK firmware submodule to matching version (${{ steps.download-layout-source.outputs.firmware_version }}) | |
| run: | | |
| git submodule update --init --remote --depth=1 --no-single-branch | |
| cd qmk_firmware | |
| git checkout -B "firmware${{ steps.download-layout-source.outputs.firmware_version }}" \ | |
| "origin/firmware${{ steps.download-layout-source.outputs.firmware_version }}" | |
| git submodule update --init --recursive | |
| cd .. | |
| git add qmk_firmware | |
| git commit -m "✨(qmk): Update firmware" || echo "No QMK change" | |
| git push origin HEAD:main | |
| - name: Install QMK-OpenRGB module | |
| if: ${{ env.LAYOUT_GEOMETRY == 'voyager' }} | |
| run: | | |
| rm -rf qmk_firmware/modules/openrgb | |
| git clone \ | |
| --depth 1 \ | |
| --branch "${QMK_OPENRGB_REF}" \ | |
| https://gitlab.com/OpenRGBDevelopers/QMK-OpenRGB.git \ | |
| qmk_firmware/modules/openrgb | |
| echo "QMK-OpenRGB commit: $(git -C qmk_firmware/modules/openrgb rev-parse HEAD)" | |
| - name: Apply OpenRGB and Keymapp dual-HID patch | |
| if: ${{ env.LAYOUT_GEOMETRY == 'voyager' }} | |
| run: | | |
| python3 scripts/patch-voyager-dual-hid.py qmk_firmware | |
| - name: Validate Voyager OpenRGB integration | |
| if: ${{ env.LAYOUT_GEOMETRY == 'voyager' }} | |
| run: | | |
| # Navigator modules must still be the ones provided by Oryx. | |
| grep -q '"zsa/navigator_trackball"' "${LAYOUT_ID}/keymap.json" | |
| grep -q '"zsa/navigator_trackpad"' "${LAYOUT_ID}/keymap.json" | |
| # Our custom layer consists only of OpenRGB + transport/endpoint work. | |
| grep -q '"openrgb"' "${LAYOUT_ID}/keymap.json" | |
| grep -q '^MOUSE_SHARED_EP = yes$' "${LAYOUT_ID}/rules.mk" | |
| # Stock OpenRGB remains on QMK Raw HID / interface 1. | |
| grep -q 'void raw_hid_receive(uint8_t \*data, uint8_t length)' \ | |
| qmk_firmware/modules/openrgb/openrgb.c | |
| # ZSA Oryx remains on the dedicated second HID interface. | |
| grep -q 'ORYX_INTERFACE' qmk_firmware/tmk_core/protocol/usb_descriptor.h | |
| grep -q 'USB_ENDPOINT_IN_ORYX' qmk_firmware/tmk_core/protocol/chibios/usb_endpoints.c | |
| grep -q 'oryx_hid_task' qmk_firmware/tmk_core/protocol/chibios/usb_main.c | |
| grep -q 'void oryx_hid_receive(uint8_t \*data, uint8_t length)' \ | |
| qmk_firmware/modules/zsa/oryx/oryx.c | |
| - name: Build qmk docker image | |
| run: docker build -t qmk . | |
| - name: Build the layout | |
| id: build-layout | |
| run: | | |
| if [ "${{ steps.download-layout-source.outputs.firmware_version }}" -ge 24 ]; then | |
| keyboard_directory="qmk_firmware/keyboards/zsa" | |
| make_prefix="zsa/" | |
| else | |
| keyboard_directory="qmk_firmware/keyboards" | |
| make_prefix="" | |
| fi | |
| rm -rf "${keyboard_directory}/${LAYOUT_GEOMETRY}/keymaps/${LAYOUT_ID}" | |
| mkdir -p "${keyboard_directory}/${LAYOUT_GEOMETRY}/keymaps" | |
| cp -r "${LAYOUT_ID}" \ | |
| "${keyboard_directory}/${LAYOUT_GEOMETRY}/keymaps/" | |
| docker run \ | |
| -v ./qmk_firmware:/root \ | |
| --rm \ | |
| qmk \ | |
| /bin/sh -c " | |
| qmk setup zsa/qmk_firmware \ | |
| -b firmware${{ steps.download-layout-source.outputs.firmware_version }} \ | |
| -y | |
| make ${make_prefix}${LAYOUT_GEOMETRY}:${LAYOUT_ID} | |
| " | |
| normalized_layout_geometry="$(echo "${LAYOUT_GEOMETRY}" | sed 's/\//_/g')" | |
| echo built_layout_file=$(find ./qmk_firmware \ | |
| -maxdepth 1 \ | |
| -type f \ | |
| -regex ".*${normalized_layout_geometry}.*\.\(bin\|hex\)$") >> "$GITHUB_OUTPUT" | |
| echo normalized_layout_geometry=${normalized_layout_geometry} >> "$GITHUB_OUTPUT" | |
| - name: Upload layout | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ steps.build-layout.outputs.normalized_layout_geometry }}_${{ env.LAYOUT_ID }} | |
| path: ${{ steps.build-layout.outputs.built_layout_file }} | |
| if-no-files-found: error |