Skip to content

Merge pull request #44 from Snowflake-Labs/feature/aem-publish-pipeline #3

Merge pull request #44 from Snowflake-Labs/feature/aem-publish-pipeline

Merge pull request #44 from Snowflake-Labs/feature/aem-publish-pipeline #3

name: Publish Skill to AEM
on:
workflow_call:
inputs:
skill_name:
description: 'Skill folder name (e.g. good-morning)'
required: true
type: string
commit_sha:
description: 'Commit SHA to checkout'
required: true
type: string
pr_number:
description: 'PR number for commenting (optional, omit for merge runs)'
required: false
type: number
secrets:
AEM_USERNAME:
required: true
AEM_PASSWORD:
required: true
AEM_AUTHOR_URL:
required: true
env:
CF_BASE_PATH: /content/dam/snowflake-site/en/content-fragments/webinars/product-demo/manage-data-pipelines
CF_DEST_BASE: /content/dam/snowflake-site/en/content-fragments/skills-library
jobs:
publish_skill:
runs-on: ubuntu-latest
env:
AEM_URL: ${{ secrets.AEM_AUTHOR_URL }}
AEM_USERNAME: ${{ secrets.AEM_USERNAME }}
AEM_PASSWORD: ${{ secrets.AEM_PASSWORD }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ inputs.commit_sha }}
sparse-checkout: |
skills/${{ inputs.skill_name }}
scripts/aem-skills
sparse-checkout-cone-mode: true
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install pyyaml
- name: Find SKILL.md
id: find_md
run: |
md_file="skills/${{ inputs.skill_name }}/SKILL.md"
if [ ! -f "$md_file" ]; then
echo "❌ SKILL.md not found at $md_file"
exit 1
fi
echo "md_file=$md_file" >> $GITHUB_OUTPUT
echo "📄 Found: $md_file"
- name: Parse SKILL.md
run: |
python3 scripts/aem-skills/parse_skill.py \
"${{ steps.find_md.outputs.md_file }}" \
--output-json parsed_skill.json
echo "📄 Parsed skill:"
cat parsed_skill.json
- name: Prepare AEM payload
run: |
python3 scripts/aem-skills/prepare_skill_payload.py \
parsed_skill.json \
--output-json skill_payload.json
echo "📦 Payload prepared"
- name: Ensure skills-library folder exists
run: |
check=$(curl -s -o /dev/null -w "%{http_code}" \
"${AEM_URL}${CF_DEST_BASE}.json" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}")
echo "skills-library folder check: $check"
if [ "$check" != "200" ]; then
echo "📁 Creating skills-library folder"
curl -s -X POST \
"${AEM_URL}/api/assets/snowflake-site/en/content-fragments/*" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}" \
-H "Content-Type: application/json" \
-d '{"class":"assetFolder","properties":{"name":"skills-library","title":"skills-library"}}'
sleep 2
fi
- name: Create or verify CF exists
id: cf_path
run: |
cf_path="${CF_DEST_BASE}/${{ inputs.skill_name }}"
echo "cf_path=$cf_path" >> $GITHUB_OUTPUT
check=$(curl -s -o /dev/null -w "%{http_code}" \
"${AEM_URL}${cf_path}.json" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}")
echo "CF existence check: HTTP $check"
if [ "$check" = "200" ]; then
echo "✅ CF already exists, will update"
else
echo "📋 Creating new CF by copying base..."
response=$(curl -s -w "\n%{http_code}" -X POST \
"${AEM_URL}${CF_BASE_PATH}" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d ":operation=copy" \
-d ":dest=${cf_path}" \
-d ":replace=true")
http_code=$(echo "$response" | tail -n1)
echo "Copy HTTP: $http_code"
if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
echo "❌ Failed to create CF"
exit 1
fi
echo "✅ CF created"
sleep 3
fi
- name: Update CF with skill content
run: |
cf_path="${{ steps.cf_path.outputs.cf_path }}"
jq -j '.cf_payload' skill_payload.json > cf_payload.txt
csrf_token=$(curl -s -u "${AEM_USERNAME}:${AEM_PASSWORD}" \
"${AEM_URL}/libs/granite/csrf/token.json" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
echo "📝 Updating CF: $cf_path"
response=$(curl -s -w "\n%{http_code}" -X POST \
"${AEM_URL}${cf_path}/jcr:content" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "CSRF-Token: $csrf_token" \
--data-binary @cf_payload.txt)
http_code=$(echo "$response" | tail -n1)
echo "Update HTTP: $http_code"
if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
echo "❌ Failed to update CF"
echo "$response" | sed '$d'
exit 1
fi
echo "✅ CF updated"
- name: Replicate CF to publish
run: |
cf_path="${{ steps.cf_path.outputs.cf_path }}"
echo "📢 Replicating CF: $cf_path"
curl -s -X POST \
"${AEM_URL}/bin/replicate.json" \
-u "${AEM_USERNAME}:${AEM_PASSWORD}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "cmd=Activate" \
-d "path=${cf_path}"
echo "✅ CF replicated"
- name: Comment PR with staging link
if: ${{ inputs.pr_number != 0 }}
uses: actions/github-script@v7
env:
AEM_AUTHOR_URL: ${{ secrets.AEM_AUTHOR_URL }}
with:
script: |
const skillName = '${{ inputs.skill_name }}';
const cfPath = '/content/dam/snowflake-site/en/content-fragments/skills-library/' + skillName;
const authorUrl = process.env.AEM_AUTHOR_URL;
const cfLink = `${authorUrl}/ui#/aem/editor.html${cfPath}`;
const body = `## ✅ Skill Staged to AEM
**Skill:** \`${skillName}\`

Check failure on line 180 in .github/workflows/publish-skill-to-aem.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/publish-skill-to-aem.yml

Invalid workflow file

You have an error in your yaml syntax on line 180
👉 **AEM Staging CF:** [Open in AEM Author](${cfLink})
> Content Fragment has been created/updated and replicated to the staging publish instance.
---
*Generated by GitHub Actions*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ inputs.pr_number }},
body
});