CatStation/.github/workflows/update-wiki.yml
2026-05-12 18:38:50 +07:00

467 lines
17 KiB
YAML

name: Update Wiki
on:
workflow_dispatch:
push:
branches: [ master, jsondump ]
paths:
- '.github/workflows/update-wiki.yml'
- 'Content.Shared/**'
- 'Content.Server/**'
- 'Content.Client/**'
- 'Resources/**'
- 'RobustToolbox/'
jobs:
update-wiki:
name: Build and Publish JSON blobs to wiki
runs-on: ubuntu-latest
steps:
- name: Checkout Master
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Detect changed paths
id: changes
uses: dorny/paths-filter@v3
with:
filters: |
general:
- '.github/workflows/update-wiki.yml'
- 'Content.Shared/**'
- 'Content.Server/**'
- 'Content.Client/**'
- 'Resources/Prototypes/**'
- 'RobustToolbox/**'
prototypes:
- '.github/workflows/update-wiki.yml'
- 'Resources/Prototypes/**'
textures:
- '.github/workflows/update-wiki.yml'
- 'Resources/Textures/**'
locale:
- '.github/workflows/update-wiki.yml'
- 'Resources/Locale/**'
- name: Setup Submodule
run: |
git submodule update --init --recursive
- name: Pull Engine Updates
uses: space-wizards/submodule-dependency@v0.1.5
- name: Update Engine Submodules
run: |
cd RobustToolbox/
git submodule update --init --recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Install Dependencies
run: dotnet restore
- name: Build Project
run: dotnet build --configuration Release --no-restore /p:WarningsAsErrors=nullable /m
- name: Generate JSON blobs for prototypes
run: dotnet ./bin/Content.Server/Content.Server.dll --cvar autogen.destination_file=prototypes.json
continue-on-error: true
- name: Upload loc to wiki
if: ${{ github.event_name == 'workflow_dispatch' || steps.changes.outputs.locale == 'true' }}
continue-on-error: true
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/loc.json
edit_summary: Update loc.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/loc.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
- name: Update meta license
if: ${{ github.event_name == 'workflow_dispatch' || steps.changes.outputs.textures == 'true' }}
continue-on-error: true
uses: jtmullen/mediawiki-edit-action@v0.1.1
with:
wiki_text_file: ./bin/Content.Server/data/meta_license.json
edit_summary: Update meta_license.json via GitHub Actions
page_name: "${{ secrets.WIKI_PAGE_ROOT }}/meta_license.json"
api_url: ${{ secrets.WIKI_ROOT_URL }}/api.php
username: ${{ secrets.WIKI_BOT_USER }}
password: ${{ secrets.WIKI_BOT_PASS }}
# Проходит по всем JSON-файлам в директории BASE и загружает каждый файл как страницу в MediaWiki.
# Имя страницы формируется из относительного пути к файлу.
- name: Upload JSON files to wiki
if: ${{ github.event_name == 'workflow_dispatch' || steps.changes.outputs.general == 'true' }}
continue-on-error: true
shell: bash
run: |
set -euo pipefail
BASE="./bin/Content.Server/data"
ROOT="${{ secrets.WIKI_PAGE_ROOT }}"
NAMESPACE="${{ secrets.WIKI_BOT_NAMESPACE }}"
API="${{ secrets.WIKI_ROOT_URL }}/api.php"
USER="${{ secrets.WIKI_BOT_USER }}"
PASS="${{ secrets.WIKI_BOT_PASS }}"
API="$(printf "%s" "$API" | tr -d '\r\n' | sed 's/[[:space:]]*$//')"
USER="$(printf "%s" "$USER" | tr -d '\r\n')"
PASS="$(printf "%s" "$PASS" | tr -d '\r\n')"
ROOT="$(printf "%s" "$ROOT" | tr -d '\r\n' | sed 's/[[:space:]]*$//')"
NAMESPACE="$(printf "%s" "$NAMESPACE" | tr -d '\r\n')"
if [[ -n "$NAMESPACE" ]]; then
MODULE_ROOT="Модуль:IanComradeBot/$NAMESPACE"
else
MODULE_ROOT="Модуль:IanComradeBot"
fi
cookiejar="$(mktemp)"
trap 'rm -f "$cookiejar"' EXIT
curl_api() {
curl --silent --show-error \
--retry 3 \
--retry-delay 5 \
--retry-all-errors \
--connect-timeout 20 \
--max-time 180 \
"$@"
}
login_token=$(curl_api -c "$cookiejar" \
--data "action=query&meta=tokens&type=login&format=json" "$API" | jq -r '.query.tokens.logintoken')
curl_api -c "$cookiejar" -b "$cookiejar" \
--data-urlencode "action=login" \
--data-urlencode "lgname=$USER" \
--data-urlencode "lgpassword=$PASS" \
--data-urlencode "lgtoken=$login_token" \
--data-urlencode "format=json" \
"$API" > /dev/null
token=$(curl_api -b "$cookiejar" \
--data "action=query&meta=tokens&format=json" "$API" | jq -r '.query.tokens.csrftoken')
edit_page_file() {
local title="$1"
local summary="$2"
local textfile="$3"
local token="$4"
curl_api -b "$cookiejar" \
--data-urlencode "action=edit" \
--data-urlencode "title=$title" \
--data-urlencode "summary=$summary" \
--data-urlencode "text@${textfile}" \
--data-urlencode "token=$token" \
--data-urlencode "bot=true" \
--data-urlencode "minor=true" \
--data-urlencode "format=json" \
"$API" | jq -r '.edit.result // "null"'
}
edit_page() {
local title="$1"
local summary="$2"
local text="$3"
local token="$4"
curl_api -b "$cookiejar" \
--data-urlencode "action=edit" \
--data-urlencode "title=$title" \
--data-urlencode "summary=$summary" \
--data-urlencode "text=$text" \
--data-urlencode "token=$token" \
--data-urlencode "bot=true" \
--data-urlencode "minor=true" \
--data-urlencode "format=json" \
"$API" | jq -r '.edit.result // "null"'
}
query_page_linecounts() {
local -n titles_ref=$1
local -n linecounts_ref=$2
linecounts_ref=()
(( ${#titles_ref[@]} == 0 )) && return 0
local titles
titles=$(printf '%s|' "${titles_ref[@]}")
titles="${titles%|}"
local resp
resp=$(curl_api -b "$cookiejar" \
--data-urlencode "action=query" \
--data-urlencode "format=json" \
--data-urlencode "formatversion=2" \
--data-urlencode "prop=revisions" \
--data-urlencode "rvprop=content" \
--data-urlencode "rvslots=main" \
--data-urlencode "titles=$titles" \
"$API")
while IFS=$'\t' read -r title linecount; do
[[ -z "${title:-}" ]] && continue
[[ -z "${linecount:-}" ]] && continue
linecounts_ref["$title"]="$linecount"
done < <(
jq -r '
.query.pages[]
| [.title, ((.revisions[0].slots.main.content? // "")| split("\n")| length)]
| @tsv
' <<< "$resp"
)
}
files=()
while IFS= read -r -d '' file; do
files+=("$file")
done < <(find "$BASE" -type f -name '*.json' -print0)
batch_size=25
for ((i=0; i<${#files[@]}; i+=batch_size)); do
batch_files=("${files[@]:i:batch_size}")
declare -a json_titles=()
declare -a module_titles=()
for file in "${batch_files[@]}"; do
rel="${file#$BASE/}"
rel="$(printf "%s" "$rel" | tr -d '\r\n' | sed 's/:/_/g')"
json_titles+=("$ROOT/$rel")
module_titles+=("$MODULE_ROOT/$rel/data")
done
declare -A json_lines=()
declare -A module_lines=()
query_page_linecounts json_titles json_lines
query_page_linecounts module_titles module_lines
for file in "${batch_files[@]}"; do
rel="${file#$BASE/}"
rel="$(printf "%s" "$rel" | tr -d '\r\n' | sed 's/:/_/g')"
json_title="$ROOT/$rel"
module_title="$MODULE_ROOT/$rel/data"
echo "Processing $rel → $json_title"
local_lines=$(awk 'END { print NR }' "$file")
remote_lines="${json_lines[$json_title]:-}"
if [[ -n "$remote_lines" && "$remote_lines" == "$local_lines" ]]; then
echo "Skipping unchanged page: $json_title"
else
echo "Uploading $rel → $json_title"
edit_page_file "$json_title" "Update $rel via GitHub Actions" "$file" "$token"
fi
lua_content=$'local loader = require("Module:JsonLoader")\nreturn loader.getFromTitle("'"$json_title"'")'
local_lines=$(printf '%s' "$lua_content" | awk 'END { print NR }')
remote_lines="${module_lines[$module_title]:-}"
if [[ -n "$remote_lines" && "$remote_lines" == "$local_lines" ]]; then
echo "Skipping unchanged module: $module_title"
else
echo "Creating/updating module → $module_title"
edit_page "$module_title" "Auto-create loader module for $rel" "$lua_content" "$token"
fi
done
done
# Создает страницы по каждому id подходящей сущности.
# Имя страницы формируется из имени сущности в entity_name.json.
- name: Create entity pages
if: ${{ github.event_name == 'workflow_dispatch' || steps.changes.outputs.prototypes == 'true' }}
continue-on-error: true
shell: bash
run: |
set -euo pipefail
FILE="./bin/Content.Server/data/entity_name.json"
API="${{ secrets.WIKI_ROOT_URL }}/api.php"
USER="${{ secrets.WIKI_BOT_USER }}"
PASS="${{ secrets.WIKI_BOT_PASS }}"
NAMESPACE="${{ secrets.WIKI_BOT_NAMESPACE }}"
API="$(printf "%s" "$API" | tr -d '\r\n')"
USER="$(printf "%s" "$USER" | tr -d '\r\n')"
PASS="$(printf "%s" "$PASS" | tr -d '\r\n')"
NAMESPACE="$(printf "%s" "$NAMESPACE" | tr -d '\r\n')"
if [[ -n "$NAMESPACE" && "${NAMESPACE: -1}" != ":" ]]; then
NAMESPACE="${NAMESPACE}:"
fi
cookiejar="$(mktemp)"
trap 'rm -f "$cookiejar"' EXIT
login_token=$(curl -sS -c "$cookiejar" \
--data "action=query&meta=tokens&type=login&format=json" "$API" | jq -r '.query.tokens.logintoken')
curl -sS -c "$cookiejar" -b "$cookiejar" \
--data-urlencode "action=login" \
--data-urlencode "lgname=$USER" \
--data-urlencode "lgpassword=$PASS" \
--data-urlencode "lgtoken=$login_token" \
--data-urlencode "format=json" \
"$API" > /dev/null
token=$(curl -sS -b "$cookiejar" \
--data "action=query&meta=tokens&format=json" "$API" | jq -r '.query.tokens.csrftoken')
mapfile -t pages < <(
jq -r '
to_entries[]
| "\(.key)|\(.value | if type == "array" then .[0] else . end)"
' "$FILE" | grep -v '|$'
)
batch_size=50
for ((i=0; i<${#pages[@]}; i+=batch_size)); do
batch=("${pages[@]:i:batch_size}")
prefix=""
if [[ -n "$NAMESPACE" ]]; then
prefix="$NAMESPACE"
fi
titles=$(
printf '%s\n' "${batch[@]}" |
cut -d'|' -f1 |
awk -v p="$prefix" '{print p $0}' |
paste -sd'|' -
)
existing_titles=$(
curl -sS -b "$cookiejar" \
--data-urlencode "action=query" \
--data-urlencode "format=json" \
--data-urlencode "titles=$titles" \
"$API" | jq -r '
.query.pages[]
| select(has("missing") | not)
| .title
'
)
while IFS='|' read -r name id; do
[[ -z "${name:-}" ]] && continue
[[ -z "${id:-}" ]] && continue
if grep -Fxq "$NAMESPACE$name" <<< "$existing_titles"; then
echo "Skipping existing page: $NAMESPACE$name"
continue
fi
content="{{сущность|$id}}"
echo "Creating page: $NAMESPACE$name → $id"
curl -sS -b "$cookiejar" \
--data-urlencode "action=edit" \
--data-urlencode "createonly=true" \
--data-urlencode "title=$NAMESPACE$name" \
--data-urlencode "text=$content" \
--data-urlencode "summary=Create $id via GitHub Actions" \
--data-urlencode "token=$token" \
--data-urlencode "bot=true" \
--data-urlencode "minor=true" \
--data-urlencode "format=json" \
"$API" | jq -r '.edit.result // "null"' || true
done < <(printf '%s\n' "${batch[@]}")
done
# Добавляет предупреждение дубликатам страниц сущностей.
- name: Duplicates entity pages
if: ${{ github.event_name == 'workflow_dispatch' || steps.changes.outputs.prototypes == 'true' }}
continue-on-error: true
shell: bash
run: |
set -euo pipefail
FILE="./bin/Content.Server/data/entity_name_wiki.json"
API="${{ secrets.WIKI_ROOT_URL }}/api.php"
USER="${{ secrets.WIKI_BOT_USER }}"
PASS="${{ secrets.WIKI_BOT_PASS }}"
API="$(printf "%s" "$API" | tr -d '\r\n')"
USER="$(printf "%s" "$USER" | tr -d '\r\n')"
PASS="$(printf "%s" "$PASS" | tr -d '\r\n')"
cookiejar="$(mktemp)"
trap 'rm -f "$cookiejar"' EXIT
warning="{{сущность/infobox|тип=дубликат}}"
login_token=$(curl -sS -c "$cookiejar" \
--data "action=query&meta=tokens&type=login&format=json" "$API" | jq -r '.query.tokens.logintoken')
curl -sS -c "$cookiejar" -b "$cookiejar" \
--data-urlencode "action=login" \
--data-urlencode "lgname=$USER" \
--data-urlencode "lgpassword=$PASS" \
--data-urlencode "lgtoken=$login_token" \
--data-urlencode "format=json" \
"$API" > /dev/null
token=$(curl -sS -b "$cookiejar" \
--data "action=query&meta=tokens&format=json" "$API" | jq -r '.query.tokens.csrftoken')
jq -r '.[]' "$FILE" |
xargs -r -d '\n' -P 1 -I{} bash -c '
set -uo pipefail
title="$1"
api="$2"
token="$3"
cookiejar="$4"
warning="$5"
if [[ -z "$title" ]]; then
exit 0
fi
page_json=$(curl -sS -b "$cookiejar" \
--data-urlencode "action=query" \
--data-urlencode "prop=revisions" \
--data-urlencode "rvprop=content" \
--data-urlencode "rvslots=main" \
--data-urlencode "format=json" \
--data-urlencode "titles=$title" \
"$api")
content=$(printf "%s" "$page_json" | jq -r \
".query.pages | to_entries[0].value.revisions[0].slots.main[\"*\"] // \"\"")
if printf "%s" "$content" | grep -Fq "$warning"; then
echo "Skipping (already has warning): $title"
exit 0
fi
echo "Prepending Infobox to: $title"
curl -sS -b "$cookiejar" \
--data-urlencode "action=edit" \
--data-urlencode "title=$title" \
--data-urlencode "prependtext=${warning}" \
--data-urlencode "summary=Add Warning via GitHub Actions" \
--data-urlencode "token=$token" \
--data-urlencode "bot=true" \
--data-urlencode "minor=true" \
--data-urlencode "format=json" \
"$api" | jq -r ".edit.result // \"null\"" || true
' _ "{}" "$API" "$token" "$cookiejar" "$warning"