From 02ab07ed478f37873cdba0f9590e85bca9a7a3c9 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Wed, 5 Aug 2026 10:54:28 +0100 Subject: [PATCH 1/5] Readme and ansible requirements file for macos runner --- macOS/github-runner/ansible/github-runner.yml | 20 ++++ macOS/github-runner/ansible/requirements.yml | 3 + .../ansible/roles/runner/tasks/main.yml | 77 +++++++++++++ macOS/github-runner/readme.md | 106 ++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 macOS/github-runner/ansible/github-runner.yml create mode 100644 macOS/github-runner/ansible/requirements.yml create mode 100644 macOS/github-runner/ansible/roles/runner/tasks/main.yml create mode 100644 macOS/github-runner/readme.md diff --git a/macOS/github-runner/ansible/github-runner.yml b/macOS/github-runner/ansible/github-runner.yml new file mode 100644 index 0000000..fbca9ae --- /dev/null +++ b/macOS/github-runner/ansible/github-runner.yml @@ -0,0 +1,20 @@ +- name: Deploy native GitHub runner for Mantid builds (macOS) + hosts: all + vars: + organization: mantidproject + repository: mantid + github_token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}" + # Check https://github.com/actions/runner/releases for the latest version. + runner_version: "2.319.1" + # Use "osx-arm64" for Apple Silicon machines, or "osx-x64" for Intel machines. + runner_arch: "osx-arm64" + + pre_tasks: + - name: Fail if github token is missing + fail: + msg: "GITHUB_TOKEN is not set" + when: github_token == "" + + roles: + - role: runner + tags: "runner" diff --git a/macOS/github-runner/ansible/requirements.yml b/macOS/github-runner/ansible/requirements.yml new file mode 100644 index 0000000..cb9538a --- /dev/null +++ b/macOS/github-runner/ansible/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: geerlingguy.mac diff --git a/macOS/github-runner/ansible/roles/runner/tasks/main.yml b/macOS/github-runner/ansible/roles/runner/tasks/main.yml new file mode 100644 index 0000000..651838f --- /dev/null +++ b/macOS/github-runner/ansible/roles/runner/tasks/main.yml @@ -0,0 +1,77 @@ +--- +- name: Check whether the runner is already configured + ansible.builtin.stat: + path: "{{ ansible_env.HOME }}/actions-runner/.runner" + register: runner_configured + +- name: Fetch GitHub Actions runner registration token + ansible.builtin.uri: + url: "https://api.github.com/repos/{{ organization }}/{{ repository }}/actions/runners/registration-token" + method: POST + headers: + Accept: "application/vnd.github+json" + Authorization: "Bearer {{ github_token }}" + X-GitHub-Api-Version: "2022-11-28" + return_content: yes + status_code: 201 + register: runner_token + when: not runner_configured.stat.exists + +- name: Create the actions-runner directory + ansible.builtin.file: + path: "{{ ansible_env.HOME }}/actions-runner" + state: directory + mode: "0755" + when: not runner_configured.stat.exists + +- name: Download the GitHub Actions runner package + ansible.builtin.get_url: + url: "https://github.com/actions/runner/releases/download/v{{ runner_version }}/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" + dest: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" + mode: "0644" + when: not runner_configured.stat.exists + +- name: Extract the GitHub Actions runner package + ansible.builtin.unarchive: + src: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" + dest: "{{ ansible_env.HOME }}/actions-runner" + remote_src: yes + when: not runner_configured.stat.exists + +- name: Clear the quarantine attribute so macOS Gatekeeper doesn't block the binaries + ansible.builtin.shell: xattr -dr com.apple.quarantine "{{ ansible_env.HOME }}/actions-runner" + when: not runner_configured.stat.exists + +- name: Configure the runner + ansible.builtin.command: + argv: + - ./config.sh + - --unattended + - --url + - "https://github.com/{{ organization }}/{{ repository }}" + - --token + - "{{ runner_token.json.token }}" + - --name + - "{{ runner_name }}" + - --labels + - "{{ runner_name }}" + - --replace + chdir: "{{ ansible_env.HOME }}/actions-runner" + when: not runner_configured.stat.exists + +- name: Check whether the runner service is already installed + ansible.builtin.stat: + path: "{{ ansible_env.HOME }}/actions-runner/.service" + register: runner_service_installed + +# Note: unlike Linux, installing/starting the launchd service does not need sudo. +- name: Install the runner as a launchd service + ansible.builtin.command: + cmd: ./svc.sh install + chdir: "{{ ansible_env.HOME }}/actions-runner" + when: not runner_service_installed.stat.exists + +- name: Start the runner service + ansible.builtin.command: + cmd: ./svc.sh start + chdir: "{{ ansible_env.HOME }}/actions-runner" diff --git a/macOS/github-runner/readme.md b/macOS/github-runner/readme.md new file mode 100644 index 0000000..48dc339 --- /dev/null +++ b/macOS/github-runner/readme.md @@ -0,0 +1,106 @@ +# Native GitHub self-hosted runner for macOS + +This describes how to register a macOS machine as a GitHub self-hosted runner in the `mantidproject/mantid` repository. + +The macOS runner is installed **natively** on the machine, following the same physical-machine model already used for the [macOS Jenkins node](../jenkins-node/README.md), with the GitHub Actions runner application registered and run as a `launchd` service instead of a Docker container. + +## Prerequisites + +- A [fine-grained GitHub token](https://github.com/settings/personal-access-tokens/new) with: + - resource owner: `mantidproject` + - repository access: Only select repositories (select `mantidproject/mantid`) + - permissions: Administration (Read and write) + + See [here](https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-a-repository--fine-grained-access-tokens) for reference and instructions for generating a registration token. + +## Manual machine setup + +If the Mac has not been used as a build node before, do the following first (identical to the Jenkins node setup, see [macOS/jenkins-node/README.md](../jenkins-node/README.md#manual-setup) for full detail): + +- Log in to the provided administrator account and create a `mantidbuilder` user (`System Settings -> Users & Groups`). +- Enable `Remote Login` and `Remote Management` under `System Settings -> General -> Sharing` for all users, and note the hostname used after the `@` in the SSH login. +- Under `System Settings -> Privacy & Security`: + - Untick "Require password after sleep or screensaver begins". + - Turn off FileVault (otherwise the machine won't accept SSH connections until someone logs in locally after a reboot). +- Install the Xcode Command Line Tools: + + ```sh + xcode-select --install + ``` + +- Add your SSH key to the machine: + + ```sh + ssh-copy-id mantidbuilder@ + ``` + +## Registering the runner + +The `ansible/` directory automates the same steps: it generates a registration token via the GitHub API and configures/installs the runner as a service. + +1. Clone the [`dockerfiles`](https://github.com/mantidproject/dockerfiles) repo and navigate to `macOS/github-runner/ansible`. + +2. Create and activate a conda environment for Ansible (or reuse the one from `macOS/jenkins-node`): + + ```sh + mamba create --prefix ./condaenv ansible + mamba activate ./condaenv + ``` + +3. Install the required collections: + + ```sh + ansible-galaxy install -r requirements.yml --force + ``` + +4. Create an `inventory.txt` file with one line per machine: + + ```ini + [all] + runner_name= + runner_name= + ``` + +5. Add your SSH key to each host if you haven't already: + + ```sh + ssh-copy-id mantidbuilder@ + ``` + +6. Export the fine-grained PAT from the prerequisites and run the playbook: + + ```sh + export GITHUB_TOKEN= + ansible-playbook -i inventory.txt github-runner.yml -u mantidbuilder -K + ``` + + `-K` prompts for the `mantidbuilder` account password, needed to install the `launchd` service. + +7. Confirm the runner(s) appear at `https://github.com/mantidproject/mantid/settings/actions/runners` within a minute or two. + + Check `runner_version` in `github-runner.yml` occasionally against the [latest runner release](https://github.com/actions/runner/releases) and bump it when it's out of date — GitHub Actions runners auto-update themselves once registered, but a very stale starting version can fail to register. + +## Removing a runner + +1. Mark the runner offline/idle on GitHub first (don't remove while a job is running). +2. On the machine: + + ```sh + cd ~/actions-runner + ./svc.sh stop + ./svc.sh uninstall + ./config.sh remove --token + ``` + + The removal token is shown on the runner's page under `Settings -> Actions -> Runners -> -> Remove`, or can be generated via the [remove-token API endpoint](https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-remove-token-for-a-repository). + +## Troubleshooting + +- If `ansible-playbook` can't connect, you may need to log in locally or via VNC once first (FileVault can block SSH until the machine is unlocked). From another Mac: Finder -> `Cmd+K` -> `vnc://`, using the `mantidbuilder` login. +- If macOS blocks the downloaded runner binaries with a Gatekeeper/quarantine warning, clear the quarantine attribute before running `config.sh`: + + ```sh + xattr -d com.apple.quarantine ~/actions-runner/bin/* + ``` + +- `./svc.sh status` and `~/actions-runner/_diag/` logs are the first places to check if the runner shows as offline. From f4c8658a26922afcba89c233dd35cd739c329815 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Wed, 5 Aug 2026 11:49:57 +0100 Subject: [PATCH 2/5] Added ansible playbook for github runner --- macOS/github-runner/ansible/github-runner.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/macOS/github-runner/ansible/github-runner.yml b/macOS/github-runner/ansible/github-runner.yml index fbca9ae..b990b19 100644 --- a/macOS/github-runner/ansible/github-runner.yml +++ b/macOS/github-runner/ansible/github-runner.yml @@ -4,9 +4,7 @@ organization: mantidproject repository: mantid github_token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}" - # Check https://github.com/actions/runner/releases for the latest version. - runner_version: "2.319.1" - # Use "osx-arm64" for Apple Silicon machines, or "osx-x64" for Intel machines. + runner_version: "latest" runner_arch: "osx-arm64" pre_tasks: From 9a2f62a53dd11869d05931e7ad291ba69871f7fc Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 13 Aug 2026 09:37:44 +0100 Subject: [PATCH 3/5] Resolve version number of latest to avoid 404 --- .DS_Store | Bin 0 -> 8196 bytes macOS/.DS_Store | Bin 0 -> 10244 bytes macOS/github-runner/.DS_Store | Bin 0 -> 8196 bytes macOS/github-runner/ansible/.DS_Store | Bin 0 -> 8196 bytes macOS/github-runner/ansible/roles/.DS_Store | Bin 0 -> 8196 bytes .../ansible/roles/runner/.DS_Store | Bin 0 -> 8196 bytes .../ansible/roles/runner/tasks/main.yml | 24 +++++++++++++++--- macOS/github-runner/readme.md | 2 +- 8 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 .DS_Store create mode 100644 macOS/.DS_Store create mode 100644 macOS/github-runner/.DS_Store create mode 100644 macOS/github-runner/ansible/.DS_Store create mode 100644 macOS/github-runner/ansible/roles/.DS_Store create mode 100644 macOS/github-runner/ansible/roles/runner/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5dfff4d547ca37d5313ae9536594d2b34924fbb5 GIT binary patch literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#c58)VS;LkBiYRQiZRDq=z_#>KA=WX^ohj(#P~pvC@~RZ;u9|#!3PuLxpQ|LTBvUt0&|nO-@WIa zbEoIbcjoSyGRBZ9m`#k;FveuMIBF_&H)wpFU)MFMB&j3>*)x{Tj`+h_$ID))8wsKa zL=lK05Je!0Koo(SBLZ}0^Cr)5?u*r^k0KC7;I@nae?P?N;+QPqguw9CL0wn^5b_cr zY&51iAhd~M0fuSkwDXIsQOi?N^Ak1k!#?=XvC7ci_%o&6^L+Q>aRVWDWPIj?S zogpbO>Z1rm5x71AJbh-dA!e`~>zY!(pUDn8wjU%C7a&zs&YC?(o+GRBf%Kp^k`9cZ z;HQlIK0fRAJSSTo8`-_KHImV)TRk^0Y}d+%2DWLD%Kl#4HNBCPS8z=~v`vczS&@~D zRx>u%+}sq8H763|@z~hLwTXCaUGs+VaYbHKzh={(%n@hE^^OZCP6as^VhS{x^BKPI$udCzfndA=Rkp4;CSSjPgs#y6U>)HmRJ`Jgr2 ztk0(Xg;o{6N7pbn_V-$OpHNXw&0kV`&#L>@-v3ateOu@5^9!_vRcf`mxVLEgcGj_a zMr<<}>^J=%XNLac6pb+Le@T7u!B*p zUY5l@>hyX=J1y@w$;nR7N!E5Ky+z@%5LT;OWTh|X4GobqzL2H#Hd*^hKFDv} zVfaDUu;rHjq?Eo@mIwSnBX4z$5beqq9kLugMv`-rcGC{Ld>D%Ot0l z)hw;j(|V7rog*8~c8fLK z+u1=j%tqM>_5yo@eZWq$583DJTXuo{$bMzNvESJhc9s2wO3XzymSY7PunPBLEt;_& z8_vXwsnNvCd{Y_*SU-L`#4$4#4TKg{Rpbw~B0#Y_iX?iXF zL&i_ZlaTQtE2gtm zHHq?6OcPDDs#ZZ+sD!rb<1|HSvhhJx)ha0;#oA__rmQqcwbC{`yX60h=U=mP?0a^J zT_&FYjS9$Ef*4jJPQ2cXByqb9?ZoX}*n>2>aR3<@$P&{XxERJ!bVEitPQUexgVzkTNK|F?v%krPn_q6pkL0;p_Dx20%prgt5$wPSQWN*8ZjZ$e;b vLS0yn6NcqD;p9IIX&fU}Zj&tGgg}x|``M$;i36_kHEu;E7lq?I_# z3-<9Gz;)swO^0+;P_Bw=iqivxst_JAK&azp-w=k69}IS;Ryx!(@`(Z z#R;SZjoQcqkq0JwfWc-i=_M8kNZ+{gyF*OkTG_%w)`NKx(HH5<&2rL z=q#$xL)kueFdOJW(a-4K0mikvuAMLU_56Oz9L%ZJO|BE@mScKc!7@w~IoN4AhC7&X zi;m%Q-K?0PGL>`clHuXT#)f3PF_jug#)mhqO(o;&8aIrL$aG<1&8B_1qjtaJo)AVs z_+db6#+Q@GPGh0%mzsoy71^?dm&z8(vlV5o*4fqFbKqc3Rg1p4&$RWxDw)lCVEQ?A zzK;fPFSyPg&n%&#odwq}_B%MUprG4@A_|*ZZ98i{BBTqRYukHV-wG_(>Fx^5;{lsv z3yquV>hWDKXyS`?S-8HCs$$RBJ;0Rx{if$5mF3g(7RTOcl3VqLe-L`%Whw;X%nT( zt8^9f*0G`$45j!R_xyV|+1| z(VD6H1wG6j+^YM*?g7&&zfwlqMrn`Vr+en^K@7vPMk}TKXT)))(qdSF>v3=Fs?oG= zw$xU`Fby<%*^;GIT2||z>Uq>rEvIB*;Nx!~;-4nUftN_vi*DlFz&YOIK2D@lVz^q6 zv6dx2jigA1>>!8902v}D$#dj2@*X)u-Y1`uugOL7J^7jZLVhJz$u;r^RKjeihUKsV zYM~D9hPBWL>tO>lK`XSuF6e;*7;pr7!Gi#@n)`;MKhw=DR+o5$dGTlK<4i{mTm*Q~qu zfvsafDPp)Bwtt5MN5DATa0KuunHaqSmrASyAz~h%3ZCjL24#AIN!Q$|#MBuGBEhb# zMRq0vNU*Dtv6w0$ZUviah$(6XqEhC%>yyYr$ZWh%QPfJrrX4(DW*y?=6}dxPVi5Cxl3u5@FG{Xaa%Fp@D7oIO z}w57b&Q|pvbJt47<&&m;ZV;-mw;&FEW-!k?8|2MX1BprDm^1y$} z15nwVZO-5;mrwB%-=5vI$FV+yl@%s8DkxXMhF`}c<=64ZuzSTitV}k%_2B(j@|0iFYPuQkRxt;kJ&;Ne`SK6hs literal 0 HcmV?d00001 diff --git a/macOS/github-runner/.DS_Store b/macOS/github-runner/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6317c162c54cbaeed565b35d0b42bdc1175bd156 GIT binary patch literal 8196 zcmeHMU2GIp6u#fI&>1G+Pzw}f?A8j!vW6`M6j4~VZRDrrZ(I7q&pNv^&`Dd5P2Z-K;(hQ12=;Q=+5Rvp5fjX+^CH_5P9H#=>dK|#HezbEYWd6!=r3c}q< zFBXb3Bn6Gy$ODlFrh9;gPZcwm%Y0^Eo4}pG z4W|PmDEKKOzmJc)JkQCN`$l%JZ4GC%npV#Z4BNHxp@MB%B(lH9c1>?M)p@ z6Vt77{9kFxBzQ@iXuI%r%@;*^TIW=!l-Q6qhU47q!$@Z-NXIlS2wT^*;ZbekGRt18iUsP>e|Ii?pUhpQ>DwR^cJ%A z(SjX}XbrL~_Ndnz6z#OU-y|bDJ(I6!h8(?KZ7K_Omb(5_0=Dfi{GR7BkDZNeB zzLXF0jXMlK*g0gmo4`)*Kww^OD5I?**(ACRXNS&)z0k)E$%L4$5oDs} zmz>TLEXB65gKUV6uoLWg_Bwl?on{}f&)7HY0{eme!hU7Hu`BE<`xBLzgBmQwGBjcZ z?!jubU@g|66&>ir4)h}j6NhjZ4hksZ7)J0Ip2Sl)juUteFX3gpiq~)wZ{r=ji;wXM zKE>zw0vGTjF5xF!#uZ$}ACe+fOG_nPx>IVDR!B|KN@=6CN!lXqmincPG$3q{$^my^ z!ltkzjS!h~j8MSQXFwis(y8kQT;0Q4wr<^DsfBVee|8Gg#qKA$=5P9InJb=o!bX$sKXFA&?;>D;w zLX{UTH!f(XLJb$;^Ic>jFWQmRoN*pTx`iFoU|G^#I|Iz&~QsV#M{r@-4 C4|Zw* literal 0 HcmV?d00001 diff --git a/macOS/github-runner/ansible/.DS_Store b/macOS/github-runner/ansible/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..79a80dea9ebca44f3f940fc28d452333f5fd2b3d GIT binary patch literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#cIyhovW6`M6j4~VZRDrrZ(I7q&$_!a&KA=WX^ohj(#P~pvC@~RZ;u9|#!3PuLxpQ|Lwou~vS-Z8j(GX3?Pjmj4FzEY z!U%*B2qO?iAdJAx5dk{0d6TC(_r+@1hY<)Pa9c)zzaJuWaZHqPLSXRfpe`r@2zdz* zG#XPK5ZFY@m?-0fz`&ID6x9RDrYM&f5azTV;p&8mGEN8-<_yA|p?qhQD-;BGC%Z_X z&X5oo_F)9V2wWclo<1{Jfw|0PW>x)uCY!e{&yUA1K&q*oF>{tYOIGCrsUdeH)f@nXRgG^uGRq!F~JFnpX78J*J)Ut&-W1@l7wS&GX2?tvT1(RWM8B zSYOVyi^C4B%+F=)T#=N`&9$hlsp;gE4u`|z&y}f3^BUF@Aa~Cz?>KGm9@>@ z5zFw01~OjGbPUTmJV-HheCv>97L@sjDLqbR*gRj?uz1OxOLcv!c4e3TV%9oZwER&m zD$C*?O?p((PRsiZaM-fqBrTyvb>MW+Y2W3LaesvF-6PBJs!C%wpgXMDw?PC z9H9p=#u5&F_N5{bQ+fL7J_K(XwvlozSU;KFb#5g zNyFkgJ*D@`+Bve(ET?1<(diiozRS@H)1rwMF^rzgpAAMqjH8LT5Z4Qs?D^rQvp7q# zZR{Y+vr%?}y};gJAF$KxL-slQmR(>!vR~P6?00sBU1fiv7PC>0rC5e$tiZikjW(>s zI<%t;-PnOa-I78pm-0&*Nphg4ggmPU0QBi}&yeKE-GF0$<_+ ze!?aEjLW!!tN2q=q&jJ-q)T^6&C&{~MOrCslr~9Qq}|e>l$M5s4^k!B4ovzK45U$l zYhE9eY~{~?(y1FKTjL{Jwr<4|92X-BG__;iAa0mQ`yWczE+92?b{>G`*Jo z0pqLkBw&2Nim7ZBd8jt_Qc9S|rb|a{7EfLIJlAfzTW!>4P|}F$@@AUOq=XUEm9fS~ zO`<#%(|Bv6s?|^yDuM0V7)?>0tbb5dwOYzYv9?jCDJxHs?X(TgF8ROW`Pb|m`<`85 zmx@Cvkfh_8^5G96%ZwWQplE9OQ8n1&m=FPhbL163?H( zvv>|K;w9qxtHkz`coT2oZM=`u_y}k4alra-@EtDVmnl5%uI4fRsOE7gRd8(AIZVVk5dFet|fC;wqc;|Qs8n?xBW1d@c>|NbH1-+yd}=YM$qGw(Jy|NjB#>}}lu literal 0 HcmV?d00001 diff --git a/macOS/github-runner/ansible/roles/.DS_Store b/macOS/github-runner/ansible/roles/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9bde1299bbd3df0de7ae136b213a93d1065369a5 GIT binary patch literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#?$#BGWer;jD59`z+sIGL-?sFJpLKUVMmy0dwar@8mVY}ke#2tDw>^Z-8}qEtCeR_M5(!O=lYkOC0p zDL_!DPkBI~6Rpr>g^mjvsM4Audq71Ml@tR)o#vxloM^H_#|0JY3__iuvNI|f3WD89 zFB*t5Bn1uI&;y|duJr&9pP8)4O3b0Z$@%-4T*0h~f3M{j?r_R2IffVLrp1J; z$Vx_Q7#(eGZHY%)6N#~SbaegdL_E5tb=}yQA}@%o+OQ{c#2#|oHt|iOCSA4ZV$~*PwyMt2d;9ta_U+GTTFEo_n0D5;%4U1kH@%ED&m$AJ=3Qr3 z(JYf`y?NIz4LLM3KcBVpB@#9_+jiP|NJ!_4u5IsfJ&F)Zis0D0B%twWYsROTbDbUWE0^L$;y;w85()%B^;)m8dRIqPW2 z@<+6oEQ>uF^_ZfamiHTEWS4936^&p$$)_Qe=tZi3%%fe#8tXDV5N?+a`8X{vn!At4wvi6yL zkZ;_X_57U$)2TjEO5Y;O1Kwb^Xzm;);8is`WjT0_#OEppik|j&wB3DO&_}dItjWa;%EASh87kV`mFzgI?g{STZ5l^@2>a{DRY2 zf~D9tc90d=2s^=^VXv@v*lG4I`FmMQmVWWgHj$s53<1svr<2Zq*@jPC@OL!S4@dn<+TlfGU;v;;5 zPjLa?;S#>bWn95k{3iXdpd0@-dZQDC<*l_!1E)TF<>K80r6kXQ5YRx_OZ=QgmKy4MM ze-3~E^OGVaz`hT>2Obl1jdh{|C7y{f9!QbdZmjXDikWsqv4Wq5qa{}j?cXXn`0 z>=L_7NdFx*kg*6+EJvJ>y%9-5cRM-=-Mg>{X>{WNGRPuFShwMzfTJj46k~V<<9L*i z{sf-HQ+O875!zoQyr0CYcnz=PZJfq?ID_{C+<$?ua1lRDL2}n*B;%K! ziC;zkWR;tGR3o0gf#?4n(|`ZJscj4&KJ-B7fxq?uYTMK8DUzA)jN`d>l$s09i#c58)VS;LkBiYP4GHuBT*w=MnQXPw;{=!EG^*_qu^ zn`(X1fSUNC@&Ape52#TTeIoHcF+LC^N=(F<_{57w@WI4*?%dsmEz~y+fw{@t@7{CI zxzlszJ9GC;8DmHl%ofJ#7-KSB95t1?8#KPouj`srl2j9d>>2a3BmQvK@v_(HMuI2; zQ3Rq0L=lK05JlkThyb10yvfs?`(icfqX!2y`prELoKgqzAo`bYKJp zKV{_i@maU$Ioa~q$nLeRk&IT`=DC4kyH-9luuY3p_V?PZ>5Zhkf@}JrZCWhIimYU` zy0Nj=)|PmzHIW#P$HvyLPQ+ttTGx$_EAoQIRU7tXjyOZEcU(Au(u;u2nc~!mN{<}B z*e1S6RHe%vT`YT~%vRModT(FY=? z>&^N!rF`=Eydyccq^X zVw=HWzv1UB*R!vR~P6?00sBU1fiv8naQ0rC5e0tiZikjaID1 zI<%n^UD$yE-I78pm-0&*Nphg4ggmPU0QBi}&yeKE-GF0$<_+ ze!?aEjLW!!tN2q=q#9|dq)T^6P0|XfSz0M=lr~9Qq}|ehl#vF74^lbV4ovzK4x~|n zYhE9eY^BeC(y1FKTm2(jwr<;iA~G=2dGRczE+92?b}%G`*Jo zA>%9ZBxHQZim7ZBd8pR+P)bA%^9M6R$TSN!)Hn2XT8B_8^UJ96$yJvcz-;E{1Uwd5mEkPhbL163?H( zvv>|K;w9qxtHkz`coT2oZM=`u_y}k4ame~_@EtDVmnl5%s^l^LsN``mop&A2JxtOv z^D7N*iCLBKqK?=99n*jRza@N)oQNV2Mc~E}Ky`b%JwcVoIFf7LjC;wqc;~1%On`8+m1d@c>|NbH1-+ydJ=YMqmGygU?|Nj9T=WXHu literal 0 HcmV?d00001 diff --git a/macOS/github-runner/ansible/roles/runner/tasks/main.yml b/macOS/github-runner/ansible/roles/runner/tasks/main.yml index 651838f..8c67cdd 100644 --- a/macOS/github-runner/ansible/roles/runner/tasks/main.yml +++ b/macOS/github-runner/ansible/roles/runner/tasks/main.yml @@ -24,16 +24,34 @@ mode: "0755" when: not runner_configured.stat.exists +# runner_version may be a pinned version (e.g. "2.319.1") or "latest". The download +# URL always needs a real version number, so resolve "latest" via the GitHub API first. +- name: Look up the latest GitHub Actions runner release + ansible.builtin.uri: + url: "https://api.github.com/repos/actions/runner/releases/latest" + headers: + Accept: "application/vnd.github+json" + return_content: yes + register: latest_runner_release + when: not runner_configured.stat.exists and runner_version == "latest" + +- name: Resolve the runner version to download + ansible.builtin.set_fact: + resolved_runner_version: >- + {{ (latest_runner_release.json.tag_name | regex_replace('^v', '')) + if runner_version == "latest" else runner_version }} + when: not runner_configured.stat.exists + - name: Download the GitHub Actions runner package ansible.builtin.get_url: - url: "https://github.com/actions/runner/releases/download/v{{ runner_version }}/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" - dest: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" + url: "https://github.com/actions/runner/releases/download/v{{ resolved_runner_version }}/actions-runner-{{ runner_arch }}-{{ resolved_runner_version }}.tar.gz" + dest: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ resolved_runner_version }}.tar.gz" mode: "0644" when: not runner_configured.stat.exists - name: Extract the GitHub Actions runner package ansible.builtin.unarchive: - src: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ runner_version }}.tar.gz" + src: "{{ ansible_env.HOME }}/actions-runner/actions-runner-{{ runner_arch }}-{{ resolved_runner_version }}.tar.gz" dest: "{{ ansible_env.HOME }}/actions-runner" remote_src: yes when: not runner_configured.stat.exists diff --git a/macOS/github-runner/readme.md b/macOS/github-runner/readme.md index 48dc339..ab33edc 100644 --- a/macOS/github-runner/readme.md +++ b/macOS/github-runner/readme.md @@ -78,7 +78,7 @@ The `ansible/` directory automates the same steps: it generates a registration t 7. Confirm the runner(s) appear at `https://github.com/mantidproject/mantid/settings/actions/runners` within a minute or two. - Check `runner_version` in `github-runner.yml` occasionally against the [latest runner release](https://github.com/actions/runner/releases) and bump it when it's out of date — GitHub Actions runners auto-update themselves once registered, but a very stale starting version can fail to register. + `runner_version` in `github-runner.yml` defaults to `latest`, which is resolved to the current release via the GitHub API at deploy time. Pin it to a specific version (e.g. `2.319.1`) if you need reproducible deploys. ## Removing a runner From 8ae2f4b5fd395b17e980c4f662ce92231527fcad Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 13 Aug 2026 09:43:36 +0100 Subject: [PATCH 4/5] Update .gitignore and remove .DS_Store --- .DS_Store | Bin 8196 -> 0 bytes .gitignore | 1 + macOS/.DS_Store | Bin 10244 -> 0 bytes macOS/github-runner/.DS_Store | Bin 8196 -> 0 bytes macOS/github-runner/ansible/.DS_Store | Bin 8196 -> 0 bytes macOS/github-runner/ansible/roles/.DS_Store | Bin 8196 -> 0 bytes .../ansible/roles/runner/.DS_Store | Bin 8196 -> 0 bytes 7 files changed, 1 insertion(+) delete mode 100644 .DS_Store delete mode 100644 macOS/.DS_Store delete mode 100644 macOS/github-runner/.DS_Store delete mode 100644 macOS/github-runner/ansible/.DS_Store delete mode 100644 macOS/github-runner/ansible/roles/.DS_Store delete mode 100644 macOS/github-runner/ansible/roles/runner/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 5dfff4d547ca37d5313ae9536594d2b34924fbb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#c58)VS;LkBiYRQiZRDq=z_#>KA=WX^ohj(#P~pvC@~RZ;u9|#!3PuLxpQ|LTBvUt0&|nO-@WIa zbEoIbcjoSyGRBZ9m`#k;FveuMIBF_&H)wpFU)MFMB&j3>*)x{Tj`+h_$ID))8wsKa zL=lK05Je!0Koo(SBLZ}0^Cr)5?u*r^k0KC7;I@nae?P?N;+QPqguw9CL0wn^5b_cr zY&51iAhd~M0fuSkwDXIsQOi?N^Ak1k!#?=XvC7ci_%o&6^L+Q>aRVWDWPIj?S zogpbO>Z1rm5x71AJbh-dA!e`~>zY!(pUDn8wjU%C7a&zs&YC?(o+GRBf%Kp^k`9cZ z;HQlIK0fRAJSSTo8`-_KHImV)TRk^0Y}d+%2DWLD%Kl#4HNBCPS8z=~v`vczS&@~D zRx>u%+}sq8H763|@z~hLwTXCaUGs+VaYbHKzh={(%n@hE^^OZCP6as^VhS{x^BKPI$udCzfndA=Rkp4;CSSjPgs#y6U>)HmRJ`Jgr2 ztk0(Xg;o{6N7pbn_V-$OpHNXw&0kV`&#L>@-v3ateOu@5^9!_vRcf`mxVLEgcGj_a zMr<<}>^J=%XNLac6pb+Le@T7u!B*p zUY5l@>hyX=J1y@w$;nR7N!E5Ky+z@%5LT;OWTh|X4GobqzL2H#Hd*^hKFDv} zVfaDUu;rHjq?Eo@mIwSnBX4z$5beqq9kLugMv`-rcGC{Ld>D%Ot0l z)hw;j(|V7rog*8~c8fLK z+u1=j%tqM>_5yo@eZWq$583DJTXuo{$bMzNvESJhc9s2wO3XzymSY7PunPBLEt;_& z8_vXwsnNvCd{Y_*SU-L`#4$4#4TKg{Rpbw~B0#Y_iX?iXF zL&i_ZlaTQtE2gtm zHHq?6OcPDDs#ZZ+sD!rb<1|HSvhhJx)ha0;#oA__rmQqcwbC{`yX60h=U=mP?0a^J zT_&FYjS9$Ef*4jJPQ2cXByqb9?ZoX}*n>2>aR3<@$P&{XxERJ!bVEitPQUexgVzkTNK|F?v%krPn_q6pkL0;p_Dx20%prgt5$wPSQWN*8ZjZ$e;b vLS0yn6NcqD;p9IIX&fU}Zj&tGgg}x|``M$;i36_kHEu;E7lq?I_# z3-<9Gz;)swO^0+;P_Bw=iqivxst_JAK&azp-w=k69}IS;Ryx!(@`(Z z#R;SZjoQcqkq0JwfWc-i=_M8kNZ+{gyF*OkTG_%w)`NKx(HH5<&2rL z=q#$xL)kueFdOJW(a-4K0mikvuAMLU_56Oz9L%ZJO|BE@mScKc!7@w~IoN4AhC7&X zi;m%Q-K?0PGL>`clHuXT#)f3PF_jug#)mhqO(o;&8aIrL$aG<1&8B_1qjtaJo)AVs z_+db6#+Q@GPGh0%mzsoy71^?dm&z8(vlV5o*4fqFbKqc3Rg1p4&$RWxDw)lCVEQ?A zzK;fPFSyPg&n%&#odwq}_B%MUprG4@A_|*ZZ98i{BBTqRYukHV-wG_(>Fx^5;{lsv z3yquV>hWDKXyS`?S-8HCs$$RBJ;0Rx{if$5mF3g(7RTOcl3VqLe-L`%Whw;X%nT( zt8^9f*0G`$45j!R_xyV|+1| z(VD6H1wG6j+^YM*?g7&&zfwlqMrn`Vr+en^K@7vPMk}TKXT)))(qdSF>v3=Fs?oG= zw$xU`Fby<%*^;GIT2||z>Uq>rEvIB*;Nx!~;-4nUftN_vi*DlFz&YOIK2D@lVz^q6 zv6dx2jigA1>>!8902v}D$#dj2@*X)u-Y1`uugOL7J^7jZLVhJz$u;r^RKjeihUKsV zYM~D9hPBWL>tO>lK`XSuF6e;*7;pr7!Gi#@n)`;MKhw=DR+o5$dGTlK<4i{mTm*Q~qu zfvsafDPp)Bwtt5MN5DATa0KuunHaqSmrASyAz~h%3ZCjL24#AIN!Q$|#MBuGBEhb# zMRq0vNU*Dtv6w0$ZUviah$(6XqEhC%>yyYr$ZWh%QPfJrrX4(DW*y?=6}dxPVi5Cxl3u5@FG{Xaa%Fp@D7oIO z}w57b&Q|pvbJt47<&&m;ZV;-mw;&FEW-!k?8|2MX1BprDm^1y$} z15nwVZO-5;mrwB%-=5vI$FV+yl@%s8DkxXMhF`}c<=64ZuzSTitV}k%_2B(j@|0iFYPuQkRxt;kJ&;Ne`SK6hs diff --git a/macOS/github-runner/.DS_Store b/macOS/github-runner/.DS_Store deleted file mode 100644 index 6317c162c54cbaeed565b35d0b42bdc1175bd156..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6u#fI&>1G+Pzw}f?A8j!vW6`M6j4~VZRDrrZ(I7q&pNv^&`Dd5P2Z-K;(hQ12=;Q=+5Rvp5fjX+^CH_5P9H#=>dK|#HezbEYWd6!=r3c}q< zFBXb3Bn6Gy$ODlFrh9;gPZcwm%Y0^Eo4}pG z4W|PmDEKKOzmJc)JkQCN`$l%JZ4GC%npV#Z4BNHxp@MB%B(lH9c1>?M)p@ z6Vt77{9kFxBzQ@iXuI%r%@;*^TIW=!l-Q6qhU47q!$@Z-NXIlS2wT^*;ZbekGRt18iUsP>e|Ii?pUhpQ>DwR^cJ%A z(SjX}XbrL~_Ndnz6z#OU-y|bDJ(I6!h8(?KZ7K_Omb(5_0=Dfi{GR7BkDZNeB zzLXF0jXMlK*g0gmo4`)*Kww^OD5I?**(ACRXNS&)z0k)E$%L4$5oDs} zmz>TLEXB65gKUV6uoLWg_Bwl?on{}f&)7HY0{eme!hU7Hu`BE<`xBLzgBmQwGBjcZ z?!jubU@g|66&>ir4)h}j6NhjZ4hksZ7)J0Ip2Sl)juUteFX3gpiq~)wZ{r=ji;wXM zKE>zw0vGTjF5xF!#uZ$}ACe+fOG_nPx>IVDR!B|KN@=6CN!lXqmincPG$3q{$^my^ z!ltkzjS!h~j8MSQXFwis(y8kQT;0Q4wr<^DsfBVee|8Gg#qKA$=5P9InJb=o!bX$sKXFA&?;>D;w zLX{UTH!f(XLJb$;^Ic>jFWQmRoN*pTx`iFoU|G^#I|Iz&~QsV#M{r@-4 C4|Zw* diff --git a/macOS/github-runner/ansible/.DS_Store b/macOS/github-runner/ansible/.DS_Store deleted file mode 100644 index 79a80dea9ebca44f3f940fc28d452333f5fd2b3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#cIyhovW6`M6j4~VZRDrrZ(I7q&$_!a&KA=WX^ohj(#P~pvC@~RZ;u9|#!3PuLxpQ|Lwou~vS-Z8j(GX3?Pjmj4FzEY z!U%*B2qO?iAdJAx5dk{0d6TC(_r+@1hY<)Pa9c)zzaJuWaZHqPLSXRfpe`r@2zdz* zG#XPK5ZFY@m?-0fz`&ID6x9RDrYM&f5azTV;p&8mGEN8-<_yA|p?qhQD-;BGC%Z_X z&X5oo_F)9V2wWclo<1{Jfw|0PW>x)uCY!e{&yUA1K&q*oF>{tYOIGCrsUdeH)f@nXRgG^uGRq!F~JFnpX78J*J)Ut&-W1@l7wS&GX2?tvT1(RWM8B zSYOVyi^C4B%+F=)T#=N`&9$hlsp;gE4u`|z&y}f3^BUF@Aa~Cz?>KGm9@>@ z5zFw01~OjGbPUTmJV-HheCv>97L@sjDLqbR*gRj?uz1OxOLcv!c4e3TV%9oZwER&m zD$C*?O?p((PRsiZaM-fqBrTyvb>MW+Y2W3LaesvF-6PBJs!C%wpgXMDw?PC z9H9p=#u5&F_N5{bQ+fL7J_K(XwvlozSU;KFb#5g zNyFkgJ*D@`+Bve(ET?1<(diiozRS@H)1rwMF^rzgpAAMqjH8LT5Z4Qs?D^rQvp7q# zZR{Y+vr%?}y};gJAF$KxL-slQmR(>!vR~P6?00sBU1fiv7PC>0rC5e$tiZikjW(>s zI<%t;-PnOa-I78pm-0&*Nphg4ggmPU0QBi}&yeKE-GF0$<_+ ze!?aEjLW!!tN2q=q&jJ-q)T^6&C&{~MOrCslr~9Qq}|e>l$M5s4^k!B4ovzK45U$l zYhE9eY~{~?(y1FKTjL{Jwr<4|92X-BG__;iAa0mQ`yWczE+92?b{>G`*Jo z0pqLkBw&2Nim7ZBd8jt_Qc9S|rb|a{7EfLIJlAfzTW!>4P|}F$@@AUOq=XUEm9fS~ zO`<#%(|Bv6s?|^yDuM0V7)?>0tbb5dwOYzYv9?jCDJxHs?X(TgF8ROW`Pb|m`<`85 zmx@Cvkfh_8^5G96%ZwWQplE9OQ8n1&m=FPhbL163?H( zvv>|K;w9qxtHkz`coT2oZM=`u_y}k4alra-@EtDVmnl5%uI4fRsOE7gRd8(AIZVVk5dFet|fC;wqc;|Qs8n?xBW1d@c>|NbH1-+yd}=YM$qGw(Jy|NjB#>}}lu diff --git a/macOS/github-runner/ansible/roles/.DS_Store b/macOS/github-runner/ansible/roles/.DS_Store deleted file mode 100644 index 9bde1299bbd3df0de7ae136b213a93d1065369a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6u#fIzzh>$s09i#?$#BGWer;jD59`z+sIGL-?sFJpLKUVMmy0dwar@8mVY}ke#2tDw>^Z-8}qEtCeR_M5(!O=lYkOC0p zDL_!DPkBI~6Rpr>g^mjvsM4Audq71Ml@tR)o#vxloM^H_#|0JY3__iuvNI|f3WD89 zFB*t5Bn1uI&;y|duJr&9pP8)4O3b0Z$@%-4T*0h~f3M{j?r_R2IffVLrp1J; z$Vx_Q7#(eGZHY%)6N#~SbaegdL_E5tb=}yQA}@%o+OQ{c#2#|oHt|iOCSA4ZV$~*PwyMt2d;9ta_U+GTTFEo_n0D5;%4U1kH@%ED&m$AJ=3Qr3 z(JYf`y?NIz4LLM3KcBVpB@#9_+jiP|NJ!_4u5IsfJ&F)Zis0D0B%twWYsROTbDbUWE0^L$;y;w85()%B^;)m8dRIqPW2 z@<+6oEQ>uF^_ZfamiHTEWS4936^&p$$)_Qe=tZi3%%fe#8tXDV5N?+a`8X{vn!At4wvi6yL zkZ;_X_57U$)2TjEO5Y;O1Kwb^Xzm;);8is`WjT0_#OEppik|j&wB3DO&_}dItjWa;%EASh87kV`mFzgI?g{STZ5l^@2>a{DRY2 zf~D9tc90d=2s^=^VXv@v*lG4I`FmMQmVWWgHj$s53<1svr<2Zq*@jPC@OL!S4@dn<+TlfGU;v;;5 zPjLa?;S#>bWn95k{3iXdpd0@-dZQDC<*l_!1E)TF<>K80r6kXQ5YRx_OZ=QgmKy4MM ze-3~E^OGVaz`hT>2Obl1jdh{|C7y{f9!QbdZmjXDikWsqv4Wq5qa{}j?cXXn`0 z>=L_7NdFx*kg*6+EJvJ>y%9-5cRM-=-Mg>{X>{WNGRPuFShwMzfTJj46k~V<<9L*i z{sf-HQ+O875!zoQyr0CYcnz=PZJfq?ID_{C+<$?ua1lRDL2}n*B;%K! ziC;zkWR;tGR3o0gf#?4n(|`ZJscj4&KJ-B7fxq?uYTMK8DUzA)jN`d>l$s09i#c58)VS;LkBiYP4GHuBT*w=MnQXPw;{=!EG^*_qu^ zn`(X1fSUNC@&Ape52#TTeIoHcF+LC^N=(F<_{57w@WI4*?%dsmEz~y+fw{@t@7{CI zxzlszJ9GC;8DmHl%ofJ#7-KSB95t1?8#KPouj`srl2j9d>>2a3BmQvK@v_(HMuI2; zQ3Rq0L=lK05JlkThyb10yvfs?`(icfqX!2y`prELoKgqzAo`bYKJp zKV{_i@maU$Ioa~q$nLeRk&IT`=DC4kyH-9luuY3p_V?PZ>5Zhkf@}JrZCWhIimYU` zy0Nj=)|PmzHIW#P$HvyLPQ+ttTGx$_EAoQIRU7tXjyOZEcU(Au(u;u2nc~!mN{<}B z*e1S6RHe%vT`YT~%vRModT(FY=? z>&^N!rF`=Eydyccq^X zVw=HWzv1UB*R!vR~P6?00sBU1fiv8naQ0rC5e0tiZikjaID1 zI<%n^UD$yE-I78pm-0&*Nphg4ggmPU0QBi}&yeKE-GF0$<_+ ze!?aEjLW!!tN2q=q#9|dq)T^6P0|XfSz0M=lr~9Qq}|ehl#vF74^lbV4ovzK4x~|n zYhE9eY^BeC(y1FKTm2(jwr<;iA~G=2dGRczE+92?b}%G`*Jo zA>%9ZBxHQZim7ZBd8pR+P)bA%^9M6R$TSN!)Hn2XT8B_8^UJ96$yJvcz-;E{1Uwd5mEkPhbL163?H( zvv>|K;w9qxtHkz`coT2oZM=`u_y}k4ame~_@EtDVmnl5%s^l^LsN``mop&A2JxtOv z^D7N*iCLBKqK?=99n*jRza@N)oQNV2Mc~E}Ky`b%JwcVoIFf7LjC;wqc;~1%On`8+m1d@c>|NbH1-+ydJ=YMqmGygU?|Nj9T=WXHu From c5a3cd47043a3faf83494f50910320917f3891e8 Mon Sep 17 00:00:00 2001 From: Silke Schomann Date: Thu, 13 Aug 2026 11:33:57 +0100 Subject: [PATCH 5/5] Use agent_name instead of runner_name --- .../ansible/roles/runner/tasks/main.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/macOS/github-runner/ansible/roles/runner/tasks/main.yml b/macOS/github-runner/ansible/roles/runner/tasks/main.yml index 8c67cdd..68b3f8f 100644 --- a/macOS/github-runner/ansible/roles/runner/tasks/main.yml +++ b/macOS/github-runner/ansible/roles/runner/tasks/main.yml @@ -1,4 +1,12 @@ --- +- name: Fail if agent_name is not set for this host + ansible.builtin.assert: + that: agent_name is defined + fail_msg: >- + agent_name is not set for {{ inventory_hostname }}. Add 'agent_name=' to this + host's line in inventory.txt, e.g.: + {{ inventory_hostname }} agent_name= + - name: Check whether the runner is already configured ansible.builtin.stat: path: "{{ ansible_env.HOME }}/actions-runner/.runner" @@ -70,9 +78,9 @@ - --token - "{{ runner_token.json.token }}" - --name - - "{{ runner_name }}" + - "{{ agent_name }}" - --labels - - "{{ runner_name }}" + - "{{ agent_name }}" - --replace chdir: "{{ ansible_env.HOME }}/actions-runner" when: not runner_configured.stat.exists