Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions .github/workflows/build-zmk-firmware.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
name: Reusable user config build

on:
push:
paths:
- "zmk-config/**"
pull_request:
paths:
- "zmk-config/**"
workflow_dispatch:

permissions:
contents: read

env:
BUILD_MATRIX_PATH: "zmk-config/build.yaml"
CONFIG_PATH: "zmk-config"
FALLBACK_BINARY: "bin"
ARCHIVE_NAME: "firmware"

jobs:
matrix:
runs-on: ubuntu-22.04
name: Fetch Build Keyboards
outputs:
build_matrix: ${{ env.BUILD_MATRIX }}
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Fetch Build Matrix
run: |
echo "BUILD_MATRIX=$(yq -oj -I0 \"${BUILD_MATRIX_PATH}\")" >> "$GITHUB_ENV"
yq -oj "${BUILD_MATRIX_PATH}"

build:
permissions:
actions: write
contents: read
runs-on: ubuntu-latest
container:
image: zmkfirmware/zmk-build-arm:stable
needs: matrix
name: Build
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.matrix.outputs.build_matrix) }}
steps:
- name: Act Workaround # https://github.com/nektos/act/issues/973
if: ${{ env.ACT }}
run: |
apt-get update && apt-get install -y curl unzip
curl -fsSL https://deb.nodesource.com/setup_22.x | bash && apt install -y nodejs

- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Create build directory
run: |
echo "BUILD_DIR=$(mktemp -d)" >> $GITHUB_ENV

- name: Prepare variables
shell: bash -x {0}
env:
board: ${{ matrix.board }}
shield: ${{ matrix.shield }}
artifact_name: ${{ matrix.artifact-name }}
snippet: ${{ matrix.snippet }}
run: |
if [ -e zephyr/module.yml ]; then
zmk_load_arg=" -DZMK_EXTRA_MODULES='${GITHUB_WORKSPACE}'"
new_tmp_dir="${TMPDIR:-/tmp}/zmk-config"
mkdir -p "${new_tmp_dir}"
echo "BASE_DIR=${new_tmp_dir}" >> $GITHUB_ENV
else
echo "BASE_DIR=${GITHUB_WORKSPACE}" >> $GITHUB_ENV
fi

if [ -n "${snippet}" ]; then
extra_west_args="-S \"${snippet}\""
fi

echo "ZEPHYR_VERSION=${ZEPHYR_VERSION}" >> $GITHUB_ENV
echo "EXTRA_WEST_ARGS=${extra_west_args}" >> $GITHUB_ENV
echo "EXTRA_CMAKE_ARGS=${shield:+-DSHIELD=\"$shield\"}${zmk_load_arg}" >> $GITHUB_ENV
echo "DISPLAY_NAME=${shield:+$shield - }${board}" >> $GITHUB_ENV
echo "ARTIFACT_NAME=${artifact_name:-${shield:+$shield-}${board//\//_}-zmk}" >> $GITHUB_ENV

- name: Copy config files to isolated temporary directory
run: |
if [ "${BASE_DIR}" != "${GITHUB_WORKSPACE}" ]; then
mkdir "${BASE_DIR}/${CONFIG_PATH}"
cp -R "${CONFIG_PATH}"/* "${BASE_DIR}/${CONFIG_PATH}/"
fi

- name: Cache west modules
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
continue-on-error: true
env:
cache_name: cache-zephyr-${{ env.ZEPHYR_VERSION }}-modules
with:
path: |
${{ env.BASE_DIR }}/modules/
${{ env.BASE_DIR }}/tools/
${{ env.BASE_DIR }}/zephyr/
${{ env.BASE_DIR }}/bootloader/
${{ env.BASE_DIR }}/zmk/
key: ${{ runner.os }}-build-${{ env.cache_name }}-${{ hashFiles('**/west.yml', '**/build.yaml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache_name }}-
${{ runner.os }}-build-
${{ runner.os }}-

- name: West Init
working-directory: ${{ env.BASE_DIR }}
run: west init -l "${BASE_DIR}/${CONFIG_PATH}"

- name: West Update
working-directory: ${{ env.BASE_DIR }}
run: west update --fetch-opt=--filter=tree:0

