Skip to content

TypeScript SDK

TypeScript SDK #202

Workflow file for this run

name: Generate Arazzo Spec from Jentic OpenAPI URL in Issue
on:
issues:
types: [ opened ]
jobs:
generate-arazzo:
if: contains(github.event.issue.body, 'openapi_url:')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Extract OpenAPI URL and Details from issue body
id: extract_info
run: |
echo "Parsing OpenAPI URL and details from issue..."
BODY="${{ github.event.issue.body }}"
URL=$(echo "$BODY" | grep -oP '(?<=openapi_url:).*' | head -n 1 | xargs)
# Attempt to extract vendor and api_name from URL structure
# Example: .../apis/openapi/vendor.com/api_name/version/openapi.json
VENDOR_NAME=$(echo "$URL" | grep -oP '(?<=apis/openapi/)[^/]+' | head -n 1)
API_NAME=$(echo "$URL" | grep -oP '(?<=apis/openapi/'"$VENDOR_NAME"'/)[^/]+' | head -n 1)
# Extract version from the part right before openapi.json
API_VERSION=$(echo "$URL" | grep -oP '[^/]+(?=/openapi\.json)' | head -n 1)
# Extract Workflow Descriptions section as a JSON array
# Looks for the specific heading from the issue template
WORKFLOW_DESCRIPTIONS=$(echo "$BODY" | awk '/^### Workflow Descriptions \(Optional\)/{flag=1;next}/^## |^### /{if(flag)flag=0}flag' | grep -E '^[-*] ' | sed -E 's/^[-*] *//' | jq -R . | jq -sc .)
if [ -z "$URL" ]; then
echo "::error::Could not extract openapi_url from issue body."
exit 1
fi
if [ -z "$VENDOR_NAME" ]; then
echo "::warning::Could not automatically determine VENDOR_NAME from URL: $URL. Defaulting path."
VENDOR_NAME="unknown-vendor-${{ github.event.issue.number }}"
fi
if [ -z "$API_NAME" ]; then
# Assume 'main' if api_name part is missing or different structure
echo "::warning::Could not automatically determine API_NAME from URL: $URL. Assuming 'main'."
API_NAME="main"
fi
if [ -z "$API_VERSION" ]; then
# Assume 'latest' if version part is missing or different structure
echo "::warning::Could not automatically determine API_VERSION from URL: $URL. Assuming 'latest'."
API_VERSION="latest"
fi
echo "Extracted URL: $URL"
echo "Determined Vendor: $VENDOR_NAME"
echo "Determined API Name: $API_NAME"
echo "Determined API Version: $API_VERSION"
echo "Extracted Workflow Descriptions: $WORKFLOW_DESCRIPTIONS"
echo "openapi_url=$URL" >> $GITHUB_OUTPUT
echo "vendor_name=$VENDOR_NAME" >> $GITHUB_OUTPUT
echo "api_name=$API_NAME" >> $GITHUB_OUTPUT
echo "api_version=$API_VERSION" >> $GITHUB_OUTPUT
echo "workflow_descriptions=$WORKFLOW_DESCRIPTIONS" >> $GITHUB_OUTPUT
- name: Call Arazzo Generator API and Create File
id: call_api_and_create_file
run: |
echo "Calling Arazzo Generator API with OpenAPI URL: ${{ steps.extract_info.outputs.openapi_url }}"
# Prepare workflow_descriptions JSON for curl
WF_DESCRIPTIONS='${{ steps.extract_info.outputs.workflow_descriptions }}'
if [ "$WF_DESCRIPTIONS" = "" ] || [ "$WF_DESCRIPTIONS" = "null" ] || [ "$WF_DESCRIPTIONS" = "[]" ]; then
WF_DESCRIPTIONS=null
fi
RESPONSE=$(jq -n --arg url "${{ steps.extract_info.outputs.openapi_url }}" \
--arg format "json" \
--argjson validate_spec true \
--argjson direct_llm false \
--rawfile wf_desc <(echo "$WF_DESCRIPTIONS") \
'{url: $url, format: $format, validate_spec: $validate_spec, direct_llm: $direct_llm, workflow_descriptions: ($wf_desc | fromjson? // null)}' | \
curl -v --show-error -X POST https://arazzo-runner.main.us-east-1.jenticprod.net/generate \
-H "Content-Type: application/json" \
-d @-)
# Determine output directory structure based on vendor/api name
VENDOR="${{ steps.extract_info.outputs.vendor_name }}"
API="${{ steps.extract_info.outputs.api_name }}"
if [ "$API" == "main" ] || [ -z "$API" ]; then
TARGET_SUBDIR="$VENDOR"
else
TARGET_SUBDIR="${VENDOR}~${API}"
fi
# Define the target file path within the current repository
TARGET_DIR="workflows/$TARGET_SUBDIR"
SPEC_FILE="$TARGET_DIR/workflows.arazzo.json"
echo "Target spec file: $SPEC_FILE"
# Ensure the target directory exists
mkdir -p "$TARGET_DIR"
# Attempt to parse and save the spec file
if ! echo "$RESPONSE" | jq -e '.arazzo_spec' > "$SPEC_FILE"; then
echo "::error::API call failed or API response did not contain expected '.arazzo_spec' field."
echo "Response was:"
echo "$RESPONSE"
echo "api_failed=true" >> $GITHUB_OUTPUT
echo "error_response=$RESPONSE" >> $GITHUB_OUTPUT
exit 1
fi
# Extract fallback status/message if custom workflow descriptions failed and caused regeneration
FALLBACK_USED=$(echo "$RESPONSE" | jq -r '.fallback_used // false')
FALLBACK_MSG=$(echo "$RESPONSE" | jq -r '.message // empty')
# Build a note for the PR body
# If the fallback regeneration logic is used after custom workflow descriptions failed to generate arazzo file then add a warning note
if [ "$FALLBACK_USED" = true ]; then
NOTE="**⚠️ WARNING:** $FALLBACK_MSG"
else
NOTE=""
fi
echo "fallback_note=$NOTE" >> "$GITHUB_OUTPUT"
echo "API call successful, $SPEC_FILE created in workspace."
# --- Debugging: Verify file --- (Run within the context of the workspace)
echo "--- Debug: Checking created file ---"
ls -la "$TARGET_DIR"
echo "Content of $SPEC_FILE (first 5 lines):"
head -n 5 "$SPEC_FILE" || echo "WARN: Could not read head of $SPEC_FILE"
echo "--- End Debugging ---"
# Optional: Check git status within the repository
- name: Check Git Status Before PR Action
run: |
echo "--- Debug: Git Status ---"
git status
echo "--- End Debug Status ---"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
# No 'path' needed, operates on the whole repo
commit-message: "feat: Add Arazzo spec for ${{ steps.extract_info.outputs.vendor_name }}/${{ steps.extract_info.outputs.api_name }}/${{ steps.extract_info.outputs.api_version }} (Issue #${{ github.event.issue.number }})"
title: "feat: Add Arazzo spec for ${{ steps.extract_info.outputs.vendor_name }}/${{ steps.extract_info.outputs.api_name }}/${{ steps.extract_info.outputs.api_version }} (Issue #${{ github.event.issue.number }})"
body: |
This PR adds the Arazzo spec generated for the OpenAPI URL provided in Issue #${{ github.event.issue.number }} to Jentic OAK.
**Vendor:** ${{ steps.extract_info.outputs.vendor_name }}
**API Name:** ${{ steps.extract_info.outputs.api_name }}
**API Version:** ${{ steps.extract_info.outputs.api_version }}
**Source URL:** ${{ steps.extract_info.outputs.openapi_url }}
Arazzo spec was automatically generated by the hosted API.
${{ steps.call_api_and_create_file.outputs.fallback_note }}
Closes #${{ github.event.issue.number }}
branch: feat/arazzo-${{ steps.extract_info.outputs.vendor_name }}-${{ steps.extract_info.outputs.api_name }}-${{ steps.extract_info.outputs.api_version }}-${{ github.event.issue.number }}
base: main # Or your target branch in jentic-arazzo-generator
# Optional: Add labels, assignees etc.
# labels: automated-pr, arazzo-spec
- name: Comment on Issue if API Failed
if: failure() && steps.call_api_and_create_file.outputs.api_failed == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const errorResponse = `${{ steps.call_api_and_create_file.outputs.error_response }}`;
let errorMessage = "❌ **Failed to generate Arazzo specification**\n\n";
try {
const response = JSON.parse(errorResponse);
if (response.error) {
errorMessage += `**Error:** ${response.error}\n\n`;
}
if (response.message) {
errorMessage += `**Details:** ${response.message}\n\n`;
}
if (response.validation_errors && response.validation_errors.length > 0) {
errorMessage += `**Validation Errors:**\n`;
response.validation_errors.forEach(error => {
errorMessage += `- ${error}\n`;
});
errorMessage += "\n";
}
} catch (e) {
errorMessage += `**Raw Response:** \`\`\`\n${errorResponse}\n\`\`\`\n\n`;
}
errorMessage += "There was an error generating the Arazzo spec from the provided OpenAPI specification URL.\n\n";
errorMessage += "If you believe this is a bug with the Arazzo generator or need additional support, please contact the development team at Jentic Community Discord (https://discord.gg/yrxmDZWMqB).\n\n";
errorMessage += "Alternatively create a new issue reporting the bug (https://github.com/jentic/jentic-public-apis/issues/new?template=BLANK_ISSUE).";
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: errorMessage
});