From b4e4e370999e58a6a415ac08b538ec1f53d84942 Mon Sep 17 00:00:00 2001 From: Jason Stirnaman Date: Wed, 11 Feb 2026 18:22:27 -0600 Subject: [PATCH] refactor(ci): use shared resolve-shared-content.sh script - Replace Node.js detect-test-products.js with shell-based approach - Add .github/scripts/resolve-shared-content.sh (from docs-v2-jts-vale-ci) - Remove Node.js setup step from detect-changes job - No external dependencies required for shared content resolution --- .github/scripts/resolve-shared-content.sh | 45 ++++++++++ .github/workflows/test.yml | 64 ++++++++++---- scripts/ci/detect-test-products.js | 101 ---------------------- 3 files changed, 93 insertions(+), 117 deletions(-) create mode 100755 .github/scripts/resolve-shared-content.sh delete mode 100755 scripts/ci/detect-test-products.js diff --git a/.github/scripts/resolve-shared-content.sh b/.github/scripts/resolve-shared-content.sh new file mode 100755 index 000000000..db3a23f12 --- /dev/null +++ b/.github/scripts/resolve-shared-content.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Resolve shared content files to their consuming product pages. +# +# Usage: +# echo "content/shared/foo.md" | ./resolve-shared-content.sh +# ./resolve-shared-content.sh < changed_files.txt +# ./resolve-shared-content.sh changed_files.txt +# +# For shared files (content/shared/*), finds all pages with matching +# `source:` frontmatter and outputs those instead. Non-shared files +# pass through unchanged. + +set -euo pipefail + +# Read input from file argument or stdin +if [[ $# -gt 0 && -f "$1" ]]; then + INPUT=$(cat "$1") +else + INPUT=$(cat) +fi + +# Process each file +while IFS= read -r file; do + [[ -z "$file" ]] && continue + + if [[ "$file" == content/shared/* ]]; then + # Extract the shared path portion (e.g., /shared/influxdb3-cli/foo.md) + SHARED_PATH="${file#content}" + + # Find all files that source this shared content + # The source frontmatter looks like: source: /shared/path/to/file.md + CONSUMERS=$(grep -rl "^source: ${SHARED_PATH}$" content/ 2>/dev/null | grep -v '^content/shared/' || true) + + if [[ -n "$CONSUMERS" ]]; then + echo "$CONSUMERS" + else + # No consumers found - output the shared file itself + # (Vale can still lint it with default config) + echo "$file" + fi + else + # Non-shared file - pass through + echo "$file" + fi +done <<< "$INPUT" | sort -u diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3020e08c6..a6d1fe532 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,12 +52,6 @@ jobs: with: fetch-depth: 0 - - name: Setup Node.js - if: github.event_name == 'pull_request' - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Analyze changes and determine products id: check run: | @@ -144,25 +138,63 @@ jobs: echo "📝 Changed content files:" echo "$CHANGED_FILES" - # Use Node.js script to detect products (handles shared content resolution) - # The script expands shared content changes to find all affected product pages - RESULT=$(echo "$CHANGED_FILES" | node scripts/ci/detect-test-products.js) + # Resolve shared content to consuming product pages + RESOLVED_FILES=$(echo "$CHANGED_FILES" | ./.github/scripts/resolve-shared-content.sh) + echo "📂 Resolved files (after shared content expansion):" + echo "$RESOLVED_FILES" - PRODUCTS_JSON=$(echo "$RESULT" | jq -c '.products') - FILES_JSON=$(echo "$RESULT" | jq -c '.files') + # Extract products from resolved file paths + PRODUCTS=() + while IFS= read -r file; do + case "$file" in + content/influxdb3/core/*) + [[ ! " ${PRODUCTS[*]} " =~ " influxdb3_core " ]] && PRODUCTS+=("influxdb3_core") + ;; + content/influxdb3/enterprise/*) + [[ ! " ${PRODUCTS[*]} " =~ " influxdb3_enterprise " ]] && PRODUCTS+=("influxdb3_enterprise") + ;; + content/influxdb3/cloud-dedicated/*) + [[ ! " ${PRODUCTS[*]} " =~ " cloud-dedicated " ]] && PRODUCTS+=("cloud-dedicated") + ;; + content/influxdb3/cloud-serverless/*) + [[ ! " ${PRODUCTS[*]} " =~ " cloud-serverless " ]] && PRODUCTS+=("cloud-serverless") + ;; + content/influxdb3/clustered/*) + [[ ! " ${PRODUCTS[*]} " =~ " clustered " ]] && PRODUCTS+=("clustered") + ;; + content/influxdb3/explorer/*) + [[ ! " ${PRODUCTS[*]} " =~ " explorer " ]] && PRODUCTS+=("explorer") + ;; + content/influxdb/cloud/*) + [[ ! " ${PRODUCTS[*]} " =~ " cloud " ]] && PRODUCTS+=("cloud") + ;; + content/influxdb/v2/*) + [[ ! " ${PRODUCTS[*]} " =~ " v2 " ]] && PRODUCTS+=("v2") + ;; + content/influxdb/v1/*) + [[ ! " ${PRODUCTS[*]} " =~ " v1 " ]] && PRODUCTS+=("v1") + ;; + content/telegraf/*) + [[ ! " ${PRODUCTS[*]} " =~ " telegraf " ]] && PRODUCTS+=("telegraf") + ;; + esac + done <<< "$RESOLVED_FILES" - # Check if we got any products - PRODUCT_COUNT=$(echo "$PRODUCTS_JSON" | jq 'length') - if [[ "$PRODUCT_COUNT" -eq 0 ]]; then + # If no products detected, use default group + if [[ ${#PRODUCTS[@]} -eq 0 ]]; then echo "📦 No specific products detected - using default group" - PRODUCTS_JSON=$(printf '%s\n' "${DEFAULT_PRODUCTS[@]}" | jq -R . | jq -s -c .) + PRODUCTS=("${DEFAULT_PRODUCTS[@]}") fi + # Convert to JSON array + PRODUCTS_JSON=$(printf '%s\n' "${PRODUCTS[@]}" | jq -R . | jq -s -c .) + FILES_JSON=$(echo "$RESOLVED_FILES" | jq -R . | jq -s -c .) + echo "test-products=$PRODUCTS_JSON" >> $GITHUB_OUTPUT echo "suggested-products=$PRODUCTS_JSON" >> $GITHUB_OUTPUT echo "affected-files=$FILES_JSON" >> $GITHUB_OUTPUT - echo "📋 Suggested products for testing: $(echo "$PRODUCTS_JSON" | jq -r 'join(", ")')" + echo "📋 Suggested products for testing: ${PRODUCTS[*]}" # Informational job for PRs - suggests tests but doesn't run them suggest-tests: diff --git a/scripts/ci/detect-test-products.js b/scripts/ci/detect-test-products.js deleted file mode 100755 index c2c567521..000000000 --- a/scripts/ci/detect-test-products.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node -/** - * Detect which products need testing based on changed content files. - * - * Usage: - * echo "content/influxdb3/core/page.md" | node scripts/ci/detect-test-products.js - * node scripts/ci/detect-test-products.js < changed-files.txt - * - * Output (JSON): - * {"products":["influxdb3_core","telegraf"],"files":["content/influxdb3/core/page.md",...]} - * - * This script: - * 1. Reads changed file paths from stdin (one per line) - * 2. Expands shared content changes to find all affected product pages - * 3. Extracts unique products from the affected file paths - * 4. Outputs JSON with products array and expanded files array - */ - -import { expandSharedContentChanges } from '../lib/content-utils.js'; - -// Product path mappings -const PRODUCT_PATTERNS = [ - { pattern: /^content\/influxdb3\/core\//, product: 'influxdb3_core' }, - { pattern: /^content\/influxdb3\/enterprise\//, product: 'influxdb3_enterprise' }, - { pattern: /^content\/influxdb3\/cloud-dedicated\//, product: 'cloud-dedicated' }, - { pattern: /^content\/influxdb3\/cloud-serverless\//, product: 'cloud-serverless' }, - { pattern: /^content\/influxdb3\/clustered\//, product: 'clustered' }, - { pattern: /^content\/influxdb3\/explorer\//, product: 'explorer' }, - { pattern: /^content\/influxdb\/cloud\//, product: 'cloud' }, - { pattern: /^content\/influxdb\/v2\//, product: 'v2' }, - { pattern: /^content\/influxdb\/v1\//, product: 'v1' }, - { pattern: /^content\/telegraf\//, product: 'telegraf' }, -]; - -/** - * Extract product identifier from a content file path - * @param {string} filePath - Content file path - * @returns {string|null} Product identifier or null - */ -function getProductFromPath(filePath) { - for (const { pattern, product } of PRODUCT_PATTERNS) { - if (pattern.test(filePath)) { - return product; - } - } - return null; -} - -/** - * Main function - */ -async function main() { - // Read changed files from stdin - const input = await new Promise((resolve) => { - let data = ''; - process.stdin.setEncoding('utf8'); - process.stdin.on('data', (chunk) => (data += chunk)); - process.stdin.on('end', () => resolve(data)); - - // Handle case where stdin is empty/closed immediately - if (process.stdin.isTTY) { - resolve(''); - } - }); - - const changedFiles = input - .trim() - .split('\n') - .filter((f) => f && f.endsWith('.md')); - - if (changedFiles.length === 0) { - console.log(JSON.stringify({ products: [], files: [] })); - process.exit(0); - } - - // Expand shared content changes to find all affected pages - const verbose = process.env.VERBOSE === 'true'; - const expandedFiles = expandSharedContentChanges(changedFiles, { verbose }); - - // Extract unique products from expanded file list - const products = new Set(); - for (const file of expandedFiles) { - const product = getProductFromPath(file); - if (product) { - products.add(product); - } - } - - // Output JSON result - const result = { - products: Array.from(products).sort(), - files: expandedFiles.sort(), - }; - - console.log(JSON.stringify(result)); -} - -main().catch((err) => { - console.error('Error:', err.message); - process.exit(1); -});