Compare commits

...

9 Commits

Author SHA1 Message Date
malobot
02cabbbc8d Update flake.lock
All checks were successful
Weekly Flake Update / Explore-Gitea-Actions (pull_request) Successful in 27s
2026-03-19 00:09:10 +00:00
5634919fa6 cut var
All checks were successful
Weekly Flake Update / update_and_check_flake (push) Successful in 5m55s
2026-03-14 13:42:53 +01:00
394c0610ce Try out workflow check 2026-03-14 13:14:15 +01:00
6dee590206 Merge pull request 'Hydra integration' (#145) from ahtlon/infrastructure:hydra_integration3 into master
Reviewed-on: malobeo/infrastructure#145
Reviewed-by: kalipso <kalipso@c3d2.de>
2026-03-14 12:21:15 +01:00
b6cd2b57f8 Document the gitea-translator module 2026-03-13 16:30:31 +01:00
c80628a1a9 Add gitea-translator server and module 2026-03-13 16:09:12 +01:00
8cd2eafaa5 Fix master build 2026-03-13 15:50:32 +01:00
ed19426eb7 Add status callback 2026-03-13 15:21:14 +01:00
7ff64a5c16 Add hydra spec files 2026-03-13 14:39:49 +01:00
8 changed files with 364 additions and 19 deletions

View File

@@ -0,0 +1,33 @@
name: Weekly Flake Update
on:
pull_request:
types:
- opened
- synchronize
- edited
- reopened
permissions:
contents: write
jobs:
Explore-Gitea-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: Check for string parsing
run: |
var=$(echo "${{ github.ref }}" | cut -d / -f 3)
echo "$var"

View File

@@ -0,0 +1,75 @@
{ nixpkgs, pulls, ... }:
let
pkgs = import nixpkgs { };
prs = builtins.fromJSON (builtins.readFile pulls);
prJobsets = pkgs.lib.mapAttrs (num: info: {
enabled = 1;
hidden = false;
description = "PR ${num}: ${info.title}";
checkinterval = 300;
schedulingshares = 20;
enableemail = false;
emailoverride = "";
keepnr = 1;
type = 1;
flake = "${info.head.repo.html_url}/archive/${info.head.ref}.tar.gz";
inputs = {
gitea_repo_name = {
type = "string";
value = "${info.head.repo.name}";
emailresponsible = false;
};
gitea_repo_owner = {
type = "string";
value = "${info.head.repo.owner.username}";
emailresponsible = false;
};
gitea_http_url = {
type = "string";
value = "https://git.dynamicdiscord.de";
emailresponsible = false;
};
gitea_status_repo = {
type = "string";
value = "${info.head.ref}";
emailresponsible = false;
};
};
}) prs;
mkFlakeJobset = branch: {
description = "Build ${branch} branch of the Malobeo Infrastructure repo";
checkinterval = 300;
enabled = "1";
schedulingshares = 100;
enableemail = false;
emailoverride = "";
keepnr = 3;
hidden = false;
type = 1;
flake = "https://git.dynamicdiscord.de/malobeo/infrastructure/archive/${branch}.tar.gz";
};
desc = prJobsets // {
"master" = mkFlakeJobset "master";
};
log = {
pulls = prs;
jobsets = desc;
};
in
{
jobsets = pkgs.runCommand "spec-jobsets.json" { } ''
cat >$out <<'EOF'
${builtins.toJSON desc}
EOF
# This is to get nice .jobsets build logs on Hydra
cat >tmp <<'EOF'
${builtins.toJSON log}
EOF
${pkgs.jq}/bin/jq . tmp
'';
}

30
.hydra/spec.json Normal file
View File

@@ -0,0 +1,30 @@
{
"enabled": 1,
"hidden": false,
"description": "Malobeo infrastructure repo",
"nixexprinput": "nixexpr",
"nixexprpath": ".hydra/declarative-jobsets.nix",
"checkinterval": 60,
"schedulingshares": 100,
"enableemail": false,
"emailoverride": "",
"keepnr": 5,
"type": 0,
"inputs": {
"nixexpr": {
"value": "https://git.dynamicdiscord.de/ahtlon/infrastructure master",
"type": "git",
"emailresponsible": false
},
"nixpkgs": {
"value": "https://github.com/NixOS/nixpkgs nixos-25.11",
"type": "git",
"emailresponsible": false
},
"pulls": {
"type": "path",
"value": "http://127.0.0.1:27364/gitea-pulls-sorted.json",
"emailresponsible": false
}
}
}

