diff --git a/.github/scripts/aggregate-passport-metadata.js b/.github/scripts/aggregate-passport-metadata.js new file mode 100755 index 000000000..1f0dd3bd5 --- /dev/null +++ b/.github/scripts/aggregate-passport-metadata.js @@ -0,0 +1,148 @@ +#!/usr/bin/env node + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +// Configuration +const PASSPORT_ROOT = './sample/Assets/Scripts/Passport'; +const TUTORIALS_DIR = path.join(PASSPORT_ROOT, '_tutorials'); +const OUTPUT_DIR = './_parsed'; +const OUTPUT_FILE = path.join(OUTPUT_DIR, 'passport-features.json'); +const FEATURES_JSON_PATH = path.join(PASSPORT_ROOT, 'features.json'); + +// Ensure output directory exists +try { + if (!fs.existsSync(OUTPUT_DIR)) { + fs.mkdirSync(OUTPUT_DIR, { recursive: true }); + } +} catch (error) { + console.error(`Error creating output directory: ${error.message}`); + process.exit(1); +} + +console.log('Processing Passport features metadata...'); + +// Load features.json to get feature groups and their features +let featureGroups = {}; +try { + const featuresContent = fs.readFileSync(FEATURES_JSON_PATH, 'utf8'); + const featuresJson = JSON.parse(featuresContent); + featureGroups = featuresJson.features || {}; +} catch (error) { + console.error(`Error reading features.json: ${error.message}`); + process.exit(1); +} + +// Find all feature group directories in _tutorials +const findFeatureGroupDirectories = () => { + const featureGroupDirs = []; + + if (!fs.existsSync(TUTORIALS_DIR)) { + console.warn(`Tutorials directory does not exist: ${TUTORIALS_DIR}`); + return featureGroupDirs; + } + + try { + const dirs = fs.readdirSync(TUTORIALS_DIR, { withFileTypes: true }); + + dirs.forEach((dirent) => { + if (dirent.isDirectory()) { + featureGroupDirs.push(path.join(TUTORIALS_DIR, dirent.name)); + } + }); + } catch (err) { + console.warn(`Error reading tutorials directory ${TUTORIALS_DIR}: ${err.message}`); + } + + return featureGroupDirs; +}; + +// Process metadata files +const processFeatureGroups = (featureGroupDirs) => { + const featuresObject = {}; + + featureGroupDirs.forEach((groupDir) => { + const groupName = path.basename(groupDir); + console.log(`Processing feature group: ${groupName}`); + + // Check if this group exists in features.json (case-insensitive) + const matchingGroup = Object.keys(featureGroups).find( + key => key.toLowerCase() === groupName.toLowerCase() + ); + + if (!matchingGroup) { + console.warn(`Feature group ${groupName} not found in features.json, skipping`); + return; + } + + // Path to metadata.json in this feature group directory + const metadataPath = path.join(groupDir, 'metadata.json'); + if (!fs.existsSync(metadataPath)) { + console.warn(`No metadata.json found for feature group ${groupName} in ${groupDir}`); + return; + } + + // Path to tutorial.md in this feature group directory + const tutorialPath = path.join(groupDir, 'tutorial.md'); + const tutorialExists = fs.existsSync(tutorialPath); + + // Use the folder name directly as the feature key + const featureKey = groupName; + + if (!featureKey) { + console.warn(`Generated empty feature key for ${groupDir}, skipping`); + return; + } + + const tutorialFile = tutorialExists ? `${featureKey}.md` : null; + + if (!tutorialExists) { + console.warn(`No tutorial.md found for feature group ${groupName} in ${groupDir}`); + } + + // Read and process metadata + try { + const metadataContent = fs.readFileSync(metadataPath, 'utf8'); + const metadata = JSON.parse(metadataContent); + + // Add additional fields + metadata.title = metadata.title || matchingGroup; + metadata.sidebar_order = metadata.sidebar_order || 0; + metadata.deprecated = metadata.deprecated || false; + + // Add feature group information + metadata.feature_group = matchingGroup; + metadata.features = Object.keys(featureGroups[matchingGroup] || {}); + + // Create the feature entry + featuresObject[featureKey] = { + tutorial: tutorialFile, + metadata: metadata + }; + } catch (error) { + console.error(`Error processing metadata file ${metadataPath}: ${error.message}`); + } + }); + + return featuresObject; +}; + +try { + // Main execution + const featureGroupDirs = findFeatureGroupDirectories(); + + if (featureGroupDirs.length === 0) { + console.warn('No feature group directories found. Output file will be empty.'); + } + + const features = processFeatureGroups(featureGroupDirs); + + // Create the final passport-features.json + fs.writeFileSync(OUTPUT_FILE, JSON.stringify(features, null, 2)); + console.log(`Created ${OUTPUT_FILE}`); +} catch (error) { + console.error(`Fatal error: ${error.message}`); + process.exit(1); +} \ No newline at end of file diff --git a/.github/scripts/process-passport-tutorials.sh b/.github/scripts/process-passport-tutorials.sh new file mode 100755 index 000000000..1100e3ce0 --- /dev/null +++ b/.github/scripts/process-passport-tutorials.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +set -e +set -x + +# Directory where docs repo is cloned +DOCS_REPO_DIR="${CLONE_DIR:-"./imx-docs"}" + +# Root of the Passport features +PASSPORT_ROOT="./sample/Assets/Scripts/Passport" +TUTORIALS_DIR="${PASSPORT_ROOT}/_tutorials" + +echo "Processing Passport tutorials..." + +# Load features.json to get feature groups +FEATURES_JSON="${PASSPORT_ROOT}/features.json" +if [ ! -f "${FEATURES_JSON}" ]; then + echo "Error: features.json not found at ${FEATURES_JSON}" + exit 1 +fi + +# Create _tutorials directory in docs repo +DOCS_TUTORIALS_DIR="${DOCS_REPO_DIR}/docs/main/example/zkEVM/unity/passport-examples/_tutorials" +mkdir -p "${DOCS_TUTORIALS_DIR}" + +# Check if _tutorials directory exists +if [ ! -d "${TUTORIALS_DIR}" ]; then + echo "Warning: _tutorials directory not found at ${TUTORIALS_DIR}" +else + # Process each feature group directory in _tutorials + find "${TUTORIALS_DIR}" -mindepth 1 -maxdepth 1 -type d -print0 | while IFS= read -r -d '' GROUP_DIR; do + echo "Processing feature group: ${GROUP_DIR}" + + # Extract feature group name from directory + GROUP_NAME=$(basename "${GROUP_DIR}") + + # Tutorial file path + TUTORIAL_FILE="${GROUP_DIR}/tutorial.md" + + if [ -f "${TUTORIAL_FILE}" ]; then + echo "Found tutorial for ${GROUP_NAME}" + + # Use the folder name directly for the destination filename + OUTPUT_FILENAME="${GROUP_NAME}.md" + + # Copy the tutorial file + cp "${TUTORIAL_FILE}" "${DOCS_TUTORIALS_DIR}/${OUTPUT_FILENAME}" + echo "Copied ${TUTORIAL_FILE} to ${DOCS_TUTORIALS_DIR}/${OUTPUT_FILENAME}" + else + echo "Warning: No tutorial.md found for feature group ${GROUP_NAME}" + fi + done +fi + +# Copy the generated JSON file +JSON_FILE="./_parsed/passport-features.json" +if [ -f "${JSON_FILE}" ]; then + # Create directory for JSON file if it doesn't exist + JSON_DIR="${DOCS_REPO_DIR}/docs/main/example/zkEVM/unity/passport-examples" + mkdir -p "${JSON_DIR}" + + # Copy JSON file + cp "${JSON_FILE}" "${JSON_DIR}/passport-features.json" + echo "Copied ${JSON_FILE} to ${JSON_DIR}/passport-features.json" +else + echo "Warning: No passport-features.json found at ${JSON_FILE}" +fi + +echo "Passport tutorial processing complete." \ No newline at end of file diff --git a/.github/workflows/publish-passport-tutorials.yml b/.github/workflows/publish-passport-tutorials.yml new file mode 100644 index 000000000..44f07ee74 --- /dev/null +++ b/.github/workflows/publish-passport-tutorials.yml @@ -0,0 +1,83 @@ +name: Publish Passport Tutorials + +on: + # Run when changes are pushed to Passport tutorials or metadata + push: + branches: + # - main + - chore/sample-app-tutorial + paths: + - 'sample/Assets/Scripts/Passport/features.json' + - 'sample/Assets/Scripts/Passport/_tutorials/**/*' + + # Allow manual triggering + workflow_dispatch: + +concurrency: + group: passport-tutorials + cancel-in-progress: false + +jobs: + PublishPassportTutorials: + name: Process and Publish Passport Tutorials + runs-on: ubuntu-latest + steps: + - name: Checkout Unity SDK Repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + fetch-depth: 0 + + - name: Create Parsed Directory + run: mkdir -p _parsed + + - name: Checkout Docs Repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: immutable/docs + token: ${{ secrets.UNITY_SDK_DOCS_WORKFLOW }} + path: imx-docs + ref: 'main' + + - name: Setup environment variables + run: echo "CLONE_DIR=./imx-docs" >> $GITHUB_ENV + + - name: Setup Git + run: | + git config --global user.name "${GITHUB_ACTOR}" + git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y jq + + - name: Process Passport Tutorials + run: | + # Make scripts executable + chmod +x .github/scripts/aggregate-passport-metadata.js + chmod +x .github/scripts/process-passport-tutorials.sh + + # Generate aggregated JSON file + node .github/scripts/aggregate-passport-metadata.js + + # Process tutorials and copy to docs repo + .github/scripts/process-passport-tutorials.sh + shell: bash + + - name: Commit and Push Changes to Docs Repo + run: | + cd "$CLONE_DIR" + if git status --porcelain | grep -q .; then + git add . + + # Commit with reference to source commit + COMMIT_MSG="docs: Update Passport tutorials from Unity SDK (Ref: ${GITHUB_SHA::8})" + git commit -m "$COMMIT_MSG" + + # Push to the target branch + git push -u origin main + echo "Successfully pushed Passport tutorial changes to docs repo" + else + echo "No changes to commit" + fi + shell: bash \ No newline at end of file diff --git a/sample/Assets/Scripts/Passport/_prompts/tutorial-generation-prompt.txt b/sample/Assets/Scripts/Passport/_prompts/tutorial-generation-prompt.txt index bc9005790..21a5d22c7 100644 --- a/sample/Assets/Scripts/Passport/_prompts/tutorial-generation-prompt.txt +++ b/sample/Assets/Scripts/Passport/_prompts/tutorial-generation-prompt.txt @@ -1,99 +1,156 @@ -# Passport Feature Tutorial Generator +# Passport Feature Group Tutorial Generator ## Task Overview -Analyze the sample/Assets/Scripts/Passport/{FeatureName}/ directory and create documentation files for the atomic Passport feature example. For the specified feature, you will create: -1. A comprehensive tutorial.md file -2. A metadata.json file +Analyze the specified {FEATURE_GROUP} from sample/Assets/Scripts/Passport/features.json and create comprehensive documentation for it. You will create: +1. A comprehensive tutorial.md file covering all features in the specified group +2. A metadata.json file for the feature group + +## Input Required +- FEATURE_GROUP: The exact name of the specific feature group to document, as it appears in features.json + +## Structure of features.json +The features.json file has the following structure: +```json +{ + "features": { + "{FEATURE_GROUP}": { + "feature1": { ... }, + "feature2": { ... }, + ... + }, + "anotherFeatureGroup": { + ... + } + } +} +``` + +You will be analyzing one specific {FEATURE_GROUP} and all features contained within it. + +## Special Case: Single-Feature Groups +IMPORTANT: If the specified {FEATURE_GROUP} contains only one feature, treat it as a standalone feature rather than a feature group. This means: +- Do not refer to it as a "feature group" in the documentation +- Skip the "Feature Group Overview" section that discusses relationships between features +- Focus solely on documenting the single feature in depth +- Adjust headings and terminology accordingly to avoid references to a "group" +- For the "Running the Feature Example" section (note: not "Examples"), provide steps specific to this single feature ## Preparation Before starting: -- Read through all SDK documentation (in the /src/Packages and /src/Packages folders) +- Read through all SDK documentation (in the /src/Packages folders) - Understand the SDK's key features, functionality, and integration patterns - Focus on the Passport SDK the most. That's your area of specialty. +- Familiarize yourself with the specified feature group defined in features.json -## Process for Each Atomic Feature Example -For the specified atomic feature in sample/Assets/Scripts/Passport/{FeatureName}/ that doesn't already have both tutorial.md and metadata.json: +## Process for the Specified Feature Group ### 1. Analysis Phase -- Read all C# code files in the feature directory -- Identify the Passport feature being demonstrated. Reference features.json at the Passport root for the feature name and order. -- Understand the feature's architecture, components, and data flow +- Identify the specified {FEATURE_GROUP} and all member features from features.json +- For each feature in the group, read all C# code files in the feature's directory (sample/Assets/Scripts/Passport/{FeatureName}/) +- Understand how the features in the group relate to each other +- Identify the common patterns, architecture, components, and data flow across the feature group - Note all frameworks, libraries, and dependencies used -- IMPORTANT: Focus only on the logic for this atomic feature, not on unrelated features or SDK initialization. +- IMPORTANT: Focus on the logical connections between features in the group while maintaining focus on each feature's specific implementation details. + +### 2. Create tutorial.md in sample/Assets/Scripts/Passport/_tutorials/{FEATURE_GROUP}/ +Create a tutorial.md file for the feature group with the following structure: -### 2. Create tutorial.md -Create a tutorial.md file in the feature's root with the following structure: +#### Group Introduction +- Brief overview of the feature group's purpose and importance +- Which specific SDK capabilities the group demonstrates +- Link to the sample app GitHub repository. (The Github repository MUST BE linked with this message: "View feature group on Github") -#### Introduction -- Brief overview of the feature's purpose -- Which specific SDK capability it demonstrates -- Link to the feature's GitHub repository. (The Github repository MUST BE linked to this message: "View feature on Github") +Note: For single-feature cases, rename this section to "Feature Introduction" and adjust the link text to "View feature on Github" -IMPORTANT: The TITLE (the text that starts with #) of the feature that comes before the "View feature on Github" link must be wrapped in a