From 9a759503f10913e5ef4f6f2698b8416cce19d127 Mon Sep 17 00:00:00 2001 From: swaroy Date: Mon, 6 Jul 2026 21:47:43 +0530 Subject: [PATCH 1/6] chore: add GH Actions workflow to auto-update image tags from changelogs Co-authored-by: Cursor --- .github/workflows/update-image-tags.yaml | 187 +++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 .github/workflows/update-image-tags.yaml diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml new file mode 100644 index 0000000..d2c42cd --- /dev/null +++ b/.github/workflows/update-image-tags.yaml @@ -0,0 +1,187 @@ +name: Update Image Tags from Changelogs + +on: + schedule: + - cron: '0 8 * * *' # daily at 08:00 UTC + workflow_dispatch: # allow manual trigger from Actions UI + +jobs: + update-tags: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install yq + run: | + YQ_VERSION="v4.44.2" + wget -qO /usr/local/bin/yq \ + "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" + chmod +x /usr/local/bin/yq + + - name: Fetch latest versions from changelogs + id: versions + run: | + fetch_latest() { + curl -sf "$1" | grep -m1 '> "$GITHUB_OUTPUT" + echo "dataservice=${DATASERVICE_VER}" >> "$GITHUB_OUTPUT" + echo "backend=${BACKEND_VER}" >> "$GITHUB_OUTPUT" + echo "frontend=${FRONTEND_VER}" >> "$GITHUB_OUTPUT" + + echo "Fetched versions:" + echo " gateway: ${GATEWAY_VER}" + echo " data-service: ${DATASERVICE_VER}" + echo " backend: ${BACKEND_VER}" + echo " frontend: ${FRONTEND_VER}" + + - name: Capture current tags (for PR body) + id: current + run: | + GW_FILE="charts/portkey-gateway/values.yaml" + APP_FILE="charts/portkey-app/values.yaml" + + echo "gw_gateway=$(yq e '.images.gatewayImage.tag' ${GW_FILE})" >> "$GITHUB_OUTPUT" + echo "gw_dataservice=$(yq e '.images.dataserviceImage.tag' ${GW_FILE})" >> "$GITHUB_OUTPUT" + echo "app_gateway=$(yq e '.images.gatewayImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_dataservice=$(yq e '.images.dataserviceImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_backend=$(yq e '.images.backendImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_frontend=$(yq e '.images.frontendImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" + + - name: Patch image tags + env: + GATEWAY_VER: ${{ steps.versions.outputs.gateway }} + DATASERVICE_VER: ${{ steps.versions.outputs.dataservice }} + BACKEND_VER: ${{ steps.versions.outputs.backend }} + FRONTEND_VER: ${{ steps.versions.outputs.frontend }} + run: | + GW_FILE="charts/portkey-gateway/values.yaml" + APP_FILE="charts/portkey-app/values.yaml" + + # portkey-gateway chart + yq e ".images.gatewayImage.tag = \"${GATEWAY_VER}\"" -i "${GW_FILE}" + yq e ".images.dataserviceImage.tag = \"${DATASERVICE_VER}\"" -i "${GW_FILE}" + + # portkey-app chart + yq e ".images.gatewayImage.tag = \"${GATEWAY_VER}\"" -i "${APP_FILE}" + yq e ".images.dataserviceImage.tag = \"${DATASERVICE_VER}\"" -i "${APP_FILE}" + yq e ".images.backendImage.tag = \"${BACKEND_VER}\"" -i "${APP_FILE}" + yq e ".images.frontendImage.tag = \"${FRONTEND_VER}\"" -i "${APP_FILE}" + + - name: Check for changes + id: diff + run: | + if git diff --quiet; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "No tag changes detected — all values.yaml files are already up to date." + else + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "Changes detected:" + git diff --stat + fi + + - name: Build PR body + if: steps.diff.outputs.changed == 'true' + env: + CUR_GW_GATEWAY: ${{ steps.current.outputs.gw_gateway }} + CUR_GW_DATASERVICE: ${{ steps.current.outputs.gw_dataservice }} + CUR_APP_GATEWAY: ${{ steps.current.outputs.app_gateway }} + CUR_APP_DATASERVICE: ${{ steps.current.outputs.app_dataservice }} + CUR_APP_BACKEND: ${{ steps.current.outputs.app_backend }} + CUR_APP_FRONTEND: ${{ steps.current.outputs.app_frontend }} + NEW_GATEWAY: ${{ steps.versions.outputs.gateway }} + NEW_DATASERVICE: ${{ steps.versions.outputs.dataservice }} + NEW_BACKEND: ${{ steps.versions.outputs.backend }} + NEW_FRONTEND: ${{ steps.versions.outputs.frontend }} + run: | + cat <<'BODY' > /tmp/pr_body.md + ## Image tag updates from changelogs + + Automated update from [Portkey changelogs](https://github.com/Portkey-AI/docs-core/tree/main/changelog). + + ### `charts/portkey-gateway/values.yaml` + + | Image | Before | After | + |-------|--------|-------| + BODY + + echo "| \`gatewayImage\` | \`${CUR_GW_GATEWAY}\` | \`${NEW_GATEWAY}\` |" >> /tmp/pr_body.md + echo "| \`dataserviceImage\` | \`${CUR_GW_DATASERVICE}\` | \`${NEW_DATASERVICE}\` |" >> /tmp/pr_body.md + + cat <<'BODY' >> /tmp/pr_body.md + + ### `charts/portkey-app/values.yaml` + + | Image | Before | After | + |-------|--------|-------| + BODY + + echo "| \`gatewayImage\` | \`${CUR_APP_GATEWAY}\` | \`${NEW_GATEWAY}\` |" >> /tmp/pr_body.md + echo "| \`dataserviceImage\` | \`${CUR_APP_DATASERVICE}\` | \`${NEW_DATASERVICE}\` |" >> /tmp/pr_body.md + echo "| \`backendImage\` | \`${CUR_APP_BACKEND}\` | \`${NEW_BACKEND}\` |" >> /tmp/pr_body.md + echo "| \`frontendImage\` | \`${CUR_APP_FRONTEND}\` | \`${NEW_FRONTEND}\` |" >> /tmp/pr_body.md + + cat <<'BODY' >> /tmp/pr_body.md + + > Rows where Before = After mean the tag was already current for that chart. + + ### Changelog sources + - Enterprise Gateway: https://github.com/Portkey-AI/docs-core/blob/main/changelog/enterprise.mdx + - Data Service: https://github.com/Portkey-AI/docs-core/blob/main/changelog/data-service.mdx + - Backend: https://github.com/Portkey-AI/docs-core/blob/main/changelog/backend.mdx + - Frontend: https://github.com/Portkey-AI/docs-core/blob/main/changelog/frontend.mdx + BODY + + - name: Create branch and open PR + if: steps.diff.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GATEWAY_VER: ${{ steps.versions.outputs.gateway }} + DATASERVICE_VER: ${{ steps.versions.outputs.dataservice }} + BACKEND_VER: ${{ steps.versions.outputs.backend }} + FRONTEND_VER: ${{ steps.versions.outputs.frontend }} + run: | + BRANCH="chore/update-image-tags-$(date +%Y%m%d)" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git checkout -B "${BRANCH}" + git add charts/portkey-gateway/values.yaml charts/portkey-app/values.yaml + git commit -m "chore: update image tags from changelogs + + - gateway: ${GATEWAY_VER} + - data-service: ${DATASERVICE_VER} + - backend: ${BACKEND_VER} + - frontend: ${FRONTEND_VER}" + + git push --force-with-lease origin "${BRANCH}" + + # Open a new PR or update an existing one for the same branch (idempotent) + EXISTING_PR=$(gh pr list --head "${BRANCH}" --json number --jq '.[0].number') + if [ -z "${EXISTING_PR}" ]; then + gh pr create \ + --base main \ + --head "${BRANCH}" \ + --title "chore: update image tags (gateway=${GATEWAY_VER}, backend=${BACKEND_VER}, frontend=${FRONTEND_VER})" \ + --body-file /tmp/pr_body.md + else + echo "PR #${EXISTING_PR} already exists for ${BRANCH} — updating body." + gh pr edit "${EXISTING_PR}" \ + --title "chore: update image tags (gateway=${GATEWAY_VER}, backend=${BACKEND_VER}, frontend=${FRONTEND_VER})" \ + --body-file /tmp/pr_body.md + fi From 38713e3ae5d7a9c22178b64ac17b684d869bc700 Mon Sep 17 00:00:00 2001 From: Swapnil Roy Date: Mon, 6 Jul 2026 22:02:04 +0530 Subject: [PATCH 2/6] Update update-image-tags.yaml --- .github/workflows/update-image-tags.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml index d2c42cd..b82b61b 100644 --- a/.github/workflows/update-image-tags.yaml +++ b/.github/workflows/update-image-tags.yaml @@ -1,6 +1,8 @@ name: Update Image Tags from Changelogs on: + push: + branches: [chore/update-image-tags-workflow] schedule: - cron: '0 8 * * *' # daily at 08:00 UTC workflow_dispatch: # allow manual trigger from Actions UI From e2556eea8a07e770a4e10945b15a3453eb97338d Mon Sep 17 00:00:00 2001 From: Swapnil Roy Date: Mon, 6 Jul 2026 22:05:06 +0530 Subject: [PATCH 3/6] Update update-image-tags.yaml --- .github/workflows/update-image-tags.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml index b82b61b..d2c42cd 100644 --- a/.github/workflows/update-image-tags.yaml +++ b/.github/workflows/update-image-tags.yaml @@ -1,8 +1,6 @@ name: Update Image Tags from Changelogs on: - push: - branches: [chore/update-image-tags-workflow] schedule: - cron: '0 8 * * *' # daily at 08:00 UTC workflow_dispatch: # allow manual trigger from Actions UI From 07c1c7b7b5fbbf9ba0c6f844b67054500d99e4c6 Mon Sep 17 00:00:00 2001 From: swaroy Date: Tue, 7 Jul 2026 13:52:37 +0530 Subject: [PATCH 4/6] fix: replace yq with sed to avoid reformatting values.yaml yq rewrites the entire file on every -i operation, changing quotes, blank lines, and indentation across unrelated sections. Replaced with sed range-address substitutions that only touch the specific tag: line for each image block, leaving everything else in the file byte-for-byte identical. Co-authored-by: Cursor --- .github/workflows/update-image-tags.yaml | 40 +++++++++++++----------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml index d2c42cd..404d6cb 100644 --- a/.github/workflows/update-image-tags.yaml +++ b/.github/workflows/update-image-tags.yaml @@ -18,13 +18,6 @@ jobs: with: fetch-depth: 0 - - name: Install yq - run: | - YQ_VERSION="v4.44.2" - wget -qO /usr/local/bin/yq \ - "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" - chmod +x /usr/local/bin/yq - - name: Fetch latest versions from changelogs id: versions run: | @@ -55,12 +48,15 @@ jobs: GW_FILE="charts/portkey-gateway/values.yaml" APP_FILE="charts/portkey-app/values.yaml" - echo "gw_gateway=$(yq e '.images.gatewayImage.tag' ${GW_FILE})" >> "$GITHUB_OUTPUT" - echo "gw_dataservice=$(yq e '.images.dataserviceImage.tag' ${GW_FILE})" >> "$GITHUB_OUTPUT" - echo "app_gateway=$(yq e '.images.gatewayImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" - echo "app_dataservice=$(yq e '.images.dataserviceImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" - echo "app_backend=$(yq e '.images.backendImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" - echo "app_frontend=$(yq e '.images.frontendImage.tag' ${APP_FILE})" >> "$GITHUB_OUTPUT" + # Read-only extraction: grep the image block then pull the tag line value + get_tag() { grep -A4 "$1:" "$2" | grep 'tag:' | head -1 | sed 's/.*tag:[[:space:]]*"\(.*\)"/\1/'; } + + echo "gw_gateway=$(get_tag gatewayImage ${GW_FILE})" >> "$GITHUB_OUTPUT" + echo "gw_dataservice=$(get_tag dataserviceImage ${GW_FILE})" >> "$GITHUB_OUTPUT" + echo "app_gateway=$(get_tag gatewayImage ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_dataservice=$(get_tag dataserviceImage ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_backend=$(get_tag backendImage ${APP_FILE})" >> "$GITHUB_OUTPUT" + echo "app_frontend=$(get_tag frontendImage ${APP_FILE})" >> "$GITHUB_OUTPUT" - name: Patch image tags env: @@ -72,15 +68,21 @@ jobs: GW_FILE="charts/portkey-gateway/values.yaml" APP_FILE="charts/portkey-app/values.yaml" + # sed range: from the image key line to the first tag: line after it. + # Only rewrites that one tag: line — every other byte in the file is untouched. + set_tag() { + sed -i "/$1:/,/tag:/ s|\(^[[:space:]]*tag: \).*|\1\"$2\"|" "$3" + } + # portkey-gateway chart - yq e ".images.gatewayImage.tag = \"${GATEWAY_VER}\"" -i "${GW_FILE}" - yq e ".images.dataserviceImage.tag = \"${DATASERVICE_VER}\"" -i "${GW_FILE}" + set_tag gatewayImage "${GATEWAY_VER}" "${GW_FILE}" + set_tag dataserviceImage "${DATASERVICE_VER}" "${GW_FILE}" # portkey-app chart - yq e ".images.gatewayImage.tag = \"${GATEWAY_VER}\"" -i "${APP_FILE}" - yq e ".images.dataserviceImage.tag = \"${DATASERVICE_VER}\"" -i "${APP_FILE}" - yq e ".images.backendImage.tag = \"${BACKEND_VER}\"" -i "${APP_FILE}" - yq e ".images.frontendImage.tag = \"${FRONTEND_VER}\"" -i "${APP_FILE}" + set_tag gatewayImage "${GATEWAY_VER}" "${APP_FILE}" + set_tag dataserviceImage "${DATASERVICE_VER}" "${APP_FILE}" + set_tag backendImage "${BACKEND_VER}" "${APP_FILE}" + set_tag frontendImage "${FRONTEND_VER}" "${APP_FILE}" - name: Check for changes id: diff From 26e5133e4d2a1d6bb79bee6356721596fcec72ba Mon Sep 17 00:00:00 2001 From: Swapnil Roy Date: Tue, 7 Jul 2026 13:56:59 +0530 Subject: [PATCH 5/6] Update update-image-tags.yaml --- .github/workflows/update-image-tags.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml index 404d6cb..c542329 100644 --- a/.github/workflows/update-image-tags.yaml +++ b/.github/workflows/update-image-tags.yaml @@ -1,6 +1,8 @@ name: Update Image Tags from Changelogs on: + push: + branches: [chore/update-image-tags-workflow] schedule: - cron: '0 8 * * *' # daily at 08:00 UTC workflow_dispatch: # allow manual trigger from Actions UI From afb4bf0b228609725bbb471c9be0e60a3a3753b4 Mon Sep 17 00:00:00 2001 From: Swapnil Roy Date: Tue, 7 Jul 2026 13:57:56 +0530 Subject: [PATCH 6/6] Update update-image-tags.yaml --- .github/workflows/update-image-tags.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/update-image-tags.yaml b/.github/workflows/update-image-tags.yaml index c542329..404d6cb 100644 --- a/.github/workflows/update-image-tags.yaml +++ b/.github/workflows/update-image-tags.yaml @@ -1,8 +1,6 @@ name: Update Image Tags from Changelogs on: - push: - branches: [chore/update-image-tags-workflow] schedule: - cron: '0 8 * * *' # daily at 08:00 UTC workflow_dispatch: # allow manual trigger from Actions UI