- name: Check ZMK revision
working-directory: ${{ env.BASE_DIR }}
run: |
zmk_revision=$(west list -f "{revision}" zmk)
echo "zmk_revision=${zmk_revision}" >> $GITHUB_ENV
echo "ZMK revision: ${zmk_revision}"

- name: West Zephyr export
working-directory: ${{ env.BASE_DIR }}
run: west zephyr-export

- name: West Build (${{ env.DISPLAY_NAME }})
working-directory: ${{ env.BASE_DIR }}
shell: sh -x {0}
run: west build -s zmk/app -d "${BUILD_DIR}" -b "${MATRIX_BOARD}" ${EXTRA_WEST_ARGS} -- -DZMK_CONFIG=${BASE_DIR}/${CONFIG_PATH} ${EXTRA_CMAKE_ARGS} ${MATRIX_CMAKE_ARGS}
env:
MATRIX_BOARD: ${{ matrix.board }}
MATRIX_CMAKE_ARGS: ${{ matrix.cmake-args }}

- name: Warn about building from main if build fails
if: failure() && env.zmk_revision == 'main'
run: |
echo "# Consider Pinning ZMK" >> $GITHUB_STEP_SUMMARY
echo "Your recent build failure might be the result of breaking changes made to ZMK's main branch." >> $GITHUB_STEP_SUMMARY
echo "Consider [pinning your ZMK version](https://zmk.dev/blog/2025/06/20/pinned-zmk) to a release for increased stability." >> $GITHUB_STEP_SUMMARY
echo "See also the [list of released versions](https://github.com/zmkfirmware/zmk/releases)." >> $GITHUB_STEP_SUMMARY
echo "If you wish to stay on main, check the most recent pending release PR for breaking changes. [Our blog](https://zmk.dev/blog) may have upgrade information if breaking changes are significant." >> $GITHUB_STEP_SUMMARY

- name: ${{ env.DISPLAY_NAME }} Kconfig file
run: |
if [ -f "${BUILD_DIR}/zephyr/.config" ]
then
grep -v -e "^#" -e "^$" "${BUILD_DIR}/zephyr/.config" | sort
else
echo "No Kconfig output"
fi
if: ${{ !cancelled() }}

- name: ${{ env.DISPLAY_NAME }} Devicetree file
run: |
if [ -f "${BUILD_DIR}/zephyr/zephyr.dts" ]
then
cat "${BUILD_DIR}/zephyr/zephyr.dts"
elif [ -f "${BUILD_DIR}/zephyr/zephyr.dts.pre" ]
then
cat -s "${BUILD_DIR}/zephyr/zephyr.dts.pre"
else
echo "No Devicetree output"
fi
if: ${{ !cancelled() }}

- name: Rename artifacts
shell: sh -x {0}
run: |
mkdir "${BUILD_DIR}/artifacts"
if [ -f "${BUILD_DIR}/zephyr/zmk.uf2" ]
then
cp "${BUILD_DIR}/zephyr/zmk.uf2" "${BUILD_DIR}/artifacts/${ARTIFACT_NAME}.uf2"
elif [ -f "${BUILD_DIR}/zephyr/zmk.${FALLBACK_BINARY}" ]
then
cp "${BUILD_DIR}/zephyr/zmk.${FALLBACK_BINARY}" "${BUILD_DIR}/artifacts/${ARTIFACT_NAME}.${FALLBACK_BINARY}"
fi

- name: Archive (${{ env.DISPLAY_NAME }})
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: artifact-${{ env.ARTIFACT_NAME }}
path: ${{ env.BUILD_DIR }}/artifacts

merge:
permissions:
actions: write
contents: read
runs-on: ubuntu-latest
needs: build
name: Merge Output Artifacts
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ env.ARCHIVE_NAME }}
pattern: artifact-*
delete-merged: true
1 change: 1 addition & 0 deletions nix/outputs/devShells.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
gha =
ciBaseInputs
++ (with pkgs; [
act
gh
zizmor
]);
Expand Down
23 changes: 23 additions & 0 deletions zmk-config/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This file generates the GitHub Actions matrix
# For simple board + shield combinations, add them
# to the top level board and shield arrays, for more
# control, add individual board + shield combinations to
# the `include` property, e.g:
#
# board: [ "nice_nano_v2" ]
# shield: [ "corne_left", "corne_right" ]
# include:
# - board: bdn9_rev2
# - board: nice_nano_v2
# shield: reviung41
#
---
include:
- board: nice_nano_v2
shield: urchin_left nice_view_adapter nice_view_gem
snippet: studio-rpc-usb-uart
cmake-args: -DCONFIG_ZMK_STUDIO=y
- board: nice_nano_v2
shield: urchin_right nice_view_adapter nice_view_gem
- board: nice_nano_v2
shield: settings_reset
30 changes: 30 additions & 0 deletions zmk-config/urchin.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# enable bluetooth
CONFIG_BT=y

