diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 55e3453..6a9f76f 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -295,6 +295,49 @@ jobs: --checklist-confirmed \ --checklist-categories 1,2,3,4,5,6,7,8,9,10,11,12,13 \ --body "Auto-approved: all CI checks passed (validate, molecule-tests)." + - name: Wait for molecule tests to complete + env: + CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + . .venv/bin/activate 2>/dev/null || true + # Poll commit status until all required checks pass or fail + MAX_WAIT=600 # 10 minutes + ELAPSED=0 + while [ $ELAPSED -lt $MAX_WAIT ]; do + STATUS=$(curl -s -H "Authorization: token $CI_GITEA_API_TOKEN" \ + "https://git.oblachno.oblachno.fyi/api/v1/repos/${{ github.repository }}/commits/$HEAD_SHA/status" \ + | python3 -c " + import sys,json + d=json.load(sys.stdin) + statuses={s['context']:s['status'] for s in d.get('statuses',[])} + # Check if all molecule-tests contexts are terminal (success/failure) + mol_contexts=[k for k in statuses if 'molecule-tests' in k] + if not mol_contexts: + print('pending') + elif all(statuses[k] in ('success','failure') for k in mol_contexts): + if any(statuses[k]=='failure' for k in mol_contexts): + print('failure') + else: + print('success') + else: + print('pending') + ") + echo "Molecule tests status: $STATUS (elapsed: ${ELAPSED}s)" + if [ "$STATUS" = "success" ]; then + echo "All molecule tests passed." + break + elif [ "$STATUS" = "failure" ]; then + echo "ERROR: Molecule tests failed. Aborting auto-merge." + exit 1 + fi + sleep 30 + ELAPSED=$((ELAPSED + 30)) + done + if [ $ELAPSED -ge $MAX_WAIT ]; then + echo "ERROR: Timed out waiting for molecule tests." + exit 1 + fi - name: Squash merge with task ID env: CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }} diff --git a/ansible/roles/gitea_runner/tasks/healthcheck.yml b/ansible/roles/gitea_runner/tasks/healthcheck.yml index 30bd8c7..a99374d 100644 --- a/ansible/roles/gitea_runner/tasks/healthcheck.yml +++ b/ansible/roles/gitea_runner/tasks/healthcheck.yml @@ -40,24 +40,22 @@ mode: "0644" - name: Reload systemd user daemon for healthcheck timer - ansible.builtin.command: systemctl --user daemon-reload - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user daemon-reload changed_when: true when: - gitea_runner_systemd_available.stat.exists - gitea_runner_docker_rootless_setup - name: Enable and start healthcheck user timer - ansible.builtin.command: systemctl --user enable --now runner-healthcheck.timer - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user enable --now runner-healthcheck.timer changed_when: true when: - gitea_runner_systemd_available.stat.exists diff --git a/ansible/roles/gitea_runner/tasks/install_runner.yml b/ansible/roles/gitea_runner/tasks/install_runner.yml index b977c45..82d4c73 100644 --- a/ansible/roles/gitea_runner/tasks/install_runner.yml +++ b/ansible/roles/gitea_runner/tasks/install_runner.yml @@ -13,9 +13,9 @@ - name: Include validation ansible.builtin.include_tasks: validate.yml +- name: Include service setup + ansible.builtin.include_tasks: service.yml + - name: Include registration ansible.builtin.include_tasks: register.yml when: not gitea_runner_skip_registration - -- name: Include service setup - ansible.builtin.include_tasks: service.yml diff --git a/ansible/roles/gitea_runner/tasks/prune.yml b/ansible/roles/gitea_runner/tasks/prune.yml index 245b17c..a5a81ea 100644 --- a/ansible/roles/gitea_runner/tasks/prune.yml +++ b/ansible/roles/gitea_runner/tasks/prune.yml @@ -18,12 +18,11 @@ register: gitea_runner_prune_timer - name: Reload systemd user daemon for prune timer - ansible.builtin.command: systemctl --user daemon-reload - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user daemon-reload changed_when: true when: - gitea_runner_systemd_available.stat.exists @@ -31,12 +30,11 @@ - gitea_runner_prune_service is changed or gitea_runner_prune_timer is changed - name: Enable and start docker-prune user timer - ansible.builtin.command: systemctl --user enable --now docker-prune.timer - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user enable --now docker-prune.timer changed_when: true when: - gitea_runner_systemd_available.stat.exists diff --git a/ansible/roles/gitea_runner/tasks/register.yml b/ansible/roles/gitea_runner/tasks/register.yml index d0a9248..9ae4b77 100644 --- a/ansible/roles/gitea_runner/tasks/register.yml +++ b/ansible/roles/gitea_runner/tasks/register.yml @@ -44,13 +44,16 @@ ('already exists' not in gitea_runner_register_output.stdout | default('')) timeout: 60 -- name: Ensure runner service is running after registration - ansible.builtin.command: systemctl --user start gitea-runner - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" +# Note: service start is handled by service.yml (included after register.yml +# in install_runner.yml). Starting here fails because the systemd unit file +# has not been created yet. + +- name: Restart runner service after (re-)registration + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user restart gitea-runner changed_when: true when: - gitea_runner_systemd_available.stat.exists diff --git a/ansible/roles/gitea_runner/tasks/rootless_docker.yml b/ansible/roles/gitea_runner/tasks/rootless_docker.yml index 8f087dc..ae01c8c 100644 --- a/ansible/roles/gitea_runner/tasks/rootless_docker.yml +++ b/ansible/roles/gitea_runner/tasks/rootless_docker.yml @@ -143,6 +143,10 @@ {% if gitea_runner_docker_rootless_net_driver == 'pasta' %} Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--ipv6" {% endif %} + Restart=always + RestartSec=5 + StartLimitIntervalSec=300 + StartLimitBurst=10 mode: "0644" owner: "{{ gitea_runner_service_user }}" group: "{{ gitea_runner_service_user }}" @@ -212,22 +216,20 @@ - not gitea_runner_rootless_docker_check.stat.exists - name: Start rootless Docker daemon (systemd user service) - ansible.builtin.command: systemctl --user start docker - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user start docker changed_when: true when: gitea_runner_docker_rootless_setup - name: Enable rootless Docker daemon (systemd user service) - ansible.builtin.command: systemctl --user enable docker - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user enable docker changed_when: true when: gitea_runner_docker_rootless_setup @@ -250,6 +252,10 @@ {% if gitea_runner_docker_rootless_net_driver == 'pasta' %} Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--ipv6" {% endif %} + Restart=always + RestartSec=5 + StartLimitIntervalSec=300 + StartLimitBurst=10 mode: "0644" owner: "{{ gitea_runner_service_user }}" group: "{{ gitea_runner_service_user }}" @@ -257,12 +263,11 @@ when: gitea_runner_docker_rootless_setup - name: Reload systemd user daemon if network config changed - ansible.builtin.command: systemctl --user daemon-reload - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user daemon-reload changed_when: true when: - gitea_runner_docker_rootless_setup @@ -300,12 +305,11 @@ when: gitea_runner_docker_rootless_setup - name: Restart rootless Docker if config changed - ansible.builtin.command: systemctl --user restart docker - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user restart docker changed_when: true when: - gitea_runner_docker_rootless_setup diff --git a/ansible/roles/gitea_runner/tasks/service.yml b/ansible/roles/gitea_runner/tasks/service.yml index bc18c8a..b47ed62 100644 --- a/ansible/roles/gitea_runner/tasks/service.yml +++ b/ansible/roles/gitea_runner/tasks/service.yml @@ -9,12 +9,11 @@ register: gitea_runner_service_file - name: Reload systemd user daemon - ansible.builtin.command: systemctl --user daemon-reload - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user daemon-reload changed_when: true when: - gitea_runner_systemd_available.stat.exists @@ -22,12 +21,11 @@ - gitea_runner_service_file is changed - name: Restart gitea-runner if service file changed - ansible.builtin.command: systemctl --user restart gitea-runner - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user restart gitea-runner changed_when: true when: - gitea_runner_systemd_available.stat.exists @@ -35,12 +33,11 @@ - gitea_runner_service_file is changed - name: Enable and start gitea-runner user service - ansible.builtin.command: systemctl --user enable --now gitea-runner - become: true - become_user: "{{ gitea_runner_service_user }}" - environment: - XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus" + ansible.builtin.command: > + runuser -u {{ gitea_runner_service_user }} -- + env XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }} + DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus + systemctl --user enable --now gitea-runner changed_when: true when: - gitea_runner_systemd_available.stat.exists diff --git a/pyproject.toml b/pyproject.toml index 3ef3fcb..cacdfb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ ci = [ "build==1.5.1", "twine==6.2.0", # Reusable CI/CD and dev tools (auto-merge, pr-review, pre-push checks, etc.) - "devx @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git@v0.50.0", + "devx @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git@v0.50.1", ] # Lint and type-checking tools (validate job) lint = [ @@ -56,7 +56,7 @@ molecule = [ dev = [ "grm[ci,lint,molecule]", # Reusable CI/CD and dev tools (pre-push hooks, create-task, create-pr) - "devx @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git@v0.50.0", + "devx @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git@v0.50.1", # Non-Python dev dependency: checkmake (Makefile linter) # Install via: go install github.com/checkmake/checkmake/cmd/checkmake@latest ]