chore: Sync MokoStandards 04.00.27 (#88)
* chore: update LICENSE from MokoStandards * chore: update update.xml from MokoStandards * chore: update phpstan.neon from MokoStandards * chore: update Makefile from MokoStandards * chore: update .gitignore from MokoStandards * chore: update composer.json from MokoStandards * chore: update .moko-standards from MokoStandards * chore: update .github/copilot.yml from MokoStandards * chore: update .github/copilot-instructions.md from MokoStandards * chore: update .github/CLAUDE.md from MokoStandards * chore: update .github/workflows/codeql-analysis.yml from MokoStandards * chore: update .github/workflows/standards-compliance.yml from MokoStandards * chore: update .github/workflows/enterprise-firewall-setup.yml from MokoStandards * chore: update .github/workflows/deploy-dev.yml from MokoStandards * chore: add .github/workflows/sync-version-on-merge.yml from MokoStandards * chore: update .github/ISSUE_TEMPLATE/config.yml from MokoStandards * chore: update .github/ISSUE_TEMPLATE/adr.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/bug_report.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/documentation.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/enterprise_support.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/feature_request.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/firewall-request.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/question.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/request-license.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/rfc.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/security.md from MokoStandards * chore: update .github/ISSUE_TEMPLATE/joomla_issue.md from MokoStandards
This commit was merged in pull request #88.
This commit is contained in:
138
.github/workflows/deploy-dev.yml
vendored
138
.github/workflows/deploy-dev.yml
vendored
@@ -22,7 +22,7 @@
|
|||||||
# INGROUP: MokoStandards.Deploy
|
# INGROUP: MokoStandards.Deploy
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/deploy-dev.yml
|
# PATH: /templates/workflows/shared/deploy-dev.yml
|
||||||
# VERSION: 04.00.25
|
# VERSION: 04.00.27
|
||||||
# BRIEF: SFTP deployment workflow for development server — synced to all governed repos
|
# BRIEF: SFTP deployment workflow for development server — synced to all governed repos
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/deploy-dev.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/deploy-dev.yml in all governed repos.
|
||||||
# Port is resolved in order: DEV_FTP_PORT variable → :port suffix in DEV_FTP_HOST → 22.
|
# Port is resolved in order: DEV_FTP_PORT variable → :port suffix in DEV_FTP_HOST → 22.
|
||||||
@@ -35,14 +35,11 @@ name: Deploy to Dev Server (SFTP)
|
|||||||
#
|
#
|
||||||
# Required org-level variables: DEV_FTP_HOST, DEV_FTP_PATH, DEV_FTP_USERNAME
|
# Required org-level variables: DEV_FTP_HOST, DEV_FTP_PATH, DEV_FTP_USERNAME
|
||||||
# Optional org-level variable: DEV_FTP_PORT (auto-detected from host or defaults to 22)
|
# Optional org-level variable: DEV_FTP_PORT (auto-detected from host or defaults to 22)
|
||||||
# Optional org/repo variable: DEV_FTP_PATH_SUFFIX
|
# Optional org/repo variable: DEV_FTP_SUFFIX — when set, appended to DEV_FTP_PATH to form the
|
||||||
# Optional org/repo variable: CUSTOM_FOLDER — when set, appended to the remote path after
|
# full remote destination: DEV_FTP_PATH/DEV_FTP_SUFFIX
|
||||||
# DEV_FTP_PATH_SUFFIX; used automatically for Dolibarr modules
|
# Ignore rules: Place a .ftp_ignore file in the repository root. Each non-empty,
|
||||||
# Optional org/repo variable: FTP_IGNORE — comma-delimited list of regex patterns, each enclosed in
|
# non-comment line is a regex pattern tested against the relative path
|
||||||
# double quotes, for files/paths to exclude from upload, e.g.:
|
# of each file (e.g. "subdir/file.txt"). The .gitignore is also
|
||||||
# "\.git*", "\.DS_Store", "configuration\.php", "\.ps1"
|
|
||||||
# Patterns are tested against the forward-slash relative path of each
|
|
||||||
# file (e.g. "subdir/file.txt"). The repository .gitignore is also
|
|
||||||
# respected automatically.
|
# respected automatically.
|
||||||
# Required org-level secret: DEV_FTP_KEY (preferred) or DEV_FTP_PASSWORD
|
# Required org-level secret: DEV_FTP_KEY (preferred) or DEV_FTP_PASSWORD
|
||||||
#
|
#
|
||||||
@@ -53,18 +50,16 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- master
|
- master
|
||||||
|
- 'dev/**'
|
||||||
- develop
|
- develop
|
||||||
- dev
|
|
||||||
- development
|
- development
|
||||||
paths:
|
|
||||||
- 'src/**'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, closed]
|
types: [opened, synchronize, reopened, closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- master
|
- master
|
||||||
|
- 'dev/**'
|
||||||
- develop
|
- develop
|
||||||
- dev
|
|
||||||
- development
|
- development
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -163,15 +158,47 @@ jobs:
|
|||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false'
|
||||||
env:
|
env:
|
||||||
SOURCE_DIR: ${{ steps.source.outputs.dir }}
|
SOURCE_DIR: ${{ steps.source.outputs.dir }}
|
||||||
FTP_IGNORE: ${{ vars.FTP_IGNORE }}
|
|
||||||
run: |
|
run: |
|
||||||
# ── Parse FTP_IGNORE ─────────────────────────────────────────────────
|
# ── Convert a gitignore-style glob line to an ERE pattern ──────────────
|
||||||
|
ftp_ignore_to_regex() {
|
||||||
|
local line="$1"
|
||||||
|
local anchored=false
|
||||||
|
# Strip inline comments and whitespace
|
||||||
|
line=$(printf '%s' "$line" | sed 's/[[:space:]]*#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||||
|
[ -z "$line" ] && return
|
||||||
|
# Skip negation patterns (not supported)
|
||||||
|
[[ "$line" == !* ]] && return
|
||||||
|
# Trailing slash = directory marker; strip it
|
||||||
|
line="${line%/}"
|
||||||
|
# Leading slash = anchored to root; strip it
|
||||||
|
if [[ "$line" == /* ]]; then
|
||||||
|
anchored=true
|
||||||
|
line="${line#/}"
|
||||||
|
fi
|
||||||
|
# Escape ERE special chars, then restore glob semantics
|
||||||
|
local regex
|
||||||
|
regex=$(printf '%s' "$line" \
|
||||||
|
| sed 's/[.+^${}()|[\\]/\\&/g' \
|
||||||
|
| sed 's/\\\*\\\*/\x01/g' \
|
||||||
|
| sed 's/\\\*/[^\/]*/g' \
|
||||||
|
| sed 's/\x01/.*/g' \
|
||||||
|
| sed 's/\\\?/[^\/]/g')
|
||||||
|
if $anchored; then
|
||||||
|
printf '^%s(/|$)' "$regex"
|
||||||
|
else
|
||||||
|
printf '(^|/)%s(/|$)' "$regex"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Read .ftp_ignore (gitignore-style globs) ─────────────────────────
|
||||||
IGNORE_PATTERNS=()
|
IGNORE_PATTERNS=()
|
||||||
if [ -n "$FTP_IGNORE" ]; then
|
IGNORE_SOURCES=()
|
||||||
while IFS= read -r -d ',' token; do
|
if [ -f ".ftp_ignore" ]; then
|
||||||
pattern=$(printf '%s' "$token" | sed 's/^[[:space:]]*"//;s/"[[:space:]]*$//')
|
while IFS= read -r line; do
|
||||||
[ -n "$pattern" ] && IGNORE_PATTERNS+=("$pattern")
|
[[ "$line" =~ ^[[:space:]]*$ || "$line" =~ ^[[:space:]]*# ]] && continue
|
||||||
done <<< "${FTP_IGNORE},"
|
regex=$(ftp_ignore_to_regex "$line")
|
||||||
|
[ -n "$regex" ] && IGNORE_PATTERNS+=("$regex") && IGNORE_SOURCES+=("$line")
|
||||||
|
done < ".ftp_ignore"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Walk src/ and classify every file ────────────────────────────────
|
# ── Walk src/ and classify every file ────────────────────────────────
|
||||||
@@ -180,9 +207,9 @@ jobs:
|
|||||||
while IFS= read -r -d '' file; do
|
while IFS= read -r -d '' file; do
|
||||||
rel="${file#${SOURCE_DIR}/}"
|
rel="${file#${SOURCE_DIR}/}"
|
||||||
SKIP=false
|
SKIP=false
|
||||||
for pat in "${IGNORE_PATTERNS[@]}"; do
|
for i in "${!IGNORE_PATTERNS[@]}"; do
|
||||||
if echo "$rel" | grep -qE "$pat" 2>/dev/null; then
|
if echo "$rel" | grep -qE "${IGNORE_PATTERNS[$i]}" 2>/dev/null; then
|
||||||
IGNORED_FILES+=("$rel | FTP_IGNORE \`$pat\`")
|
IGNORED_FILES+=("$rel | .ftp_ignore \`${IGNORE_SOURCES[$i]}\`")
|
||||||
SKIP=true; break
|
SKIP=true; break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -262,13 +289,10 @@ jobs:
|
|||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false'
|
||||||
id: remote
|
id: remote
|
||||||
env:
|
env:
|
||||||
DEV_FTP_PATH: ${{ vars.DEV_FTP_PATH }}
|
DEV_FTP_PATH: ${{ vars.DEV_FTP_PATH }}
|
||||||
DEV_FTP_PATH_SUFFIX: ${{ vars.DEV_FTP_PATH_SUFFIX }}
|
DEV_FTP_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
|
||||||
CUSTOM_FOLDER: ${{ vars.CUSTOM_FOLDER }}
|
|
||||||
run: |
|
run: |
|
||||||
BASE="$DEV_FTP_PATH"
|
BASE="$DEV_FTP_PATH"
|
||||||
SUFFIX="$DEV_FTP_PATH_SUFFIX"
|
|
||||||
CUSTOM="$CUSTOM_FOLDER"
|
|
||||||
|
|
||||||
if [ -z "$BASE" ]; then
|
if [ -z "$BASE" ]; then
|
||||||
echo "❌ DEV_FTP_PATH is not set."
|
echo "❌ DEV_FTP_PATH is not set."
|
||||||
@@ -277,24 +301,50 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Always append suffix when set — path is BASE/SUFFIX
|
# DEV_FTP_SUFFIX is required — it identifies the remote subdirectory for this repo.
|
||||||
if [ -n "$SUFFIX" ]; then
|
# Without it we cannot safely determine the deployment target.
|
||||||
REMOTE="${BASE%/}/${SUFFIX#/}"
|
if [ -z "$DEV_FTP_SUFFIX" ]; then
|
||||||
else
|
echo "⏭️ DEV_FTP_SUFFIX variable is not set — skipping deployment."
|
||||||
REMOTE="$BASE"
|
echo " Set DEV_FTP_SUFFIX as a repo or org variable to enable deploy-dev."
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "path=" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Append CUSTOM_FOLDER when set — makes Dolibarr module paths automatic
|
REMOTE="${BASE%/}/${DEV_FTP_SUFFIX#/}"
|
||||||
if [ -n "$CUSTOM" ]; then
|
|
||||||
REMOTE="${REMOTE%/}/${CUSTOM#/}"
|
# ── Platform-specific path safety guards ──────────────────────────────
|
||||||
echo "ℹ️ CUSTOM_FOLDER appended: ${CUSTOM}"
|
PLATFORM=""
|
||||||
|
if [ -f ".moko-standards" ]; then
|
||||||
|
PLATFORM=$(grep -E '^platform:' .moko-standards | sed 's/.*:[[:space:]]*//' | tr -d '"')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$PLATFORM" = "crm-module" ]; then
|
||||||
|
# Dolibarr modules must deploy under htdocs/custom/ — guard against
|
||||||
|
# accidentally overwriting server root or unrelated directories.
|
||||||
|
if [[ "$REMOTE" != *custom* ]]; then
|
||||||
|
echo "❌ Safety check failed: Dolibarr (crm-module) remote path must contain 'custom'."
|
||||||
|
echo " Current path: ${REMOTE}"
|
||||||
|
echo " Set DEV_FTP_SUFFIX to the module's htdocs/custom/ subdirectory."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PLATFORM" = "waas-component" ]; then
|
||||||
|
# Joomla extensions may only deploy to the server's tmp/ directory.
|
||||||
|
if [[ "$REMOTE" != *tmp* ]]; then
|
||||||
|
echo "❌ Safety check failed: Joomla (waas-component) remote path must contain 'tmp'."
|
||||||
|
echo " Current path: ${REMOTE}"
|
||||||
|
echo " Set DEV_FTP_SUFFIX to a path under the server tmp/ directory."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ℹ️ Remote path: ${REMOTE}"
|
||||||
echo "path=${REMOTE}" >> "$GITHUB_OUTPUT"
|
echo "path=${REMOTE}" >> "$GITHUB_OUTPUT"
|
||||||
echo "Remote path: ${REMOTE}"
|
|
||||||
|
|
||||||
- name: Detect SFTP authentication method
|
- name: Detect SFTP authentication method
|
||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true'
|
||||||
id: auth
|
id: auth
|
||||||
env:
|
env:
|
||||||
HAS_KEY: ${{ secrets.DEV_FTP_KEY }}
|
HAS_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
@@ -326,14 +376,14 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true'
|
||||||
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.31.0
|
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.31.0
|
||||||
with:
|
with:
|
||||||
php-version: '8.1'
|
php-version: '8.1'
|
||||||
tools: composer
|
tools: composer
|
||||||
|
|
||||||
- name: Setup MokoStandards deploy tools
|
- name: Setup MokoStandards deploy tools
|
||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
|
||||||
@@ -345,9 +395,7 @@ jobs:
|
|||||||
composer install --no-dev --no-interaction --quiet
|
composer install --no-dev --no-interaction --quiet
|
||||||
|
|
||||||
- name: Clear remote destination folder
|
- name: Clear remote destination folder
|
||||||
if: >-
|
if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true'
|
||||||
steps.source.outputs.skip == 'false' &&
|
|
||||||
inputs.clear_remote == true
|
|
||||||
env:
|
env:
|
||||||
SFTP_HOST: ${{ steps.conn.outputs.host }}
|
SFTP_HOST: ${{ steps.conn.outputs.host }}
|
||||||
SFTP_PORT: ${{ steps.conn.outputs.port }}
|
SFTP_PORT: ${{ steps.conn.outputs.port }}
|
||||||
@@ -449,7 +497,7 @@ jobs:
|
|||||||
php /tmp/moko_clear.php
|
php /tmp/moko_clear.php
|
||||||
|
|
||||||
- name: Deploy via SFTP
|
- name: Deploy via SFTP
|
||||||
if: steps.source.outputs.skip == 'false'
|
if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true'
|
||||||
env:
|
env:
|
||||||
SFTP_HOST: ${{ steps.conn.outputs.host }}
|
SFTP_HOST: ${{ steps.conn.outputs.host }}
|
||||||
SFTP_PORT: ${{ steps.conn.outputs.port }}
|
SFTP_PORT: ${{ steps.conn.outputs.port }}
|
||||||
|
|||||||
140
.github/workflows/sync-version-on-merge.yml
vendored
Normal file
140
.github/workflows/sync-version-on-merge.yml
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# This file is part of a Moko Consulting project.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: GitHub.Workflow
|
||||||
|
# INGROUP: MokoStandards.Automation
|
||||||
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
|
# PATH: /templates/workflows/shared/sync-version-on-merge.yml
|
||||||
|
# VERSION: 04.00.35
|
||||||
|
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
|
||||||
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos.
|
||||||
|
# README.md is the single source of truth for the repository version.
|
||||||
|
|
||||||
|
name: Sync Version from README
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
dry_run:
|
||||||
|
description: 'Dry run (preview only, no commit)'
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-version:
|
||||||
|
name: Propagate README version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up PHP
|
||||||
|
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.31.0
|
||||||
|
with:
|
||||||
|
php-version: '8.1'
|
||||||
|
tools: composer
|
||||||
|
|
||||||
|
- name: Setup MokoStandards tools
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 --quiet \
|
||||||
|
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
|
||||||
|
/tmp/mokostandards
|
||||||
|
cd /tmp/mokostandards
|
||||||
|
composer install --no-dev --no-interaction --quiet
|
||||||
|
|
||||||
|
- name: Auto-bump patch version
|
||||||
|
if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }}
|
||||||
|
run: |
|
||||||
|
# If README.md was part of this push, the author already bumped the version — skip.
|
||||||
|
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^README\.md$'; then
|
||||||
|
echo "README.md changed in this push — skipping auto-bump"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CURRENT=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1)
|
||||||
|
if [ -z "$CURRENT" ]; then
|
||||||
|
echo "⚠️ No VERSION found in README.md — skipping auto-bump"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increment the patch component (zero-padded to 2 digits)
|
||||||
|
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
|
||||||
|
MINOR=$(echo "$CURRENT" | cut -d. -f2)
|
||||||
|
PATCH=$(echo "$CURRENT" | cut -d. -f3)
|
||||||
|
NEW_PATCH=$(printf '%02d' $(( 10#$PATCH + 1 )))
|
||||||
|
NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||||
|
|
||||||
|
echo "Auto-bumping patch: $CURRENT → $NEW_VERSION"
|
||||||
|
sed -i "s/^\(\s*VERSION:\s*\)${CURRENT}/\1${NEW_VERSION}/" README.md
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git add README.md
|
||||||
|
git commit -m "chore(version): auto-bump patch ${CURRENT} → ${NEW_VERSION} [skip ci]" \
|
||||||
|
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
|
||||||
|
git push
|
||||||
|
|
||||||
|
- name: Extract version from README.md
|
||||||
|
id: readme_version
|
||||||
|
run: |
|
||||||
|
git pull --ff-only 2>/dev/null || true
|
||||||
|
VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1)
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
echo "⚠️ No VERSION in README.md — skipping propagation"
|
||||||
|
echo "skip=true" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "skip=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "✅ README.md version: $VERSION"
|
||||||
|
|
||||||
|
- name: Run version sync
|
||||||
|
if: ${{ steps.readme_version.outputs.skip != 'true' && inputs.dry_run != true }}
|
||||||
|
run: |
|
||||||
|
php /tmp/mokostandards/api/maintenance/update_version_from_readme.php \
|
||||||
|
--path . \
|
||||||
|
--create-issue \
|
||||||
|
--repo "${{ github.repository }}"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
|
||||||
|
- name: Commit updated files
|
||||||
|
if: ${{ steps.readme_version.outputs.skip != 'true' && inputs.dry_run != true }}
|
||||||
|
run: |
|
||||||
|
if git diff --quiet; then
|
||||||
|
echo "ℹ️ No version changes needed"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
VERSION="${{ steps.readme_version.outputs.version }}"
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git add -A
|
||||||
|
git commit -m "chore(version): sync badges and headers to ${VERSION} [skip ci]" \
|
||||||
|
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
|
||||||
|
git push
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.readme_version.outputs.version }}"
|
||||||
|
echo "## 📦 Version Sync — ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Source:** \`README.md\` FILE INFORMATION block" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Version:** \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
Reference in New Issue
Block a user