diff --git a/.mokogitea/workflows/auto-release.yml b/.mokogitea/workflows/auto-release.yml index 8d0ac29..72ce95a 100644 --- a/.mokogitea/workflows/auto-release.yml +++ b/.mokogitea/workflows/auto-release.yml @@ -74,6 +74,8 @@ jobs: if ! command -v composer &> /dev/null; then sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 fi + # Always fetch latest CLI tools — never use stale cache from previous runs + rm -rf /tmp/moko-platform-api git clone --depth 1 --branch main --quiet \ "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ /tmp/moko-platform-api @@ -135,6 +137,8 @@ jobs: if ! command -v composer &> /dev/null; then sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 fi + # Always fetch latest CLI tools — never use stale cache from previous runs + rm -rf /tmp/moko-platform-api git clone --depth 1 --branch main --quiet \ "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ /tmp/moko-platform-api @@ -197,6 +201,8 @@ jobs: MOKO_API="/tmp/moko-platform-api/cli" php ${MOKO_API}/version_bump.php --path . --minor 2>&1 || true VERSION=$(php ${MOKO_API}/version_read.php --path .) + # Strip any pre-release suffix — stable releases have no suffix + VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//') echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "Bumped to: ${VERSION}" @@ -294,7 +300,8 @@ jobs: git add -A git commit -m "chore(release): build ${VERSION} [skip ci]" \ --author="gitea-actions[bot] " - git push -u origin HEAD + # Detached HEAD on PR merge — push explicitly to main + git push origin HEAD:refs/heads/main # -- STEP 6: Create tag --------------------------------------------------- - name: "Step 6: Create git tag" @@ -385,7 +392,7 @@ jobs: git add updates.xml git commit -m "chore: update stable channel ${VERSION} [skip ci]" \ --author="gitea-actions[bot] " - git push origin HEAD 2>&1 || true + git push origin HEAD:refs/heads/main 2>&1 || true fi # -- STEP 8b: Update release description with changelog ---------------------- diff --git a/.mokogitea/workflows/pre-release.yml b/.mokogitea/workflows/pre-release.yml index 0f0d000..162b08f 100644 --- a/.mokogitea/workflows/pre-release.yml +++ b/.mokogitea/workflows/pre-release.yml @@ -60,6 +60,8 @@ jobs: if ! command -v composer &> /dev/null; then sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 fi + # Always fetch latest CLI tools — never use stale cache from previous runs + rm -rf /tmp/moko-platform-api git clone --depth 1 --branch main --quiet \ "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ /tmp/moko-platform-api diff --git a/.mokogitea/workflows/update-server.yml b/.mokogitea/workflows/update-server.yml index 061476f..339d3f5 100644 --- a/.mokogitea/workflows/update-server.yml +++ b/.mokogitea/workflows/update-server.yml @@ -85,13 +85,11 @@ jobs: if ! command -v composer &> /dev/null; then sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1 fi - if [ -d "/tmp/moko-platform" ]; then - echo "moko-platform already available — skipping clone" - else - git clone --depth 1 --branch main --quiet \ - "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ - /tmp/moko-platform 2>/dev/null || true - fi + # Always fetch latest CLI tools — never use stale cache from previous runs + rm -rf /tmp/moko-platform + git clone --depth 1 --branch main --quiet \ + "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ + /tmp/moko-platform 2>/dev/null || true if [ -d "/tmp/moko-platform" ] && [ -f "/tmp/moko-platform/composer.json" ]; then cd /tmp/moko-platform && composer install --no-dev --no-interaction --quiet 2>/dev/null || true fi @@ -116,6 +114,9 @@ jobs: VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "0.0.0") + # Strip any existing suffix before applying stability + VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//') + # Determine stability from branch or manual input if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then STABILITY="${{ inputs.stability }}" diff --git a/README.md b/README.md index a4c8bd8..7611cae 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DEFGROUP: MokoStandards.Root INGROUP: MokoStandards REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform PATH: /README.md -VERSION: 09.02.08 +VERSION: 09.02.09 BRIEF: Project overview and documentation --> diff --git a/cli/release_cascade.php b/cli/release_cascade.php index 8295983..db96629 100644 --- a/cli/release_cascade.php +++ b/cli/release_cascade.php @@ -131,7 +131,7 @@ foreach ($tagsToDelete as $tag) { // ── Version-aware cleanup: delete releases with lesser version numbers ─────── if ($version !== null) { // Normalize version for comparison (strip any suffix) - $baseVersion = preg_replace('/-[a-z]+$/', '', $version); + $baseVersion = preg_replace('/(-(dev|alpha|beta|rc))+$/', '', $version); // Check all channels (including ones not in the cascade map for this stability) $allChannels = ['development', 'alpha', 'beta', 'release-candidate', 'stable']; diff --git a/cli/release_package.php b/cli/release_package.php index 8ff92e8..134c572 100644 --- a/cli/release_package.php +++ b/cli/release_package.php @@ -402,6 +402,18 @@ if ($isJoomlaPackage) { echo " Sub-package: {$subName}.zip\n"; } + // Ensure package manifest has folder="packages" on element + // since sub-packages are stored in a packages/ subdirectory + $pkgManifests = glob("{$sourceDir}/pkg_*.xml") ?: []; + foreach ($pkgManifests as $pkgXml) { + $pkgContent = file_get_contents($pkgXml); + if (strpos($pkgContent, '') !== false && strpos($pkgContent, 'folder="packages"') === false) { + $pkgContent = str_replace('', '', $pkgContent); + file_put_contents($pkgXml, $pkgContent); + echo " Fixed: added folder=\"packages\" to " . basename($pkgXml) . "\n"; + } + } + // Copy top-level XML and PHP files into the package root $topLevelFiles = array_merge( glob("{$sourceDir}/*.xml") ?: [], diff --git a/cli/version_bump.php b/cli/version_bump.php index 5674635..b6a24db 100644 --- a/cli/version_bump.php +++ b/cli/version_bump.php @@ -31,7 +31,7 @@ $mokoManifest = "{$root}/.mokogitea/manifest.xml"; $mokoContent = ''; if (file_exists($mokoManifest)) { $mokoContent = file_get_contents($mokoManifest); - if (preg_match('|(\d{2}\.\d{2}\.\d{2})(?:-([a-z]+))?|', $mokoContent, $m)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2})(?:-((?:(?:dev|alpha|beta|rc)-?)+))?|', $mokoContent, $m)) { $mokoVersion = $m[1]; $mokoSuffix = isset($m[2]) ? $m[2] : ''; } @@ -64,7 +64,7 @@ foreach ($manifestFiles as $xmlFile) { if (strpos($xmlContent, '') === false) { continue; } - if (preg_match('|(\d{2}\.\d{2}\.\d{2})(-[a-z]+)?|', $xmlContent, $xm)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2})((?:-(?:dev|alpha|beta|rc))+)?|', $xmlContent, $xm)) { $candidate = $xm[1]; if ($manifestVersion === null || version_compare($candidate, $manifestVersion, '>')) { $manifestVersion = $candidate; @@ -120,7 +120,7 @@ $newFull = $new; // -- Update .mokogitea/manifest.xml (canonical — preserves suffix) -- if (file_exists($mokoManifest) && !empty($mokoContent)) { $updated = preg_replace( - '|\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?|', + '|\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?|', "{$newFull}", $mokoContent, 1 @@ -131,7 +131,7 @@ if (file_exists($mokoManifest) && !empty($mokoContent)) { // -- Update README.md -- if (file_exists($readme) && !empty($readmeContent)) { $updated = preg_replace( - '/(VERSION:\s*)\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?/m', + '/(VERSION:\s*)\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?/m', '${1}' . $newFull, $readmeContent, 1 @@ -156,7 +156,7 @@ foreach ($xmlPatterns as $pattern) { continue; } $newContent = preg_replace( - '|\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?|', + '|\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?|', "{$newFull}", $content ); @@ -176,7 +176,7 @@ $packageJsonFile = "{$root}/package.json"; if (file_exists($packageJsonFile)) { $pkgContent = file_get_contents($packageJsonFile); $updatedPkg = preg_replace( - '/("version"\s*:\s*")\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?(")/m', + '/("version"\s*:\s*")\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?(")/m', '${1}' . $newFull . '${2}', $pkgContent ); @@ -191,7 +191,7 @@ $pyprojectFile = "{$root}/pyproject.toml"; if (file_exists($pyprojectFile)) { $pyContent = file_get_contents($pyprojectFile); $updatedPy = preg_replace( - '/^(version\s*=\s*")\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?(")/m', + '/^(version\s*=\s*")\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?(")/m', '${1}' . $newFull . '${2}', $pyContent ); diff --git a/cli/version_check.php b/cli/version_check.php index 07bc853..e5e2379 100644 --- a/cli/version_check.php +++ b/cli/version_check.php @@ -59,7 +59,7 @@ foreach ($xmlGlobs as $glob) { $xmlContent = file_get_contents($file); if (strpos($xmlContent, '(\d{2}\.\d{2}\.\d{2})(?:-[a-z]+)?|', $xmlContent, $xm)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2})(?:(?:-(?:dev|alpha|beta|rc))+)?|', $xmlContent, $xm)) { $relPath = str_replace($root . '/', '', $file); $relPath = str_replace($root . '\\', '', $relPath); $versions[$relPath] = $xm[1]; diff --git a/cli/version_read.php b/cli/version_read.php index bdc2350..5c76856 100644 --- a/cli/version_read.php +++ b/cli/version_read.php @@ -30,7 +30,7 @@ if (file_exists($mokoManifest)) { $xml = @simplexml_load_file($mokoManifest); if ($xml !== false) { $v = (string)($xml->identity->version ?? ''); - if (preg_match('/^\d{2}\.\d{2}\.\d{2}(-[a-z]+)?$/', $v)) { + if (preg_match('/^\d{2}\.\d{2}\.\d{2}((?:-(?:dev|alpha|beta|rc))+)?$/', $v)) { $mokoVersion = $v; } } @@ -66,10 +66,10 @@ foreach ($manifestFiles as $xmlFile) { if (strpos($xmlContent, '') === false) { continue; } - if (preg_match('|(\d{2}\.\d{2}\.\d{2}(?:-[a-z]+)?)|', $xmlContent, $xm)) { + if (preg_match('|(\d{2}\.\d{2}\.\d{2}(?:(?:-(?:dev|alpha|beta|rc))+)?)|', $xmlContent, $xm)) { $candidate = $xm[1]; - $candidateBase = preg_replace('/-[a-z]+$/', '', $candidate); - $currentBase = $manifestVersion ? preg_replace('/-[a-z]+$/', '', $manifestVersion) : null; + $candidateBase = preg_replace('/(-(dev|alpha|beta|rc))+$/', '', $candidate); + $currentBase = $manifestVersion ? preg_replace('/(-(dev|alpha|beta|rc))+$/', '', $manifestVersion) : null; if ($currentBase === null || version_compare($candidateBase, $currentBase, '>')) { $manifestVersion = $candidate; } @@ -119,7 +119,7 @@ if ($version === null) { // -- Backfill: if manifest.xml exists but lacks , insert it -- if (file_exists($mokoManifest)) { $content = file_get_contents($mokoManifest); - if (!preg_match('|\d{2}\.\d{2}\.\d{2}(-[a-z]+)?|', $content)) { + if (!preg_match('|\d{2}\.\d{2}\.\d{2}((?:-(?:dev|alpha|beta|rc))+)?|', $content)) { if (strpos($content, ' -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# FILE INFORMATION -# DEFGROUP: Gitea.Workflow -# INGROUP: MokoStandards -# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform -# PATH: /templates/workflows/dependency-audit.yml -# VERSION: 01.00.00 -# BRIEF: Scheduled dependency audit — runs composer audit across repos - -name: Dependency Audit - -on: - schedule: - - cron: '0 8 * * 1' # Every Monday at 08:00 UTC - workflow_dispatch: - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - audit: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - tools: composer - - - name: Run composer audit - id: audit - run: | - if [ ! -f composer.json ]; then - echo "No composer.json found — skipping." - echo "skip=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "skip=false" >> "$GITHUB_OUTPUT" - - set +e - AUDIT_OUTPUT=$(composer audit --format=json 2>&1) - AUDIT_EXIT=$? - set -e - - echo "$AUDIT_OUTPUT" > audit-results.json - - if [ "$AUDIT_EXIT" -ne 0 ]; then - echo "vulnerable=true" >> "$GITHUB_OUTPUT" - else - echo "vulnerable=false" >> "$GITHUB_OUTPUT" - fi - - - name: Parse vulnerabilities - if: steps.audit.outputs.skip != 'true' - id: parse - run: | - if [ "${{ steps.audit.outputs.vulnerable }}" = "true" ]; then - echo "## Vulnerabilities Found" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - - # Extract advisory count - ADVISORIES=$(jq -r '.advisories | length // 0' audit-results.json 2>/dev/null || echo "0") - echo "Found **${ADVISORIES}** advisories." >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - - # List each advisory - jq -r ' - .advisories | to_entries[] | - "| \(.key) | \(.value[0].title // "N/A") | \(.value[0].cve // "N/A") | \(.value[0].affectedVersions // "N/A") |" - ' audit-results.json 2>/dev/null | { - echo "| Package | Title | CVE | Affected Versions |" - echo "|---------|-------|-----|-------------------|" - cat - } >> "$GITHUB_STEP_SUMMARY" - - echo "count=${ADVISORIES}" >> "$GITHUB_OUTPUT" - else - echo "## No Vulnerabilities Found" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - echo "All dependencies passed the audit." >> "$GITHUB_STEP_SUMMARY" - echo "count=0" >> "$GITHUB_OUTPUT" - fi - - - name: Notify via ntfy - if: steps.audit.outputs.vulnerable == 'true' - run: | - NTFY_URL="${{ vars.NTFY_URL }}" - NTFY_TOPIC="${{ vars.NTFY_TOPIC }}" - REPO="${{ github.repository }}" - COUNT="${{ steps.parse.outputs.count }}" - RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - curl -s \ - -H "Title: Dependency Audit: ${REPO}" \ - -H "Priority: high" \ - -H "Tags: warning,package" \ - -H "Click: ${RUN_URL}" \ - -d "Found ${COUNT} vulnerability advisory(ies) in ${REPO}. Review the workflow run for details." \ - "${NTFY_URL}/${NTFY_TOPIC}" - - - name: Summary - if: always() && steps.audit.outputs.skip != 'true' - run: | - echo "" >> "$GITHUB_STEP_SUMMARY" - echo "---" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - echo "Audit completed at $(date -u '+%Y-%m-%d %H:%M:%S UTC')." >> "$GITHUB_STEP_SUMMARY" - echo "Repository: **${{ github.repository }}**" >> "$GITHUB_STEP_SUMMARY" - echo "Branch: **${{ github.ref_name }}**" >> "$GITHUB_STEP_SUMMARY" diff --git a/templates/workflows/deploy-module.yml b/templates/workflows/deploy-module.yml deleted file mode 100644 index 151a62b..0000000 --- a/templates/workflows/deploy-module.yml +++ /dev/null @@ -1,223 +0,0 @@ -# Copyright (C) 2026 Moko Consulting -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# FILE INFORMATION -# DEFGROUP: Gitea.Workflow -# INGROUP: moko-platform.Deploy -# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform -# PATH: /templates/workflows/deploy-module.yml -# VERSION: 02.00.00 -# BRIEF: Deploy Dolibarr module to dev, demo, or live environments -# -# Secrets required: -# GA_TOKEN - Gitea API token for repo access -# DEPLOY_SSH_KEY - SSH private key for server access -# LIVE_TARGETS - JSON array of live instances (optional), e.g.: -# [{"host":"client1.example.com","user":"deploy", -# "mods_dir":"/path/MokoDoliMods", -# "custom_dir":"/path/htdocs/custom"}] -# -# Variables required: -# DEV_HOST, DEV_USER, DEV_MODS_DIR, DEV_CUSTOM_DIR -# DEMO_HOST, DEMO_USER, DEMO_MODS_DIR, DEMO_CUSTOM_DIR - -name: "Dolibarr: Deploy Module" - -on: - workflow_dispatch: - inputs: - module_repo: - description: 'Module repo name (e.g. MokoCRM, MokoDoliSign)' - required: true - server: - description: 'Target environment' - required: true - default: 'dev' - type: choice - options: - - dev - - demo - - live - - dev+demo - - all - -env: - GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} - ORG: ${{ vars.GITEA_ORG || 'MokoConsulting' }} - -jobs: - deploy: - name: Deploy ${{ inputs.module_repo }} to ${{ inputs.server }} - runs-on: ubuntu-latest - - steps: - - name: Validate module repo - run: | - REPO="${{ inputs.module_repo }}" - STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - -H "Authorization: token ${{ secrets.GA_TOKEN }}" \ - "${GITEA_URL}/api/v1/repos/${ORG}/${REPO}") - if [ "$STATUS" != "200" ]; then - echo "::error::${ORG}/${REPO} not found (HTTP ${STATUS})" - exit 1 - fi - echo "REPO=${REPO}" >> $GITHUB_ENV - - LINK_NAME=$(echo "$REPO" | sed 's/MokoDoli//;s/Moko//' | tr '[:upper:]' '[:lower:]') - [ "$REPO" = "MokoCRM" ] && LINK_NAME="mokocrm" - [ "$REPO" = "MokoDoliProjTemplate" ] && LINK_NAME="mokoprojtemplate" - echo "LINK_NAME=${LINK_NAME}" >> $GITHUB_ENV - - - name: Get latest stable tag - run: | - TAGS=$(curl -s \ - -H "Authorization: token ${{ secrets.GA_TOKEN }}" \ - "${GITEA_URL}/api/v1/repos/${ORG}/${{ env.REPO }}/tags?limit=1") - TAG=$(echo "$TAGS" | jq -r '.[0].name // empty') - echo "TAG=${TAG}" >> $GITHUB_ENV - [ -n "$TAG" ] && echo "Deploying: $TAG" || echo "No tags - deploying main" - - - name: Deploy to dev - if: inputs.server == 'dev' || inputs.server == 'dev+demo' || inputs.server == 'all' - uses: appleboy/ssh-action@v1 - with: - host: ${{ vars.DEV_HOST }} - username: ${{ vars.DEV_USER }} - key: ${{ secrets.DEPLOY_SSH_KEY }} - script: | - REPO="${{ env.REPO }}" - LINK="${{ env.LINK_NAME }}" - TAG="${{ env.TAG }}" - MODS="${{ vars.DEV_MODS_DIR }}" - CUSTOM="${{ vars.DEV_CUSTOM_DIR }}" - - mkdir -p "$MODS" && cd "$MODS" - if [ -d "$REPO" ]; then - cd "$REPO" && git fetch --tags origin - else - git clone "${{ env.GITEA_URL }}/${{ env.ORG }}/${REPO}.git" - cd "$REPO" - fi - - if [ -n "$TAG" ]; then - git checkout "$TAG" --quiet - else - git checkout main --quiet - git pull --ff-only origin main --quiet - fi - - cd "$CUSTOM" - [ -L "$LINK" ] || [ -d "$LINK" ] && rm -rf "$LINK" - ln -sf "$MODS/$REPO/src" "$LINK" - echo "OK: $LINK -> $MODS/$REPO/src (${TAG:-main})" - - - name: Deploy to demo - if: inputs.server == 'demo' || inputs.server == 'dev+demo' || inputs.server == 'all' - uses: appleboy/ssh-action@v1 - with: - host: ${{ vars.DEMO_HOST }} - username: ${{ vars.DEMO_USER }} - key: ${{ secrets.DEPLOY_SSH_KEY }} - script: | - REPO="${{ env.REPO }}" - LINK="${{ env.LINK_NAME }}" - TAG="${{ env.TAG }}" - MODS="${{ vars.DEMO_MODS_DIR }}" - CUSTOM="${{ vars.DEMO_CUSTOM_DIR }}" - - mkdir -p "$MODS" && cd "$MODS" - if [ -d "$REPO" ]; then - cd "$REPO" && git fetch --tags origin - else - git clone "${{ env.GITEA_URL }}/${{ env.ORG }}/${REPO}.git" - cd "$REPO" - fi - - if [ -n "$TAG" ]; then - git checkout "$TAG" --quiet - else - git checkout main --quiet - git pull --ff-only origin main --quiet - fi - - cd "$CUSTOM" - [ -L "$LINK" ] || [ -d "$LINK" ] && rm -rf "$LINK" - ln -sf "$MODS/$REPO/src" "$LINK" - echo "OK: $LINK -> $MODS/$REPO/src (${TAG:-main})" - - - name: Deploy to live - if: inputs.server == 'live' || inputs.server == 'all' - env: - LIVE_TARGETS: ${{ secrets.LIVE_TARGETS }} - DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - run: | - if [ -z "$LIVE_TARGETS" ] || [ "$LIVE_TARGETS" = "null" ]; then - echo "::error::LIVE_TARGETS secret is not configured." - echo "Set it to a JSON array of target objects." - exit 1 - fi - - COUNT=$(echo "$LIVE_TARGETS" | jq 'length') - echo "Deploying to ${COUNT} live instance(s)..." - - echo "$DEPLOY_KEY" > /tmp/deploy_key - chmod 600 /tmp/deploy_key - - FAILED=0 - for i in $(seq 0 $((COUNT - 1))); do - HOST=$(echo "$LIVE_TARGETS" | jq -r ".[$i].host") - USER=$(echo "$LIVE_TARGETS" | jq -r ".[$i].user") - MODS=$(echo "$LIVE_TARGETS" | jq -r ".[$i].mods_dir") - CUSTOM=$(echo "$LIVE_TARGETS" | jq -r ".[$i].custom_dir") - PORT=$(echo "$LIVE_TARGETS" | jq -r ".[$i].port // 22") - LABEL=$(echo "$LIVE_TARGETS" | jq -r ".[$i].label // empty") - [ -z "$LABEL" ] && LABEL="$HOST" - - echo "" - echo "=== Instance $((i+1))/${COUNT}: ${LABEL} (${USER}@${HOST}:${PORT}) ===" - - ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 \ - -i /tmp/deploy_key -p "$PORT" "${USER}@${HOST}" \ - "REPO='${{ env.REPO }}' LINK='${{ env.LINK_NAME }}' TAG='${{ env.TAG }}' MODS='${MODS}' CUSTOM='${CUSTOM}' GITEA_URL='${{ env.GITEA_URL }}' ORG='${{ env.ORG }}' bash" <<'REMOTE_SCRIPT' || { echo "::warning::Failed: ${LABEL}"; FAILED=$((FAILED+1)); continue; } - mkdir -p "$MODS" && cd "$MODS" - if [ -d "$REPO" ]; then - cd "$REPO" && git fetch --tags origin - else - git clone "${GITEA_URL}/${ORG}/${REPO}.git" - cd "$REPO" - fi - - if [ -n "$TAG" ]; then - git checkout "$TAG" --quiet - else - git checkout main --quiet - git pull --ff-only origin main --quiet - fi - - cd "$CUSTOM" - [ -L "$LINK" ] || [ -d "$LINK" ] && rm -rf "$LINK" - ln -sf "$MODS/$REPO/src" "$LINK" - echo "OK: $LINK -> $MODS/$REPO/src (${TAG:-main})" - REMOTE_SCRIPT - done - - rm -f /tmp/deploy_key - - if [ "$FAILED" -gt 0 ]; then - echo "::error::${FAILED} of ${COUNT} live deployment(s) failed" - exit 1 - fi - echo "All ${COUNT} live instance(s) deployed successfully." - - - name: Summary - if: always() - run: | - echo "## Deploy: ${{ env.REPO }} -> ${{ inputs.server }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY - echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY - echo "| Module | \`${{ env.REPO }}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Symlink | \`${{ env.LINK_NAME }}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Version | \`${{ env.TAG || 'main' }}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Target | \`${{ inputs.server }}\` |" >> $GITHUB_STEP_SUMMARY diff --git a/templates/workflows/gitleaks.yml.template b/templates/workflows/gitleaks.yml.template deleted file mode 100644 index 113581a..0000000 --- a/templates/workflows/gitleaks.yml.template +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2026 Moko Consulting -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# FILE INFORMATION -# DEFGROUP: Gitea.Workflow -# INGROUP: MokoStandards.Security -# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API -# PATH: /templates/workflows/gitleaks.yml.template -# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens -# -# +========================================================================+ -# | SECRET SCANNING | -# +========================================================================+ -# | | -# | Scans commits for leaked secrets using Gitleaks. | -# | | -# | - PR scan: only new commits in the PR | -# | - Scheduled: full repo scan weekly | -# | - Alerts via ntfy on findings | -# | | -# +========================================================================+ - -name: Secret Scanning - -on: - pull_request: - branches: - - main - - 'dev/**' - schedule: - - cron: '0 5 * * 1' # Weekly Monday 05:00 UTC - workflow_dispatch: - -permissions: - contents: read - -env: - NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }} - NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }} - -jobs: - gitleaks: - name: Gitleaks Secret Scan - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install Gitleaks - run: | - GITLEAKS_VERSION="8.21.2" - curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ - | tar -xz -C /usr/local/bin gitleaks - gitleaks version - - - name: Scan for secrets - id: scan - run: | - echo "### Secret Scanning" >> $GITHUB_STEP_SUMMARY - ARGS="--source . --verbose --report-format json --report-path /tmp/gitleaks-report.json" - - if [ "${{ github.event_name }}" = "pull_request" ]; then - # Scan only PR commits - ARGS="$ARGS --log-opts=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" - echo "Scanning PR commits only" >> $GITHUB_STEP_SUMMARY - else - echo "Full repository scan" >> $GITHUB_STEP_SUMMARY - fi - - if gitleaks detect $ARGS 2>&1; then - echo "result=clean" >> "$GITHUB_OUTPUT" - echo "**No secrets detected.**" >> $GITHUB_STEP_SUMMARY - else - echo "result=found" >> "$GITHUB_OUTPUT" - FINDINGS=$(jq length /tmp/gitleaks-report.json 2>/dev/null || echo "unknown") - echo "**${FINDINGS} potential secret(s) detected.**" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Review the findings and rotate any exposed credentials immediately." >> $GITHUB_STEP_SUMMARY - exit 1 - fi - - - name: Notify on findings - if: failure() && steps.scan.outputs.result == 'found' - run: | - REPO="${{ github.event.repository.name }}" - curl -sS \ - -H "Title: ${REPO} — secrets detected in code" \ - -H "Tags: rotating_light,key" \ - -H "Priority: urgent" \ - -d "Gitleaks found potential secrets. Review and rotate credentials immediately." \ - "${NTFY_URL}/${NTFY_TOPIC}" || true diff --git a/templates/workflows/mcp/mcp-auto-release.yml.template b/templates/workflows/mcp/mcp-auto-release.yml.template deleted file mode 100644 index 74daa33..0000000 --- a/templates/workflows/mcp/mcp-auto-release.yml.template +++ /dev/null @@ -1,278 +0,0 @@ -# MCP Server Auto-Release -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later -# -# MCP-specific release pipeline that builds TypeScript, runs validation, -# attaches the compiled dist/ as a release artifact, and creates a GitHub -# Release with tool inventory in the release notes. -# -# This replaces the generic auto-release.yml for MCP server repos. - -name: MCP Release - -on: - push: - branches: - - main - paths: - - 'src/**' - - 'package.json' - - 'tsconfig.json' - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -permissions: - contents: write - issues: write - -jobs: - build-and-release: - name: Build, Validate & Release - runs-on: ubuntu-latest - if: >- - !contains(github.event.head_commit.message, '[skip ci]') && - github.actor != 'github-actions[bot]' - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GH_TOKEN || github.token }} - fetch-depth: 0 - - # ── Build ──────────────────────────────────────────────────────── - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install dependencies - run: npm ci - - - name: TypeScript compile check - run: npx tsc --noEmit - - - name: Build - run: npm run build - - - name: Verify dist output - run: | - for f in index.js client.js config.js types.js; do - test -f "dist/${f}" || (echo "ERROR: dist/${f} not found" && exit 1) - done - echo "✓ All dist files present" - - # ── Tool Inventory ─────────────────────────────────────────────── - - name: Generate tool inventory - id: tools - run: | - TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || echo "0") - echo "count=${TOOL_COUNT}" >> "$GITHUB_OUTPUT" - - # Extract tool names - TOOL_LIST=$(grep -oE "'[a-z_]+'" src/index.ts | head -100 | tr -d "'" | sort -u) - echo "Tools registered: ${TOOL_COUNT}" - - # Generate inventory for release notes - echo "## Tool Inventory (${TOOL_COUNT} tools)" > /tmp/tool-inventory.md - echo "" >> /tmp/tool-inventory.md - grep -B0 -A1 "server\.tool(" src/index.ts | grep -oE "'[^']+'" | while IFS= read -r name; do - read -r desc 2>/dev/null || true - CLEAN_NAME=$(echo "$name" | tr -d "'") - CLEAN_DESC=$(echo "$desc" | tr -d "'" | sed 's/,$//') - if [ -n "$CLEAN_NAME" ] && [ -n "$CLEAN_DESC" ]; then - echo "- \`${CLEAN_NAME}\` — ${CLEAN_DESC}" >> /tmp/tool-inventory.md - fi - done - - # ── Version ────────────────────────────────────────────────────── - - 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 --branch version/04 --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: Read version from README.md - id: version - run: | - VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null) - if [ -z "$VERSION" ]; then - echo "No VERSION in README.md — skipping release" - echo "skip=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - - MAJOR=$(echo "$VERSION" | awk -F. '{print $1}') - MINOR=$(echo "$VERSION" | awk -F. '{printf "%s.%s", $1, $2}') - PATCH=$(echo "$VERSION" | awk -F. '{print $3}') - - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT" - echo "major=$MAJOR" >> "$GITHUB_OUTPUT" - echo "minor=$MINOR" >> "$GITHUB_OUTPUT" - echo "release_tag=v${MAJOR}" >> "$GITHUB_OUTPUT" - - if [ "$PATCH" = "00" ]; then - echo "skip=true" >> "$GITHUB_OUTPUT" - else - echo "skip=false" >> "$GITHUB_OUTPUT" - if [ "$PATCH" = "01" ]; then - echo "is_first=true" >> "$GITHUB_OUTPUT" - else - echo "is_first=false" >> "$GITHUB_OUTPUT" - fi - fi - - - name: Check if already released - if: steps.version.outputs.skip != 'true' - id: check - run: | - TAG="${{ steps.version.outputs.release_tag }}" - TAG_EXISTS=false - git rev-parse "$TAG" >/dev/null 2>&1 && TAG_EXISTS=true - echo "tag_exists=$TAG_EXISTS" >> "$GITHUB_OUTPUT" - - # ── Release Artifact ───────────────────────────────────────────── - - name: Package dist - if: steps.version.outputs.skip != 'true' - run: | - VERSION="${{ steps.version.outputs.version }}" - REPO_NAME="${{ github.event.repository.name }}" - tar -czf "/tmp/${REPO_NAME}-${VERSION}.tar.gz" -C dist . - echo "artifact=/tmp/${REPO_NAME}-${VERSION}.tar.gz" >> "$GITHUB_OUTPUT" - - # ── Version Updates ────────────────────────────────────────────── - - name: Set platform version - if: >- - steps.version.outputs.skip != 'true' && - steps.check.outputs.tag_exists != 'true' - run: | - VERSION="${{ steps.version.outputs.version }}" - php /tmp/mokostandards/api/cli/version_set_platform.php \ - --path . --version "$VERSION" --branch main - - - name: Update version badges - if: >- - steps.version.outputs.skip != 'true' && - steps.check.outputs.tag_exists != 'true' - run: | - VERSION="${{ steps.version.outputs.version }}" - find . -name "*.md" ! -path "./.git/*" ! -path "./vendor/*" | while read -r f; do - if grep -q '\[VERSION:' "$f" 2>/dev/null; then - sed -i "s/\[VERSION:[[:space:]]*[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\}\]/[VERSION: ${VERSION}]/" "$f" - fi - done - - - name: Commit release changes - if: >- - steps.version.outputs.skip != 'true' && - steps.check.outputs.tag_exists != 'true' - run: | - if git diff --quiet && git diff --cached --quiet; then - echo "No changes to commit" - exit 0 - fi - VERSION="${{ steps.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(release): build ${VERSION} [skip ci]" \ - --author="github-actions[bot] " - git push - - # ── Version Branch ─────────────────────────────────────────────── - - name: Archive version branch - if: steps.check.outputs.tag_exists != 'true' - run: | - BRANCH="${{ steps.version.outputs.branch }}" - git push origin HEAD:"$BRANCH" --force - echo "Updated archive branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY - - # ── Tag & Release ──────────────────────────────────────────────── - - name: Create git tag - if: >- - steps.version.outputs.skip != 'true' && - steps.check.outputs.tag_exists != 'true' && - steps.version.outputs.is_first == 'true' - run: | - TAG="${{ steps.version.outputs.release_tag }}" - if ! git rev-parse "$TAG" >/dev/null 2>&1; then - git tag "$TAG" - git push origin "$TAG" - fi - - - name: GitHub Release - if: >- - steps.version.outputs.skip != 'true' && - steps.check.outputs.tag_exists != 'true' - env: - GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} - run: | - VERSION="${{ steps.version.outputs.version }}" - RELEASE_TAG="${{ steps.version.outputs.release_tag }}" - MAJOR="${{ steps.version.outputs.major }}" - BRANCH="${{ steps.version.outputs.branch }}" - TOOL_COUNT="${{ steps.tools.outputs.count }}" - REPO_NAME="${{ github.event.repository.name }}" - - # Build release notes - NOTES=$(php /tmp/mokostandards/api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null) - [ -z "$NOTES" ] && NOTES="Release ${VERSION}" - - { - echo "$NOTES" - echo "" - echo "---" - echo "" - echo "### MCP Server Info" - echo "- **Tools registered**: ${TOOL_COUNT}" - echo "- **Node.js**: 20+" - echo "- **MCP SDK**: $(node -p \"require('./package.json').dependencies['@modelcontextprotocol/sdk']\" 2>/dev/null || echo 'unknown')" - echo "" - cat /tmp/tool-inventory.md 2>/dev/null || true - } > /tmp/release_notes.md - - EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true) - - ARTIFACT="/tmp/${REPO_NAME}-${VERSION}.tar.gz" - - if [ -z "$EXISTING" ]; then - gh release create "$RELEASE_TAG" \ - --title "v${MAJOR} (latest: ${VERSION})" \ - --notes-file /tmp/release_notes.md \ - --target "$BRANCH" \ - "$ARTIFACT" - echo "Release created: ${RELEASE_TAG} (${VERSION})" >> $GITHUB_STEP_SUMMARY - else - gh release edit "$RELEASE_TAG" \ - --title "v${MAJOR} (latest: ${VERSION})" \ - --notes-file /tmp/release_notes.md - gh release upload "$RELEASE_TAG" "$ARTIFACT" --clobber 2>/dev/null || true - echo "Release updated: ${RELEASE_TAG} -> ${VERSION}" >> $GITHUB_STEP_SUMMARY - fi - - # ── Summary ────────────────────────────────────────────────────── - - name: Pipeline Summary - if: always() - run: | - VERSION="${{ steps.version.outputs.version }}" - TOOL_COUNT="${{ steps.tools.outputs.count }}" - if [ "${{ steps.version.outputs.skip }}" = "true" ]; then - echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY - else - echo "" >> $GITHUB_STEP_SUMMARY - echo "## MCP Release Complete" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY - echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY - echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Tools | ${TOOL_COUNT} |" >> $GITHUB_STEP_SUMMARY - echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Tag | \`${{ steps.version.outputs.release_tag }}\` |" >> $GITHUB_STEP_SUMMARY - fi diff --git a/templates/workflows/mcp/mcp-build-test.yml.template b/templates/workflows/mcp/mcp-build-test.yml.template deleted file mode 100644 index cb631c7..0000000 --- a/templates/workflows/mcp/mcp-build-test.yml.template +++ /dev/null @@ -1,61 +0,0 @@ -# MCP Server Build & Validation -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later -# -# Builds the MCP server, validates TypeScript compilation, and checks -# that tools are properly registered with valid Zod schemas. - -name: MCP Build & Validate - -on: - push: - branches: [main, dev/**] - paths: ['src/**', 'package.json', 'tsconfig.json'] - pull_request: - branches: [main] - paths: ['src/**', 'package.json', 'tsconfig.json'] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20, 22] - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm ci - - - name: TypeScript compile - run: npx tsc --noEmit - - - name: Build - run: npm run build - - - name: Verify dist output exists - run: | - test -f dist/index.js || (echo "ERROR: dist/index.js not found" && exit 1) - test -f dist/client.js || (echo "ERROR: dist/client.js not found" && exit 1) - test -f dist/config.js || (echo "ERROR: dist/config.js not found" && exit 1) - test -f dist/types.js || (echo "ERROR: dist/types.js not found" && exit 1) - echo "✓ All required dist files present" - - - name: Verify shebang in index.js - run: | - head -1 dist/index.js | grep -q "#!/usr/bin/env node" || echo "WARNING: Missing shebang in dist/index.js" - - - name: Count registered tools - run: | - TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || true) - echo "Registered tools: ${TOOL_COUNT}" - if [ "${TOOL_COUNT}" -eq 0 ]; then - echo "ERROR: No tools registered in src/index.ts" - exit 1 - fi diff --git a/templates/workflows/mcp/mcp-sdk-check.yml.template b/templates/workflows/mcp/mcp-sdk-check.yml.template deleted file mode 100644 index b926cd3..0000000 --- a/templates/workflows/mcp/mcp-sdk-check.yml.template +++ /dev/null @@ -1,105 +0,0 @@ -# MCP SDK Version Check -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later -# -# Weekly check for MCP SDK updates. Creates an issue when a new version -# of @modelcontextprotocol/sdk is available. - -name: MCP SDK Version Check - -on: - schedule: - - cron: '0 9 * * 1' # Every Monday at 9am UTC - workflow_dispatch: - -jobs: - check-sdk: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Check for SDK updates - id: sdk-check - run: | - CURRENT=$(node -p "require('./package.json').dependencies['@modelcontextprotocol/sdk']" | sed 's/[\^~]//') - LATEST=$(npm view @modelcontextprotocol/sdk version 2>/dev/null || echo "unknown") - - echo "current=${CURRENT}" >> $GITHUB_OUTPUT - echo "latest=${LATEST}" >> $GITHUB_OUTPUT - - if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then - echo "update_available=true" >> $GITHUB_OUTPUT - echo "MCP SDK update available: ${CURRENT} → ${LATEST}" - else - echo "update_available=false" >> $GITHUB_OUTPUT - echo "MCP SDK is up to date: ${CURRENT}" - fi - - - name: Check for Zod updates - id: zod-check - run: | - CURRENT=$(node -p "require('./package.json').dependencies['zod']" | sed 's/[\^~]//') - LATEST=$(npm view zod version 2>/dev/null || echo "unknown") - - echo "current=${CURRENT}" >> $GITHUB_OUTPUT - echo "latest=${LATEST}" >> $GITHUB_OUTPUT - - if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then - echo "update_available=true" >> $GITHUB_OUTPUT - else - echo "update_available=false" >> $GITHUB_OUTPUT - fi - - - name: Create update issue - if: steps.sdk-check.outputs.update_available == 'true' - uses: actions/github-script@v7 - with: - script: | - const title = `chore(deps): update @modelcontextprotocol/sdk ${process.env.CURRENT} → ${process.env.LATEST}`; - const body = [ - '## MCP SDK Update Available', - '', - `| Package | Current | Latest |`, - `|---------|---------|--------|`, - `| @modelcontextprotocol/sdk | ${process.env.CURRENT} | ${process.env.LATEST} |`, - `| zod | ${process.env.ZOD_CURRENT} | ${process.env.ZOD_LATEST} |`, - '', - '### Steps', - '1. Update package.json', - '2. Run `npm install`', - '3. Run `npm run build` to verify compilation', - '4. Test all tools against target API', - '', - '### Changelog', - `https://github.com/modelcontextprotocol/typescript-sdk/releases`, - ].join('\n'); - - // Check for existing open issue - const existing = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - labels: 'api-change', - }); - - const alreadyExists = existing.data.some(i => i.title.includes('@modelcontextprotocol/sdk')); - if (!alreadyExists) { - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title, - body, - labels: ['api-change', 'chore'], - }); - } - env: - CURRENT: ${{ steps.sdk-check.outputs.current }} - LATEST: ${{ steps.sdk-check.outputs.latest }} - ZOD_CURRENT: ${{ steps.zod-check.outputs.current }} - ZOD_LATEST: ${{ steps.zod-check.outputs.latest }} diff --git a/templates/workflows/mcp/mcp-tool-inventory.yml.template b/templates/workflows/mcp/mcp-tool-inventory.yml.template deleted file mode 100644 index f935b0c..0000000 --- a/templates/workflows/mcp/mcp-tool-inventory.yml.template +++ /dev/null @@ -1,57 +0,0 @@ -# MCP Tool Inventory -# Copyright (C) 2026 Moko Consulting -# SPDX-License-Identifier: GPL-3.0-or-later -# -# Generates a tool inventory report on each push to main. -# Extracts tool names, descriptions, and parameter counts from src/index.ts. - -name: MCP Tool Inventory - -on: - push: - branches: [main] - paths: ['src/index.ts'] - workflow_dispatch: - -jobs: - inventory: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Generate tool inventory - run: | - echo "# MCP Tool Inventory" > TOOLS.md - echo "" >> TOOLS.md - echo "Auto-generated from \`src/index.ts\` on $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> TOOLS.md - echo "" >> TOOLS.md - - # Count tools - TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || true) - echo "**Total tools: ${TOOL_COUNT}**" >> TOOLS.md - echo "" >> TOOLS.md - - # Extract tool names and descriptions - echo "| Tool | Description |" >> TOOLS.md - echo "|------|-------------|" >> TOOLS.md - - grep -A1 "server\.tool(" src/index.ts | grep -E "^\s*'" | while read -r line; do - TOOL_NAME=$(echo "$line" | sed "s/.*'\([^']*\)'.*/\1/") - # Get next line for description - DESC=$(grep -A2 "'${TOOL_NAME}'" src/index.ts | grep -E "^\s*'" | tail -1 | sed "s/.*'\([^']*\)'.*/\1/" || echo "") - echo "| \`${TOOL_NAME}\` | ${DESC} |" >> TOOLS.md - done - - echo "" >> TOOLS.md - echo "---" >> TOOLS.md - echo "*Generated by MCP Tool Inventory workflow*" >> TOOLS.md - - cat TOOLS.md - - - name: Upload inventory artifact - uses: actions/upload-artifact@v4 - with: - name: tool-inventory - path: TOOLS.md - retention-days: 90