Compare commits
14 Commits
development
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| af82b46fe0 | |||
| 02d8bfb089 | |||
| 6aebfc1953 | |||
| 8fb3262eb3 | |||
| 03b53d937a | |||
| eb5513f4af | |||
| 003e9617a0 | |||
| 01139c6fd4 | |||
| a6d843fd9b | |||
| b40482d8a5 | |||
| 8ebbfa7aed | |||
| 83b47ce849 | |||
| d383d1fc09 | |||
| 31941e80c3 |
@@ -102,13 +102,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
php /tmp/moko-platform-api/cli/release_publish.php \
|
php /tmp/moko-platform-api/cli/release_publish.php \
|
||||||
--path . --stability rc --bump minor --branch rc \
|
--path . --stability rc --bump minor --branch rc \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
|
--skip-update-stream
|
||||||
|
|
||||||
- name: Summary
|
- name: Summary
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "Branch renamed to rc, minor bump, RC + lesser stream releases built, updates.xml synced" >> $GITHUB_STEP_SUMMARY
|
echo "Branch renamed to rc, minor bump, RC release built (updates.xml managed by Gitea Pages)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
||||||
release:
|
release:
|
||||||
@@ -167,7 +168,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
php /tmp/moko-platform-api/cli/release_publish.php \
|
php /tmp/moko-platform-api/cli/release_publish.php \
|
||||||
--path . --stability stable --bump minor --branch main \
|
--path . --stability stable --bump minor --branch main \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
|
--skip-update-stream
|
||||||
|
|
||||||
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
||||||
- name: "Step 9: Mirror release to GitHub"
|
- name: "Step 9: Mirror release to GitHub"
|
||||||
|
|||||||
@@ -105,6 +105,19 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check for merge conflict markers
|
||||||
|
run: |
|
||||||
|
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
|
||||||
|
if [ -n "$CONFLICTS" ]; then
|
||||||
|
echo "::error::Merge conflict markers found in source files"
|
||||||
|
echo "## Conflict Markers Found" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "No conflict markers found"
|
||||||
|
|
||||||
- name: Detect platform
|
- name: Detect platform
|
||||||
id: platform
|
id: platform
|
||||||
run: |
|
run: |
|
||||||
@@ -134,6 +147,98 @@ jobs:
|
|||||||
echo "PHP lint: ${ERRORS} error(s)"
|
echo "PHP lint: ${ERRORS} error(s)"
|
||||||
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
|
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
|
||||||
|
|
||||||
|
- name: Joomla JEXEC guard check
|
||||||
|
if: steps.platform.outputs.platform == 'joomla'
|
||||||
|
run: |
|
||||||
|
ERRORS=0
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
# Skip vendor, node_modules, and index.html stub files
|
||||||
|
case "$file" in ./vendor/*|./node_modules/*) continue ;; esac
|
||||||
|
# Check first 10 lines for JEXEC or JPATH guard
|
||||||
|
if ! head -20 "$file" | grep -qE "defined\s*\(\s*['\"](_JEXEC|JPATH_BASE|\\\\JPATH_PLATFORM)['\"]"; then
|
||||||
|
echo "::error file=${file}::Missing JEXEC guard: ${file}"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done < <(find . -name "*.php" -path "*/src/*" -not -path "./.git/*" -not -path "./vendor/*" -print0)
|
||||||
|
if [ "$ERRORS" -gt 0 ]; then
|
||||||
|
echo "::error::${ERRORS} PHP file(s) missing defined('_JEXEC') or die guard"
|
||||||
|
echo "## JEXEC Guard Check: Failed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "${ERRORS} file(s) in src/ are missing the Joomla execution guard." >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "JEXEC guard: OK"
|
||||||
|
|
||||||
|
- name: Joomla directory listing protection
|
||||||
|
if: steps.platform.outputs.platform == 'joomla'
|
||||||
|
run: |
|
||||||
|
MISSING=0
|
||||||
|
SOURCE_DIR="src"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && exit 0
|
||||||
|
while IFS= read -r dir; do
|
||||||
|
if [ ! -f "${dir}/index.html" ]; then
|
||||||
|
echo "::warning::Missing index.html in ${dir} (directory listing protection)"
|
||||||
|
MISSING=$((MISSING + 1))
|
||||||
|
fi
|
||||||
|
done < <(find "$SOURCE_DIR" -type d -not -path "./.git/*" -not -path "*/vendor/*" -not -path "*/node_modules/*")
|
||||||
|
if [ "$MISSING" -gt 0 ]; then
|
||||||
|
echo "## Directory Protection" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "${MISSING} director(ies) missing index.html" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
echo "Directory protection: ${MISSING} missing (advisory)"
|
||||||
|
|
||||||
|
- name: Joomla script file and asset checks
|
||||||
|
if: steps.platform.outputs.platform == 'joomla'
|
||||||
|
run: |
|
||||||
|
ERRORS=0
|
||||||
|
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||||
|
[ -z "$MANIFEST" ] && exit 0
|
||||||
|
MANIFEST_DIR=$(dirname "$MANIFEST")
|
||||||
|
|
||||||
|
# Check scriptfile exists if declared
|
||||||
|
SCRIPTFILE=$(sed -n 's/.*<scriptfile>\([^<]*\)<\/scriptfile>.*/\1/p' "$MANIFEST" 2>/dev/null)
|
||||||
|
if [ -n "$SCRIPTFILE" ]; then
|
||||||
|
if [ ! -f "${MANIFEST_DIR}/${SCRIPTFILE}" ]; then
|
||||||
|
echo "::error::Manifest declares <scriptfile>${SCRIPTFILE}</scriptfile> but file not found at ${MANIFEST_DIR}/${SCRIPTFILE}"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "Script file: ${MANIFEST_DIR}/${SCRIPTFILE} (OK)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Require joomla.asset.json and validate it
|
||||||
|
ASSET_JSON=$(find "$MANIFEST_DIR" -name "joomla.asset.json" -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
if [ -z "$ASSET_JSON" ]; then
|
||||||
|
echo "::error::joomla.asset.json not found — Joomla asset system is required"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
if command -v php &> /dev/null; then
|
||||||
|
php -r "json_decode(file_get_contents('$ASSET_JSON')); if(json_last_error()!==JSON_ERROR_NONE){echo json_last_error_msg();exit(1);}" 2>&1 || {
|
||||||
|
echo "::error::joomla.asset.json is not valid JSON"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
echo "joomla.asset.json: valid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate all XML files in src/ are well-formed
|
||||||
|
XML_ERRORS=0
|
||||||
|
if command -v php &> /dev/null; then
|
||||||
|
while IFS= read -r -d '' xmlfile; do
|
||||||
|
if ! php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('$xmlfile'); if(!\$x){foreach(libxml_get_errors() as \$e) echo trim(\$e->message) . ' in $xmlfile'; exit(1);}" 2>&1; then
|
||||||
|
XML_ERRORS=$((XML_ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done < <(find "$MANIFEST_DIR" -name "*.xml" -not -path "./.git/*" -print0)
|
||||||
|
fi
|
||||||
|
if [ "$XML_ERRORS" -gt 0 ]; then
|
||||||
|
echo "::error::${XML_ERRORS} XML file(s) are malformed"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "XML well-formedness: OK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$ERRORS" -gt 0 ] && exit 1
|
||||||
|
echo "Joomla asset checks: OK"
|
||||||
|
|
||||||
- name: Validate platform manifest
|
- name: Validate platform manifest
|
||||||
run: |
|
run: |
|
||||||
PLATFORM="${{ steps.platform.outputs.platform }}"
|
PLATFORM="${{ steps.platform.outputs.platform }}"
|
||||||
@@ -151,6 +256,13 @@ jobs:
|
|||||||
for ELEMENT in name version description; do
|
for ELEMENT in name version description; do
|
||||||
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
|
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
|
||||||
done
|
done
|
||||||
|
# Block legacy raw/branch update server URLs on MokoGitea
|
||||||
|
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogitea\|git\.mokoconsulting\.tech' || true)
|
||||||
|
if [ -n "$RAW_URLS" ]; then
|
||||||
|
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGitea. Use the Gitea Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
|
||||||
|
echo "$RAW_URLS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "Joomla manifest valid"
|
echo "Joomla manifest valid"
|
||||||
;;
|
;;
|
||||||
dolibarr)
|
dolibarr)
|
||||||
@@ -183,6 +295,138 @@ jobs:
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
- name: Validate Joomla language files
|
||||||
|
if: steps.platform.outputs.platform == 'joomla'
|
||||||
|
run: |
|
||||||
|
ERRORS=0
|
||||||
|
WARNINGS=0
|
||||||
|
|
||||||
|
# Require both en-GB and en-US language directories
|
||||||
|
LANG_ROOT=$(find . -path "*/language" -type d -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
if [ -z "$LANG_ROOT" ]; then
|
||||||
|
echo "No language/ directory found — skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$LANG_ROOT/en-GB" ]; then
|
||||||
|
echo "::error::Missing en-GB language directory (${LANG_ROOT}/en-GB)"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
if [ ! -d "$LANG_ROOT/en-US" ]; then
|
||||||
|
echo "::error::Missing en-US language directory (${LANG_ROOT}/en-US)"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check that en-GB and en-US have matching .ini files
|
||||||
|
if [ -d "$LANG_ROOT/en-GB" ] && [ -d "$LANG_ROOT/en-US" ]; then
|
||||||
|
for GB_INI in "$LANG_ROOT/en-GB"/*.ini; do
|
||||||
|
[ ! -f "$GB_INI" ] && continue
|
||||||
|
US_INI="$LANG_ROOT/en-US/$(basename "$GB_INI")"
|
||||||
|
if [ ! -f "$US_INI" ]; then
|
||||||
|
echo "::error::$(basename "$GB_INI") exists in en-GB but missing from en-US"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for US_INI in "$LANG_ROOT/en-US"/*.ini; do
|
||||||
|
[ ! -f "$US_INI" ] && continue
|
||||||
|
GB_INI="$LANG_ROOT/en-GB/$(basename "$US_INI")"
|
||||||
|
if [ ! -f "$GB_INI" ]; then
|
||||||
|
echo "::error::$(basename "$US_INI") exists in en-US but missing from en-GB"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find all .ini language files
|
||||||
|
INI_FILES=$(find . -path "*/language/*/*.ini" -not -path "./.git/*" 2>/dev/null)
|
||||||
|
if [ -z "$INI_FILES" ]; then
|
||||||
|
echo "No .ini language files found"
|
||||||
|
[ "$ERRORS" -gt 0 ] && exit 1
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found $(echo "$INI_FILES" | wc -l) language file(s)"
|
||||||
|
|
||||||
|
for FILE in $INI_FILES; do
|
||||||
|
FNAME=$(basename "$FILE")
|
||||||
|
LINENUM=0
|
||||||
|
SEEN_KEYS=""
|
||||||
|
|
||||||
|
while IFS= read -r line || [ -n "$line" ]; do
|
||||||
|
LINENUM=$((LINENUM + 1))
|
||||||
|
|
||||||
|
# Skip empty lines and comments
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
echo "$line" | grep -qE '^\s*;' && continue
|
||||||
|
echo "$line" | grep -qE '^\s*$' && continue
|
||||||
|
|
||||||
|
# Must match KEY="VALUE" format
|
||||||
|
if ! echo "$line" | grep -qE '^[A-Z_][A-Z0-9_]*=".*"$'; then
|
||||||
|
echo "::error file=${FILE},line=${LINENUM}::Malformed line: ${line}"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract key and check for duplicates
|
||||||
|
KEY=$(echo "$line" | sed 's/=.*//')
|
||||||
|
if echo "$SEEN_KEYS" | grep -qx "$KEY"; then
|
||||||
|
echo "::error file=${FILE},line=${LINENUM}::Duplicate key: ${KEY}"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
SEEN_KEYS="${SEEN_KEYS}
|
||||||
|
${KEY}"
|
||||||
|
done < "$FILE"
|
||||||
|
|
||||||
|
echo " ${FILE}: checked ${LINENUM} lines"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Cross-check en-GB vs en-US key consistency
|
||||||
|
GB_DIR=$(find . -path "*/language/en-GB" -type d -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
US_DIR=$(find . -path "*/language/en-US" -type d -not -path "./.git/*" 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
if [ -n "$GB_DIR" ] && [ -n "$US_DIR" ]; then
|
||||||
|
for GB_FILE in "$GB_DIR"/*.ini; do
|
||||||
|
[ ! -f "$GB_FILE" ] && continue
|
||||||
|
FNAME=$(basename "$GB_FILE")
|
||||||
|
US_FILE="$US_DIR/$FNAME"
|
||||||
|
[ ! -f "$US_FILE" ] && continue
|
||||||
|
|
||||||
|
GB_KEYS=$(grep -oP '^[A-Z_][A-Z0-9_]*(?==)' "$GB_FILE" 2>/dev/null | sort)
|
||||||
|
US_KEYS=$(grep -oP '^[A-Z_][A-Z0-9_]*(?==)' "$US_FILE" 2>/dev/null | sort)
|
||||||
|
|
||||||
|
# Keys in en-GB but not en-US
|
||||||
|
MISSING_US=$(comm -23 <(echo "$GB_KEYS") <(echo "$US_KEYS"))
|
||||||
|
if [ -n "$MISSING_US" ]; then
|
||||||
|
echo "::warning::Keys in en-GB/$FNAME but missing from en-US/$FNAME:"
|
||||||
|
echo "$MISSING_US" | while read -r k; do echo " - $k"; done
|
||||||
|
WARNINGS=$((WARNINGS + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Keys in en-US but not en-GB
|
||||||
|
MISSING_GB=$(comm -13 <(echo "$GB_KEYS") <(echo "$US_KEYS"))
|
||||||
|
if [ -n "$MISSING_GB" ]; then
|
||||||
|
echo "::warning::Keys in en-US/$FNAME but missing from en-GB/$FNAME:"
|
||||||
|
echo "$MISSING_GB" | while read -r k; do echo " - $k"; done
|
||||||
|
WARNINGS=$((WARNINGS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "### Language File Validation"
|
||||||
|
echo "| Metric | Count |"
|
||||||
|
echo "|---|---|"
|
||||||
|
echo "| Files checked | $(echo "$INI_FILES" | wc -l) |"
|
||||||
|
echo "| Errors | ${ERRORS} |"
|
||||||
|
echo "| Warnings | ${WARNINGS} |"
|
||||||
|
} >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "$ERRORS" -gt 0 ]; then
|
||||||
|
echo "::error::Language validation failed with ${ERRORS} error(s)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Language files: OK (${WARNINGS} warning(s))"
|
||||||
|
|
||||||
- name: Check changelog has unreleased entry
|
- name: Check changelog has unreleased entry
|
||||||
run: |
|
run: |
|
||||||
if [ ! -f "CHANGELOG.md" ]; then
|
if [ ! -f "CHANGELOG.md" ]; then
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
||||||
# PATH: /templates/workflows/joomla/repo_health.yml.template
|
# PATH: /templates/workflows/joomla/repo_health.yml.template
|
||||||
# VERSION: 09.23.00
|
# VERSION: 09.23.00
|
||||||
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
|
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
name: "Generic: Repo Health"
|
name: "Generic: Repo Health"
|
||||||
@@ -24,13 +24,12 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
profile:
|
profile:
|
||||||
description: 'Validation profile: all, release, scripts, or repo'
|
description: 'Validation profile: all, scripts, or repo'
|
||||||
required: true
|
required: true
|
||||||
default: all
|
default: all
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- all
|
- all
|
||||||
- release
|
|
||||||
- scripts
|
- scripts
|
||||||
- repo
|
- repo
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -40,10 +39,6 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Release policy - Repository Variables Only
|
|
||||||
RELEASE_REQUIRED_REPO_VARS: RS_FTP_PATH_SUFFIX
|
|
||||||
RELEASE_OPTIONAL_REPO_VARS: DEV_FTP_SUFFIX
|
|
||||||
|
|
||||||
# Scripts governance policy
|
# Scripts governance policy
|
||||||
SCRIPTS_REQUIRED_DIRS:
|
SCRIPTS_REQUIRED_DIRS:
|
||||||
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
|
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
|
||||||
@@ -138,101 +133,6 @@ jobs:
|
|||||||
printf '%s\n' 'ERROR: Access denied. Admin permission required.' >> "${GITHUB_STEP_SUMMARY}"
|
printf '%s\n' 'ERROR: Access denied. Admin permission required.' >> "${GITHUB_STEP_SUMMARY}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
release_config:
|
|
||||||
name: Release configuration
|
|
||||||
needs: access_check
|
|
||||||
if: ${{ needs.access_check.outputs.allowed == 'true' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 20
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Guardrails release vars
|
|
||||||
env:
|
|
||||||
PROFILE_RAW: ${{ github.event.inputs.profile }}
|
|
||||||
RS_FTP_PATH_SUFFIX: ${{ vars.RS_FTP_PATH_SUFFIX }}
|
|
||||||
DEV_FTP_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
profile="${PROFILE_RAW:-all}"
|
|
||||||
case "${profile}" in
|
|
||||||
all|release|scripts|repo) ;;
|
|
||||||
*)
|
|
||||||
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ "${profile}" = 'scripts' ] || [ "${profile}" = 'repo' ]; then
|
|
||||||
{
|
|
||||||
printf '%s\n' '### Release configuration (Repository Variables)'
|
|
||||||
printf '%s\n' "Profile: ${profile}"
|
|
||||||
printf '%s\n' 'Status: SKIPPED'
|
|
||||||
printf '%s\n' 'Reason: profile excludes release validation'
|
|
||||||
printf '\n'
|
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
IFS=',' read -r -a required <<< "${RELEASE_REQUIRED_REPO_VARS}"
|
|
||||||
IFS=',' read -r -a optional <<< "${RELEASE_OPTIONAL_REPO_VARS}"
|
|
||||||
|
|
||||||
missing=()
|
|
||||||
missing_optional=()
|
|
||||||
|
|
||||||
for k in "${required[@]}"; do
|
|
||||||
v="${!k:-}"
|
|
||||||
[ -z "${v}" ] && missing+=("${k}")
|
|
||||||
done
|
|
||||||
|
|
||||||
for k in "${optional[@]}"; do
|
|
||||||
v="${!k:-}"
|
|
||||||
[ -z "${v}" ] && missing_optional+=("${k}")
|
|
||||||
done
|
|
||||||
|
|
||||||
{
|
|
||||||
printf '%s\n' '### Release configuration (Repository Variables)'
|
|
||||||
printf '%s\n' "Profile: ${profile}"
|
|
||||||
printf '%s\n' '| Variable | Status |'
|
|
||||||
printf '%s\n' '|---|---|'
|
|
||||||
printf '%s\n' "| RS_FTP_PATH_SUFFIX | ${RS_FTP_PATH_SUFFIX:-NOT SET} |"
|
|
||||||
printf '%s\n' "| DEV_FTP_SUFFIX | ${DEV_FTP_SUFFIX:-NOT SET} |"
|
|
||||||
printf '\n'
|
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
|
|
||||||
if [ "${#missing_optional[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
printf '%s\n' '### Missing optional repository variables'
|
|
||||||
for m in "${missing_optional[@]}"; do printf '%s\n' "- ${m}"; done
|
|
||||||
printf '\n'
|
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${#missing[@]}" -gt 0 ]; then
|
|
||||||
{
|
|
||||||
printf '%s\n' '### Missing required repository variables'
|
|
||||||
for m in "${missing[@]}"; do printf '%s\n' "- ${m}"; done
|
|
||||||
printf '%s\n' 'ERROR: Guardrails failed. Missing required repository variables.'
|
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
{
|
|
||||||
printf '%s\n' '### Repository variables validation result'
|
|
||||||
printf '%s\n' 'Status: OK'
|
|
||||||
printf '%s\n' 'All required repository variables present.'
|
|
||||||
printf '%s\n' ''
|
|
||||||
printf '%s\n' '**Note**: Organization secrets (RS_FTP_HOST, RS_FTP_USER, etc.) are validated at deployment time, not in repository health checks.'
|
|
||||||
printf '\n'
|
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
|
||||||
|
|
||||||
scripts_governance:
|
scripts_governance:
|
||||||
name: Scripts governance
|
name: Scripts governance
|
||||||
needs: access_check
|
needs: access_check
|
||||||
@@ -256,14 +156,14 @@ jobs:
|
|||||||
|
|
||||||
profile="${PROFILE_RAW:-all}"
|
profile="${PROFILE_RAW:-all}"
|
||||||
case "${profile}" in
|
case "${profile}" in
|
||||||
all|release|scripts|repo) ;;
|
all|scripts|repo) ;;
|
||||||
*)
|
*)
|
||||||
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
|
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "${profile}" = 'release' ] || [ "${profile}" = 'repo' ]; then
|
if [ "${profile}" = 'repo' ]; then
|
||||||
{
|
{
|
||||||
printf '%s\n' '### Scripts governance'
|
printf '%s\n' '### Scripts governance'
|
||||||
printf '%s\n' "Profile: ${profile}"
|
printf '%s\n' "Profile: ${profile}"
|
||||||
@@ -370,14 +270,14 @@ jobs:
|
|||||||
|
|
||||||
profile="${PROFILE_RAW:-all}"
|
profile="${PROFILE_RAW:-all}"
|
||||||
case "${profile}" in
|
case "${profile}" in
|
||||||
all|release|scripts|repo) ;;
|
all|scripts|repo) ;;
|
||||||
*)
|
*)
|
||||||
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
|
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "${profile}" = 'release' ] || [ "${profile}" = 'scripts' ]; then
|
if [ "${profile}" = 'scripts' ]; then
|
||||||
{
|
{
|
||||||
printf '%s\n' '### Repository health'
|
printf '%s\n' '### Repository health'
|
||||||
printf '%s\n' "Profile: ${profile}"
|
printf '%s\n' "Profile: ${profile}"
|
||||||
@@ -704,7 +604,7 @@ jobs:
|
|||||||
printf '%s\n' '| Domain | Status | Notes |'
|
printf '%s\n' '| Domain | Status | Notes |'
|
||||||
printf '%s\n' '|---|---|---|'
|
printf '%s\n' '|---|---|---|'
|
||||||
printf '%s\n' '| Access control | OK | Admin-only execution gate |'
|
printf '%s\n' '| Access control | OK | Admin-only execution gate |'
|
||||||
printf '%s\n' '| Release variables | OK | Repository variables validation |'
|
printf '%s\n' '| Release policy | N/A | Releases handled by MokoGitea |'
|
||||||
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
|
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
|
||||||
printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
|
printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
|
||||||
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
|
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
|
||||||
@@ -773,11 +673,10 @@ jobs:
|
|||||||
report-issues:
|
report-issues:
|
||||||
name: "Report Issues"
|
name: "Report Issues"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [access_check, release_config, scripts_governance, repo_health]
|
needs: [access_check, scripts_governance, repo_health]
|
||||||
if: >-
|
if: >-
|
||||||
always() &&
|
always() &&
|
||||||
(needs.release_config.result == 'failure' ||
|
(needs.scripts_governance.result == 'failure' ||
|
||||||
needs.scripts_governance.result == 'failure' ||
|
|
||||||
needs.repo_health.result == 'failure')
|
needs.repo_health.result == 'failure')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -803,10 +702,6 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
report_gate "Release Configuration" \
|
|
||||||
"${{ needs.release_config.result }}" \
|
|
||||||
"Required repository variables are missing (RS_FTP_PATH_SUFFIX). Check repository settings."
|
|
||||||
|
|
||||||
report_gate "Scripts Governance" \
|
report_gate "Scripts Governance" \
|
||||||
"${{ needs.scripts_governance.result }}" \
|
"${{ needs.scripts_governance.result }}" \
|
||||||
"Scripts directory policy violations detected. Review required and allowed directories."
|
"Scripts directory policy violations detected. Review required and allowed directories."
|
||||||
@@ -814,4 +709,3 @@ jobs:
|
|||||||
report_gate "Repository Health" \
|
report_gate "Repository Health" \
|
||||||
"${{ needs.repo_health.result }}" \
|
"${{ needs.repo_health.result }}" \
|
||||||
"Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
|
"Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
</languages>
|
</languages>
|
||||||
|
|
||||||
<updateservers>
|
<updateservers>
|
||||||
<server type="extension" name="MokoJoomBackup Updates">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/raw/branch/main/updates.xml</server>
|
<server type="extension" name="MokoJoomBackup Updates">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/updates.xml</server>
|
||||||
</updateservers>
|
</updateservers>
|
||||||
|
<dlid prefix="dlid=" suffix=""/>
|
||||||
|
<blockChildUninstall>true</blockChildUninstall>
|
||||||
</extension>
|
</extension>
|
||||||
|
|||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<updates>
|
|
||||||
<update>
|
|
||||||
<name>Package - MokoJoomBackup</name>
|
|
||||||
<description>Full-site backup and restore for Joomla</description>
|
|
||||||
<element>mokobackup</element>
|
|
||||||
<type>package</type>
|
|
||||||
<version>01.00.00</version>
|
|
||||||
<infourl title="Changelog">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/releases/tag/v01.00.00</infourl>
|
|
||||||
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/releases/download/v01.00.00/pkg_mokobackup-01.00.00.zip</downloadurl>
|
|
||||||
<sha256></sha256>
|
|
||||||
<targetplatform name="joomla" version="[45]\.\d+"/>
|
|
||||||
<php_minimum>8.1.0</php_minimum>
|
|
||||||
</update>
|
|
||||||
</updates>
|
|
||||||
Reference in New Issue
Block a user