From 0a8e15ee3204cf50532848e4d6e9ed5a16a3ee6b Mon Sep 17 00:00:00 2001 From: devon-thyne Date: Thu, 29 Jan 2026 12:45:55 -0500 Subject: [PATCH 1/2] v1.0.0 - Initial Implementation --- .github/workflows/pre-commit.yml | 43 ++++++ .gitignore | 1 + .pre-commit-config.yaml | 21 +++ .pre-commit-hooks.yaml | 7 + CHANGELOG.md | 8 ++ README.md | 139 +++++++++++++++++++ hooks/drawio-auto-export.sh | 184 ++++++++++++++++++++++++++ tests/test-multiple-pages--page-1.png | Bin 0 -> 2155 bytes tests/test-multiple-pages--page-2.png | Bin 0 -> 2144 bytes tests/test-multiple-pages.drawio | 24 ++++ tests/test-single-page.drawio | 13 ++ tests/test-single-page.png | Bin 0 -> 1169 bytes 12 files changed, 440 insertions(+) create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .pre-commit-hooks.yaml create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 hooks/drawio-auto-export.sh create mode 100644 tests/test-multiple-pages--page-1.png create mode 100644 tests/test-multiple-pages--page-2.png create mode 100644 tests/test-multiple-pages.drawio create mode 100644 tests/test-single-page.drawio create mode 100644 tests/test-single-page.png diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..7d6ce28 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,43 @@ +name: pre-commit + +on: + push: + branches-ignore: + - main + +jobs: + pre-commit: + runs-on: ubuntu-latest + + container: + image: python:3.11-bullseye + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Mark workspace as safe for git + run: | + export HOME=/github/home + git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - name: Install system dependencies + run: | + apt-get update + apt-get install -y \ + libasound2 \ + libatk-bridge2.0-0 \ + libatk1.0-dev \ + libcups2 \ + libdbus-1-dev \ + libgbm1 \ + libgtk-3-0 \ + libimage-exiftool-perl \ + libnss3 \ + xvfb + + - name: Install pre-commit + run: pip3 install pre-commit + + - name: Run pre-commit + run: pre-commit run --all-files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..6aa9eae --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: no-commit-to-branch + - id: check-merge-conflict + - id: check-yaml + - id: trailing-whitespace + - id: check-symlinks + - id: end-of-file-fixer + - id: mixed-line-ending + + - repo: local + hooks: + - id: drawio-auto-export + name: Draw.io Auto Export + description: >- + Automatically exports .drawio files in repository into .png whenever you commit changes + entry: hooks/drawio-auto-export.sh + language: script + files: \.drawio$ diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..8935fd7 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,7 @@ +- id: drawio-auto-export + name: Draw.io Auto Export + description: >- + Automatically exports .drawio files in repository into .png whenever you commit changes + entry: hooks/drawio-auto-export.sh + language: script + files: \.drawio$ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1332768 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Latest Version +1.0.0 + +# Version History +## Version 1.0.0 (2025-01-28) (devon-thyne) +### Initial Version +* Pre-commit hook that will auto-export `.drawio` files in repository to `.png` whenever you commit changes +* Done so with a thin and simple bash script diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e02d16 --- /dev/null +++ b/README.md @@ -0,0 +1,139 @@ +pre-commit drawio auto-export +============================= + +This pre-commit hook automatically exports [Draw.io](https://www.drawio.com/) (`.drawio`) files in repository into `.png` whenever you commit changes. + +**Table of Contents:** + +- [Installation](#installation) +- [Features](#features) +- [Requirements](#requirements) +- [Supported Platforms](#supported-platforms) +- [CI/CD Examples](#cicd-examples) + * [GitHub](#github) + * [Gitlab](#gitlab) +- [Acknowledgements](#acknowledgements) + +## Installation + +Add the hook to your `.pre-commit-config.yaml`: + +```yaml +repos: + - repo: https://github.com/devon-thyne/pre-commit-drawio-auto-export.git + rev: v1.0.0 + hooks: + - id: drawio-auto-export +``` + +## Features + +- Automatically detects all `.drawio` files within repository +- Exports diagram file(s) to `.png` using the draw.io CLI (AppImage for Linux, Desktop app for macOS) + - Exports multi-paged diagram files as multiple `.png` image(s) each suffixed with the diagram page's name +- Fails if any files are generated net-new or modified +- Automatically stages changes to new or modified exported files + +## Requirements + +* BASH interpreter +* `exiftool` +* `xvfb` (linux only) +* `Draw.io Desktop` (macos only) + +## Supported Platforms + +### Linux +- [xvfb](https://linux.die.net/man/1/xvfb) must be installed. +- **Note:** the script will automatically download and cache the Draw.io AppImage if not already present. + - path: `~/.cache/pre-commit/drawio` + +### macOS +- [Draw.io Desktop](https://github.com/jgraph/drawio-desktop/releases) must be installed in `/Applications`. +- **Note:** exports briefly display the Draw.io icon in the Dock due to macOS constraints + +### Windows +- **not supported** +- use windows subsystem for linux + +## CI/CD Examples + +> [!TIP] +> Suggest pre-building your own pre-commit docker image with the necessary dependencies + +### GitHub + +The following example demonstrates how to run this hook in GitHub Actions. +Trigger conditions (e.g. push, pull_request, branches) are intentionally left to the user. + +```yaml +name: pre-commit + +jobs: + pre-commit: + runs-on: ubuntu-latest + + container: + image: python:3.11-bullseye + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Mark workspace as safe for git + run: | + export HOME=/github/home + git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - name: Install system dependencies + run: | + apt-get update + apt-get install -y \ + libasound2 \ + libatk-bridge2.0-0 \ + libatk1.0-dev \ + libcups2 \ + libdbus-1-dev \ + libgbm1 \ + libgtk-3-0 \ + libimage-exiftool-perl \ + libnss3 \ + xvfb + + - name: Install pre-commit + run: pip3 install pre-commit + + - name: Run pre-commit + run: pre-commit run --all-files +``` + +### Gitlab + +The following example demonstrates how to run this hook in GitLab CI/CD. +Pipeline triggers and execution rules (e.g. branches, merge requests) should be defined by the user. + +```yaml +pre-commit: + stage: pre-commit + image: python:3.11-bullseye + script: + - apt update + - | + apt install -y \ + libasound2 \ + libatk-bridge2.0-0 \ + libatk1.0-dev \ + libcups2 \ + libdbus-1-dev \ + libgbm1 \ + libgtk-3-0 \ + libimage-exiftool-perl \ + libnss3 \ + xvfb + - pip3 install pre-commit + - pre-commit run --all-files +``` + +## Acknowledgements + +This project was inspired by an early CI/CD-based Draw.io export workflow shared by a colleague. That initial work sparked the idea to formalize and extend the approach into a reusable, pre-commit–based tool with additional logic around change detection, local generation, and reproducibility. diff --git a/hooks/drawio-auto-export.sh b/hooks/drawio-auto-export.sh new file mode 100644 index 0000000..f1c0c61 --- /dev/null +++ b/hooks/drawio-auto-export.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Synopsis: pre-commit script that exports .drawio files to `.png` whenever you commit changes +set -euo pipefail + +OS="$(uname -s)" +ARCH="$(uname -m)" + +FORMAT="png" +DIAGRAMS=() +CHANGES_DETECTED=0 + +# Parse Arguments +while [[ $# -gt 0 ]]; do + case "$1" in + *.drawio) + DIAGRAMS+=("$1") + shift + ;; + *) + echo "[ERROR]: Unknown option: $1" >&2 + echo "Usage: $0 ..." >&2 + exit 1 + ;; + esac +done + +# Check Requirements +if command -v exiftool >/dev/null 2>&1; then + EXIFTOOL="$(command -v exiftool)" +elif [ -x /usr/local/bin/exiftool ]; then + EXIFTOOL=/usr/local/bin/exiftool +elif [ -x /opt/homebrew/bin/exiftool ]; then + EXIFTOOL=/opt/homebrew/bin/exiftool +else + echo "[ERROR]: exiftool not found. Install it or add it to PATH." >&2 + exit 1 +fi +if [[ "$OS" == "Linux" ]]; then + if ! command -v xvfb-run &>/dev/null; then + echo "[ERROR]: xvfb-run is required but not installed." >&2 + exit 1 + fi +fi + +# Diagram Files Input Validation +if [[ ${#DIAGRAMS[@]} -eq 0 ]]; then + exit 0 +fi +echo "Diagrams to convert ($FORMAT):" +for d in "${DIAGRAMS[@]}"; do + echo " - $d" +done +echo "" + +# Functions +sha256() { + git show ":$1" | sha256sum | awk '{print $1}' +} + +check_diagram_changes() { + local tmpfile="$1" + local out="$2" + local diagram_hash="$3" + local before_hash="$4" + local before_perm="$5" + + "$EXIFTOOL" -Comment="drawio-diagram-hash:$diagram_hash" "$tmpfile" >/dev/null 2>&1 + + if [[ "$before_hash" != "n/a" ]]; then + mv -f "$tmpfile" "$out" + chmod "$before_perm" "$out" + echo "[ALERT]: file has changed - $out" + CHANGES_DETECTED=1 + else + mv "$tmpfile" "$out" + echo "[ALERT]: new file - $out" + CHANGES_DETECTED=1 + fi +} + +process_diagram_page() { + local diagram="$1" + local drawio_binary="$2" + local output_file="$3" + local page_index="${4:-1}" + + local tmpfile=$(mktemp) + local diagram_hash=$(sha256 "$diagram") + local before_hash="n/a" + local before_perm="n/a" + + if [[ -f "$output_file" ]]; then + before_hash=$("$EXIFTOOL" -Comment -s3 "$output_file" | sed 's/^drawio-diagram-hash://') + if [[ "$OS" == "Linux" ]]; then + before_perm=$(stat -c "%a" "$output_file") + else + before_perm=$(stat -f "%Lp" "$output_file") + fi + fi + if [[ "$diagram_hash" != "$before_hash" ]]; then + if [[ "$OS" == "Linux" ]]; then + xvfb-run -a "$drawio_binary" \ + --export --page-index "$page_index" --format "$FORMAT" --output "$tmpfile" "$diagram" \ + --disable-gpu --headless --no-sandbox >/dev/null 2>&1 + else + "$drawio_binary" \ + --export --page-index "$page_index" --format "$FORMAT" --output "$tmpfile" "$diagram" \ + --disable-gpu --headless --no-sandbox >/dev/null 2>&1 + fi + check_diagram_changes "$tmpfile" "$output_file" "$diagram_hash" "$before_hash" "$before_perm" + fi +} + +process_diagram() { + local diagram="$1" + local drawio_binary="$2" + + local output_file="${diagram%.drawio}.${FORMAT}" + local diagram_pages="$(\ + cat "$diagram" | grep '/dev/null 2>&1) + fi + for d in "${DIAGRAMS[@]}"; do + process_diagram "$d" "$APPIMAGE_DIR/squashfs-root/drawio" + done + +# MacOS Export +elif [[ "$OS" == "Darwin" ]]; then + DRAWIO_BIN="/Applications/draw.io.app/Contents/MacOS/draw.io" + if [[ ! -x "$DRAWIO_BIN" ]]; then + echo "[ERROR]: Draw.io app not found in /Applications. Please install it." >&2 + exit 1 + fi + for d in "${DIAGRAMS[@]}"; do + process_diagram "$d" "$DRAWIO_BIN" + done + +else + echo "[ERROR]: Unsupported OS - $OS" >&2 + exit 1 +fi + +if [[ $CHANGES_DETECTED -eq 1 ]]; then + exit 1 +fi diff --git a/tests/test-multiple-pages--page-1.png b/tests/test-multiple-pages--page-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ae6e4d1dd085874d716b2afa5d6440f415f0c8eb GIT binary patch literal 2155 zcmaJ@c{JPG7EWuPtLEXVp^6%Uijc%qR6>cV<|!ejn&;NkR#6>jL#Yy470Oi-HAY)< zjTa3SElLM!?2Vwt80!7re{Ze#);nwMv(Gwvt$p^l_SxUwIrer|0=&|^AP`6Zg|u)4 zbP6D*+$VwEwdb}8puFNN-Qvt6!^3eAaiD-0Okzl+WprO(GI{F>f>~EpqRiw zh~7{bd>91cYC~C=IVY7eN;&Qn*vj@T(cqp8CYlT>m4bRxY(KimV5{oS>-losGYNcd+_@Wk8X z-GKolhVKn}f27=G?Mp}E##}EDBf1R1nr@AZ8+&(s`{(bYg9h&oz+*@6J&EL}H2loF z)Pr9OL&-agsYcuoCH@~TPQ8$^`7xr6o}?2QYiS(f+a5!V{?YgM<>NzEEUnZKO@K8g z??%MePEJm0c~iz~ulxh}TK(MY|AxfzRmJGsIZhFEk0w=Wtw(cc;@VeY?E9yXQ{Ej3 ztByqL_a)E~*53r`?>!m;?po(|lklm*H~mwcd(@IHXAIb@%`_vPpySV3-n4?z!IvB3 z21SdUHu?_txA`&#N}y|_&&@qs!fFI@Kp_5o_y2;f8?P8V)NpScNC2FqAMOc@i|=gw z=m(&(47;rT+)*?ELBT+6A7ol@zV-(k|JUz~sn_2+)BEk*UF+o37gK8;UR=_pM;jFD z;$jRx7J+@O3pJ!pt;0!V=b!euvWAU8BU&kJYx&II>e5WP9p85;#d{_QRvZGPgi>CZ zaBc7rQ*-RW@sD>6WC_STg+yUOwuQ9p!|o zdhB!4R!ym4rzb~*Z1LH_!Qn|LzT1sN&ERVAXy#P}mVV^dnFe2zU5utjliSht zxZT}LFBCL-Oc#qvY>!#MYu&k#GS|Zs&pooawc<1@Gid=!dxPoD5|GxDM+Z;0XwHt) zkqBLXq<*c-E9)p3NNB-zTyng7WQ1&~z03$h(@af;LY7U8=aeKHELlz)_6N7W`uXUQ>ES1t*H5?yOE{Lj7{$ zn#?U8E0|{uG!*<0JMa8VLp1%u%Mg{zPe?Hf)K)Y=y|qv?ExnYI82prl_K( zQO#VRl6JKJKnChqvc>#Ta`KOwHK0NWu=t9@7u?R7XZ$5ikMJhxX}ltFc-H1pk*dSV z^aU^3^P*s%l*QrVSDvkXoHdce!W;TIdhu+=hqo}AI?LQKw9f8H7Oc%J5``^lrv%;t|91re$H zTLX`jMhI|d*dz(SsDytOYfFHMRXF%AXbe~iTJSE$2R<6*iI{2ANnp4oT}C3KI_EOD zgq~b{K&z=VmOXv?qT$`b_NxnhU5a>~a_RCw6chP@2p_%#U13Vk~(^lGa-xr3e6eE*l7T!OO5k2IK>5n|4$ z|Grdr@t18&?X<%^Q?7LokdlgOI|7Vh0}vcn?Bdy_k@D*NxiX1A{rhu+TNo+7)T)*8 zqhsQ@nYW=JPJ(5vb!#lovQ9N-I6zpwiv_VgwPvd&5Fv; zW`n~04$)@&s^t&QKaW`$bdi+EwZFXe>r;IQt8;+4PyWR literal 0 HcmV?d00001 diff --git a/tests/test-multiple-pages--page-2.png b/tests/test-multiple-pages--page-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e05cf0c2109fc97e73c43f820acd2360a8063a6 GIT binary patch literal 2144 zcmZ`*c{tQx7oTJuS<4!UUNn|zFlNRQGS-Abne1bieTcEO*b+(zH3n0JdYP1{!Po{Z zma#82mZ1sR##WZ({r>*{y?@+$p68tVoafxn`P}ol_b=O+3xK7;AP`8v(!#_Ju<^h$ z;^hE#$Btw}z_>)3Vj|I@!NEQuksxmzHaZ|w-8%s5hrgbv3X$Fsvus8>_8@ z)I@4ykuYDlCjyB@dTL>{us$elUvGpC66Fc^LSZ$uVOW$l%-cr?;iIX6#QOSb!@Gm@ zdO#qaYD<#~4tU}+(I@kS)rpkAf&`&xW&hJgVFJ=KJi?4gnh?VkoycRwE6xkOkfg_V zcSig_9~!wZ(Q(s-vp1D$hiI!&^x@TJUB1F%g0p%>Xo>Uht>il$9VXA1&YWyIoo?&D z!>QSMlxXOW7c;~0@CuZmbIBk=Bv*f#>K!H5Bk)Bq$+FTL26>_TZz;kSJPlQ%G!3W|-4-1?M# zCgTLeu0CkOG(%ib02RF|6Y%M8;24=2Fr?)5hs~trsa*9`;JGng!+fgc*OOSpdSP;3 zG~!23z{Fdhx*H>1S#oR4j-cd&GC94dDzgXDS#pLUlMUPBZ@gGDZ+*JSu8sB4Yf~qY zAx*arZ!z0be1|BCfP;!-eF0*mfL?+&^hjG<8#?t^%)#Dv&r>bSaUP*lu$`?%d+q|Y z>l+ILr7}7=Mq@M`UBe$T-JI}eC;Tt2PuYejJazA&Z0x1IAA6=P1uRA|NYHgO{-OEd z#)wLq(&WVgsI~73gEF+@Qk=8$?fq-an?(3)_m;nzQd*=b#d7EOA?i-=KIN%On11m3 z_)r4s;=u;s08WOEkzN1(*{!fC`r=e(=bV|oDNf^n#!se5Mu`$P>JP*IP+76S(L+S0CrpC?7qjZc|-*KZS*#kM@ zgJqVFA)-%LDl02D=jn|CbEyK-aDUd9JjRo>w6q5&k-t{HjVUT25cStaUUPb_G}9iWf(vS6SaQrdTf!!1yuS3>B3P0=~}f@cC2qUudar_ z!^o?vkj^t^nPGgG=J=S+AH7#@ypuF$d32_W1=L*@=z@krGdD?A<#wB8tvo_Lsg zwR4JWjfw7*d^y-ALiXxevly+)hfD( z44otd&*WQAAA$D)?D5)<}+jZ|IF)ncZFR7<)b z1TXv)?k_bLy7n9=v&I{JMA;6LsyJApALIGN-oE_OvjjO**l8}O`fNXXv8+KnD*t%7 zc_AV=UEVZ;o+L;i`!7~Q&JC7h+3(FVx zX!7#%08N^29~w*=ax!IjBPxCatRyNU&JV4ZFo$U);quG%01;ZAZv38yzEUpQgN!iL z35Z}7y-<__@YILL-KeqH_p1}N=3S&hydC_2p-d^lpb^2)N#%NAbP!XXaCg~GE* zVW`i*06-^N`bFW^XHBuITV&_=4~yo|VM_W(VEz~{=$&xEwuq!xl1VOAE}EER#X*V# z5mOub%r@lmo`?XgxU1%1gOy=*>DTf^HV4CFH+${N%qi_fST5y+yoFzb%rmNHImw}^f97R-j|MjdGe21_op0eM)`??fVPX8*sV*Ml z(#3HXFC^riTsVrnFCZ#@SE=qg{TXb-S*xO8E@Y}nXMoR|0LSJtinRmt!@i@Mp{Zkw zLlqNQ;r@Mc;k4A_`Plng0Cbxlo>H@6M(Za16elL$@bi9?LBd{|1GX)ZYe7vSD;Ods zMb37;W?fdcPWarj_@YbAwZS2_{?Sss%Q?3u{Ndk&#|ot`mNO(~X&%Jh?4PbvY!>!Q z2kvriisp3cK|Vh(788uNDgy)jHqExQ6_-q_3sXZp;xe#PKO3pp)3ez5gB7fjM#(*l)#i2(-9hojyUxsdhokwi{-|?$}EUU@C~YaW5I~or7DK36B=JrE~U* zWI$Ed*g>^X5dVcLAxT@v^37OCr^C6%DT42~JN|`Fg`;z0b5ecORpWn?xBsJj?83-{ z>6Jav!yIyNq#U|CgX7Op5a{smEH17A_#klqBiu(pX&Y=Xqui+i@PI5$ZA{3<9*O@0 DXetav literal 0 HcmV?d00001 diff --git a/tests/test-multiple-pages.drawio b/tests/test-multiple-pages.drawio new file mode 100644 index 0000000..9e5740a --- /dev/null +++ b/tests/test-multiple-pages.drawio @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test-single-page.drawio b/tests/test-single-page.drawio new file mode 100644 index 0000000..0ae39c5 --- /dev/null +++ b/tests/test-single-page.drawio @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/test-single-page.png b/tests/test-single-page.png new file mode 100644 index 0000000000000000000000000000000000000000..0039cb079bc631b881cfb826cd2ece46a4ada0ac GIT binary patch literal 1169 zcmeAS@N?(olHy`uVBq!ia0vp^H9+jZ!2~43kF?kWshASih!W@g+}zZ>5{8tb#PZC1 z-IUD4^rFOE-HgQI3@c+JGmF#|V7YMQyZ<&qfoSOx~>d!8*dd6HtU>jG88keQ}Gn)QPfb)+jb|R#8o$M za{^EMQsD!aI1^s7Y$#!huwvAi%P`H4!CSq7C}FjQn!kVlc64;~Q=30;-mjlOH495h zzC3%j%%J7t$B&aH3ElpC_Uzf*++3%6lWG65HMF%~zj-6_>%iMqhFGoIoSZl3#W|+f z%FD~YefxIe#EFcIj9(ZsB@FO>xPZrqh*|_oItB@T@@7});6!`b=UubA( zWo6|n#q#oUpi>v}-|}{6{`lcTK$5@z`P;W|A3uJ)ySw|zla!a-XIQjeAK%E&&+p+T z9%OdW)8K*@``v`X!jI3Mv6XgJx?Ww}RcL$k_;G8AzP88Do~4zpTD^Mph7AUre^w_R z4q4g0XYbyok z;lej>a^_f?n3PmhSg5NXPcgDIz9V$y_|2O$e;qMO`YLeiO8@q$vl1@oD(k)7waY3* z>CyD*;!|GrXU^Dg>eQ)y`|LU@s;ZYt z?D^~0tG6iVocR3t^DD)YdCkqt3;EeR-R1qgy}f;XkJdURCMr$~uAceg#EFAv-Ewkt z#J0bBm33Q2!>#({`San)uDd254vmS4dG_pC!9o>P)vMR8MNRwm=FOT-Q7;->7CAJ2 zXlLSa_(>}lJ-9cWUzs9Ix~Yn W_G}l&zvnW5A`G6celF{r5}E+X Date: Thu, 29 Jan 2026 12:46:08 -0500 Subject: [PATCH 2/2] make hook script executable --- hooks/drawio-auto-export.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 hooks/drawio-auto-export.sh diff --git a/hooks/drawio-auto-export.sh b/hooks/drawio-auto-export.sh old mode 100644 new mode 100755