4 Commits

Author SHA1 Message Date
Kevin Veen-Birkenbach
f270a5c7c6 Release version 1.0.1
Some checks failed
CI / test (push) Has been cancelled
Stable Tag / test (push) Has been cancelled
Stable Tag / tag-stable (push) Has been cancelled
2025-12-23 17:50:24 +01:00
Kevin Veen-Birkenbach
5e5b6c8933 fix(nix/e2e): keep Playwright install output off stdout
Some checks failed
CI / test (push) Has been cancelled
- Build matomo-bootstrap with setuptools/wheel in Nix
- Run playwright install via a dedicated pythonPlaywright env and redirect logs to stderr
- Add Nix-based E2E path: nix runner service + persistent nix/home volumes + host networking
- Add E2E test that runs bootstrap via `nix run` and asserts token-only stdout

https://chatgpt.com/share/694ab489-7028-800f-8398-a19a99faffd0
2025-12-23 17:44:41 +01:00
Kevin Veen-Birkenbach
1af480ee91 chore(nix): pin nixpkgs via flake.lock for reproducible runs
https://chatgpt.com/share/694ab489-7028-800f-8398-a19a99faffd0
2025-12-23 17:29:03 +01:00
Kevin Veen-Birkenbach
4f7de18a11 Release version 1.0.0
Some checks failed
CI / test (push) Has been cancelled
Stable Tag / test (push) Has been cancelled
Stable Tag / tag-stable (push) Has been cancelled
2025-12-23 13:33:39 +01:00
6 changed files with 161 additions and 9 deletions

11
CHANGELOG.md Normal file
View File

@@ -0,0 +1,11 @@
## [1.0.1] - 2025-12-23
* * Support for running `matomo-bootstrap` **fully via Nix** in a clean, containerized environment.
* A **token-only stdout contract**: the bootstrap command now prints only the API token, making it safe for automation.
* Reproducible Nix builds via a pinned `flake.lock`.
## [1.0.0] - 2025-12-23
* 🥳

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1766309749,
"narHash": "sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC+2IVK0NoVEzDoOh4DA4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a6531044f6d0bef691ea18d4d4ce44d0daa6e816",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -19,16 +19,19 @@
rec {
matomo-bootstrap = python.pkgs.buildPythonApplication {
pname = "matomo-bootstrap";
version = "0.1.0"; # keep in sync with pyproject.toml
version = "1.0.1"; # keep in sync with pyproject.toml
pyproject = true;
src = self;
# Runtime deps (Python)
nativeBuildInputs = with python.pkgs; [
setuptools
wheel
];
propagatedBuildInputs = with python.pkgs; [
playwright
];
# Optional: keep tests off in nix build by default
doCheck = false;
meta = with pkgs.lib; {
@@ -46,16 +49,22 @@
apps = forAllSystems (system:
let
pkgs = import nixpkgs { inherit system; };
python = pkgs.python312;
pythonPlaywright = python.withPackages (ps: [
ps.playwright
]);
matomo = self.packages.${system}.matomo-bootstrap;
playwright-install = pkgs.writeShellApplication {
name = "matomo-bootstrap-playwright-install";
runtimeInputs = [ matomo ];
runtimeInputs = [ pythonPlaywright ];
text = ''
# Installs the Playwright Chromium browser into the user cache.
# This is needed when the Matomo instance is not installed yet and
# the web installer must be driven via Playwright.
exec ${matomo}/bin/python -m playwright install chromium
# Install Playwright browsers.
# IMPORTANT: Do not print anything to stdout (tests expect token-only stdout).
exec ${pythonPlaywright}/bin/python -m playwright install chromium 1>&2
'';
};
in

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "matomo-bootstrap"
version = "0.1.0"
version = "1.0.1"
description = "Headless bootstrap tooling for Matomo (installation + API token provisioning)"
readme = "README.md"
requires-python = ">=3.10"

View File

@@ -27,3 +27,50 @@ services:
MATOMO_DATABASE_USERNAME: matomo
MATOMO_DATABASE_PASSWORD: matomo_pw
MATOMO_DATABASE_DBNAME: matomo
nix:
image: nixos/nix:latest
container_name: e2e-nix
depends_on:
matomo:
condition: service_started
# Run as root to avoid /nix big-lock permission issues
user: "0:0"
working_dir: /work
volumes:
# Project root as flake
- ../../:/work:ro
# Nix store (removed by docker compose down -v)
- e2e_nix_store:/nix
# HOME/XDG for nix + playwright
- e2e_nix_home:/tmp/home
environment:
NIX_CONFIG: "experimental-features = nix-command flakes"
TERM: "xterm"
HOME: "/tmp/home"
USER: "root"
LOGNAME: "root"
XDG_CACHE_HOME: "/tmp/home/.cache"
XDG_CONFIG_HOME: "/tmp/home/.config"
XDG_DATA_HOME: "/tmp/home/.local/share"
MATOMO_SITE_NAME: "Matomo E2E"
MATOMO_SITE_URL: "http://127.0.0.1:8080"
MATOMO_TIMEZONE: "Germany - Berlin"
command: >
sh -lc "mkdir -p /tmp/home/.cache /tmp/home/.config /tmp/home/.local/share;
tail -f /dev/null"
# Allow access to host-published Matomo port
network_mode: host
volumes:
e2e_nix_store:
e2e_nix_home:

View File

@@ -0,0 +1,58 @@
import os
import subprocess
import unittest
MATOMO_URL = os.environ.get("MATOMO_URL", "http://127.0.0.1:8080")
ADMIN_USER = os.environ.get("MATOMO_ADMIN_USER", "administrator")
ADMIN_PASSWORD = os.environ.get("MATOMO_ADMIN_PASSWORD", "AdminSecret123!")
ADMIN_EMAIL = os.environ.get("MATOMO_ADMIN_EMAIL", "administrator@example.org")
class TestMatomoBootstrapE2ENix(unittest.TestCase):
def test_bootstrap_creates_api_token_via_nix(self) -> None:
script = f"""set -euo pipefail
export NIX_CONFIG='experimental-features = nix-command flakes'
export TERM='xterm'
# Make sure we have a writable HOME (compose already sets HOME=/tmp/home)
mkdir -p "$HOME" "$HOME/.cache" "$HOME/.config" "$HOME/.local/share"
# IMPORTANT:
# Nix flakes read the local repo as git+file:///work.
# Git refuses if the repo is not owned by the current user (root in the container).
# Mark it as safe explicitly.
git config --global --add safe.directory /work
# 1) Install Playwright Chromium (cached in the container environment)
nix run --no-write-lock-file -L .#matomo-bootstrap-playwright-install
# 2) Run bootstrap (must print ONLY token)
nix run --no-write-lock-file -L .#matomo-bootstrap -- \\
--base-url '{MATOMO_URL}' \\
--admin-user '{ADMIN_USER}' \\
--admin-password '{ADMIN_PASSWORD}' \\
--admin-email '{ADMIN_EMAIL}' \\
--token-description 'e2e-test-token-nix'
"""
cmd = [
"docker",
"compose",
"-f",
"tests/e2e/docker-compose.yml",
"exec",
"-T",
"nix",
"sh",
"-lc",
script,
]
token = subprocess.check_output(cmd).decode().strip()
self.assertRegex(token, r"^[a-f0-9]{32,64}$")
if __name__ == "__main__":
unittest.main()