From 0aa1feab97f2c6aaa53567001dae1e021b27d1da Mon Sep 17 00:00:00 2001 From: Emmanuel Raviart Date: Sun, 29 Dec 2024 23:54:12 +0100 Subject: [PATCH] Create Forgejo repositories if needed & push consolidated texts --- example.env | 6 +++ src/lib/server/auditors/config.ts | 65 +++++++++++++++++++++++++++ src/lib/server/config.ts | 15 +++++++ src/scripts/export_codes_to_git.ts | 71 +++++++++++++++++++++++++++--- 4 files changed, 150 insertions(+), 7 deletions(-) diff --git a/example.env b/example.env index f3eb1fd..977d6b3 100644 --- a/example.env +++ b/example.env @@ -14,4 +14,10 @@ DB_USER="legi" # Change value of DB_PASSWORD! DB_PASSWORD="legi" +# Forgejo configuration used to store git version of law +FORGEJO_SSH_ACCOUNT="git@YOUR.FORGEJO.SERVER.DOMAIN" +FORGEJO_SSH_PORT=22 +FORGEJO_TOKEN="YOUR SECRET FORGEJO TOKEN" +FORGEJO_URL="https://YOUR.FORGEJO.SERVER.DOMAIN" + TITLE="Tricoteuses (exemple)" diff --git a/src/lib/server/auditors/config.ts b/src/lib/server/auditors/config.ts index b70e4f3..fc08976 100644 --- a/src/lib/server/auditors/config.ts +++ b/src/lib/server/auditors/config.ts @@ -1,5 +1,7 @@ import { + auditEmail, auditEmptyToNull, + auditHttpUrl, auditInteger, auditRequire, auditStringToNumber, @@ -42,6 +44,7 @@ export function auditConfig( auditDb, auditRequire, ) + audit.attribute(data, "forgejo", true, errors, remainingKeys, auditForgejo) audit.attribute( data, "title", @@ -102,6 +105,68 @@ export function auditDb( return audit.reduceRemaining(data, errors, remainingKeys) } +export function auditForgejo( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "sshAccount", + true, + errors, + remainingKeys, + auditEmail, + auditRequire, + ) + audit.attribute( + data, + "sshPort", + true, + errors, + remainingKeys, + auditTrimString, + auditStringToNumber, + auditInteger, + auditTest( + (value) => 0 <= value && value <= 65536, + "Must be an integer between 0 and 65536", + ), + auditRequire, + ) + audit.attribute( + data, + "token", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + audit.attribute( + data, + "url", + true, + errors, + remainingKeys, + auditHttpUrl, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + export function validateConfig(data: unknown): [unknown, unknown] { return auditConfig(cleanAudit, data) } diff --git a/src/lib/server/config.ts b/src/lib/server/config.ts index 31ff21c..bdb1cbe 100644 --- a/src/lib/server/config.ts +++ b/src/lib/server/config.ts @@ -17,6 +17,12 @@ export interface Config { user: string password: string } + forgejo?: { + sshAccount: string + sshPort: number + token: string + url: string + } title: string } @@ -35,6 +41,15 @@ const [config, error] = validateConfig({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, }, + forgejo: + process.env.FORGEJO_URL == null + ? undefined + : { + sshAccount: process.env.FORGEJO_SSH_ACCOUNT, + sshPort: process.env.FORGEJO_SSH_PORT, + token: process.env.FORGEJO_TOKEN, + url: process.env.FORGEJO_URL, + }, title: process.env.TITLE, }) as [Config, unknown] if (error !== null) { diff --git a/src/scripts/export_codes_to_git.ts b/src/scripts/export_codes_to_git.ts index aa02551..fc55b5e 100644 --- a/src/scripts/export_codes_to_git.ts +++ b/src/scripts/export_codes_to_git.ts @@ -1,11 +1,16 @@ +import assert from "assert" import path from "path" import sade from "sade" +import { $, cd } from "zx" import type { LegiTexteVersion } from "$lib/legal/legi" +import config from "$lib/server/config" import { db } from "$lib/server/databases" import { generateConsolidatedTextGit } from "$lib/server/gitify/generators" import { slugify } from "$lib/strings" +const { forgejo } = config + async function exportCodesToGit( targetDir: string, { @@ -20,6 +25,7 @@ async function exportCodesToGit( silent?: boolean } = {}, ): Promise { + let exitCode = 0 if (only !== undefined && typeof only === "string") { only = [only] } @@ -41,20 +47,71 @@ async function exportCodesToGit( continue } } + if ( + [ + "LEGITEXT000006074068", // Code des pensions militaires d'invalidité et des victimes de la guerre + "LEGITEXT000006070302", // Code des pensions civiles et militaires de retraite + "LEGITEXT000006069565", // Code de la consommation + ].includes(codeId) + ) { + continue + } if (only !== undefined && !only.includes(codeId)) { continue } - const codeSlug = slugify( + const codeTitle = codeTexteVersion.META.META_SPEC.META_TEXTE_VERSION.TITREFULL ?? - codeTexteVersion.META.META_SPEC.META_TEXTE_VERSION.TITRE ?? - codeId, - "_", - ) - await generateConsolidatedTextGit(codeId, path.join(targetDir, codeSlug)) + codeTexteVersion.META.META_SPEC.META_TEXTE_VERSION.TITRE ?? + codeId + const codeSlug = slugify(codeTitle, "_") + const codeRepositoryDir = path.join(targetDir, codeSlug) + const result = await generateConsolidatedTextGit(codeId, codeRepositoryDir) + if (result !== 0) { + if (exitCode === 0) { + exitCode = result + } + continue + } + if (push && forgejo !== undefined) { + const response = await fetch( + new URL(`/api/v1/repos/textes_consolides/${codeSlug}`, forgejo.url), + { headers: { Accept: "application/json" } }, + ) + if (response.status === 404) { + // Create respository. + const response = await fetch( + new URL(`/api/v1/orgs/textes_consolides/repos`, forgejo.url), + { + body: JSON.stringify( + { + default_branch: "main", + description: codeTitle, + name: codeSlug, + }, + null, + 2, + ), + headers: { + Accept: "application/json", + Authorization: `token ${forgejo.token}`, + "Content-Type": "application/json", + }, + method: "POST", + }, + ) + assert(response.ok) + } else { + assert(response.ok) + } + cd(codeRepositoryDir) + const origin = `[${forgejo.sshAccount}:${forgejo.sshPort}]:textes_consolides/${codeSlug}.git` + await $`git remote add origin ${origin}` + await $`git push --force --tags --set-upstream origin main` + } } - return 0 + return exitCode } sade("export_codes_to_git ", true)