diff --git a/.github/workflows/spec-update-old.yaml b/.github/workflows/spec-update-old.yaml new file mode 100644 index 000000000..8216a1982 --- /dev/null +++ b/.github/workflows/spec-update-old.yaml @@ -0,0 +1,311 @@ +name: "Spec File Update Workflow" +run-name: "Spec File Update Workflow: ${{ github.event.inputs.file }}-${{ github.event.inputs.file-ref }}" + +on: + workflow_dispatch: + inputs: + file: + description: "Which spec file to update" + type: choice + required: false + options: + - core + - document-grounding + - orchestration + - prompt-registry + - sap-rpt + default: orchestration + file-ref: + description: "Branch or tag to checkout the spec file from" + required: false + default: main + type: string + create-pr: + description: "Create a pull request after updating the spec file" + required: false + default: true + type: boolean + +env: + MVN_MULTI_THREADED_ARGS: --batch-mode --no-transfer-progress --fail-at-end --show-version --threads 1C + JAVA_VERSION: 21 + # keep the following two variables in sync with our 'cache-maven-dependencies.yaml' workflow + MAVEN_CACHE_KEY: maven-dependencies + MAVEN_CACHE_DIR: ~/.m2 + +jobs: + generate: + name: "Download, Generate, Compile and Push" + runs-on: [ ubuntu-latest ] + permissions: + pull-requests: write + contents: write + outputs: + spec_diff: ${{ steps.spec_diff.outputs.spec_diff }} + branch: ${{ steps.push.outputs.branch }} + pr_url: ${{ steps.create-pr.outputs.pr_url }} + compilation_result: ${{ steps.compile.outputs.compilation_result }} + test_result: ${{ steps.compile.outputs.test_result }} + env: + API_BASE_URL: "https://github.tools.sap/api/v3/repos" + CHOICE: ${{ github.event.inputs.file }} + REF: ${{ github.event.inputs.file-ref }} + CREATE_PR: ${{ github.event.inputs.create-pr }} + steps: + - name: "Checkout repository" + uses: actions/checkout@v6 + with: + token: ${{ secrets.BOT_SDK_JS_FOR_DOCS_REPO_PR }} + + - name: "Determine PR base" + id: pr_base + # If updating orchestration and orchestration-staging exists on remote, use it as PR base. + run: | + BASE=main + if [ "${{ env.CHOICE }}" = "orchestration" ] && [ -n "$(git ls-remote --heads origin orchestration-staging)" ]; then + BASE=orchestration-staging + fi + echo "PR base: $BASE" + echo "BASE=$BASE" >> "$GITHUB_OUTPUT" + + - name: "Setup Java" + uses: actions/setup-java@v5 + with: + distribution: "sapmachine" + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: "Restore Dependencies" + id: restore-dependencies + uses: actions/cache/restore@v5 + with: + key: ${{ env.MAVEN_CACHE_KEY }} + path: ${{ env.MAVEN_CACHE_DIR }} + + - name: "Checkout or Create Branch" + id: branch + env: + BASE: ${{ steps.pr_base.outputs.BASE }} + CHOICE: ${{ env.CHOICE }} + REF: ${{ env.REF }} + run: | + BRANCH="spec-update/$CHOICE/$REF" + + # try to fetch the base and the target branch (ignore failures if missing) + git fetch --no-tags --depth=1 origin "$BASE" || true + git fetch origin "$BRANCH" || true + + # if remote target branch exists, base the local branch on it + if git ls-remote --heads origin "$BRANCH" | grep -q "refs/heads/$BRANCH"; then + git checkout -B "$BRANCH" "origin/$BRANCH" + else + # otherwise, create the branch from origin/BASE if it exists, else from current HEAD + if git ls-remote --heads origin "$BASE" | grep -q "refs/heads/$BASE"; then + git checkout -B "$BRANCH" "origin/$BASE" + else + git checkout -B "$BRANCH" + fi + fi + + echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" + + - name: "Download specification file" + id: download + env: + GH_ENTERPRISE_TOKEN: ${{ secrets.GH_TOOLS_TOKEN }} + run: | + case $CHOICE in + core) + API_URL="$API_BASE_URL/cloudsdk/cloud-sdk-java-tests/contents/aicore.yaml?ref=$REF" + FILE_PATH='core/src/main/resources/spec/aicore.yaml' + ;; + document-grounding) + API_URL="$API_BASE_URL/AI/rage-proxy-inference/contents/docs/public/business_api_hub/api_hub_merged_spec.yaml?ref=$REF" + FILE_PATH='core-services/document-grounding/src/main/resources/spec/grounding.yaml' + ;; + orchestration) + API_URL="$API_BASE_URL/AI/llm-orchestration/contents/src/spec/v2.yaml?ref=$REF" + FILE_PATH='orchestration/src/main/resources/spec/orchestration.yaml' + ;; + prompt-registry) + API_URL="$API_BASE_URL/AI/prompt-registry/contents/src/spec/generated/prompt-registry-combined.yaml?ref=$REF" + FILE_PATH='core-services/prompt-registry/src/main/resources/spec/prompt-registry.yaml' + ;; + sap-rpt) # https://github.tools.sap/DL-COE/sap-rpt-1-public-content + API_URL="$API_BASE_URL/DL-COE/sap-rpt-1-public-content/contents/sap-rpt-1_openapi.json?ref=$REF" + FILE_PATH='foundation-models/sap-rpt/src/main/resources/spec/sap-rpt-1_openapi.json' + ;; + esac + + echo "Downloading $CHOICE specification file from $API_URL ..." + + gh api $API_URL -H "Accept: application/vnd.github.raw" > $FILE_PATH + + - name: "Exit if there are no spec changes" + id: spec_diff + env: + GH_TOKEN: ${{ secrets.BOT_SDK_JS_FOR_DOCS_REPO_PR }} + run: | + # if there are no spec changes in this commit, check if previous run on this branch is red. If it is red, exit 1; if it is green, exit 0. + if [[ `git status --porcelain` ]]; then + echo "Spec changes detected, continuing with generation." + echo "spec_diff=true" >> "$GITHUB_OUTPUT" + else + echo "No spec changes detected. Checking status of previous run." + echo "spec_diff=false" >> "$GITHUB_OUTPUT" + + # The current run of this workflow + CURRENT_RUN=${{ github.run_id }} + + # name must match the workflow run-name pattern above + RUN_NAME="Spec File Update Workflow: $CHOICE-$REF" + echo "Run name used for search: $RUN_NAME" + + # Get the most recent completed run of this workflow with respect to the same feature branch + PREVIOUS_RUN=$(gh run list \ + --workflow "${{ github.workflow }}" \ + --branch main \ + --json databaseId,status,conclusion,displayTitle \ + --jq "map(select(.databaseId != ${CURRENT_RUN} and (.displayTitle | contains(\"${RUN_NAME}\")))) | .[0]") + + echo "Previous run: $PREVIOUS_RUN" + + if [ -n "$PREVIOUS_RUN" ] && [ "$PREVIOUS_RUN" != "null" ]; then + CONCLUSION=$(echo "$PREVIOUS_RUN" | jq -r '.conclusion') + echo "Previous run conclusion: $CONCLUSION" + + if [ "$CONCLUSION" = "failure" ]; then + echo "Previous run failed and there were no spec changes since, thus failing this run as well." + echo "prev_run_success=false" >> "$GITHUB_OUTPUT" + else + echo "Previous run succeeded and there were no spec changes since, thus the current run succeeds as well." + echo "prev_run_success=true" >> "$GITHUB_OUTPUT" + fi + else + echo "There was no previous run, thus the current run succeeds." + echo "prev_run_success=true" >> "$GITHUB_OUTPUT" + fi + fi + + - name: "Generate" + id: generate + if: steps.spec_diff.outputs.spec_diff == 'true' + run: | + if mvn install -DskipTests -Dgenerate ${{ env.MVN_MULTI_THREADED_ARGS }} ; then + echo "generation_result=success" >> "$GITHUB_OUTPUT" + else + echo "generation_result=failure" >> "$GITHUB_OUTPUT" + fi + + - name: "Compile and Test" + id: compile + if: steps.spec_diff.outputs.spec_diff == 'true' + # Compilation can easily fail e.g. from re-namings and has to be fixed manually. + # Thus, this action raises the PR anyway and only reports success or failure of compilation and testing. + run: | + if mvn test-compile ${{ env.MVN_MULTI_THREADED_ARGS }} ; then + echo "compilation_result=success" >> "$GITHUB_OUTPUT" + if mvn test ${{ env.MVN_MULTI_THREADED_ARGS }} ; then + echo "test_result=success" >> "$GITHUB_OUTPUT" + else + echo "test_result=failure" >> "$GITHUB_OUTPUT" + fi + else + echo "compilation_result=failure" >> "$GITHUB_OUTPUT" + echo "test_result=skipped" >> "$GITHUB_OUTPUT" + fi + + - name: "Push changes" + id: push + if: steps.spec_diff.outputs.spec_diff == 'true' + run: | + git config --global user.email "cloudsdk@sap.com" + git config --global user.name "SAP Cloud SDK Bot" + git add --all + git status + git commit -m "Update $CHOICE based on $REF" + git push --set-upstream origin ${{ steps.branch.outputs.branch }} + + - name: "Create PR" + id: create-pr + if: ${{ env.CREATE_PR == 'true' && steps.spec_diff.outputs.spec_diff == 'true'}} + env: + GH_TOKEN: ${{ secrets.BOT_SDK_JS_FOR_DOCS_REPO_PR }} + BRANCH: ${{ steps.branch.outputs.branch }} + BASE: ${{ steps.pr_base.outputs.BASE }} + run: | + if gh pr list --head $BRANCH --json number -q '.[].number' | grep -q .; then + echo "An open PR already exists for this branch. Skipping PR creation." + exit 0 + fi + + PR_URL=$(gh pr create --base $BASE --head $BRANCH --title "feat: [DevOps] Update $CHOICE specification" --body " + ## Context + + Update $CHOICE specification file based on $REF. + + This PR was created automatically by the [spec-update workflow](https://github.com/SAP/ai-sdk-java/actions/workflows/spec-update.yaml). + You can commit on top of this branch, but as long as this PR is open the action can't be re-run. + + - Compilation outcome: ${{ steps.compile.outputs.compilation_result }} + - Test run outcome: ${{ steps.compile.outputs.test_result }} + + Before merging, make sure to update tests and release notes, if necessary. + + ## Definition of Done + + - [ ] Unit tests cover new classes + - [ ] Release notes updated + ") && echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT" + + - name: "Generate Job Summary" + if: ${{ always() }} + env: + BRANCH: ${{ steps.branch.outputs.branch }} + PR_URL: ${{ steps.create-pr.outputs.pr_url }} + BASE: ${{ steps.pr_base.outputs.BASE }} + run: | + DIFF_URL="https://github.com/SAP/ai-sdk-java/compare/$BASE...$BRANCH" + echo "## Workflow Execution Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Step | Status |" >> $GITHUB_STEP_SUMMARY + echo "|------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| File Download | ${{ steps.download.outcome == 'success' && '✅' || '❌' }} ${{ steps.download.outcome }}" >> $GITHUB_STEP_SUMMARY + echo "| Spec File Changes | ${{ steps.spec_diff.outputs.spec_diff == 'true' && '🔄 Changes Detected' || 'âšī¸ No Changes' }}" >> $GITHUB_STEP_SUMMARY + + if ${{ steps.spec_diff.outputs.spec_diff == 'false' }}; then + echo "| Outcome Previous Run | ${{ steps.spec_diff.outputs.prev_run_success == 'true' && '✅ (Current run succeeds as a result.)' || '❌ (Current run fails as a result.)' }}" >> $GITHUB_STEP_SUMMARY + fi + + if ${{ steps.spec_diff.outputs.spec_diff == 'true' }}; then + echo "| Client Generation | ${{ steps.generate.outputs.generation_result == 'success' && '✅' || '❌' }} ${{ steps.generate.outputs.generation_result }}" >> $GITHUB_STEP_SUMMARY + echo "| Client Compilation | ${{ steps.compile.outputs.compilation_result == 'success' && '✅' || '❌' }} ${{ steps.compile.outputs.compilation_result }}" >> $GITHUB_STEP_SUMMARY + echo "| Client Testing | ${{ steps.compile.outputs.test_result == 'success' && '✅' || steps.compile.outputs.test_result == 'skipped' && '⏊' || '❌' }} ${{ steps.compile.outputs.test_result }}" >> $GITHUB_STEP_SUMMARY + echo "| Branch Creation | ${{ steps.push.outcome == 'success' && '✅ [Branch Link]($DIFF_URL)' || '❌ failure' }}" >> $GITHUB_STEP_SUMMARY + echo "| Pull Request Creation | ${{ env.CREATE_PR == 'false' && '⏊ skipped' || '' }}${{ env.CREATE_PR == 'true' && steps.push.outcome == 'success' && '✅ [PR Link]($PR_URL)' || '' }}" >> $GITHUB_STEP_SUMMARY + fi + + - name: "Fail if generation failed" + if: steps.generate.outputs.generation_result == 'failure' + run: | + echo "Client generation failed. Please check the Generate step logs for details." + exit 1 + + - name: "Fail if no spec changes and previous run failed" + if: steps.spec_diff.outputs.prev_run_success == 'false' + run: | + echo "Previous run failed and there were no spec changes since, thus failing this run as well." + exit 1 + + - name: "Slack Notification" + if: failure() && github.event.inputs.create-pr == 'true' + uses: slackapi/slack-github-action@v2.1.1 + with: + webhook: ${{ secrets.SLACK_WEBHOOK }} + webhook-type: incoming-webhook + payload: | + blocks: + - type: "section" + text: + type: "mrkdwn" + text: "âš ī¸ Weekly spec update failed! đŸ˜Ŧ Please inspect & fix by clicking "