diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 833737d..fd73ae6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,6 +17,8 @@ Closes #(issue number) ## Checklist - [ ] I have read the contribution guidelines +- [ ] User-facing documentation changes include matching English and German updates +- [ ] I ran `npm run check:docs` - [ ] I have verified links work correctly - [ ] Code examples are tested - [ ] Spelling and grammar checked diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..80c511b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + docs: + name: Docs (Node.js ${{ matrix.node }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: [22, 24] + steps: + - name: Check out repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - name: Set up Node.js + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 + with: + node-version: ${{ matrix.node }} + cache: npm + - name: Install dependencies + run: npm ci + - name: Install Playwright Chromium + run: npx playwright install --with-deps chromium + - name: Check bilingual documentation + run: npm run check:docs + - name: Build docs + run: npm run build + - name: Validate site artifact + run: test -s dist/index.html + + actionlint: + name: Validate GitHub Actions + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - name: Run actionlint + uses: reviewdog/action-actionlint@6fb7acc99f4a1008869fa8a0f09cfca740837d9d # v1.72.0 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a80b151..ebf8762 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: Deploy to GitHub Pages +name: Deploy to GitHub Pages on: push: @@ -6,28 +6,42 @@ on: - main pull_request: +permissions: + contents: read + +concurrency: + group: pages-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 + cache: npm - name: Install dependencies - run: npm install + run: npm ci - name: Install Playwright Chromium run: npx playwright install --with-deps chromium + - name: Check bilingual documentation + run: npm run check:docs + - name: Build run: npm run build + - name: Validate Pages artifact + run: test -s dist/index.html + - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 with: path: ./dist @@ -44,4 +58,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/README.md b/README.md index 411715b..5af328c 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,23 @@ npm run dev Visit `http://localhost:3000` to preview. +## Contributing documentation + +User-facing documentation is maintained in English and German. Every page under +`src/content/docs/` must be added or updated together with its counterpart under +`src/content/docs/de/`, including Markdown plugin reference pages. Keep required +frontmatter keys and internal links aligned, then run: + +```bash +npm run check:docs +``` + +Locale-only exceptions are limited to intentional legal or local pages and must +be documented with a reason in `scripts/docs-parity.config.mjs`. +First-party plugin examples must use the canonical typed package name +`@semrel/-`; legacy aliases belong only in explicitly +allowlisted migration or deprecation context. + ## Build ```bash @@ -26,4 +43,3 @@ Deploys to GitHub Pages at `semrel.io` via GitHub Actions. - [Astro Documentation](https://docs.astro.build) - [Starlight Documentation](https://starlight.astro.build) - [semrel Repository](https://github.com/GoSemantics/semrel) - diff --git a/package.json b/package.json index 283fcb8..d71bc2a 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,9 @@ "build": "astro build", "preview": "astro preview", "astro": "astro", + "docs:parity": "node scripts/check-docs-parity.mjs", + "test:docs": "node --test scripts/check-docs-parity.test.mjs", + "check:docs": "npm run test:docs && npm run docs:parity", "lighthouse": "node scripts/lighthouse-all.js", "lighthouse:build": "node scripts/lighthouse-all.js --build", "lighthouse:seo": "node scripts/lighthouse-all.js --build --categories seo,accessibility", diff --git a/public/llms-full.txt b/public/llms-full.txt index 21d9d71..4144490 100644 --- a/public/llms-full.txt +++ b/public/llms-full.txt @@ -62,7 +62,7 @@ git log → Condition Plugin → Analyzer Plugin → SemVer Bump Decision tag_prefix: "v" plugins: - - uses: github # provider + - uses: "@semrel/provider-github" # provider name: github-release args: owner: MyOrg @@ -191,8 +191,8 @@ linux/arm64, darwin/amd64, darwin/arm64, windows/amd64. ## Installing plugins ```bash -semrel plugin install github # installs provider-github -semrel plugin install @semrel/slack # installs hook-slack from the registry +semrel plugin install @semrel/provider-github # installs provider-github +semrel plugin install @semrel/hook-slack # installs hook-slack from the registry semrel plugin list # shows installed plugins semrel plugin restore # restores from .semrel.lock ``` diff --git a/scripts/check-docs-parity.mjs b/scripts/check-docs-parity.mjs new file mode 100644 index 0000000..6b038ab --- /dev/null +++ b/scripts/check-docs-parity.mjs @@ -0,0 +1,402 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseFrontmatter } from '@astrojs/markdown-remark'; +import { + counterpartExceptions, + legacyPluginNameExceptions, +} from './docs-parity.config.mjs'; + +const DOC_EXTENSIONS = new Set(['.md', '.mdx']); +const REQUIRED_FRONTMATTER = ['title', 'description']; +const PLUGIN_TYPE_PREFIX = /^(?:analyzer|condition|generator|hook|packager|provider|publisher|updater)-/; +const LEGACY_PLUGIN_NAMES = new Map([ + ['@semrel/bitbucket', '@semrel/provider-bitbucket'], + ['@semrel/cargo', '@semrel/updater-cargo'], + ['@semrel/changelog-md', '@semrel/generator-changelog-md'], + ['@semrel/conventional', '@semrel/analyzer-conventional'], + ['@semrel/default', '@semrel/analyzer-default'], + ['@semrel/docker', '@semrel/updater-docker'], + ['@semrel/email', '@semrel/hook-email'], + ['@semrel/generic', '@semrel/condition-generic'], + ['@semrel/generic-http', '@semrel/publisher-generic-http'], + ['@semrel/git', '@semrel/provider-git'], + ['@semrel/gitea', '@semrel/provider-gitea'], + ['@semrel/gitea-actions', '@semrel/condition-gitea-actions'], + ['@semrel/github', '@semrel/provider-github'], + ['@semrel/github-actions', '@semrel/condition-github-actions'], + ['@semrel/gitlab', '@semrel/provider-gitlab'], + ['@semrel/gitlab-ci', '@semrel/condition-gitlab-ci'], + ['@semrel/gitplugin', '@semrel/hook-gitplugin'], + ['@semrel/go', '@semrel/updater-go'], + ['@semrel/gradle', '@semrel/updater-gradle'], + ['@semrel/helm', '@semrel/updater-helm'], + ['@semrel/homebrew', '@semrel/updater-homebrew'], + ['@semrel/jira', '@semrel/hook-jira'], + ['@semrel/matrix', '@semrel/hook-matrix'], + ['@semrel/maven', '@semrel/updater-maven'], + ['@semrel/nfpm', '@semrel/packager-nfpm'], + ['@semrel/npm', '@semrel/updater-npm'], + ['@semrel/nuget', '@semrel/updater-nuget'], + ['@semrel/oci', '@semrel/publisher-oci'], + ['@semrel/python', '@semrel/updater-python'], + ['@semrel/release-notes', '@semrel/generator-release-notes'], + ['@semrel/slack', '@semrel/hook-slack'], + ['@semrel/teams', '@semrel/hook-teams'], + ['@semrel/terraform', '@semrel/updater-terraform'], +]); + +function canonicalForUnscoped(name) { + if (PLUGIN_TYPE_PREFIX.test(name)) return `@semrel/${name}`; + return LEGACY_PLUGIN_NAMES.get(`@semrel/${name}`); +} + +function toPosix(value) { + return value.split(path.sep).join('/'); +} + +function withoutExtension(value) { + return value.replace(/\.mdx?$/i, ''); +} + +function routeFromPage(locale, page) { + const suffix = page === 'index' + ? '' + : page.endsWith('/index') + ? page.slice(0, -'/index'.length) + : page; + const localized = locale === 'de' ? `/de/${suffix}` : `/${suffix}`; + return normalizeRoute(localized); +} + +export function normalizeRoute(value) { + let route = value.replace(/[?#].*$/, '').replace(/\/+/g, '/'); + if (route !== '/' && route.endsWith('/')) route = route.slice(0, -1); + return route || '/'; +} + +export function frontmatterShape(value) { + if (value === null) return 'null'; + if (Array.isArray(value)) return value.map(frontmatterShape); + if (typeof value === 'object') { + return Object.fromEntries( + Object.keys(value).sort().map((key) => [key, frontmatterShape(value[key])]), + ); + } + return typeof value; +} + +function sameShape(left, right) { + return JSON.stringify(frontmatterShape(left)) === JSON.stringify(frontmatterShape(right)); +} + +function collectFiles(directory) { + return fs.readdirSync(directory, { withFileTypes: true }) + .flatMap((entry) => { + const absolute = path.join(directory, entry.name); + if (entry.isDirectory()) return collectFiles(absolute); + return DOC_EXTENSIONS.has(path.extname(entry.name).toLowerCase()) ? [absolute] : []; + }); +} + +export function makePageRecord(relativePath, source) { + const normalized = toPosix(relativePath); + const locale = normalized.startsWith('de/') ? 'de' : 'en'; + const localePath = locale === 'de' ? normalized.slice(3) : normalized; + const page = withoutExtension(localePath); + const parsed = parseFrontmatter(source); + return { + locale, + page, + relativePath: normalized, + route: routeFromPage(locale, page), + frontmatter: parsed.frontmatter, + content: parsed.content, + source, + }; +} + +export function validateExceptionConfig(exceptions) { + const issues = []; + const seen = new Set(); + for (const exception of exceptions) { + const key = `${exception.locale}:${exception.page}`; + if (!['en', 'de'].includes(exception.locale)) { + issues.push(`Exception ${key} has an invalid locale.`); + } + if (!/^(legal|local)\//.test(exception.page ?? '')) { + issues.push(`Exception ${key} is not under legal/ or local/.`); + } + if (typeof exception.reason !== 'string' || exception.reason.trim() === '') { + issues.push(`Exception ${key} needs a non-empty reason.`); + } + if (seen.has(key)) issues.push(`Exception ${key} is duplicated.`); + seen.add(key); + } + return issues; +} + +export function validateParity(records, exceptions = []) { + const issues = validateExceptionConfig(exceptions); + const exceptionKeys = new Set(exceptions.map(({ locale, page }) => `${locale}:${page}`)); + const pages = new Map(); + + for (const record of records) { + const key = `${record.locale}:${record.page}`; + if (pages.has(key)) { + issues.push(`${record.relativePath}: duplicate documentation route ${record.route}.`); + } + pages.set(key, record); + + for (const required of REQUIRED_FRONTMATTER) { + if (typeof record.frontmatter[required] !== 'string' || record.frontmatter[required].trim() === '') { + issues.push(`${record.relativePath}: frontmatter "${required}" must be a non-empty string.`); + } + } + } + + const pageNames = new Set(records.map(({ page }) => page)); + for (const page of [...pageNames].sort()) { + const english = pages.get(`en:${page}`); + const german = pages.get(`de:${page}`); + if (!english && !exceptionKeys.has(`de:${page}`)) { + issues.push(`de/${page}: German page has no English counterpart.`); + } + if (!german && !exceptionKeys.has(`en:${page}`)) { + issues.push(`${page}: English page has no German counterpart.`); + } + if (english && german && !sameShape(english.frontmatter, german.frontmatter)) { + issues.push( + `${english.relativePath} / ${german.relativePath}: frontmatter keys or value shapes differ.`, + ); + } + } + + for (const exception of exceptions) { + const source = pages.get(`${exception.locale}:${exception.page}`); + const counterpartLocale = exception.locale === 'en' ? 'de' : 'en'; + if (!source) { + issues.push(`Exception ${exception.locale}:${exception.page} does not name an existing page.`); + } else if (pages.has(`${counterpartLocale}:${exception.page}`)) { + issues.push(`Exception ${exception.locale}:${exception.page} is stale; its counterpart exists.`); + } + } + + return issues; +} + +function maskCodeFences(source) { + return source.replace(/^( {0,3})(```|~~~)[^\n]*\n[\s\S]*?^\1\2[^\n]*$/gm, (block) => + block.replace(/[^\n]/g, ' ')); +} + +export function findInternalLinks(source) { + const content = maskCodeFences(source); + const links = []; + const patterns = [ + /(?]+)>?(?:\s+["'][^"']*["'])?\s*\)/g, + /\b(?:href|to)=["']([^"']+)["']/g, + ]; + for (const pattern of patterns) { + for (const match of content.matchAll(pattern)) { + const target = match[1]; + if (/^(?:[/#.]{1,2}|[a-zA-Z0-9_-])/.test(target) && !/^[a-z][a-z0-9+.-]*:/i.test(target)) { + links.push({ + target, + line: content.slice(0, match.index).split('\n').length, + }); + } + } + } + return links; +} + +function collectFrontmatterLinks(value, links = []) { + if (Array.isArray(value)) { + value.forEach((item) => collectFrontmatterLinks(item, links)); + } else if (value && typeof value === 'object') { + for (const [key, item] of Object.entries(value)) { + if (['href', 'link'].includes(key) && typeof item === 'string') { + links.push({ target: item, line: 1 }); + } else { + collectFrontmatterLinks(item, links); + } + } + } + return links; +} + +function resolveTarget(target, sourceRoute) { + if ( + target === '' + || target.startsWith('#') + || target.startsWith('//') + || target.startsWith('{') + || /^[a-z][a-z0-9+.-]*:/i.test(target) + ) { + return null; + } + try { + return normalizeRoute(new URL(target, `https://docs.invalid${sourceRoute}/`).pathname); + } catch { + return `INVALID:${target}`; + } +} + +function checkLinks(records, publicRoot) { + const issues = []; + const routes = new Set(records.map(({ route }) => route)); + + for (const record of records) { + const links = [ + ...findInternalLinks(record.content), + ...collectFrontmatterLinks(record.frontmatter), + ]; + for (const { target, line } of links) { + const route = resolveTarget(target, record.route); + if (!route) continue; + const publicPath = path.join(publicRoot, ...route.slice(1).split('/')); + const targetExists = routes.has(route) || fs.existsSync(publicPath); + if (!targetExists) { + issues.push(`${record.relativePath}:${line}: internal link "${target}" has no target.`); + continue; + } + + if ( + record.locale === 'de' + && target.startsWith('/') + && !route.startsWith('/de') + && routes.has(route) + && routes.has(normalizeRoute(`/de${route}`)) + ) { + issues.push(`${record.relativePath}:${line}: German page links to English route "${target}".`); + } + if (record.locale === 'en' && route.startsWith('/de') && routes.has(route)) { + issues.push(`${record.relativePath}:${line}: English page links to German route "${target}".`); + } + } + } + return issues; +} + +function sidebarLinks(configSource) { + const withoutBlockComments = configSource.replace(/\/\*[\s\S]*?\*\//g, ''); + return [...withoutBlockComments.matchAll(/\blink:\s*['"]([^'"]+)['"]/g)] + .map((match) => match[1]) + .filter((link) => link.startsWith('/')); +} + +function checkSidebar(records, astroConfigPath) { + const issues = []; + const routes = new Set(records.map(({ route }) => route)); + const config = fs.readFileSync(astroConfigPath, 'utf8'); + for (const target of new Set(sidebarLinks(config))) { + const route = normalizeRoute(target); + if (!routes.has(route)) { + issues.push(`astro.config.mjs: sidebar target "${target}" has no English page.`); + } + const germanRoute = route === '/' ? '/de' : normalizeRoute(`/de${route}`); + if (!routes.has(germanRoute)) { + issues.push(`astro.config.mjs: sidebar target "${target}" has no German page.`); + } + } + return issues; +} + +export function checkPluginNames(records, exceptions = []) { + const issues = []; + const exceptionKeys = new Set(); + for (const exception of exceptions) { + const key = `${exception.page}:${exception.kind}:${exception.name}`; + const validName = exception.kind === 'reference' + ? LEGACY_PLUGIN_NAMES.has(exception.name) + : Boolean(canonicalForUnscoped(exception.name)); + if ( + typeof exception.page !== 'string' + || !['reference', 'install', 'uses'].includes(exception.kind) + || !validName + || typeof exception.reason !== 'string' + || exception.reason.trim() === '' + ) { + issues.push(`Legacy plugin-name exception ${key} needs a valid page, legacy name, and reason.`); + } + exceptionKeys.add(key); + } + + for (const record of records) { + const names = [...record.source.matchAll(/@semrel\/[a-z0-9-]+/g)].map((match) => match[0]); + for (const name of new Set(names)) { + const canonical = LEGACY_PLUGIN_NAMES.get(name); + if (canonical && !exceptionKeys.has(`${record.page}:reference:${name}`)) { + issues.push(`${record.relativePath}: legacy plugin name "${name}" must be "${canonical}".`); + } + } + + const bareInstalls = [...record.source.matchAll(/semrel plugin install\s+([a-z][a-z0-9-]*)/g)] + .map((match) => match[1]); + for (const name of new Set(bareInstalls)) { + const canonical = canonicalForUnscoped(name); + if (canonical && !exceptionKeys.has(`${record.page}:install:${name}`)) { + issues.push(`${record.relativePath}: bare plugin name "${name}" must be "${canonical}".`); + } + } + + const bareUses = [...record.source.matchAll( + /\buses:\s+([a-z][a-z0-9-]*)(?:@[a-zA-Z0-9_.-]+)?(?=\s|$|[`'",])/g, + )].map((match) => match[1]); + for (const name of new Set(bareUses)) { + const canonical = canonicalForUnscoped(name); + if (canonical && !exceptionKeys.has(`${record.page}:uses:${name}`)) { + issues.push(`${record.relativePath}: bare uses name "${name}" must be "${canonical}".`); + } + } + + const detail = record.page.match( + /^plugins\/(?:analyzers|conditions|generators|hooks|packagers|providers|publishers|updaters)\/([^/]+)$/, + ); + if (detail) { + const canonical = `@semrel/${detail[1]}`; + if (!names.includes(canonical)) { + issues.push(`${record.relativePath}: plugin page must show canonical name "${canonical}".`); + } + } + } + return issues; +} + +export function checkRepository(rootDirectory = process.cwd()) { + const docsRoot = path.join(rootDirectory, 'src', 'content', 'docs'); + const files = collectFiles(docsRoot); + const records = []; + const issues = []; + + for (const file of files) { + const relativePath = path.relative(docsRoot, file); + try { + records.push(makePageRecord(relativePath, fs.readFileSync(file, 'utf8'))); + } catch (error) { + issues.push(`${toPosix(relativePath)}: invalid frontmatter (${error.message}).`); + } + } + + issues.push(...validateParity(records, counterpartExceptions)); + issues.push(...checkPluginNames(records, legacyPluginNameExceptions)); + issues.push(...checkLinks(records, path.join(rootDirectory, 'public'))); + issues.push(...checkSidebar(records, path.join(rootDirectory, 'astro.config.mjs'))); + return { files: records.length, issues }; +} + +function main() { + const { files, issues } = checkRepository(); + if (issues.length > 0) { + console.error(`Documentation parity check failed with ${issues.length} issue(s):`); + issues.forEach((issue) => console.error(`- ${issue}`)); + process.exitCode = 1; + return; + } + console.log(`Documentation parity check passed (${files} English/German Markdown and MDX pages).`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) { + main(); +} diff --git a/scripts/check-docs-parity.test.mjs b/scripts/check-docs-parity.test.mjs new file mode 100644 index 0000000..368b525 --- /dev/null +++ b/scripts/check-docs-parity.test.mjs @@ -0,0 +1,75 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { + checkPluginNames, + findInternalLinks, + frontmatterShape, + makePageRecord, + validateExceptionConfig, + validateParity, +} from './check-docs-parity.mjs'; + +const page = (file, title = 'Title') => makePageRecord(file, `--- +title: ${title} +description: Description +--- + +Content +`); + +test('pairs Markdown and MDX pages by route and compares frontmatter shape', () => { + const records = [page('plugins/example.md'), page('de/plugins/example.mdx', 'Beispiel')]; + assert.deepEqual(validateParity(records), []); + + records[1].frontmatter.sidebar = { order: 1 }; + assert.match(validateParity(records).join('\n'), /frontmatter keys or value shapes differ/); +}); + +test('reports missing counterparts and restricts exceptions to legal or local pages', () => { + assert.match(validateParity([page('guide/only-english.mdx')]).join('\n'), /no German counterpart/); + assert.deepEqual(validateExceptionConfig([ + { locale: 'en', page: 'legal/terms', reason: 'Jurisdiction-specific' }, + ]), []); + assert.match(validateExceptionConfig([ + { locale: 'en', page: 'guide/terms', reason: '' }, + ]).join('\n'), /not under legal\/ or local|non-empty reason/); +}); + +test('finds Markdown and MDX links but ignores fenced examples and images', () => { + const links = findInternalLinks(` +[Guide](/guide/) +Plugins +![Logo](/logo.svg) +\`\`\`md +[Example](/not-a-real-page/) +\`\`\` +`); + assert.deepEqual(links.map(({ target }) => target), ['/guide/', '/plugins/']); +}); + +test('frontmatter shape is key-order independent and preserves nested types', () => { + assert.deepEqual( + frontmatterShape({ nested: { count: 1, enabled: true }, title: 'English' }), + frontmatterShape({ title: 'Deutsch', nested: { enabled: false, count: 2 } }), + ); +}); + +test('requires typed canonical names on first-party plugin pages', () => { + const legacy = page('plugins/hooks/hook-teams.md'); + legacy.source += '\nsemrel plugin install @semrel/teams\n'; + assert.match(checkPluginNames([legacy]).join('\n'), /must be "@semrel\/hook-teams"/); + + const canonical = page('plugins/hooks/hook-teams.md'); + canonical.source += '\nsemrel plugin install @semrel/hook-teams\n'; + assert.deepEqual(checkPluginNames([canonical]), []); + + const bare = page('plugins/overview.mdx'); + bare.source += '\nsemrel plugin install github\n'; + assert.match(checkPluginNames([bare]).join('\n'), /bare plugin name "github"/); + + bare.source = bare.source.replace('semrel plugin install github', 'uses: github'); + assert.match(checkPluginNames([bare]).join('\n'), /bare uses name "github"/); + + bare.source = bare.source.replace('uses: github', 'uses: provider-github'); + assert.match(checkPluginNames([bare]).join('\n'), /bare uses name "provider-github"/); +}); diff --git a/scripts/docs-parity.config.mjs b/scripts/docs-parity.config.mjs new file mode 100644 index 0000000..73f0cf9 --- /dev/null +++ b/scripts/docs-parity.config.mjs @@ -0,0 +1,14 @@ +export const counterpartExceptions = [ + // Keep this list limited to intentional locale-only legal or local pages. + // Example: { locale: 'de', page: 'legal/example', reason: 'German-only legal requirement' }, +]; + +export const legacyPluginNameExceptions = [ + // Use only when a page intentionally documents a compatibility alias. + { + page: 'plugins/managing', + kind: 'install', + name: 'github', + reason: 'The compatibility warning contrasts this legacy alias with the canonical name.', + }, +]; diff --git a/src/content/docs/api/registry.mdx b/src/content/docs/api/registry.mdx index 7c013a8..b3fec1a 100644 --- a/src/content/docs/api/registry.mdx +++ b/src/content/docs/api/registry.mdx @@ -75,7 +75,7 @@ Lists plugins with pagination and filtering. Returns a plugin by namespace and name. ```bash -curl https://registry.semrel.io/api/v1/plugins/@semrel/github +curl https://registry.semrel.io/api/v1/plugins/@semrel/provider-github ``` ### `GET /api/v1/plugins/:id/versions` diff --git a/src/content/docs/de/api/registry.mdx b/src/content/docs/de/api/registry.mdx index 90393ca..3cc6def 100644 --- a/src/content/docs/de/api/registry.mdx +++ b/src/content/docs/de/api/registry.mdx @@ -75,7 +75,7 @@ Listet Plugins mit Paginierung und Filtern auf. Gibt ein Plugin über Namespace und Name zurück. ```bash -curl https://registry.semrel.io/api/v1/plugins/@semrel/github +curl https://registry.semrel.io/api/v1/plugins/@semrel/provider-github ``` ### `GET /api/v1/plugins/:id/versions` diff --git a/src/content/docs/de/getting-started/installation.mdx b/src/content/docs/de/getting-started/installation.mdx index 75d4743..dddd46b 100644 --- a/src/content/docs/de/getting-started/installation.mdx +++ b/src/content/docs/de/getting-started/installation.mdx @@ -27,7 +27,7 @@ import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; ``` Die **alpine**-Variante bringt `git` und `ca-certificates` mit — alles, was semrel braucht. - Sieh in der [Docker-Anleitung](/guide/docker/) nach, wenn du mehr über Image-Varianten und darüber erfahren willst, wie du Versionen pinnst. + Sieh in der [Docker-Anleitung](/de/guide/docker/) nach, wenn du mehr über Image-Varianten und darüber erfahren willst, wie du Versionen pinnst. ```bash @@ -93,13 +93,17 @@ semrel version v0.9.0 fetch-depth: 0 - name: Run semrel - uses: docker://ghcr.io/semrels/semrel:latest-alpine + uses: docker://ghcr.io/semrels/semrel:latest-action with: args: release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` + Das spezielle `-action`-Image läuft als root, weil GitHub dies für den + Zugriff einer Docker-Container-Action auf den Runner-Workspace voraussetzt. + Die regulären Images bleiben Nicht-root-Images für `docker run` und Container-Jobs. + Oder führe semrel in einem **container job** aus (praktisch, wenn spätere Schritte es ebenfalls brauchen): ```yaml @@ -137,7 +141,7 @@ semrel version v0.9.0 ``` Das `dotenv`-Artefakt stellt `SEMREL_VERSION`, `SEMREL_TAG` und `SEMREL_CHANGELOG` für Folgejobs automatisch bereit. - Mehr Details findest du im [CI-Outputs-Anleitung](/guide/ci-outputs/). + Mehr Details findest du im [CI-Outputs-Anleitung](/de/guide/ci-outputs/). Installiere semrel über die Go-Toolchain, wenn du ein Setup ohne Docker bevorzugst: @@ -207,7 +211,7 @@ semrel version v0.9.0 ## Plugins aus der Registry installieren @@ -233,7 +237,7 @@ export SEMREL_CACHE_DIR=.semrel export SEMREL_CACHE_TTL=24h ``` -Mehr Details findest du in der [Plugin Registry-Übersicht](/plugins/registry/) und im [Plugin-Publishing-Anleitung](/plugins/publishing/). +Mehr Details findest du in der [Plugin Registry-Übersicht](/de/plugins/registry/) und im [Plugin-Publishing-Anleitung](/de/plugins/publishing/). ## Shell-Completion diff --git a/src/content/docs/de/getting-started/introduction.mdx b/src/content/docs/de/getting-started/introduction.mdx index 95cd4c3..09360db 100644 --- a/src/content/docs/de/getting-started/introduction.mdx +++ b/src/content/docs/de/getting-started/introduction.mdx @@ -64,7 +64,7 @@ flowchart TD style I fill:#6e40c9,color:#fff,stroke:none ``` -Jede Phase kann von einem separaten Plugin-Executable übernommen werden. Installiere offizielle Plugins mit Befehlen wie `semrel plugin install github` und konfiguriere sie anschließend in `.semrel.yaml`. +Jede Phase kann von einem separaten Plugin-Executable übernommen werden. Installiere offizielle Plugins mit Befehlen wie `semrel plugin install @semrel/provider-github` und konfiguriere sie anschließend in `.semrel.yaml`. ## semrel vs. die Alternativen diff --git a/src/content/docs/de/getting-started/quick-start.mdx b/src/content/docs/de/getting-started/quick-start.mdx index 533ecd4..7cad559 100644 --- a/src/content/docs/de/getting-started/quick-start.mdx +++ b/src/content/docs/de/getting-started/quick-start.mdx @@ -82,7 +82,7 @@ import { Steps, Aside } from '@astrojs/starlight/components'; ## Nächste Schritte -- [Vollständige CLI-Referenz](/guide/cli/) -- [Alle Konfigurationsoptionen](/guide/configuration/) -- [Monorepo-Unterstützung](/guide/monorepo/) -- [Ein Plugin schreiben](/plugins/overview/) \ No newline at end of file +- [Vollständige CLI-Referenz](/de/guide/cli/) +- [Alle Konfigurationsoptionen](/de/guide/configuration/) +- [Monorepo-Unterstützung](/de/guide/monorepo/) +- [Ein Plugin schreiben](/de/plugins/overview/) \ No newline at end of file diff --git a/src/content/docs/de/guide/cli.mdx b/src/content/docs/de/guide/cli.mdx index 97b3b05..91a0fc5 100644 --- a/src/content/docs/de/guide/cli.mdx +++ b/src/content/docs/de/guide/cli.mdx @@ -345,13 +345,13 @@ semrel plugin install [--plugin-dir ] ```bash # Die neueste Version installieren -semrel plugin install @semrel/github +semrel plugin install @semrel/provider-github # Eine bestimmte Version installieren -semrel plugin install @semrel/github@1.2.0 +semrel plugin install @semrel/provider-github@1.2.0 # In ein benutzerdefiniertes Verzeichnis installieren -semrel plugin install @semrel/github --plugin-dir ~/.semrel/plugins +semrel plugin install @semrel/provider-github --plugin-dir ~/.semrel/plugins ``` Verwende die vollständige Referenz `@namespace/name`, wenn der Registry-Eintrag zu einem Namespace gehört. Nackte Namen wie `github` funktionieren nur für Plugins ohne Namespace in der Registry. @@ -376,7 +376,7 @@ semrel plugin update --check semrel plugin update # Einzelnes Plugin aktualisieren -semrel plugin update @semrel/github +semrel plugin update @semrel/provider-github ``` ### `semrel plugin restore` diff --git a/src/content/docs/de/guide/configuration.mdx b/src/content/docs/de/guide/configuration.mdx index a1a7971..62e8ced 100644 --- a/src/content/docs/de/guide/configuration.mdx +++ b/src/content/docs/de/guide/configuration.mdx @@ -50,10 +50,10 @@ YAML verwendet für einige Schlüssel `camelCase` (z. B. `tagPrefix`). TOML und ceiling_strategy: clamp plugins: - - uses: github-actions + - uses: @semrel/condition-github-actions phase: condition - - uses: github + - uses: @semrel/provider-github phase: release args: token: ${{ env.GITHUB_TOKEN }} @@ -66,7 +66,7 @@ YAML verwendet für einige Schlüssel `camelCase` (z. B. `tagPrefix`). TOML und file: internal/version/version.go var_name: Version - - uses: slack + - uses: @semrel/hook-slack args: webhook_url: ${{ env.SLACK_WEBHOOK }} ``` @@ -553,7 +553,7 @@ Eine geordnete Liste von Plugins, die für die Release Pipeline geladen werden. ```yaml plugins: # Gate: abort if not running in GitHub Actions - - uses: github-actions + - uses: @semrel/condition-github-actions phase: condition # Pre-tag: update Go version variable before tagging @@ -564,7 +564,7 @@ Eine geordnete Liste von Plugins, die für die Release Pipeline geladen werden. var_name: Version # Release: create GitHub release with changelog - - uses: github + - uses: @semrel/provider-github phase: release # default, can be omitted args: token: ${{ env.GITHUB_TOKEN }} @@ -572,7 +572,7 @@ Eine geordnete Liste von Plugins, die für die Release Pipeline geladen werden. repo: my-repo # Hook: notify Slack after release - - uses: slack + - uses: @semrel/hook-slack args: webhook_url: ${{ env.SLACK_WEBHOOK }} ``` @@ -662,7 +662,7 @@ Jeder Schlüssel in `args:` wird dem Plugin-Prozess als Umgebungsvariable mit de ```yaml plugins: - - uses: github + - uses: @semrel/provider-github args: token: ${{ env.GITHUB_TOKEN }} owner: MyOrg @@ -733,9 +733,9 @@ schemaVersion: 1 tagPrefix: "v" plugins: - - uses: analyzer-conventional - - uses: generator-changelog-md - - uses: provider-github + - uses: @semrel/analyzer-conventional + - uses: @semrel/generator-changelog-md + - uses: @semrel/provider-github ``` Dein Editor markiert jetzt unbekannte Schlüssel, warnt vor fehlenden Pflichtfeldern und bietet Autovervollständigung für alle bekannten Optionen. @@ -747,7 +747,7 @@ Jeder `args:`-Block eines Plugins kann unabhängig validiert werden. Platziere d ```yaml # yaml-language-server: $schema=https://registry.semrel.io/schemas/core/v1.json plugins: - - uses: provider-github + - uses: @semrel/provider-github # yaml-language-server: $schema=https://registry.semrel.io/schemas/plugins/provider-github/latest.json args: token: ${{ env.GITHUB_TOKEN }} @@ -783,4 +783,4 @@ semrel config validate # ✓ Config is valid (schema version 1) ``` -Die vollständige Befehlsreferenz findest du unter [semrel config](/guide/cli#semrel-config). \ No newline at end of file +Die vollständige Befehlsreferenz findest du unter [semrel config](/de/guide/cli#semrel-config). \ No newline at end of file diff --git a/src/content/docs/de/guide/docker.mdx b/src/content/docs/de/guide/docker.mdx index 13048e1..ccc0989 100644 --- a/src/content/docs/de/guide/docker.mdx +++ b/src/content/docs/de/guide/docker.mdx @@ -15,9 +15,11 @@ semrel ist als offizielles Docker-Image unter `ghcr.io/SemRels/semrel` verfügba | `ghcr.io/SemRels/semrel:1.0.0` | distroless (Debian 12) | git, ca-certificates | Fest gepinnte Version | | `ghcr.io/SemRels/semrel:latest-alpine` | Alpine 3.22 | git, ca-certificates, openssh-client, Shell | Für SSH-Remotes oder Shell-Scripting in CI | | `ghcr.io/SemRels/semrel:1.0.0-alpine` | Alpine 3.22 | git, ca-certificates, openssh-client, Shell | Fest gepinnte Alpine-Version | +| `ghcr.io/SemRels/semrel:latest-action` | Alpine 3.22 | git, ca-certificates, openssh-client, Shell | Nur für GitHub-Docker-Container-Actions | +| `ghcr.io/SemRels/semrel:1.0.0-action` | Alpine 3.22 | git, ca-certificates, openssh-client, Shell | Fest gepinntes GitHub-Actions-Image | @@ -57,13 +59,18 @@ Oder als Docker-Action-Schritt: ```yaml - name: semrel ausführen - uses: docker://ghcr.io/SemRels/semrel:latest + uses: docker://ghcr.io/SemRels/semrel:latest-action with: args: release env: SEMREL_PLUGIN_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` +GitHub bindet den Action-Workspace mit der Benutzerkennung des Runners ein und +setzt für Docker-Container-Actions root voraus. Verwende den speziellen +`-action`-Tag nur mit `uses: docker://...`; die regulären Images bleiben bewusst +Nicht-root-Images. + ## GitLab CI ```yaml @@ -129,7 +136,9 @@ ghcr.io/SemRels/semrel:1.0.0-alpine # Alpine ## Sicherheitshinweise -- Beide Images laufen standardmäßig als **nicht-root-Benutzer**. +- Beide regulären Images laufen standardmäßig als **nicht-root-Benutzer**. +- Das optionale `-action`-Image läuft ausschließlich für GitHub-Docker- + Container-Actions als root. Verwende es nicht für allgemeine Container-Workloads. - Das `latest`-Image (distroless) hat keine Shell und keinen Paketmanager — minimale Angriffsfläche. - Das Alpine-Image ist auf `3.22` gepinnt und wird mit `apk upgrade --no-cache` gebaut, um alle Sicherheits-Patches einzuspielen. - Images werden mit [cosign](https://github.com/sigstore/cosign) signiert und enthalten eine SBOM-Attestierung. diff --git a/src/content/docs/de/guide/monorepo.mdx b/src/content/docs/de/guide/monorepo.mdx index b3f8bcc..879fd69 100644 --- a/src/content/docs/de/guide/monorepo.mdx +++ b/src/content/docs/de/guide/monorepo.mdx @@ -48,7 +48,7 @@ tagPrefix: "packages/api@v" branches: - name: main plugins: - - uses: @semrel/github + - uses: @semrel/provider-github ``` ### Releases ausführen (CI-Matrix) @@ -85,7 +85,7 @@ schemaVersion: 1 branches: - name: main plugins: - - uses: @semrel/github # gemeinsames Plugin für alle Packages + - uses: @semrel/provider-github # gemeinsames Plugin für alle Packages workspace: strategy: independent # jedes Package bekommt sein eigenes Semver diff --git a/src/content/docs/de/guide/schemas.mdx b/src/content/docs/de/guide/schemas.mdx index f550b44..fe52df6 100644 --- a/src/content/docs/de/guide/schemas.mdx +++ b/src/content/docs/de/guide/schemas.mdx @@ -17,8 +17,8 @@ schemaVersion: 1 tagPrefix: "v" plugins: - - uses: analyzer-conventional - - uses: provider-github + - uses: @semrel/analyzer-conventional + - uses: @semrel/provider-github args: token: ${{ env.GITHUB_TOKEN }} ``` @@ -86,7 +86,7 @@ Einen `yaml-language-server`-Kommentar an der `args:`-Zeile ergänzen, um Inline ```yaml # yaml-language-server: $schema=https://registry.semrel.io/schemas/core/v1.json plugins: - - uses: github + - uses: @semrel/provider-github # yaml-language-server: $schema=https://registry.semrel.io/schemas/plugins/github/latest.json args: token: ${{ env.GITHUB_TOKEN }} @@ -94,7 +94,7 @@ plugins: repo: my-repo assets: dist/*.tar.gz - - uses: slack + - uses: @semrel/hook-slack # yaml-language-server: $schema=https://registry.semrel.io/schemas/plugins/slack/latest.json args: webhook_url: ${{ env.SLACK_WEBHOOK }} @@ -197,4 +197,4 @@ Wenn du ein semrel-Plugin pflegst, füge deinem Repository eine Datei `schema/v1 Wenn dein Plugin in der semrel-registry registriert ist, wird das Schema automatisch unter `/schemas/plugins/{name}/v1.json` ausgeliefert. -Sieh im [plugin development guide](/guide/plugin-development#add-a-json-schema) nach, wenn du eine vollständige Schritt-für-Schritt-Anleitung möchtest. \ No newline at end of file +Sieh im [plugin development guide](/de/guide/plugin-development#add-a-json-schema) nach, wenn du eine vollständige Schritt-für-Schritt-Anleitung möchtest. \ No newline at end of file diff --git a/src/content/docs/de/infrastructure/web-service.mdx b/src/content/docs/de/infrastructure/web-service.mdx index ceb1f8d..06d4209 100644 --- a/src/content/docs/de/infrastructure/web-service.mdx +++ b/src/content/docs/de/infrastructure/web-service.mdx @@ -85,5 +85,5 @@ Aktuell enthält die API die Backend-Grundlagen und eine Platzhalter-Route `GET ## Zugehörige Dokumentation -- [Plugin Registry](/plugins/registry/) -- [Plugin Publishing Guide](/plugins/publishing/) +- [Plugin Registry](/de/plugins/registry/) +- [Plugin Publishing Guide](/de/plugins/publishing/) diff --git a/src/content/docs/de/plugins/analyzers/analyzer-conventional.md b/src/content/docs/de/plugins/analyzers/analyzer-conventional.md index 85ebdcf..b07681c 100644 --- a/src/content/docs/de/plugins/analyzers/analyzer-conventional.md +++ b/src/content/docs/de/plugins/analyzers/analyzer-conventional.md @@ -8,7 +8,7 @@ Ermittelt den nächsten SemVer-Bump aus Conventional-Commit-Nachrichten. Es ordn ## Installation ```bash -semrel plugin install @semrel/conventional +semrel plugin install @semrel/analyzer-conventional ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/conventional ```yaml version: 1 plugins: - - uses: @semrel/conventional + - uses: @semrel/analyzer-conventional args: breaking_change_label: 'BREAKING CHANGE' minor_types: feat diff --git a/src/content/docs/de/plugins/analyzers/analyzer-default.md b/src/content/docs/de/plugins/analyzers/analyzer-default.md index c3c35d5..2765e27 100644 --- a/src/content/docs/de/plugins/analyzers/analyzer-default.md +++ b/src/content/docs/de/plugins/analyzers/analyzer-default.md @@ -8,7 +8,7 @@ Ermittelt den nächsten SemVer-Bump, indem Commit-Nachrichten mit regulären Aus ## Installation ```bash -semrel plugin install @semrel/default +semrel plugin install @semrel/analyzer-default ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/default ```yaml version: 1 plugins: - - uses: @semrel/default + - uses: @semrel/analyzer-default args: major_pattern: 'BREAKING|major:' minor_pattern: '^feat' diff --git a/src/content/docs/de/plugins/conditions/condition-generic.md b/src/content/docs/de/plugins/conditions/condition-generic.md index 246da14..3105055 100644 --- a/src/content/docs/de/plugins/conditions/condition-generic.md +++ b/src/content/docs/de/plugins/conditions/condition-generic.md @@ -8,7 +8,7 @@ Führt einen Shell-Befehl aus und besteht nur, wenn dieser Befehl mit Status 0 e ## Installation ```bash -semrel plugin install @semrel/generic +semrel plugin install @semrel/condition-generic ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/generic ```yaml version: 1 plugins: - - uses: @semrel/generic + - uses: @semrel/condition-generic args: command: 'test "$SEMREL_BRANCH" = "main"' ``` diff --git a/src/content/docs/de/plugins/conditions/condition-gitea-actions.md b/src/content/docs/de/plugins/conditions/condition-gitea-actions.md index c95af15..3745194 100644 --- a/src/content/docs/de/plugins/conditions/condition-gitea-actions.md +++ b/src/content/docs/de/plugins/conditions/condition-gitea-actions.md @@ -8,7 +8,7 @@ Bestätigt, dass die aktuelle Release innerhalb von Gitea Actions läuft. Nutze ## Installation ```bash -semrel plugin install @semrel/gitea-actions +semrel plugin install @semrel/condition-gitea-actions ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/gitea-actions ```yaml version: 1 plugins: - - uses: @semrel/gitea-actions + - uses: @semrel/condition-gitea-actions ``` ## Umgebungsvariablen diff --git a/src/content/docs/de/plugins/conditions/condition-github-actions.md b/src/content/docs/de/plugins/conditions/condition-github-actions.md index f7169bc..c7a783e 100644 --- a/src/content/docs/de/plugins/conditions/condition-github-actions.md +++ b/src/content/docs/de/plugins/conditions/condition-github-actions.md @@ -8,7 +8,7 @@ Bestätigt, dass die aktuelle Release innerhalb von GitHub Actions läuft. Das i ## Installation ```bash -semrel plugin install @semrel/github-actions +semrel plugin install @semrel/condition-github-actions ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/github-actions ```yaml version: 1 plugins: - - uses: @semrel/github-actions + - uses: @semrel/condition-github-actions ``` ## Umgebungsvariablen diff --git a/src/content/docs/de/plugins/conditions/condition-gitlab-ci.md b/src/content/docs/de/plugins/conditions/condition-gitlab-ci.md index 56676d2..cbe8c02 100644 --- a/src/content/docs/de/plugins/conditions/condition-gitlab-ci.md +++ b/src/content/docs/de/plugins/conditions/condition-gitlab-ci.md @@ -8,7 +8,7 @@ Bestätigt, dass die aktuelle Release innerhalb von GitLab CI läuft. Das ist ei ## Installation ```bash -semrel plugin install @semrel/gitlab-ci +semrel plugin install @semrel/condition-gitlab-ci ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/gitlab-ci ```yaml version: 1 plugins: - - uses: @semrel/gitlab-ci + - uses: @semrel/condition-gitlab-ci ``` ## Umgebungsvariablen diff --git a/src/content/docs/de/plugins/examples.mdx b/src/content/docs/de/plugins/examples.mdx index 57c3214..13f6fe0 100644 --- a/src/content/docs/de/plugins/examples.mdx +++ b/src/content/docs/de/plugins/examples.mdx @@ -45,18 +45,18 @@ Offizielle Plugins werden in der Organisation [SemRels](https://github.com/SemRe ```yaml plugins: - - uses: updater-go + - uses: @semrel/updater-go args: file: internal/version/version.go var_name: Version - - uses: packager-nfpm + - uses: @semrel/packager-nfpm args: config: packaging/nfpm.yaml target: dist/packages packagers: deb,rpm,apk - - uses: publisher-oci + - uses: @semrel/publisher-oci args: ref: ghcr.io/semrels/myapp:{version} artifacts: dist/packages/myapp_amd64.deb,dist/packages/myapp_amd64.rpm @@ -66,12 +66,12 @@ plugins: ```yaml plugins: - - uses: updater-docker + - uses: @semrel/updater-docker args: file: Dockerfile arg_name: VERSION - - uses: publisher-generic-http + - uses: @semrel/publisher-generic-http args: url: https://uploads.example.com/releases/{version}/{artifact} method: PUT @@ -83,12 +83,12 @@ plugins: ```yaml plugins: - - uses: updater-helm + - uses: @semrel/updater-helm args: file: charts/myapp/Chart.yaml update_app_version: "true" - - uses: publisher-oci + - uses: @semrel/publisher-oci args: ref: ghcr.io/semrels/charts/myapp:{version} artifacts: dist/charts/myapp-{version}.tgz diff --git a/src/content/docs/de/plugins/generators/generator-changelog-html.md b/src/content/docs/de/plugins/generators/generator-changelog-html.md index 25ae328..888e5c2 100644 --- a/src/content/docs/de/plugins/generators/generator-changelog-html.md +++ b/src/content/docs/de/plugins/generators/generator-changelog-html.md @@ -24,7 +24,7 @@ plugins: css_file: .semrel/templates/changelog.css # optional signature: "true" # optional semrel.io footer, opt-in max_commits: "100" - - uses: @semrel/github # receives the HTML as SEMREL_CHANGELOG + - uses: @semrel/provider-github # receives the HTML as SEMREL_CHANGELOG ``` ## Environment variables diff --git a/src/content/docs/de/plugins/generators/generator-changelog-md.md b/src/content/docs/de/plugins/generators/generator-changelog-md.md index bc3b023..6d3a916 100644 --- a/src/content/docs/de/plugins/generators/generator-changelog-md.md +++ b/src/content/docs/de/plugins/generators/generator-changelog-md.md @@ -40,7 +40,7 @@ plugins: keep_releases: "10" # 10 vollständige Einträge behalten; ältere werden zusammengefasst signature: "true" # optionaler semrel.io-Footer, explizit opt-in - - uses: @semrel/gitlab + - uses: @semrel/provider-gitlab ``` ## Wie es funktioniert diff --git a/src/content/docs/de/plugins/generators/generator-release-notes.md b/src/content/docs/de/plugins/generators/generator-release-notes.md index f33344c..19e4c38 100644 --- a/src/content/docs/de/plugins/generators/generator-release-notes.md +++ b/src/content/docs/de/plugins/generators/generator-release-notes.md @@ -25,8 +25,8 @@ plugins: max_commits: "50" include_body: "false" signature: "true" # optional semrel.io footer, opt-in - - uses: @semrel/gitlab # receives the formatted notes as SEMREL_CHANGELOG - - uses: @semrel/slack # same + - uses: @semrel/provider-gitlab # receives the formatted notes as SEMREL_CHANGELOG + - uses: @semrel/hook-slack # same ``` ## Environment variables diff --git a/src/content/docs/de/plugins/hooks/hook-email.md b/src/content/docs/de/plugins/hooks/hook-email.md index bfcbd9b..1b7fec9 100644 --- a/src/content/docs/de/plugins/hooks/hook-email.md +++ b/src/content/docs/de/plugins/hooks/hook-email.md @@ -8,7 +8,7 @@ Sendet nach einem semrel-Lauf Release-Benachrichtigungen per SMTP. Er kann Versi ## Installation ```bash -semrel plugin install @semrel/email +semrel plugin install @semrel/hook-email ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/email ```yaml version: 1 plugins: - - uses: @semrel/email + - uses: @semrel/hook-email args: smtp_host: smtp.example.com smtp_port: 587 diff --git a/src/content/docs/de/plugins/hooks/hook-gitplugin.md b/src/content/docs/de/plugins/hooks/hook-gitplugin.md index bfeedc2..323f02e 100644 --- a/src/content/docs/de/plugins/hooks/hook-gitplugin.md +++ b/src/content/docs/de/plugins/hooks/hook-gitplugin.md @@ -8,7 +8,7 @@ description: Überträgt Release-bezogene Änderungen in ein anderes Git-Reposit ## Installation ```bash -semrel plugin install @semrel/gitplugin +semrel plugin install @semrel/hook-gitplugin ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/gitplugin ```yaml version: 1 plugins: - - uses: @semrel/gitplugin + - uses: @semrel/hook-gitplugin args: repo: 'https://github.com/SemRels/release-mirror.git' branch: main diff --git a/src/content/docs/de/plugins/hooks/hook-jira.md b/src/content/docs/de/plugins/hooks/hook-jira.md index 46effd4..a9fb2c8 100644 --- a/src/content/docs/de/plugins/hooks/hook-jira.md +++ b/src/content/docs/de/plugins/hooks/hook-jira.md @@ -8,7 +8,7 @@ Aktualisiert Jira-Release-Metadaten, nachdem semrel eine Version veröffentlicht ## Installation ```bash -semrel plugin install @semrel/jira +semrel plugin install @semrel/hook-jira ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/jira ```yaml version: 1 plugins: - - uses: @semrel/jira + - uses: @semrel/hook-jira args: base_url: 'https://jira.example.com' # Token wird aus der Umgebungsvariable SEMREL_PLUGIN_TOKEN gelesen diff --git a/src/content/docs/de/plugins/hooks/hook-matrix.md b/src/content/docs/de/plugins/hooks/hook-matrix.md index 2eb04c6..ec23676 100644 --- a/src/content/docs/de/plugins/hooks/hook-matrix.md +++ b/src/content/docs/de/plugins/hooks/hook-matrix.md @@ -8,7 +8,7 @@ Veröffentlicht Release-Benachrichtigungen in einem Matrix-Raum. Das funktionier ## Installation ```bash -semrel plugin install @semrel/matrix +semrel plugin install @semrel/hook-matrix ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/matrix ```yaml version: 1 plugins: - - uses: @semrel/matrix + - uses: @semrel/hook-matrix args: homeserver: 'https://matrix.example.com' # Token wird aus der Umgebungsvariable SEMREL_PLUGIN_TOKEN gelesen diff --git a/src/content/docs/de/plugins/hooks/hook-slack.md b/src/content/docs/de/plugins/hooks/hook-slack.md index dad37d5..27c2ec0 100644 --- a/src/content/docs/de/plugins/hooks/hook-slack.md +++ b/src/content/docs/de/plugins/hooks/hook-slack.md @@ -8,7 +8,7 @@ Veröffentlicht Release-Benachrichtigungen in Slack über einen eingehenden Webh ## Installation ```bash -semrel plugin install @semrel/slack +semrel plugin install @semrel/hook-slack ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -18,7 +18,7 @@ semrel plugin install @semrel/slack ```yaml version: 1 plugins: - - uses: @semrel/slack + - uses: @semrel/hook-slack args: webhook_url: '${{ env.SLACK_WEBHOOK_URL }}' channel: '#releases' diff --git a/src/content/docs/de/plugins/hooks/hook-teams.md b/src/content/docs/de/plugins/hooks/hook-teams.md index ebb0fd7..58e1847 100644 --- a/src/content/docs/de/plugins/hooks/hook-teams.md +++ b/src/content/docs/de/plugins/hooks/hook-teams.md @@ -8,7 +8,7 @@ Sendet Release-Benachrichtigungen an Microsoft Teams über Incoming Webhooks. Nu ## Installation ```bash -semrel plugin install @semrel/teams +semrel plugin install @semrel/hook-teams ``` `semrel plugin install` lädt die Binärdatei nach `.semrel/plugins/` herunter und aktualisiert `.semrel.lock`. Committe `.semrel.lock`, um die Version für dein Team festzuschreiben. @@ -17,7 +17,7 @@ semrel plugin install @semrel/teams ```yaml plugins: - - uses: hook-teams + - uses: @semrel/hook-teams args: webhook_url: "https://your-tenant.webhook.office.com/webhookb2/..." title: "🚀 New Release" # optional diff --git a/src/content/docs/de/plugins/index.mdx b/src/content/docs/de/plugins/index.mdx index 203d62a..722040c 100644 --- a/src/content/docs/de/plugins/index.mdx +++ b/src/content/docs/de/plugins/index.mdx @@ -15,37 +15,38 @@ Für die Migration von Updater-only-Flows auf Packager/Publisher-Pipelines nutze | Plugin | Kategorie | Beschreibung | | --- | --- | --- | -| [`condition-generic`](/plugins/conditions/condition-generic/) | Condition | Führt einen Shell-Befehl aus und besteht nur, wenn dieser Befehl mit Status 0 endet. | -| [`condition-gitea-actions`](/plugins/conditions/condition-gitea-actions/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von Gitea Actions läuft. | -| [`condition-github-actions`](/plugins/conditions/condition-github-actions/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von GitHub Actions läuft. | -| [`condition-gitlab-ci`](/plugins/conditions/condition-gitlab-ci/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von GitLab CI läuft. | -| [`hook-email`](/plugins/hooks/hook-email/) | Hook | Sendet nach einem semrel-Lauf Release-Benachrichtigungen per SMTP. | -| [`hook-gitplugin`](/plugins/hooks/hook-gitplugin/) | Hook | Überträgt Release-bezogene Änderungen in ein anderes Git-Repository oder eine andere Branch. | -| [`hook-jira`](/plugins/hooks/hook-jira/) | Hook | Aktualisiert Jira-Release-Metadaten, nachdem semrel eine Version veröffentlicht hat. | -| [`hook-matrix`](/plugins/hooks/hook-matrix/) | Hook | Veröffentlicht Release-Benachrichtigungen in einem Matrix-Raum. | -| [`hook-slack`](/plugins/hooks/hook-slack/) | Hook | Veröffentlicht Release-Benachrichtigungen in Slack über einen eingehenden Webhook. | -| [`hook-teams`](/plugins/hooks/hook-teams/) | Hook | Sendet Release-Benachrichtigungen an Microsoft Teams über Incoming Webhooks. | -| [`analyzer-conventional`](/plugins/analyzers/analyzer-conventional/) | Analyzer | Ermittelt den nächsten SemVer-Bump aus Conventional-Commit-Nachrichten. | -| [`analyzer-default`](/plugins/analyzers/analyzer-default/) | Analyzer | Ermittelt den nächsten SemVer-Bump, indem Commit-Nachrichten mit regulären Ausdrücken abgeglichen werden. | -| [`generator-changelog-html`](/plugins/generators/generator-changelog-html/) | Generator | Erzeugt einen HTML-Changelog für die anstehende Release. | -| [`generator-changelog-md`](/plugins/generators/generator-changelog-md/) | Generator | Erzeugt einen Markdown-Changelog für die anstehende Release. | -| [`generator-release-notes`](/plugins/generators/generator-release-notes/) | Generator | Erstellt kompakte Release Notes aus dem aktuellen Release-Kontext und der Commit-Historie. | -| [`updater-cargo`](/plugins/updaters/updater-cargo/) | Updater | Aktualisiert das Versionsfeld in einem Rust-Cargo-Manifest. | -| [`updater-docker`](/plugins/updaters/updater-docker/) | Updater | Aktualisiert ein Versionsargument in einer Dockerfile. | -| [`updater-go`](/plugins/updaters/updater-go/) | Updater | Aktualisiert eine Go-Quelldatei, die die Projektversion bereitstellt. | -| [`updater-gradle`](/plugins/updaters/updater-gradle/) | Updater | Aktualisiert den Versionsschlüssel in einer Gradle-Properties-Datei. | -| [`updater-helm`](/plugins/updaters/updater-helm/) | Updater | Aktualisiert Chart-Metadaten in einer Helm-`Chart.yaml`-Datei. | -| [`updater-homebrew`](/plugins/updaters/updater-homebrew/) | Updater | Aktualisiert eine Homebrew-Formula mit der neuen Release-URL und Prüfsumme. | -| [`updater-maven`](/plugins/updaters/updater-maven/) | Updater | Aktualisiert die in einer Maven-`pom.xml`-Datei deklarierte Version. | -| [`updater-npm`](/plugins/updaters/updater-npm/) | Updater | Aktualisiert das Versionsfeld in einer `package.json`-Datei. | -| [`updater-nuget`](/plugins/updaters/updater-nuget/) | Updater | Aktualisiert die Versionseigenschaft in einer `.csproj`- oder anderen NuGet-Projektdatei. | -| [`updater-python`](/plugins/updaters/updater-python/) | Updater | Aktualisiert Python-Paketversionsmetadaten in `pyproject.toml` oder einer ähnlichen Backend-Datei. | -| [`updater-terraform`](/plugins/updaters/updater-terraform/) | Updater | Aktualisiert eine Terraform-Variable, die die Anwendungsversion speichert. | -| [`packager-nfpm`](/plugins/packagers/packager-nfpm/) | Packager | Baut Linux-Pakete (`deb`, `rpm`, `apk`) mit nFPM. | -| [`publisher-generic-http`](/plugins/publishers/publisher-generic-http/) | Publisher | Lädt Release-Artefakte zu generischen HTTP-Endpunkten hoch. | -| [`publisher-oci`](/plugins/publishers/publisher-oci/) | Publisher | Veröffentlicht Release-Artefakte in OCI-Registries. | -| [`provider-bitbucket`](/plugins/providers/provider-bitbucket/) | Provider | Veröffentlicht Release-Informationen aus dem semrel-Release-Kontext in Bitbucket. | -| [`provider-git`](/plugins/providers/provider-git/) | Provider | Erstellt Git-Tags und überträgt optional Branch-Updates über das lokale Git-Remote. | -| [`provider-gitea`](/plugins/providers/provider-gitea/) | Provider | Veröffentlicht Releases in einer Gitea-Instanz. | -| [`provider-github`](/plugins/providers/provider-github/) | Provider | Veröffentlicht Releases in GitHub mit dem erzeugten semrel-Tag, der Version und dem Changelog. | -| [`provider-gitlab`](/plugins/providers/provider-gitlab/) | Provider | Veröffentlicht Releases in GitLab. | +| [`condition-generic`](/de/plugins/conditions/condition-generic/) | Condition | Führt einen Shell-Befehl aus und besteht nur, wenn dieser Befehl mit Status 0 endet. | +| [`condition-gitea-actions`](/de/plugins/conditions/condition-gitea-actions/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von Gitea Actions läuft. | +| [`condition-github-actions`](/de/plugins/conditions/condition-github-actions/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von GitHub Actions läuft. | +| [`condition-gitlab-ci`](/de/plugins/conditions/condition-gitlab-ci/) | Condition | Bestätigt, dass die aktuelle Release innerhalb von GitLab CI läuft. | +| [`hook-email`](/de/plugins/hooks/hook-email/) | Hook | Sendet nach einem semrel-Lauf Release-Benachrichtigungen per SMTP. | +| [`hook-gitplugin`](/de/plugins/hooks/hook-gitplugin/) | Hook | Überträgt Release-bezogene Änderungen in ein anderes Git-Repository oder eine andere Branch. | +| [`hook-jira`](/de/plugins/hooks/hook-jira/) | Hook | Aktualisiert Jira-Release-Metadaten, nachdem semrel eine Version veröffentlicht hat. | +| [`hook-matrix`](/de/plugins/hooks/hook-matrix/) | Hook | Veröffentlicht Release-Benachrichtigungen in einem Matrix-Raum. | +| [`hook-slack`](/de/plugins/hooks/hook-slack/) | Hook | Veröffentlicht Release-Benachrichtigungen in Slack über einen eingehenden Webhook. | +| [`hook-teams`](/de/plugins/hooks/hook-teams/) | Hook | Sendet Release-Benachrichtigungen an Microsoft Teams über Incoming Webhooks. | +| [`analyzer-conventional`](/de/plugins/analyzers/analyzer-conventional/) | Analyzer | Ermittelt den nächsten SemVer-Bump aus Conventional-Commit-Nachrichten. | +| [`analyzer-default`](/de/plugins/analyzers/analyzer-default/) | Analyzer | Ermittelt den nächsten SemVer-Bump, indem Commit-Nachrichten mit regulären Ausdrücken abgeglichen werden. | +| [`generator-changelog-html`](/de/plugins/generators/generator-changelog-html/) | Generator | Erzeugt einen HTML-Changelog für die anstehende Release. | +| [`generator-changelog-md`](/de/plugins/generators/generator-changelog-md/) | Generator | Erzeugt einen Markdown-Changelog für die anstehende Release. | +| [`generator-release-notes`](/de/plugins/generators/generator-release-notes/) | Generator | Erstellt kompakte Release Notes aus dem aktuellen Release-Kontext und der Commit-Historie. | +| [`updater-cargo`](/de/plugins/updaters/updater-cargo/) | Updater | Aktualisiert das Versionsfeld in einem Rust-Cargo-Manifest. | +| [`updater-docker`](/de/plugins/updaters/updater-docker/) | Updater | Aktualisiert ein Versionsargument in einer Dockerfile. | +| [`updater-go`](/de/plugins/updaters/updater-go/) | Updater | Aktualisiert eine Go-Quelldatei, die die Projektversion bereitstellt. | +| [`updater-gradle`](/de/plugins/updaters/updater-gradle/) | Updater | Aktualisiert den Versionsschlüssel in einer Gradle-Properties-Datei. | +| [`updater-helm`](/de/plugins/updaters/updater-helm/) | Updater | Aktualisiert Chart-Metadaten in einer Helm-`Chart.yaml`-Datei. | +| [`updater-homebrew`](/de/plugins/updaters/updater-homebrew/) | Updater | Aktualisiert eine Homebrew-Formula mit der neuen Release-URL und Prüfsumme. | +| [`updater-maven`](/de/plugins/updaters/updater-maven/) | Updater | Aktualisiert die in einer Maven-`pom.xml`-Datei deklarierte Version. | +| [`updater-npm`](/de/plugins/updaters/updater-npm/) | Updater | Aktualisiert das Versionsfeld in einer `package.json`-Datei. | +| [`updater-nuget`](/de/plugins/updaters/updater-nuget/) | Updater | Aktualisiert die Versionseigenschaft in einer `.csproj`- oder anderen NuGet-Projektdatei. | +| [`updater-python`](/de/plugins/updaters/updater-python/) | Updater | Aktualisiert Python-Paketversionsmetadaten in `pyproject.toml` oder einer ähnlichen Backend-Datei. | +| [`updater-terraform`](/de/plugins/updaters/updater-terraform/) | Updater | Aktualisiert eine Terraform-Variable, die die Anwendungsversion speichert. | +| [`packager-nfpm`](/de/plugins/packagers/packager-nfpm/) | Packager | Baut Linux-Pakete (`deb`, `rpm`, `apk`) mit nFPM. | +| [`publisher-docker`](/de/plugins/publishers/publisher-docker/) | Publisher | Pusht ein vorhandenes lokales Docker-Image und meldet dessen unveränderlichen Digest. | +| [`publisher-generic-http`](/de/plugins/publishers/publisher-generic-http/) | Publisher | Lädt Release-Artefakte zu generischen HTTP-Endpunkten hoch. | +| [`publisher-oci`](/de/plugins/publishers/publisher-oci/) | Publisher | Veröffentlicht Release-Artefakte in OCI-Registries. | +| [`provider-bitbucket`](/de/plugins/providers/provider-bitbucket/) | Provider | Veröffentlicht Release-Informationen aus dem semrel-Release-Kontext in Bitbucket. | +| [`provider-git`](/de/plugins/providers/provider-git/) | Provider | Erstellt Git-Tags und überträgt optional Branch-Updates über das lokale Git-Remote. | +| [`provider-gitea`](/de/plugins/providers/provider-gitea/) | Provider | Veröffentlicht Releases in einer Gitea-Instanz. | +| [`provider-github`](/de/plugins/providers/provider-github/) | Provider | Veröffentlicht Releases in GitHub mit dem erzeugten semrel-Tag, der Version und dem Changelog. | +| [`provider-gitlab`](/de/plugins/providers/provider-gitlab/) | Provider | Veröffentlicht Releases in GitLab. | diff --git a/src/content/docs/de/plugins/managing.mdx b/src/content/docs/de/plugins/managing.mdx index d6aec90..35ed3e9 100644 --- a/src/content/docs/de/plugins/managing.mdx +++ b/src/content/docs/de/plugins/managing.mdx @@ -17,7 +17,7 @@ Das Plugin-Management-System stellt sicher, dass jedes Teammitglied und jeder CI Alle offiziellen Plugins gehören zum Namespace `@semrel`. Dieser muss immer angegeben werden: ```bash - semrel plugin install @semrel/github + semrel plugin install @semrel/provider-github ``` Einen nackten Namen (`github`) akzeptiert semrel nur, wenn der Registry-Eintrag **keinen** Namespace hat. @@ -25,7 +25,7 @@ Das Plugin-Management-System stellt sicher, dass jedes Teammitglied und jeder CI 2. **Bei Bedarf eine Version pinnen** ```bash - semrel plugin install @semrel/github@1.2.0 + semrel plugin install @semrel/provider-github@1.2.0 ``` 3. **Die Lock-Datei committen** @@ -35,17 +35,18 @@ Das Plugin-Management-System stellt sicher, dass jedes Teammitglied und jeder CI -