View File

@@ -12,6 +12,7 @@
- [musik](./projekte/musik.md) - [musik](./projekte/musik.md)
- [TODO](./todo.md) - [TODO](./todo.md)
- [Modules]() - [Modules]()
- [Gitea-translator](./module/gitea-translator.md)
- [Initrd-ssh](./module/initssh.md) - [Initrd-ssh](./module/initssh.md)
- [Disks](./module/disks.md) - [Disks](./module/disks.md)
- [How-to]() - [How-to]()

View File

@@ -0,0 +1,21 @@
# Gitea-tanslator
The module can be used by importing `inputs.self.nixosModules.malobeo.gitea-translator`
This module starts a python server that fetches the gitea pull request api and translates it to a file that hydra understands.
To use, just set the parameters of the gitea server, then send a GET request to either `http://${host}:${port}/` or `http://${host}:${port}/gitea-pulls-sorted.json`
## Module config
##### enable (default = false) - enables the module
##### baseurl (default = "git.dynamicdiscord.de") - Base URL of the Gitea instance
##### owner (default = "malobeo") - Repository owner
##### repo (default = "infrastructure") - Repository name
##### host (default = "127.0.0.1") - Address the server binds to
##### port (default = 27364) - Port the server listens on
## Hydra config
If you change the default port or host, the file `.hydra/spec.json` has to be modified accordingly.
With the module running on the hydra host, create a new hydra project, then:
- Set `Declarative spec file` to `.hydra/spec.json`
- Change declaritive input type to `Git checkout`
- Set your git repo location in the field below that

38
flake.lock generated
View File