# increase bluetooth signal power
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y

# enable deep sleep support
CONFIG_ZMK_SLEEP=y

# the keyboard disconnects from bluetooth.
# uses very little power, but it may take
# a few seconds to reconnect after waking.
# 1.800.000 ms = 30 minutes
CONFIG_ZMK_IDLE_SLEEP_TIMEOUT=1800000

# "Eager Debouncing"
# Trying to lower the input lag.
# CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=1
# CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS=5

# --- DISPLAY SETTINGS ---

# enable display
CONFIG_ZMK_DISPLAY=y
# custom status screen (nice-view-gem)
CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y
# turn off gem animation to save battery
CONFIG_NICE_VIEW_GEM_ANIMATION=n

# source: https://github.com/M165437/nice-view-gem/blob/main/README.md
46 changes: 46 additions & 0 deletions zmk-config/urchin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"layouts": {
"default_transform": {
"layout": [
{ "row": 0, "col": 0, "x": -2, "y": 0.75 },
{ "row": 0, "col": 1, "x": -1, "y": 0 },
{ "row": 0, "col": 2, "x": 0, "y": -0.25 },
{ "row": 0, "col": 3, "x": 1, "y": 0 },
{ "row": 0, "col": 4, "x": 2, "y": 0.25 },
{ "row": 0, "col": 5, "x": 6, "y": 0.25 },
{ "row": 0, "col": 6, "x": 7, "y": 0 },
{ "row": 0, "col": 7, "x": 8, "y": -0.25 },
{ "row": 0, "col": 8, "x": 9, "y": 0 },
{ "row": 0, "col": 9, "x": 10, "y": 0.5 },

{ "row": 1, "col": 0, "x": -2, "y": 1.75 },
{ "row": 1, "col": 1, "x": -1, "y": 1 },
{ "row": 1, "col": 2, "x": 0, "y": 0.75 },
{ "row": 1, "col": 3, "x": 1, "y": 1 },
{ "row": 1, "col": 4, "x": 2, "y": 1.25 },
{ "row": 1, "col": 5, "x": 6, "y": 1.25 },
{ "row": 1, "col": 6, "x": 7, "y": 1 },
{ "row": 1, "col": 7, "x": 8, "y": 0.75 },
{ "row": 1, "col": 8, "x": 9, "y": 1 },
{ "row": 1, "col": 9, "x": 10, "y": 1.5 },

{ "row": 2, "col": 0, "x": -2, "y": 2.75 },
{ "row": 2, "col": 1, "x": -1, "y": 2 },
{ "row": 2, "col": 2, "x": 0, "y": 1.75 },
{ "row": 2, "col": 3, "x": 1, "y": 2 },
{ "row": 2, "col": 4, "x": 2, "y": 2.25 },
{ "row": 2, "col": 5, "x": 6, "y": 2.25 },
{ "row": 2, "col": 6, "x": 7, "y": 2 },
{ "row": 2, "col": 7, "x": 8, "y": 1.75 },
{ "row": 2, "col": 8, "x": 9, "y": 2 },
{ "row": 2, "col": 9, "x": 10, "y": 2.5 },

{ "row": 3, "col": 3, "x": 0.5, "y": 3.75, "r": 15, "rx": 2.98, "ry": 8.395 },
{ "row": 3, "col": 4, "x": 0.75, "y": 3.5, "r": 30, "rx": 1.73, "ry": 7.895 },
{ "row": 3, "col": 5, "x": 7.75, "y": 4, "r": -30, "rx": 6.48, "ry": 9.145 },
{ "row": 3, "col": 6, "x": 7.5, "y": 3.57, "r": -15, "rx": 6.73, "ry": 8.395 }
]
}
},
"sensors": []
}
Loading