From 649eb224b7fc81a06d69a6a2eb9849496271fa4d Mon Sep 17 00:00:00 2001
From: Patrick Kollitsch <patrick@davids-neighbour.com>
Date: Thu, 30 Jan 2025 23:46:16 +0000
Subject: [PATCH] ci(workflow): add CODEOWNERS for i18n
---
.github/CODEOWNERS | 37 ++++++++++++
.github/scripts/codeowners.mjs | 93 +++++++++++++++++++++++++++++++
.github/workflows/update-codeowners.yaml | 37 ++++++++++++
3 files changed, 167 insertions(+), 0 deletions(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..d2708b2
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,37 @@
+# Lines starting with '#' are comments.
+# Each line is a file pattern followed by one or more owners.
+# These owners will be the default owners for everything in the repo.
+# * <@insert_github_username>
+#
+# Order is important. The last matching pattern has the most precedence.
+
+# This file is also being managed automatically by the gitown tool.
+* @davidsneighbour
+
+# i18n - automatically created
+/i18n/ca.toml @mrodriguezestivill
+/i18n/es.toml @eddex @hello @jerryzihye @regisphilibert @melvinsalasrivera @mrodriguezestivill @sarahrhgrefalda
+/i18n/pl.toml @izikeros
+/i18n/cs.toml @petr.vala
+/i18n/bg.toml @foxbg @jerryzihye @sarahrhgrefalda
+/i18n/he.toml @MeirKriheli
+/i18n/hi.toml @neerajsharma.9
+/i18n/fi.toml @github
+/i18n/ru.toml @365029+uonick @agrrh @eddex @jerryzihye @sarahrhgrefalda
+/i18n/tr.toml @sarahrhgrefalda @yagizhan49
+/i18n/en.toml @eddex @jan.steinke @jerryzihye @kinski @regisphilibert @sarahrhgrefalda
+/i18n/zh-tw.toml @peter-jerry-ye @s104213083 @sarahrhgrefalda
+/i18n/uk.toml @jerryzihye @mivanchenko @sarahrhgrefalda
+/i18n/nl.toml @eddex @jerryzihye @johan.vervloet @sarahrhgrefalda
+/i18n/fr.toml @charles @eddex @jerryzihye @login @manu @sarahrhgrefalda
+/i18n/oc.toml @59049879+ensag-dev
+/i18n/sv.toml @36725726+besynnerlig @jerryzihye @sarahrhgrefalda @thenajnth
+/i18n/it.toml @alainpoeta @jerryzihye @login @sarahrhgrefalda
+/i18n/no.toml @login @sarahrhgrefalda @sh @xaner4
+/i18n/pt.toml @37813631+eriicf @eddex @jerryzihye @lazarodm @login @sarahrhgrefalda
+/i18n/de.toml @46083627+thomham @dominik.infuehr @eddex @jan.steinke @jerryzihye @kinski @login @sarahrhgrefalda
+/i18n/hu.toml @73439774+winux1 @sarahrhgrefalda
+/i18n/ja.toml @86867075+ssatosays
+/i18n/zh.toml @435878393 @eddex @jerryzihye @jerryzihye @o18382 @sarahrhgrefalda
+/i18n/id.toml @63356065+fitrarhm
+# i18n - end
diff --git a/.github/scripts/codeowners.mjs b/.github/scripts/codeowners.mjs
new file mode 100644
index 0000000..8439a57
--- /dev/null
+++ b/.github/scripts/codeowners.mjs
@@ -0,0 +1,93 @@
+import { execSync } from "child_process";
+import fs from "fs";
+import path from "path";
+import dotenv from "dotenv";
+import fetch from "node-fetch";
+
+// Load environment variables
+dotenv.config();
+
+// GitHub API Token (required)
+const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
+if (!GITHUB_TOKEN) {
+ console.error("❌ ERROR: GITHUB_TOKEN is not set. Add it to .env.");
+ process.exit(1);
+}
+
+// Directory to scan (i18n folder)
+const TARGET_DIR = process.argv[2] || "i18n";
+const SECTION = process.argv[3] || path.basename(TARGET_DIR);
+const REPO_ROOT = execSync("git rev-parse --show-toplevel").toString().trim();
+const CODEOWNERS_FILE = path.join(REPO_ROOT, ".github", "CODEOWNERS");
+
+// Section markers
+const SECTION_START = `# ${SECTION} - automatically created`;
+const SECTION_END = `# ${SECTION} - end`;
+
+// Get commit authors for a specific file
+const getCommitAuthors = (file) => {
+ try {
+ return execSync(`git log --format='%ae' -- "${file}" | sort -u`)
+ .toString()
+ .trim()
+ .split("\n")
+ .filter((email) => email);
+ } catch (error) {
+ return [];
+ }
+};
+
+// Fetch GitHub username from email
+const fetchGitHubUsername = async (email) => {
+ try {
+ const url = `https://api.github.com/search/users?q=${email}+in:email`;
+ const response = await fetch(url, {
+ headers: { Authorization: `token ${GITHUB_TOKEN}` },
+ });
+ const data = await response.json();
+ if (data.items && data.items.length > 0) {
+ return `@${data.items[0].login}`;
+ }
+ return `@${email.split("@")[0]}`; // Fallback
+ } catch (error) {
+ console.error(`❌ ERROR fetching GitHub username for ${email}:`, error);
+ return `@${email.split("@")[0]}`;
+ }
+};
+
+// Process files and generate CODEOWNERS entries
+const generateCodeowners = async () => {
+ const files = execSync(`find ${TARGET_DIR} -type f`)
+ .toString()
+ .trim()
+ .split("\n");
+ let codeownersContent = "";
+
+ for (const file of files) {
+ const authors = await Promise.all(
+ getCommitAuthors(file).map(fetchGitHubUsername),
+ );
+
+ if (authors.length > 0) {
+ codeownersContent += `/${file} ${authors.join(" ")}\n`;
+ }
+ }
+
+ if (!fs.existsSync(path.dirname(CODEOWNERS_FILE))) {
+ fs.mkdirSync(path.dirname(CODEOWNERS_FILE), { recursive: true });
+ }
+
+ let existingContent = fs.existsSync(CODEOWNERS_FILE)
+ ? fs.readFileSync(CODEOWNERS_FILE, "utf8")
+ : "";
+ existingContent = existingContent
+ .replace(new RegExp(`\n?${SECTION_START}[\\s\\S]*?${SECTION_END}`, "g"), "")
+ .trim();
+
+ const updatedContent = `${existingContent}\n\n${SECTION_START}\n${codeownersContent}${SECTION_END}\n`;
+ fs.writeFileSync(CODEOWNERS_FILE, updatedContent.trim() + "\n");
+
+ console.log(`✅ CODEOWNERS updated for section: [${SECTION}]`);
+};
+
+generateCodeowners();
diff --git a/.github/workflows/update-codeowners.yaml b/.github/workflows/update-codeowners.yaml
new file mode 100644
index 0000000..5e96ede
--- /dev/null
+++ b/.github/workflows/update-codeowners.yaml
@@ -0,0 +1,37 @@
+name: Update CODEOWNERS
+
+on:
+ push:
+ branches:
+ - main
+ schedule:
+ - cron: "0 0 1 * *" # runs on the first day of the month
+ workflow_dispatch: # allow manual runs
+
+jobs:
+ update-codeowners:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v3
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: "18"
+
+ - name: Install Dependencies
+ run: npm install node-fetch dotenv
+
+ - name: Run Generate CODEOWNERS
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: node .github/scripts/codeowners.mjs i18n
+
+ - name: Commit and Push Changes
+ run: |
+ git config --global user.name "Patrick Kollitsch"
+ git config --global user.email "83281+davidsneighbour@users.noreply.github.com"
+ git add .github/CODEOWNERS
+ git commit -m "chore(codeowners): update CODEOWNERS for i18n" || exit 0
+ git push
--
Gitblit v1.10.0