Migrate .github to .gitea, add pages workflow and nginx stack
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: artixlinux/artixlinux:base
|
||||||
|
options: --privileged
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install docs dependencies
|
||||||
|
run: |
|
||||||
|
pacman -Syu --noconfirm --needed --overwrite='*' \
|
||||||
|
ruby \
|
||||||
|
ruby-bundler \
|
||||||
|
nodejs \
|
||||||
|
npm \
|
||||||
|
git \
|
||||||
|
docker
|
||||||
|
|
||||||
|
- name: Build Jekyll docs
|
||||||
|
run: |
|
||||||
|
cd docs
|
||||||
|
bundle config set --local path vendor/bundle
|
||||||
|
bundle install
|
||||||
|
bundle exec jekyll build
|
||||||
|
ls -la _site/
|
||||||
|
|
||||||
|
- name: Deploy to gitea-docs volume
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
-v "$(pwd)/docs/_site":/source:ro \
|
||||||
|
-v gitea-docs:/target \
|
||||||
|
alpine:latest \
|
||||||
|
sh -c "rm -rf /target/* && cp -a /source/. /target/ && ls -la /target/"
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
name: AI Moderator
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
pull_request:
|
|
||||||
types: [opened]
|
|
||||||
discussion:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
discussions: write
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
moderate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/github-script@v9
|
|
||||||
env:
|
|
||||||
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const coc = (() => { try { return fs.readFileSync('.github/CODE_OF_CONDUCT.md', 'utf8'); } catch (e) { return ''; } })();
|
|
||||||
const contributing = (() => { try { return fs.readFileSync('CONTRIBUTING.md', 'utf8'); } catch (e) { return ''; } })();
|
|
||||||
|
|
||||||
const content = context.payload.issue?.body
|
|
||||||
|| context.payload.pull_request?.body
|
|
||||||
|| context.payload.discussion?.body
|
|
||||||
|| '';
|
|
||||||
if (!content.trim()) {
|
|
||||||
console.log('No content to analyze');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const actor = context.payload.sender?.login;
|
|
||||||
if (actor === 'c-ludenberg') {
|
|
||||||
console.log('Repo owner, skipping moderation');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isDiscussion = context.payload.discussion !== undefined;
|
|
||||||
|
|
||||||
const prompt = [
|
|
||||||
'You are an AI moderator for the Antergos NeXT project, an Artix-based',
|
|
||||||
'Linux distribution (dinit init, KDE Plasma).',
|
|
||||||
'Speak in first person. Be direct, confident, and have some snark.',
|
|
||||||
'The project has a playful but no-nonsense tone - match it.',
|
|
||||||
'',
|
|
||||||
'Your job is NOT to police opinions, bug reports, feature requests,',
|
|
||||||
'pull requests, technical questions, or constructive criticism.',
|
|
||||||
'Those are all normal and welcome. A normal PR description or issue',
|
|
||||||
'is NEVER a violation, no matter how long, detailed, or assertive it is.',
|
|
||||||
'',
|
|
||||||
'ONLY flag content that genuinely violates the Code of Conduct:',
|
|
||||||
'harassment, personal attacks, hate speech, slurs, spam, scams,',
|
|
||||||
'doxxing, malicious links, or threats.',
|
|
||||||
'',
|
|
||||||
'When in doubt, or if the content is merely technical, opinionated,',
|
|
||||||
'or critical of the project - violation is FALSE.',
|
|
||||||
'',
|
|
||||||
'If the content says it is a test or contains phrases like moderator',
|
|
||||||
'or test or reply here, play along with the joke but still enforce the rules.',
|
|
||||||
'',
|
|
||||||
'Code of Conduct:',
|
|
||||||
coc,
|
|
||||||
'',
|
|
||||||
'Contributing Guidelines:',
|
|
||||||
contributing,
|
|
||||||
'',
|
|
||||||
'Analyze the content below for violations.',
|
|
||||||
'Respond with ONLY valid JSON - no markdown, no backticks.',
|
|
||||||
'',
|
|
||||||
'{',
|
|
||||||
' "violation": true/false,',
|
|
||||||
' "message": "your direct first-person response",',
|
|
||||||
' "action": "warn",',
|
|
||||||
' "severity": 1-10',
|
|
||||||
'}',
|
|
||||||
'',
|
|
||||||
'"action" options: "warn" (post warning), "hide" (minimize comment), "lock" (lock issue/discussion)',
|
|
||||||
'For issues use "warn" or "lock". For comments you may use "hide".',
|
|
||||||
'Only use "lock" or "hide" for severe violations.',
|
|
||||||
'',
|
|
||||||
'Content:',
|
|
||||||
content
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
const model = 'llama-3.1-8b-instant';
|
|
||||||
|
|
||||||
let decision;
|
|
||||||
try {
|
|
||||||
const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Bearer ${process.env.GROQ_API_KEY}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model,
|
|
||||||
messages: [
|
|
||||||
{ role: 'system', content: 'You are a helpful community moderator. Respond only with valid JSON as instructed.' },
|
|
||||||
{ role: 'user', content: prompt }
|
|
||||||
],
|
|
||||||
temperature: 0.1,
|
|
||||||
max_tokens: 250
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
const raw = data.choices?.[0]?.message?.content || '{}';
|
|
||||||
decision = JSON.parse(raw.replace(/```json|```/g, '').trim());
|
|
||||||
console.log(`Decision: ${JSON.stringify(decision)}`);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(`API error: ${err}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decision.violation) {
|
|
||||||
console.log('Content deemed acceptable');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof decision.severity === 'number' && decision.severity < 4) {
|
|
||||||
console.log(`Low severity (${decision.severity}), no action taken`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const number = context.payload.issue?.number
|
|
||||||
|| context.payload.pull_request?.number
|
|
||||||
|| context.payload.discussion?.number;
|
|
||||||
if (!number) {
|
|
||||||
console.log('No issue/PR/discussion number found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (isDiscussion) {
|
|
||||||
const discId = context.payload.discussion.node_id;
|
|
||||||
if (discId) {
|
|
||||||
const msg = decision.message.replace(/"/g, '\\"');
|
|
||||||
await github.graphql(`
|
|
||||||
mutation {
|
|
||||||
addDiscussionComment(input: {discussionId: "${discId}", body: "${msg}"}) {
|
|
||||||
comment { id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await github.rest.issues.addLabels({
|
|
||||||
owner, repo, issue_number: number, labels: ['ai-moderated']
|
|
||||||
});
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner, repo, issue_number: number, body: decision.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decision.action === 'hide') {
|
|
||||||
const commentId = context.payload.comment?.node_id;
|
|
||||||
if (commentId) {
|
|
||||||
await github.graphql(`
|
|
||||||
mutation {
|
|
||||||
minimizeComment(input: {subjectId: "${commentId}", classifier: OFF_TOPIC}) {
|
|
||||||
minimizedComment { isMinimized }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
console.log('Comment minimized');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decision.action === 'lock') {
|
|
||||||
if (isDiscussion) {
|
|
||||||
const discId = context.payload.discussion.node_id;
|
|
||||||
if (discId) {
|
|
||||||
await github.graphql(`
|
|
||||||
mutation {
|
|
||||||
lockLockable(input: {lockableId: "${discId}"}) {
|
|
||||||
lockedRecord { activeLockReason }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await github.rest.issues.lock({ owner, repo, issue_number: number, lock_reason: 'too_heated' });
|
|
||||||
}
|
|
||||||
console.log('Locked');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Action completed: ' + decision.action);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(`GitHub API error: ${err}`);
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
name: Build ISO
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: artixlinux/artixlinux:base
|
|
||||||
options: --privileged
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
pacman -Syu --noconfirm --needed --overwrite='*' \
|
|
||||||
artools \
|
|
||||||
git \
|
|
||||||
squashfs-tools \
|
|
||||||
sudo \
|
|
||||||
python \
|
|
||||||
python-pip
|
|
||||||
|
|
||||||
- name: Bootstrap Antergos package signing key
|
|
||||||
run: |
|
|
||||||
KEY_FINGERPRINT=AA644A095D2AF5F950FADB57C51BFE8D3A985236
|
|
||||||
curl -fsSL -o /tmp/antergos-next.gpg https://raw.githubusercontent.com/Antergos-NeXT/antergos-packages/master/packages/antergos-next-keyring/antergos-next.gpg
|
|
||||||
pacman-key --init
|
|
||||||
pacman-key --add /tmp/antergos-next.gpg
|
|
||||||
gpg --homedir /etc/pacman.d/gnupg --batch --with-colons --fingerprint "$KEY_FINGERPRINT" | grep -q "fpr:::::::::$KEY_FINGERPRINT:"
|
|
||||||
pacman-key --lsign-key "$KEY_FINGERPRINT"
|
|
||||||
rm -f /tmp/antergos-next.gpg
|
|
||||||
|
|
||||||
|
|
||||||
- name: Set up WORKSPACE_DIR
|
|
||||||
run: |
|
|
||||||
echo "WORKSPACE_DIR=${{ github.workspace }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Debug workspace
|
|
||||||
run: |
|
|
||||||
echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE"
|
|
||||||
echo "github.workspace=${{ github.workspace }}"
|
|
||||||
pwd
|
|
||||||
ls -la
|
|
||||||
|
|
||||||
- name: Override pacman.conf with antergos-pkgs repo
|
|
||||||
run: |
|
|
||||||
mkdir -p /root/.config/artools/pacman.conf.d
|
|
||||||
cp "pacman.conf.d/iso-x86_64.conf" \
|
|
||||||
/root/.config/artools/pacman.conf.d/iso-x86_64.conf
|
|
||||||
# Also override the default in case USER_CONF_DIR differs
|
|
||||||
cp "pacman.conf.d/iso-x86_64.conf" \
|
|
||||||
/usr/share/artools/pacman.conf.d/iso-x86_64.conf
|
|
||||||
|
|
||||||
- name: Check available swap and block devices
|
|
||||||
run: |
|
|
||||||
swapon --show || echo "No swap"
|
|
||||||
lsblk
|
|
||||||
free -h
|
|
||||||
|
|
||||||
- name: Setup tmpfs for build directory
|
|
||||||
run: |
|
|
||||||
mkdir -p /var/lib/artools/buildiso
|
|
||||||
mount -t tmpfs -o size=12G,exec,suid,dev tmpfs /var/lib/artools/buildiso
|
|
||||||
mount | grep buildiso
|
|
||||||
|
|
||||||
- name: Build ISO
|
|
||||||
run: |
|
|
||||||
sudo -E ./buildiso -p antergos
|
|
||||||
|
|
||||||
- name: Generate checksums
|
|
||||||
run: |
|
|
||||||
cd "${WORKSPACE_DIR}/iso/antergos"
|
|
||||||
ISO=$(ls antergos-*.iso | head -1)
|
|
||||||
[[ -z "$ISO" || ! -f "$ISO" ]] && { echo "No ISO found"; exit 1; }
|
|
||||||
sha256sum "$ISO" > "$ISO.sha256"
|
|
||||||
cat "$ISO.sha256"
|
|
||||||
|
|
||||||
- name: Upload ISO artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Antergos-NeXT-ISO
|
|
||||||
path: ${{ github.workspace }}/iso/
|
|
||||||
|
|
||||||
- name: Upload to Internet Archive
|
|
||||||
if: false # My NVMe tried to unalive itself, 1536 unsafe shutdowns, ext4 cooked medium-rare, so I'm raw-dogging my own distro now. Set to true when I stop being my own QA team.
|
|
||||||
env:
|
|
||||||
IA_ACCESS_KEY: ${{ secrets.IA_ACCESS_KEY }}
|
|
||||||
IA_SECRET_KEY: ${{ secrets.IA_SECRET_KEY }}
|
|
||||||
run: |
|
|
||||||
pip install --break-system-packages internetarchive
|
|
||||||
|
|
||||||
mkdir -p "$HOME/.config/internetarchive"
|
|
||||||
cat > "$HOME/.config/internetarchive/ia.ini" <<EOF
|
|
||||||
[s3]
|
|
||||||
access = $IA_ACCESS_KEY
|
|
||||||
secret = $IA_SECRET_KEY
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ISO_DIR="${WORKSPACE_DIR}/iso"
|
|
||||||
ISO=$(ls "$ISO_DIR"/antergos/*.iso 2>/dev/null | head -1)
|
|
||||||
[[ -z "$ISO" || ! -f "$ISO" ]] && { echo "No ISO found"; exit 1; }
|
|
||||||
|
|
||||||
DATE=$(date +%Y.%m.%d)
|
|
||||||
IDENTIFIER="antergos-next-$(date +%Y%m%d)-${{ github.run_number }}"
|
|
||||||
|
|
||||||
SIZE=$(stat -c%s "$ISO")
|
|
||||||
if [[ $SIZE -lt 524288000 ]]; then
|
|
||||||
echo "WARNING: ISO smaller than expected (${SIZE} bytes)"
|
|
||||||
file "$ISO" | grep -q "ISO 9660\|UDF" || { echo "Corrupted ISO"; exit 1; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
ia upload "$IDENTIFIER" "$ISO" \
|
|
||||||
--metadata="title:Antergos NeXT $(date +%Y.%m.%d)" \
|
|
||||||
--metadata="mediatype:software" \
|
|
||||||
--metadata="collection:open_source_software" \
|
|
||||||
--metadata="description:Antergos NeXT technical successor ISO — KDE Plasma, Dinit, Calamares installer" \
|
|
||||||
--metadata="subject:Antergos; Linux; Artix; Dinit; KDE Plasma; Calamares" \
|
|
||||||
--retries 5
|
|
||||||
|
|
||||||
echo "Uploaded to: https://archive.org/details/$IDENTIFIER"
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
name: Deploy docs to Pages
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["master"]
|
|
||||||
paths: ["docs/**"]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pages: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: "pages"
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: docs
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
- name: Setup Ruby
|
|
||||||
uses: ruby/setup-ruby@v1
|
|
||||||
with:
|
|
||||||
ruby-version: '3.3'
|
|
||||||
bundler-cache: true
|
|
||||||
cache-version: 0
|
|
||||||
working-directory: '${{ github.workspace }}/docs'
|
|
||||||
- name: Setup Pages
|
|
||||||
id: pages
|
|
||||||
uses: actions/configure-pages@v6
|
|
||||||
- name: Build with Jekyll
|
|
||||||
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
|
||||||
env:
|
|
||||||
JEKYLL_ENV: production
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-pages-artifact@v4
|
|
||||||
with:
|
|
||||||
path: docs/_site/
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
environment:
|
|
||||||
name: github-pages
|
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
steps:
|
|
||||||
- name: Deploy to GitHub Pages
|
|
||||||
id: deployment
|
|
||||||
uses: actions/deploy-pages@v5
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
ports:
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- /volume1/docker/gitea-docs:/usr/share/caddy:ro
|
||||||
|
restart: always
|
||||||
Reference in New Issue
Block a user