Umzug zugewiesener Repos nach WEBklar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
51c4852488
commit
6e6c9a4c24
4 files changed
+369
-1
No files matched your search
@@ -21,6 +21,10 @@ import { createHash } from 'node:crypto'
|
||||
* Dateiinhalt (Klartext, keine Kodierung) je `"owner/repo:pfad"`, z. B. `"knso/x:.webklar-preview.json"`.
|
||||
* @param {string[]} [options.orgs]
|
||||
* Organisationen, die von Anfang an existieren (mit leerer Owners-Mitgliedschaft).
|
||||
* @param {Record<string, string>} [options.redirects]
|
||||
* Vorab gesetzte Weiterleitungen (alter `"owner/repo"` -> neuer `"owner/repo"`), z. B. fuer ein
|
||||
* bereits von Hand verschobenes Repo, ohne dass dafuer ein Transfer-Aufruf noetig war. Der Ziel-
|
||||
* Repo-Eintrag muss separat ueber `options.repos` angelegt werden.
|
||||
* @param {string} [options.user] Login, das `GET /user` meldet. Voreinstellung `'webklar-system'`.
|
||||
* @returns {Promise<{
|
||||
* baseUrl: string,
|
||||
@@ -439,6 +443,9 @@ export async function startFakeGitea(options = {}) {
|
||||
contents.set(`${keyFrom(fullName)}:${filePath}`, text)
|
||||
}
|
||||
for (const name of options.orgs || []) createOrgRecord(name)
|
||||
for (const [from, to] of Object.entries(options.redirects || {})) {
|
||||
redirects.set(keyFrom(from), to)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ oeffentlich --- */
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import { test, before, after } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs/promises'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { startFakeGitea } from './helpers/fakeGitea.js'
|
||||
import { startFakeAppwrite } from './helpers/fakeAppwrite.js'
|
||||
|
||||
let gitea
|
||||
let aw
|
||||
let tmp
|
||||
let originalCwd
|
||||
let previewWorkDir
|
||||
let moveRepoToOrg
|
||||
let isOrgRepo
|
||||
let isInternalRepo
|
||||
let repoLockKey
|
||||
let currentRepoFullName
|
||||
|
||||
// Schluessel: urspruenglich gesetzter repoFullName -> Appwrite-$id. Wird beim Seeden befuellt
|
||||
// (siehe Controller-Ruling R2) - eine Live-Suche ueber repoFullName wuerde nach einem Umzug
|
||||
// nichts mehr finden, weil sich das Feld dann geaendert hat.
|
||||
const idByRepo = new Map()
|
||||
|
||||
/** Liefert das gespeicherte Dokument des Repos, ueber den zur Seed-Zeit gebauten Id-Index. */
|
||||
function doc(name) {
|
||||
return aw.get('websiteProjects', idByRepo.get(name))
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
gitea = await startFakeGitea({
|
||||
repos: [
|
||||
{ full_name: 'JUSN/D-ner-Nation' },
|
||||
{ full_name: 'knso/emmas-schatzkiste' },
|
||||
{ full_name: 'ANDJ/Steuerungstechnik' },
|
||||
{ full_name: 'knso/hytail-ark' },
|
||||
{ full_name: 'WEBklar/schon-da' },
|
||||
{ full_name: 'JUSN/schon-da' },
|
||||
{ full_name: 'WEBklar/von-hand' },
|
||||
{ full_name: 'ANDJ/unberuehrt' },
|
||||
],
|
||||
hooks: {
|
||||
'knso/emmas-schatzkiste': [{ id: 110, url: 'https://project.webklar.com/webhook/gitea' }],
|
||||
'knso/hytail-ark': [{ id: 7, url: 'https://webklar.com/webhook/hytail-ark/deploy' }],
|
||||
},
|
||||
// knso/von-hand wurde von Hand bereits nach WEBklar/von-hand verschoben (kein Transfer-Aufruf noetig).
|
||||
redirects: {
|
||||
'knso/von-hand': 'WEBklar/von-hand',
|
||||
},
|
||||
})
|
||||
|
||||
const repoNames = [
|
||||
'JUSN/D-ner-Nation',
|
||||
'knso/emmas-schatzkiste',
|
||||
'ANDJ/Steuerungstechnik',
|
||||
'knso/hytail-ark',
|
||||
'WEBklar/schon-da',
|
||||
'JUSN/schon-da',
|
||||
'knso/von-hand', // Appwrite kennt noch den alten Namen (siehe Brief)
|
||||
'ANDJ/unberuehrt',
|
||||
]
|
||||
const websiteProjects = repoNames.map((repoFullName) => {
|
||||
const $id = randomUUID()
|
||||
idByRepo.set(repoFullName, $id)
|
||||
return { $id, repoFullName, projectName: repoFullName.split('/').pop() }
|
||||
})
|
||||
|
||||
aw = await startFakeAppwrite({ seed: { websiteProjects } })
|
||||
|
||||
originalCwd = process.cwd()
|
||||
tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'repo-move-'))
|
||||
process.chdir(tmp)
|
||||
|
||||
Object.assign(process.env, {
|
||||
GITEA_BASE_URL: gitea.baseUrl,
|
||||
GITEA_API_TOKEN: 'test-token',
|
||||
APPWRITE_ENDPOINT: aw.endpoint,
|
||||
APPWRITE_API_KEY: 'test-key',
|
||||
PREVIEW_DEPLOY_ROOT: '',
|
||||
TRAEFIK_DYNAMIC_DIR: '',
|
||||
})
|
||||
// config.js liest die Umgebung beim Import
|
||||
;({ previewWorkDir } = await import('../server/services/previewDeploy.js'))
|
||||
;({ moveRepoToOrg, isOrgRepo, isInternalRepo, repoLockKey, currentRepoFullName } = await import(
|
||||
'../server/services/repoMove.js'
|
||||
))
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
process.chdir(originalCwd)
|
||||
await gitea.close()
|
||||
await aw.close()
|
||||
await fs.rm(tmp, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('verschiebt Repo aus eigenem Konto', async () => {
|
||||
await fs.mkdir(previewWorkDir('JUSN/D-ner-Nation'), { recursive: true })
|
||||
const r = await moveRepoToOrg(doc('JUSN/D-ner-Nation'))
|
||||
assert.deepEqual(r, { moved: { from: 'JUSN/D-ner-Nation', to: 'WEBklar/D-ner-Nation' }, warnings: [] })
|
||||
assert.deepEqual(gitea.calls.find((c) => c.path.endsWith('/transfer')).body, { new_owner: 'WEBklar' })
|
||||
const d = aw.get('websiteProjects', doc('JUSN/D-ner-Nation').$id)
|
||||
assert.equal(d.repoFullName, 'WEBklar/D-ner-Nation')
|
||||
assert.equal(d.giteaRepoUrl, `${gitea.baseUrl}/WEBklar/D-ner-Nation`)
|
||||
assert.equal(d.giteaRepoName, 'D-ner-Nation')
|
||||
await assert.rejects(fs.access(previewWorkDir('JUSN/D-ner-Nation')))
|
||||
})
|
||||
test('löscht den alten Portal-Webhook', async () => {
|
||||
await moveRepoToOrg(doc('knso/emmas-schatzkiste'))
|
||||
assert.deepEqual(gitea.hooksOf('WEBklar/emmas-schatzkiste'), [])
|
||||
})
|
||||
test('schon in WEBklar: nichts passiert', async () => {
|
||||
assert.deepEqual(await moveRepoToOrg(doc('WEBklar/schon-da')), { moved: null, warnings: [] })
|
||||
})
|
||||
test('internes Repo per Liste und per fremdem Webhook', async () => {
|
||||
for (const name of ['ANDJ/Steuerungstechnik', 'knso/hytail-ark']) {
|
||||
assert.deepEqual(await moveRepoToOrg(doc(name)), { moved: null, warnings: ['Internes Repo, bleibt wo es ist.'] })
|
||||
}
|
||||
assert.equal(gitea.calls.filter((c) => c.path.endsWith('/transfer') && /steuerung|hytail/i.test(c.path)).length, 0)
|
||||
})
|
||||
test('Name existiert in WEBklar', async () => {
|
||||
const r = await moveRepoToOrg(doc('JUSN/schon-da'))
|
||||
assert.deepEqual(r, { moved: null, warnings: ['In WEBklar gibt es schon ein Repo namens schon-da. Bitte in Gitea umbenennen und dann ‚Pushes nachtragen‘ klicken.'] })
|
||||
})
|
||||
test('Weiterleitung korrigiert Projektdaten', async () => {
|
||||
const r = await moveRepoToOrg(doc('knso/von-hand'))
|
||||
assert.deepEqual(r.moved, { from: 'knso/von-hand', to: 'WEBklar/von-hand' })
|
||||
assert.equal(gitea.calls.filter((c) => c.path.endsWith('/transfer') && c.path.includes('von-hand')).length, 0)
|
||||
assert.equal(aw.get('websiteProjects', doc('knso/von-hand').$id).repoFullName, 'WEBklar/von-hand')
|
||||
})
|
||||
test('Erkennung ohne Groß-/Kleinschreibung', async () => {
|
||||
assert.equal(isOrgRepo('webklar/x'), true)
|
||||
assert.equal(await isInternalRepo('andj/steuerungstechnik'), true)
|
||||
})
|
||||
test('repoLockKey', () => {
|
||||
assert.equal(repoLockKey('JUSN/D-ner-Nation'), 'repo:jusn/d-ner-nation')
|
||||
})
|
||||
test('currentRepoFullName', async () => {
|
||||
assert.equal(await currentRepoFullName('WEBklar/D-ner-Nation'), 'WEBklar/D-ner-Nation') // Eintrag vorhanden
|
||||
assert.equal(await currentRepoFullName('JUSN/D-ner-Nation'), 'WEBklar/D-ner-Nation') // kein Eintrag, Weiterleitung
|
||||
})
|
||||
test('Gitea nicht erreichbar', async () => {
|
||||
gitea.setDown(true)
|
||||
const r = await moveRepoToOrg(doc('ANDJ/unberuehrt'))
|
||||
gitea.setDown(false)
|
||||
assert.equal(r.moved, null)
|
||||
assert.match(r.warnings[0], /^Gitea ist gerade nicht erreichbar \(.+\)\. Bitte später ‚Pushes nachtragen‘ klicken\.$/)
|
||||
})
|
||||
Reference in new issue
Block a user