@@ -126,11 +126,11 @@
"spectrum": "spectrum" "spectrum": "spectrum"
}, },
"locked": { "locked": {
"lastModified": 1772055583, "lastModified": 1773872447,
"narHash": "sha256-iPIm1orqkhsxqju6EVODOrV1BmyA5HNTZ8a1o812bFM=", "narHash": "sha256-IWTp4EMUfZwnuF5S/AjWfOFzCbbgkMzRwNd0qHC/EMg=",
"owner": "astro", "owner": "astro",
"repo": "microvm.nix", "repo": "microvm.nix",
"rev": "f6dcfb7c16cc3775536c825dc0698d4ede13d063", "rev": "b202882536b018a76f0b6e71a48677f41f4de9d8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -177,11 +177,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1771969195, "lastModified": 1773533765,
"narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=", "narHash": "sha256-qonGfS2lzCgCl59Zl63jF6dIRRpvW3AJooBGMaXjHiY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e", "rev": "f8e82243fd601afb9f59ad230958bd073795cbfe",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -209,11 +209,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1771848320, "lastModified": 1773734432,
"narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", "narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2fc6539b481e1d2569f25f8799236694180c0993", "rev": "cda48547b432e8d3b18b4180ba07473762ec8558",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -225,11 +225,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1771903837, "lastModified": 1773814637,
"narHash": "sha256-sdaqdnsQCv3iifzxwB22tUwN/fSHoN7j2myFW5EIkGk=", "narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e764fc9a405871f1f6ca3d1394fb422e0a0c3951", "rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -264,11 +264,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772048434, "lastModified": 1773698643,
"narHash": "sha256-/wA0OaH6kZ/pFA+nXR/tvg5oupOmEDmMS5us79JT60o=", "narHash": "sha256-VCiDjE8kNs8uCAK73Ezk1r3fFuc4JepvW07YFqaN968=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "334daa7c273dd8bf7a0cd370e4e16022b64e55e9", "rev": "8237de83e8200d16fe0c4467b02a1c608ff28044",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -280,11 +280,11 @@
"spectrum": { "spectrum": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1759482047, "lastModified": 1772189877,
"narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", "narHash": "sha256-i1p90Rgssb//aNiTDFq46ZG/fk3LmyRLChtp/9lddyA=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", "rev": "fe39e122d898f66e89ffa17d4f4209989ccb5358",
"revCount": 996, "revCount": 1255,
"type": "git", "type": "git",
"url": "https://spectrum-os.org/git/spectrum" "url": "https://spectrum-os.org/git/spectrum"
}, },

View File

@@ -0,0 +1,78 @@
{ config, self, lib, inputs, pkgs, ... }:
with lib;
let
cfg = config.services.malobeo.gitea-translator;
in
{
options = {
services.malobeo.gitea-translator = {
enable = mkOption {
default = false;
type = types.bool;
description = lib.mdDoc "Start a webserver for hydra to use the gitea pull request api.";
};
baseurl = mkOption {
type = types.str;
default = "git.dynamicdiscord.de";
description = lib.mdDoc "Base URL of the Gitea instance.";
};
owner = mkOption {
type = types.str;
default = "malobeo";
description = lib.mdDoc "Repository owner on the Gitea instance.";
};
repo = mkOption {
type = types.str;
default = "infrastructure";
description = lib.mdDoc "Repository name on the Gitea instance.";
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = lib.mdDoc "Address the server binds to.";
};
port = mkOption {
type = types.port;
default = 27364;
description = lib.mdDoc "Port the server listens on.";
};
};
};
config = mkIf cfg.enable {
systemd.services.gitea-translator = {
description = "Gitea Pull Request Translator for Hydra";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.python3}/bin/python3 ${inputs.self + /scripts/gitea_hydra_server.py} \
--baseurl ${cfg.baseurl} \
--owner ${cfg.owner} \
--repo ${cfg.repo} \
--host ${cfg.host} \
--port ${toString cfg.port}
'';
Restart = "on-failure";
RestartSec = 5;
# Hardening because why not
DynamicUser = true;
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
};
};
};
}

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
#imports
import os
import json
import argparse
from http.server import BaseHTTPRequestHandler, HTTPServer
import urllib.request
def _get_api_response(baseurl, owner, repo):
###https://docs.gitea.com/api/1.21/#tag/repository/operation/repoListPullRequests
###GET /api/v1/repos/{owner}/{repo}/pulls
url=(f"https://{baseurl}/api/v1/repos/{owner}/{repo}/pulls?state=open")
headers={"Accept": "application/json"}
req=urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read().decode("utf-8"))
def _parse_response(baseurl, owner, repo):
target_repo_url=f"https://{baseurl}/{owner}/{repo}.git"
pulls: dict={}
response=_get_api_response(baseurl, owner, repo)
for pr in response:
pr["target_repo_url"]=target_repo_url
pulls[str(pr["number"])]=pr
return pulls
class PullsHandler(BaseHTTPRequestHandler):
_VALID_PATHS={"/", "/gitea-pulls-sorted.json"}
# Class variables to store configuration
baseurl = None
owner = None
repo = None
def do_GET(self):
if self.path not in self._VALID_PATHS:
self.send_error(404, "Not Found")
return
answer=dict(_parse_response(self.baseurl, self.owner, self.repo))
body=json.dumps(answer, indent=2, sort_keys=True).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, fmt, *args):
print(
f"[gitea-translator] {self.address_string()} - {fmt % args}",
flush=True,
)
def main():
parser = argparse.ArgumentParser(
description="Hydra Server to Gitea-pull-request translator"
)
parser.add_argument(
"--baseurl",
default="git.dynamicdiscord.de",
help="Base URL of Gitea instance (default: git.dynamicdiscord.de)"
)
parser.add_argument(
"--owner",
default="malobeo",
help="Repository owner (default: malobeo)"
)
parser.add_argument(
"--repo",
default="infrastructure",
help="Repository name (default: infrastructure)"
)
parser.add_argument(
"--host",
default="127.0.0.1",
help="Host to bind to (default: 127.0.0.1)"
)
parser.add_argument(
"--port",
type=int,
default=27364,
help="Port to bind to (default: 27364)"
)
args = parser.parse_args()
# Set class variables so they're accessible in request handlers
PullsHandler.baseurl = args.baseurl
PullsHandler.owner = args.owner
PullsHandler.repo = args.repo
print(
f"[gitea-translator] Starting, pulling from {args.baseurl}/{args.owner}/{args.repo}",
flush=True,
)
server=HTTPServer((args.host, args.port), PullsHandler)
print(
f"[gitea-translator] online @ {args.host}:{args.port}",
flush=True,
)
server.serve_forever()
if __name__ == "__main__":
main()