workflow: auto-update recipe-reference on release (#5988)
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
||||
#!/bin/bash
|
||||
# Compare two validation structure files and output changes
|
||||
# Usage: ./diff-validation-structures.sh old-validation-structure.json new-validation-structure.json
|
||||
# Output: validation-changes.json
|
||||
|
||||
set -e
|
||||
|
||||
OLD_FILE=${1:-"old-validation-structure.json"}
|
||||
NEW_FILE=${2:-"new-validation-structure.json"}
|
||||
|
||||
if [ ! -f "$OLD_FILE" ]; then
|
||||
echo "Error: Old validation structure file not found: $OLD_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$NEW_FILE" ]; then
|
||||
echo "Error: New validation structure file not found: $NEW_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract versions for metadata
|
||||
OLD_VERSION=$(jq -r '.version' "$OLD_FILE")
|
||||
NEW_VERSION=$(jq -r '.version' "$NEW_FILE")
|
||||
|
||||
# Build the changes JSON using jq
|
||||
jq -n \
|
||||
--arg old_version "$OLD_VERSION" \
|
||||
--arg new_version "$NEW_VERSION" \
|
||||
--arg compared_at "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
||||
--argjson old_data "$(cat "$OLD_FILE")" \
|
||||
--argjson new_data "$(cat "$NEW_FILE")" \
|
||||
'
|
||||
{
|
||||
old_version: $old_version,
|
||||
new_version: $new_version,
|
||||
compared_at: $compared_at,
|
||||
has_changes: false,
|
||||
changes: {
|
||||
struct_fields: {
|
||||
added: [],
|
||||
removed: [],
|
||||
type_changed: [],
|
||||
comment_changed: []
|
||||
},
|
||||
validation_functions: {
|
||||
added: [],
|
||||
removed: [],
|
||||
signature_changed: [],
|
||||
error_messages_changed: []
|
||||
}
|
||||
}
|
||||
} |
|
||||
|
||||
# Detect field changes
|
||||
. as $result |
|
||||
|
||||
# Find added fields (in new but not in old) - compare by struct.field
|
||||
($new_data.struct_fields | map(.struct + "." + .field)) as $new_fields |
|
||||
($old_data.struct_fields | map(.struct + "." + .field)) as $old_fields |
|
||||
($new_fields - $old_fields) as $added_field_keys |
|
||||
|
||||
# Find removed fields (in old but not in new) - compare by struct.field
|
||||
($old_fields - $new_fields) as $removed_field_keys |
|
||||
|
||||
# Find fields with type changes - compare by struct.field
|
||||
(
|
||||
$new_data.struct_fields |
|
||||
map(select((.struct + "." + .field) as $key | $old_fields | contains([$key])) |
|
||||
{struct: .struct, field: .field, new_type: .type, new_comment: .inline_comment}
|
||||
)
|
||||
) as $new_common |
|
||||
(
|
||||
$old_data.struct_fields |
|
||||
map(select((.struct + "." + .field) as $key | $new_fields | contains([$key])) |
|
||||
{struct: .struct, field: .field, old_type: .type, old_comment: .inline_comment}
|
||||
)
|
||||
) as $old_common |
|
||||
|
||||
# Compare types and comments for common fields
|
||||
(
|
||||
$new_common | map(
|
||||
. as $new_item |
|
||||
($old_common | map(select(.struct == $new_item.struct and .field == $new_item.field)) | .[0]) as $old_item |
|
||||
if $old_item.old_type != $new_item.new_type then
|
||||
{
|
||||
struct: $new_item.struct,
|
||||
field: $new_item.field,
|
||||
old_type: $old_item.old_type,
|
||||
new_type: $new_item.new_type
|
||||
}
|
||||
else
|
||||
empty
|
||||
end
|
||||
)
|
||||
) as $type_changed |
|
||||
|
||||
(
|
||||
$new_common | map(
|
||||
. as $new_item |
|
||||
($old_common | map(select(.struct == $new_item.struct and .field == $new_item.field)) | .[0]) as $old_item |
|
||||
if $old_item.old_comment != $new_item.new_comment then
|
||||
{
|
||||
struct: $new_item.struct,
|
||||
field: $new_item.field,
|
||||
old_comment: $old_item.old_comment,
|
||||
new_comment: $new_item.new_comment
|
||||
}
|
||||
else
|
||||
empty
|
||||
end
|
||||
)
|
||||
) as $comment_changed |
|
||||
|
||||
# Find validation function changes
|
||||
($new_data.validation_functions | map(.function)) as $new_funcs |
|
||||
($old_data.validation_functions | map(.function)) as $old_funcs |
|
||||
($new_funcs - $old_funcs) as $added_funcs |
|
||||
($old_funcs - $new_funcs) as $removed_funcs |
|
||||
|
||||
# Find functions with signature changes
|
||||
(
|
||||
$new_data.validation_functions |
|
||||
map(select(.function as $f | $old_funcs | contains([$f])) |
|
||||
{function: .function, new_signature: .signature, new_errors: .error_messages}
|
||||
)
|
||||
) as $new_common_funcs |
|
||||
(
|
||||
$old_data.validation_functions |
|
||||
map(select(.function as $f | $new_funcs | contains([$f])) |
|
||||
{function: .function, old_signature: .signature, old_errors: .error_messages}
|
||||
)
|
||||
) as $old_common_funcs |
|
||||
|
||||
(
|
||||
$new_common_funcs | map(
|
||||
. as $new_func |
|
||||
($old_common_funcs | map(select(.function == $new_func.function)) | .[0]) as $old_func |
|
||||
if $old_func.old_signature != $new_func.new_signature then
|
||||
{
|
||||
function: $new_func.function,
|
||||
old_signature: $old_func.old_signature,
|
||||
new_signature: $new_func.new_signature
|
||||
}
|
||||
else
|
||||
empty
|
||||
end
|
||||
)
|
||||
) as $signature_changed |
|
||||
|
||||
(
|
||||
$new_common_funcs | map(
|
||||
. as $new_func |
|
||||
($old_common_funcs | map(select(.function == $new_func.function)) | .[0]) as $old_func |
|
||||
if $old_func.old_errors != $new_func.new_errors then
|
||||
{
|
||||
function: $new_func.function,
|
||||
old_errors: $old_func.old_errors,
|
||||
new_errors: $new_func.new_errors
|
||||
}
|
||||
else
|
||||
empty
|
||||
end
|
||||
)
|
||||
) as $error_messages_changed |
|
||||
|
||||
# Build final result with detected changes
|
||||
.changes.struct_fields.added = (
|
||||
$added_field_keys | map(
|
||||
. as $key |
|
||||
($key | split(".")) as $parts |
|
||||
$new_data.struct_fields | map(select(.struct == $parts[0] and .field == $parts[1])) | .[0]
|
||||
)
|
||||
) |
|
||||
.changes.struct_fields.removed = (
|
||||
$removed_field_keys | map(
|
||||
. as $key |
|
||||
($key | split(".")) as $parts |
|
||||
$old_data.struct_fields | map(select(.struct == $parts[0] and .field == $parts[1])) | .[0]
|
||||
)
|
||||
) |
|
||||
.changes.struct_fields.type_changed = $type_changed |
|
||||
.changes.struct_fields.comment_changed = $comment_changed |
|
||||
|
||||
.changes.validation_functions.added = (
|
||||
$added_funcs | map(
|
||||
. as $func |
|
||||
$new_data.validation_functions | map(select(.function == $func)) | .[0]
|
||||
)
|
||||
) |
|
||||
.changes.validation_functions.removed = (
|
||||
$removed_funcs | map(
|
||||
. as $func |
|
||||
$old_data.validation_functions | map(select(.function == $func)) | .[0]
|
||||
)
|
||||
) |
|
||||
.changes.validation_functions.signature_changed = $signature_changed |
|
||||
.changes.validation_functions.error_messages_changed = $error_messages_changed |
|
||||
|
||||
# Set has_changes flag
|
||||
.has_changes = (
|
||||
(.changes.struct_fields.added | length) > 0 or
|
||||
(.changes.struct_fields.removed | length) > 0 or
|
||||
(.changes.struct_fields.type_changed | length) > 0 or
|
||||
(.changes.struct_fields.comment_changed | length) > 0 or
|
||||
(.changes.validation_functions.added | length) > 0 or
|
||||
(.changes.validation_functions.removed | length) > 0 or
|
||||
(.changes.validation_functions.signature_changed | length) > 0 or
|
||||
(.changes.validation_functions.error_messages_changed | length) > 0
|
||||
)
|
||||
'
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
#!/bin/bash
|
||||
# Extract and resolve Recipe schema from OpenAPI spec at a specific git version
|
||||
# Usage: ./extract-schema.sh <version>
|
||||
# Example: ./extract-schema.sh v1.15.0
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=${1:-"main"}
|
||||
GOOSE_REPO=${GOOSE_REPO:-"$HOME/Development/goose"}
|
||||
|
||||
if [ ! -d "$GOOSE_REPO" ]; then
|
||||
echo "Error: GOOSE_REPO directory not found: $GOOSE_REPO" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$GOOSE_REPO"
|
||||
|
||||
# Verify version exists (for non-main versions)
|
||||
if [ "$VERSION" != "main" ]; then
|
||||
if ! git rev-parse "$VERSION" >/dev/null 2>&1; then
|
||||
echo "Error: Version $VERSION not found in git history" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Extract OpenAPI spec from git
|
||||
if [ "$VERSION" = "main" ]; then
|
||||
if [ ! -f ui/desktop/openapi.json ]; then
|
||||
echo "Error: ui/desktop/openapi.json not found in working directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
OPENAPI_JSON=$(cat ui/desktop/openapi.json)
|
||||
else
|
||||
OPENAPI_JSON=$(git show "$VERSION:ui/desktop/openapi.json" 2>/dev/null || {
|
||||
echo "Error: Could not find ui/desktop/openapi.json at version $VERSION" >&2
|
||||
exit 1
|
||||
})
|
||||
fi
|
||||
|
||||
# Use Node.js to extract and resolve Recipe schema
|
||||
echo "$OPENAPI_JSON" | node -e "
|
||||
const openApiSpec = JSON.parse(require('fs').readFileSync(0, 'utf-8'));
|
||||
|
||||
/**
|
||||
* Resolves \$ref references in OpenAPI schemas by expanding them with the actual schema definitions
|
||||
* Ported from ui/desktop/src/recipe/validation.ts
|
||||
*/
|
||||
function resolveRefs(schema, openApiSpec) {
|
||||
if (!schema || typeof schema !== 'object') {
|
||||
return schema;
|
||||
}
|
||||
|
||||
// Handle \$ref
|
||||
if (typeof schema.\$ref === 'string') {
|
||||
const refPath = schema.\$ref.replace('#/', '').split('/');
|
||||
let resolved = openApiSpec;
|
||||
|
||||
for (const segment of refPath) {
|
||||
if (resolved && typeof resolved === 'object' && segment in resolved) {
|
||||
resolved = resolved[segment];
|
||||
} else {
|
||||
console.warn(\`Could not resolve \$ref: \${schema.\$ref}\`);
|
||||
return schema; // Return original if can't resolve
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved && typeof resolved === 'object') {
|
||||
// Recursively resolve refs in the resolved schema
|
||||
return resolveRefs(resolved, openApiSpec);
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
// Handle allOf (merge schemas)
|
||||
if (Array.isArray(schema.allOf)) {
|
||||
const merged = {};
|
||||
for (const subSchema of schema.allOf) {
|
||||
if (typeof subSchema === 'object' && subSchema !== null) {
|
||||
const resolved = resolveRefs(subSchema, openApiSpec);
|
||||
Object.assign(merged, resolved);
|
||||
}
|
||||
}
|
||||
// Keep other properties from the original schema
|
||||
const { allOf, ...rest } = schema;
|
||||
return { ...merged, ...rest };
|
||||
}
|
||||
|
||||
// Handle oneOf/anyOf (keep as union)
|
||||
if (Array.isArray(schema.oneOf)) {
|
||||
return {
|
||||
...schema,
|
||||
oneOf: schema.oneOf.map((subSchema) =>
|
||||
typeof subSchema === 'object' && subSchema !== null
|
||||
? resolveRefs(subSchema, openApiSpec)
|
||||
: subSchema
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (Array.isArray(schema.anyOf)) {
|
||||
return {
|
||||
...schema,
|
||||
anyOf: schema.anyOf.map((subSchema) =>
|
||||
typeof subSchema === 'object' && subSchema !== null
|
||||
? resolveRefs(subSchema, openApiSpec)
|
||||
: subSchema
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// Handle object properties
|
||||
if (schema.type === 'object' && schema.properties && typeof schema.properties === 'object') {
|
||||
const resolvedProperties = {};
|
||||
for (const [key, value] of Object.entries(schema.properties)) {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
resolvedProperties[key] = resolveRefs(value, openApiSpec);
|
||||
} else {
|
||||
resolvedProperties[key] = value;
|
||||
}
|
||||
}
|
||||
return {
|
||||
...schema,
|
||||
properties: resolvedProperties,
|
||||
};
|
||||
}
|
||||
|
||||
// Handle array items
|
||||
if (schema.type === 'array' && schema.items && typeof schema.items === 'object') {
|
||||
return {
|
||||
...schema,
|
||||
items: resolveRefs(schema.items, openApiSpec),
|
||||
};
|
||||
}
|
||||
|
||||
// Return schema as-is if no refs to resolve
|
||||
return schema;
|
||||
}
|
||||
|
||||
// Extract Recipe schema
|
||||
const recipeSchema = openApiSpec.components?.schemas?.Recipe;
|
||||
|
||||
if (!recipeSchema) {
|
||||
console.error('Error: Recipe schema not found in OpenAPI specification');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Resolve all \$refs in the schema
|
||||
const resolvedSchema = resolveRefs(recipeSchema, openApiSpec);
|
||||
|
||||
// Convert OpenAPI schema to JSON Schema format
|
||||
const jsonSchema = {
|
||||
'\$schema': 'http://json-schema.org/draft-07/schema#',
|
||||
...resolvedSchema,
|
||||
title: resolvedSchema.title || 'Recipe',
|
||||
description: resolvedSchema.description || 'A Recipe represents a personalized, user-generated agent configuration that defines specific behaviors and capabilities within the Goose system.',
|
||||
};
|
||||
|
||||
// Output the resolved schema
|
||||
console.log(JSON.stringify(jsonSchema, null, 2));
|
||||
"
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
# Extract validation structure from Rust source files
|
||||
# Usage: ./extract-validation-structure.sh <version>
|
||||
# Example: ./extract-validation-structure.sh v1.15.0
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=${1:-"main"}
|
||||
GOOSE_REPO=${GOOSE_REPO:-"$HOME/Development/goose"}
|
||||
|
||||
if [ ! -d "$GOOSE_REPO" ]; then
|
||||
echo "Error: GOOSE_REPO directory not found: $GOOSE_REPO" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$GOOSE_REPO"
|
||||
|
||||
# Verify version exists (for non-main versions)
|
||||
if [ "$VERSION" != "main" ]; then
|
||||
if ! git rev-parse "$VERSION" >/dev/null 2>&1; then
|
||||
echo "Error: Version $VERSION not found in git history" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start JSON output
|
||||
# Use ISO 8601 format that works on both macOS and Linux
|
||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u -Iseconds 2>/dev/null || date -u)
|
||||
cat << EOF
|
||||
{
|
||||
"version": "$VERSION",
|
||||
"extracted_at": "$TIMESTAMP",
|
||||
"struct_fields": [
|
||||
EOF
|
||||
|
||||
# Extract fields from multiple structs
|
||||
FIRST_FIELD=true
|
||||
|
||||
# Get file content from git history or working directory
|
||||
if [ "$VERSION" = "main" ]; then
|
||||
MOD_RS_CONTENT=$(cat crates/goose/src/recipe/mod.rs)
|
||||
else
|
||||
MOD_RS_CONTENT=$(git show "$VERSION:crates/goose/src/recipe/mod.rs" 2>/dev/null || {
|
||||
echo "Error: Failed to read mod.rs from version $VERSION" >&2
|
||||
exit 1
|
||||
})
|
||||
fi
|
||||
|
||||
# List of structs to extract (in order of appearance in file)
|
||||
STRUCTS="Recipe Author Settings Response SubRecipe RecipeParameter"
|
||||
|
||||
# Create a temporary file to collect all fields
|
||||
TEMP_FIELDS=$(mktemp)
|
||||
|
||||
for STRUCT_NAME in $STRUCTS; do
|
||||
# Extract just this struct's definition (from "pub struct Name" to the closing "}")
|
||||
echo "$MOD_RS_CONTENT" | awk "
|
||||
/^pub struct $STRUCT_NAME/ { in_struct=1; next }
|
||||
in_struct && /^}/ { exit }
|
||||
in_struct && /^[[:space:]]+pub [a-z_]+:/ { print }
|
||||
" | while IFS= read -r line; do
|
||||
# Extract field name (word after 'pub ')
|
||||
field_name=$(echo "$line" | sed -E 's/.*pub ([a-z_]+):.*/\1/')
|
||||
|
||||
# Extract type (between : and , or // or end of line)
|
||||
field_type=$(echo "$line" | sed -E 's/.*:\s*([^,\/]+).*/\1/' | sed 's/[[:space:]]*$//')
|
||||
|
||||
# Extract inline comment (after //)
|
||||
inline_comment=""
|
||||
if echo "$line" | grep -q "//"; then
|
||||
inline_comment=$(echo "$line" | sed -E 's/.*\/\/\s*(.*)$/\1/' | sed 's/[[:space:]]*$//' | sed 's/"/\\"/g')
|
||||
fi
|
||||
|
||||
# Check if optional
|
||||
is_optional="false"
|
||||
if echo "$field_type" | grep -q "Option<"; then
|
||||
is_optional="true"
|
||||
fi
|
||||
|
||||
# Output to temp file
|
||||
cat << FIELD_JSON >> "$TEMP_FIELDS"
|
||||
{
|
||||
"struct": "$STRUCT_NAME",
|
||||
"field": "$field_name",
|
||||
"type": "$field_type",
|
||||
"optional": $is_optional,
|
||||
"inline_comment": "$inline_comment"
|
||||
}
|
||||
FIELD_JSON
|
||||
done
|
||||
done
|
||||
|
||||
# Output fields with proper comma separation
|
||||
if [ -s "$TEMP_FIELDS" ]; then
|
||||
# Read all JSON objects into an array and format with commas
|
||||
jq -s '.' "$TEMP_FIELDS" | jq -r 'to_entries | .[] | (if .key > 0 then "," else "" end) + " " + (.value | tostring)'
|
||||
fi
|
||||
|
||||
rm -f "$TEMP_FIELDS"
|
||||
|
||||
# Close struct_fields array, start validation_functions
|
||||
cat << EOF
|
||||
|
||||
],
|
||||
"validation_functions": [
|
||||
EOF
|
||||
|
||||
# Extract validation functions with error messages and code snippets
|
||||
FIRST_FUNC=true
|
||||
|
||||
# Get validation file content from git history or working directory
|
||||
# Note: validate_recipe.rs may not exist in older versions
|
||||
if [ "$VERSION" = "main" ]; then
|
||||
if [ -f crates/goose/src/recipe/validate_recipe.rs ]; then
|
||||
VALIDATE_RS_CONTENT=$(cat crates/goose/src/recipe/validate_recipe.rs)
|
||||
else
|
||||
VALIDATE_RS_CONTENT=""
|
||||
fi
|
||||
else
|
||||
VALIDATE_RS_CONTENT=$(git show "$VERSION:crates/goose/src/recipe/validate_recipe.rs" 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
if [ -n "$VALIDATE_RS_CONTENT" ]; then
|
||||
echo "$VALIDATE_RS_CONTENT" | rg "^fn validate_" -A 30 | \
|
||||
awk '
|
||||
/^fn validate_/ {
|
||||
if (func_name != "") {
|
||||
# Output previous function
|
||||
if (first_func == "true") {
|
||||
first_func = "false"
|
||||
} else {
|
||||
print ","
|
||||
}
|
||||
printf " {\n"
|
||||
printf " \"function\": \"%s\",\n", func_name
|
||||
printf " \"signature\": \"%s\",\n", signature
|
||||
printf " \"error_messages\": [%s],\n", error_msgs
|
||||
printf " \"code_snippet\": %s\n", code_snippet
|
||||
printf " }"
|
||||
}
|
||||
|
||||
# Start new function
|
||||
func_name = $0
|
||||
gsub(/^fn /, "", func_name)
|
||||
gsub(/\(.*/, "", func_name)
|
||||
signature = $0
|
||||
gsub(/"/, "\\\"", signature)
|
||||
error_msgs = ""
|
||||
code_snippet = "\"...\""
|
||||
first_func = (first_func == "") ? "true" : first_func
|
||||
}
|
||||
|
||||
/anyhow::anyhow!\("/ {
|
||||
# Extract error message
|
||||
msg = $0
|
||||
gsub(/.*anyhow::anyhow!\("/, "", msg)
|
||||
gsub(/".*/, "", msg)
|
||||
gsub(/"/, "\\\"", msg)
|
||||
if (error_msgs != "") error_msgs = error_msgs ", "
|
||||
error_msgs = error_msgs "\"" msg "\""
|
||||
}
|
||||
|
||||
END {
|
||||
# Output last function
|
||||
if (func_name != "") {
|
||||
if (first_func != "true") {
|
||||
print ","
|
||||
}
|
||||
printf " {\n"
|
||||
printf " \"function\": \"%s\",\n", func_name
|
||||
printf " \"signature\": \"%s\",\n", signature
|
||||
printf " \"error_messages\": [%s],\n", error_msgs
|
||||
printf " \"code_snippet\": %s\n", code_snippet
|
||||
printf " }"
|
||||
}
|
||||
}
|
||||
'
|
||||
fi
|
||||
|
||||
# Close validation_functions array and JSON
|
||||
cat << EOF
|
||||
|
||||
]
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
# End-to-end pipeline test
|
||||
# Usage: ./run-pipeline.sh <old_version> <new_version>
|
||||
# Example: ./run-pipeline.sh v1.9.0 v1.15.0
|
||||
|
||||
set -e
|
||||
|
||||
OLD_VERSION=${1:-"v1.9.0"}
|
||||
NEW_VERSION=${2:-"v1.15.0"}
|
||||
|
||||
echo "=========================================="
|
||||
echo "Recipe Validation Documentation Pipeline"
|
||||
echo "=========================================="
|
||||
echo "Old Version: $OLD_VERSION"
|
||||
echo "New Version: $NEW_VERSION"
|
||||
echo ""
|
||||
|
||||
# Change to output directory
|
||||
cd "$(dirname "$0")/../output"
|
||||
|
||||
echo "Step 1: Extracting validation structure from $OLD_VERSION..."
|
||||
if ! ../scripts/extract-validation-structure.sh "$OLD_VERSION" > old-validation-structure.json 2>&1; then
|
||||
echo "✗ Failed to extract validation structure from $OLD_VERSION" >&2
|
||||
echo "Error output:" >&2
|
||||
cat old-validation-structure.json >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Extracted $(jq '.struct_fields | length' old-validation-structure.json) fields, $(jq '.validation_functions | length' old-validation-structure.json) functions"
|
||||
|
||||
echo ""
|
||||
echo "Step 1b: Extracting schema from $OLD_VERSION..."
|
||||
if ! ../scripts/extract-schema.sh "$OLD_VERSION" > old-schema.json 2>&1; then
|
||||
echo "✗ Failed to extract schema from $OLD_VERSION" >&2
|
||||
echo "Error output:" >&2
|
||||
cat old-schema.json >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Extracted schema ($(jq '.properties | length' old-schema.json) properties)"
|
||||
|
||||
echo ""
|
||||
echo "Step 2: Extracting validation structure from $NEW_VERSION..."
|
||||
if ! ../scripts/extract-validation-structure.sh "$NEW_VERSION" > new-validation-structure.json 2>&1; then
|
||||
echo "✗ Failed to extract validation structure from $NEW_VERSION" >&2
|
||||
echo "Error output:" >&2
|
||||
cat new-validation-structure.json >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Extracted $(jq '.struct_fields | length' new-validation-structure.json) fields, $(jq '.validation_functions | length' new-validation-structure.json) functions"
|
||||
|
||||
echo ""
|
||||
echo "Step 2b: Extracting schema from $NEW_VERSION..."
|
||||
if ! ../scripts/extract-schema.sh "$NEW_VERSION" > new-schema.json 2>&1; then
|
||||
echo "✗ Failed to extract schema from $NEW_VERSION" >&2
|
||||
echo "Error output:" >&2
|
||||
cat new-schema.json >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Extracted schema ($(jq '.properties | length' new-schema.json) properties)"
|
||||
|
||||
echo ""
|
||||
echo "Step 3: Comparing validation structures..."
|
||||
../scripts/diff-validation-structures.sh old-validation-structure.json new-validation-structure.json > validation-changes.json 2>&1
|
||||
|
||||
HAS_CHANGES=$(jq -r '.has_changes' validation-changes.json)
|
||||
echo "✓ Comparison complete. Has changes: $HAS_CHANGES"
|
||||
|
||||
if [ "$HAS_CHANGES" = "true" ]; then
|
||||
echo ""
|
||||
echo "Changes detected:"
|
||||
echo " - Fields added: $(jq '.changes.struct_fields.added | length' validation-changes.json)"
|
||||
echo " - Fields removed: $(jq '.changes.struct_fields.removed | length' validation-changes.json)"
|
||||
echo " - Fields type changed: $(jq '.changes.struct_fields.type_changed | length' validation-changes.json)"
|
||||
echo " - Fields comment changed: $(jq '.changes.struct_fields.comment_changed | length' validation-changes.json)"
|
||||
echo " - Validation functions added: $(jq '.changes.validation_functions.added | length' validation-changes.json)"
|
||||
echo " - Validation functions removed: $(jq '.changes.validation_functions.removed | length' validation-changes.json)"
|
||||
echo " - Validation functions signature changed: $(jq '.changes.validation_functions.signature_changed | length' validation-changes.json)"
|
||||
echo " - Validation functions error messages changed: $(jq '.changes.validation_functions.error_messages_changed | length' validation-changes.json)"
|
||||
|
||||
echo ""
|
||||
echo "Step 4: Synthesizing validation changes documentation..."
|
||||
|
||||
# Run goose and capture output, filtering out session logs
|
||||
goose run --recipe ../recipes/synthesize-validation-changes.yaml 2>&1 | \
|
||||
sed -E 's/\x1B\[[0-9;]*[mK]//g' | \
|
||||
grep -v "^starting session" | \
|
||||
grep -v "^ session id:" | \
|
||||
grep -v "^ working directory:" | \
|
||||
grep -v "^─── text_editor" | \
|
||||
grep -v "^path:" | \
|
||||
grep -v "^command:" | \
|
||||
grep -v "^Closing session" | \
|
||||
grep -v "^Loading recipe:" | \
|
||||
grep -v "^Description:" | \
|
||||
sed '/^$/N;/^\n$/D' > validation-changes.md.tmp
|
||||
|
||||
# Check if we got meaningful content (more than just whitespace)
|
||||
if [ -s validation-changes.md.tmp ] && grep -q "# Recipe Validation Changes" validation-changes.md.tmp; then
|
||||
mv validation-changes.md.tmp validation-changes.md
|
||||
echo "✓ Generated validation-changes.md ($(wc -l < validation-changes.md) lines)"
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Pipeline Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Output files:"
|
||||
echo " - old-validation-structure.json"
|
||||
echo " - old-schema.json"
|
||||
echo " - new-validation-structure.json"
|
||||
echo " - new-schema.json"
|
||||
echo " - validation-changes.json"
|
||||
echo " - validation-changes.md"
|
||||
echo ""
|
||||
echo "Review validation-changes.md for documentation updates."
|
||||
else
|
||||
echo "✗ Failed to generate validation-changes.md"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "No Changes Detected"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "No validation changes between $OLD_VERSION and $NEW_VERSION."
|
||||
echo "Documentation update not needed."
|
||||
fi
|
||||
Reference in New Issue
Block a user