From 1d1c8404f0893ded015b237e862ba6752816084c Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Fri, 22 May 2026 19:05:22 +0100 Subject: [PATCH 1/3] feat: add cleanup process for sunsetted postman collections --- .github/workflows/release-postman.yml | 8 ++ tools/postman/Makefile | 4 + .../scripts/delete-sunsetted-collections.sh | 101 ++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100755 tools/postman/scripts/delete-sunsetted-collections.sh diff --git a/.github/workflows/release-postman.yml b/.github/workflows/release-postman.yml index 35d90f6905..17bc600f53 100644 --- a/.github/workflows/release-postman.yml +++ b/.github/workflows/release-postman.yml @@ -57,3 +57,11 @@ jobs: working-directory: ./tools/postman run: | make upload_collection + + - name: Delete Sunsetted Collections + env: + POSTMAN_API_KEY: ${{ secrets.postman_api_key }} + WORKSPACE_ID: ${{ secrets.workspace_id }} + working-directory: ./tools/postman + run: | + make delete_sunsetted diff --git a/tools/postman/Makefile b/tools/postman/Makefile index cff840cf7b..f8ec420c3b 100644 --- a/tools/postman/Makefile +++ b/tools/postman/Makefile @@ -29,6 +29,10 @@ transform_collection_test: upload_collection: ./scripts/upload-collection.sh +.PHONY: delete_sunsetted +delete_sunsetted: + ./scripts/delete-sunsetted-collections.sh + .PHONY: build build: fetch_openapi convert_to_collection diff --git a/tools/postman/scripts/delete-sunsetted-collections.sh b/tools/postman/scripts/delete-sunsetted-collections.sh new file mode 100755 index 0000000000..e5b5015ddc --- /dev/null +++ b/tools/postman/scripts/delete-sunsetted-collections.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -euo pipefail + +######################################################### +# Delete Postman collections for sunsetted API versions. +# A collection is deleted when its version date is NOT in versions.json. +# +# Environment variables: +# POSTMAN_API_KEY - API Key for Postman API +# WORKSPACE_ID - Identifier for the Postman Workspace +# FULL_OPENAPI_FOLDER - Path to openapi/v2/ directory (default: ../../openapi/v2/) +# TMP_FOLDER - Folder for temporary files (default: ../tmp) +######################################################### + +FULL_OPENAPI_FOLDER=${FULL_OPENAPI_FOLDER:-"../../openapi/v2/"} +TMP_FOLDER=${TMP_FOLDER:-"../tmp"} +COLLECTIONS_LIST_FILE="${TMP_FOLDER}/collections-list-cleanup.json" +VERSIONS_JSON="${FULL_OPENAPI_FOLDER}versions.json" + +execute_curl() { + local args=("$@") + if [[ "${RUNNER_DEBUG:-0}" == "1" ]]; then + args+=("-v") + echo "Debug mode enabled - using verbose curl output" + fi + curl "${args[@]}" 2>&1 | grep -i -v "api-key\|x-api-key\|PMAK-" || true +} + +if [[ ! -f "${VERSIONS_JSON}" ]]; then + echo "ERROR: versions.json not found at ${VERSIONS_JSON}" + exit 1 +fi + +echo "Fetching list of collections from workspace" +echo "curl -o ${COLLECTIONS_LIST_FILE} --location 'https://api.getpostman.com/collections?workspace=${WORKSPACE_ID}' --header 'X-API-Key: **********'" +execute_curl --show-error --fail --silent \ + --retry 3 --retry-delay 30 --retry-max-time 1200 --retry-all-errors \ + -o "${COLLECTIONS_LIST_FILE}" \ + --location "https://api.getpostman.com/collections?workspace=${WORKSPACE_ID}" \ + --header "X-API-Key: ${POSTMAN_API_KEY}" + +if ! jq -e '.collections' "${COLLECTIONS_LIST_FILE}" > /dev/null 2>&1; then + echo "ERROR: Failed to fetch collections list - response missing 'collections' key" + exit 1 +fi + +collection_count=$(jq '.collections | length' "${COLLECTIONS_LIST_FILE}") +if [[ "${collection_count}" -eq 0 ]]; then + echo "[INFO] No collections found in workspace" + exit 0 +fi + +echo "Current collections in the workspace:" +jq '.collections[] | {id, name}' "${COLLECTIONS_LIST_FILE}" + +deleted=0 + +while IFS= read -r row; do + id=$(echo "${row}" | jq -r '.id') + name=$(echo "${row}" | jq -r '.name') + + # Never delete the starred (current) collection + if [[ "${name}" == *"⭐"* ]]; then + echo "[SKIP] Keeping starred (current) collection: ${name}" + continue + fi + + # Extract version date (YYYY-MM-DD) from the collection name + version=$(echo "${name}" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1 || true) + if [[ -z "${version}" ]]; then + echo "[SKIP] Keeping collection with no version date in name: ${name}" + continue + fi + + # Condition 1: version must NOT be in versions.json + in_versions=$(jq --arg v "${version}" 'map(select(. == $v)) | length' "${VERSIONS_JSON}") + if [[ "${in_versions}" -gt 0 ]]; then + echo "[SKIP] Keeping collection for active version ${version}: ${name}" + continue + fi + + # delete + echo "[DELETE] Removing collection: ${name} (id: ${id})" + echo "curl --request DELETE --location 'https://api.getpostman.com/collections/${id}' --header 'X-API-Key: **********'" + + http_code=$(execute_curl --silent --show-error \ + --write-out "%{http_code}" \ + -o /dev/null \ + --request DELETE \ + --location "https://api.getpostman.com/collections/${id}" \ + --header "X-API-Key: ${POSTMAN_API_KEY}") + + if [[ "${http_code}" != "200" ]]; then + echo "[ERROR] Failed to delete collection: ${name} (id: ${id}), HTTP status: ${http_code}" + else + deleted=$((deleted + 1)) + fi + +done < <(jq -c '.collections[]' "${COLLECTIONS_LIST_FILE}") + +echo "[SUMMARY] Deleted ${deleted} sunsetted collection(s)" From 11d6aed81ad9e232ee834896f0537080a84d9616 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Mon, 25 May 2026 11:55:00 +0100 Subject: [PATCH 2/3] Fix to the current script --- .github/workflows/release-postman.yml | 7 -- tools/postman/Makefile | 4 - .../scripts/delete-sunsetted-collections.sh | 101 ------------------ tools/postman/scripts/upload-collection.sh | 45 ++++---- 4 files changed, 25 insertions(+), 132 deletions(-) delete mode 100755 tools/postman/scripts/delete-sunsetted-collections.sh diff --git a/.github/workflows/release-postman.yml b/.github/workflows/release-postman.yml index 17bc600f53..4ea2d369fd 100644 --- a/.github/workflows/release-postman.yml +++ b/.github/workflows/release-postman.yml @@ -58,10 +58,3 @@ jobs: run: | make upload_collection - - name: Delete Sunsetted Collections - env: - POSTMAN_API_KEY: ${{ secrets.postman_api_key }} - WORKSPACE_ID: ${{ secrets.workspace_id }} - working-directory: ./tools/postman - run: | - make delete_sunsetted diff --git a/tools/postman/Makefile b/tools/postman/Makefile index f8ec420c3b..cff840cf7b 100644 --- a/tools/postman/Makefile +++ b/tools/postman/Makefile @@ -29,10 +29,6 @@ transform_collection_test: upload_collection: ./scripts/upload-collection.sh -.PHONY: delete_sunsetted -delete_sunsetted: - ./scripts/delete-sunsetted-collections.sh - .PHONY: build build: fetch_openapi convert_to_collection diff --git a/tools/postman/scripts/delete-sunsetted-collections.sh b/tools/postman/scripts/delete-sunsetted-collections.sh deleted file mode 100755 index e5b5015ddc..0000000000 --- a/tools/postman/scripts/delete-sunsetted-collections.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -######################################################### -# Delete Postman collections for sunsetted API versions. -# A collection is deleted when its version date is NOT in versions.json. -# -# Environment variables: -# POSTMAN_API_KEY - API Key for Postman API -# WORKSPACE_ID - Identifier for the Postman Workspace -# FULL_OPENAPI_FOLDER - Path to openapi/v2/ directory (default: ../../openapi/v2/) -# TMP_FOLDER - Folder for temporary files (default: ../tmp) -######################################################### - -FULL_OPENAPI_FOLDER=${FULL_OPENAPI_FOLDER:-"../../openapi/v2/"} -TMP_FOLDER=${TMP_FOLDER:-"../tmp"} -COLLECTIONS_LIST_FILE="${TMP_FOLDER}/collections-list-cleanup.json" -VERSIONS_JSON="${FULL_OPENAPI_FOLDER}versions.json" - -execute_curl() { - local args=("$@") - if [[ "${RUNNER_DEBUG:-0}" == "1" ]]; then - args+=("-v") - echo "Debug mode enabled - using verbose curl output" - fi - curl "${args[@]}" 2>&1 | grep -i -v "api-key\|x-api-key\|PMAK-" || true -} - -if [[ ! -f "${VERSIONS_JSON}" ]]; then - echo "ERROR: versions.json not found at ${VERSIONS_JSON}" - exit 1 -fi - -echo "Fetching list of collections from workspace" -echo "curl -o ${COLLECTIONS_LIST_FILE} --location 'https://api.getpostman.com/collections?workspace=${WORKSPACE_ID}' --header 'X-API-Key: **********'" -execute_curl --show-error --fail --silent \ - --retry 3 --retry-delay 30 --retry-max-time 1200 --retry-all-errors \ - -o "${COLLECTIONS_LIST_FILE}" \ - --location "https://api.getpostman.com/collections?workspace=${WORKSPACE_ID}" \ - --header "X-API-Key: ${POSTMAN_API_KEY}" - -if ! jq -e '.collections' "${COLLECTIONS_LIST_FILE}" > /dev/null 2>&1; then - echo "ERROR: Failed to fetch collections list - response missing 'collections' key" - exit 1 -fi - -collection_count=$(jq '.collections | length' "${COLLECTIONS_LIST_FILE}") -if [[ "${collection_count}" -eq 0 ]]; then - echo "[INFO] No collections found in workspace" - exit 0 -fi - -echo "Current collections in the workspace:" -jq '.collections[] | {id, name}' "${COLLECTIONS_LIST_FILE}" - -deleted=0 - -while IFS= read -r row; do - id=$(echo "${row}" | jq -r '.id') - name=$(echo "${row}" | jq -r '.name') - - # Never delete the starred (current) collection - if [[ "${name}" == *"⭐"* ]]; then - echo "[SKIP] Keeping starred (current) collection: ${name}" - continue - fi - - # Extract version date (YYYY-MM-DD) from the collection name - version=$(echo "${name}" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1 || true) - if [[ -z "${version}" ]]; then - echo "[SKIP] Keeping collection with no version date in name: ${name}" - continue - fi - - # Condition 1: version must NOT be in versions.json - in_versions=$(jq --arg v "${version}" 'map(select(. == $v)) | length' "${VERSIONS_JSON}") - if [[ "${in_versions}" -gt 0 ]]; then - echo "[SKIP] Keeping collection for active version ${version}: ${name}" - continue - fi - - # delete - echo "[DELETE] Removing collection: ${name} (id: ${id})" - echo "curl --request DELETE --location 'https://api.getpostman.com/collections/${id}' --header 'X-API-Key: **********'" - - http_code=$(execute_curl --silent --show-error \ - --write-out "%{http_code}" \ - -o /dev/null \ - --request DELETE \ - --location "https://api.getpostman.com/collections/${id}" \ - --header "X-API-Key: ${POSTMAN_API_KEY}") - - if [[ "${http_code}" != "200" ]]; then - echo "[ERROR] Failed to delete collection: ${name} (id: ${id}), HTTP status: ${http_code}" - else - deleted=$((deleted + 1)) - fi - -done < <(jq -c '.collections[]' "${COLLECTIONS_LIST_FILE}") - -echo "[SUMMARY] Deleted ${deleted} sunsetted collection(s)" diff --git a/tools/postman/scripts/upload-collection.sh b/tools/postman/scripts/upload-collection.sh index 59d681a567..c182568d4a 100755 --- a/tools/postman/scripts/upload-collection.sh +++ b/tools/postman/scripts/upload-collection.sh @@ -57,26 +57,6 @@ execute_curl --show-error --fail --silent -o "${COLLECTIONS_LIST_FILE}" \ collection_exists=$(jq '.collections | any(.name=="'"${current_collection_name}"'")' "${COLLECTIONS_LIST_FILE}") if [ "$collection_exists" = "false" ]; then - # Check if a collection with a star icon already exists - previous_star_collection_id=$(jq -r '.collections | map(select(.name | startswith("⭐")).id)[0] // empty' "${COLLECTIONS_LIST_FILE}") - if [[ -n "${previous_star_collection_id}" ]]; then - previous_collection_name=$(jq -r '.collections | map(select(.id=="'"${previous_star_collection_id}"'").name)[0]' "${COLLECTIONS_LIST_FILE}") - new_collection_name="${previous_collection_name//⭐/}" - - echo "Removing star icon from the previous collection name" - echo "curl -o ${COLLECTIONS_LIST_FILE} - --location 'https://api.getpostman.com/collections/${previous_star_collection_id}' - --header 'X-API-Key: **********' - --data '{\"collection\": {\"info\": {\"name\": \"${new_collection_name}\"}}}'" - - execute_curl --show-error --fail --silent --request PATCH \ - --location "https://api.getpostman.com/collections/${previous_star_collection_id}" \ - --header "Content-Type: application/json" \ - --header "X-API-Key: ${POSTMAN_API_KEY}" \ - --data "{\"collection\": {\"info\": {\"name\": \"${new_collection_name}\"}}}" - - fi - # Create new collection echo "Creating new remote collection ${current_collection_name}" echo "curl -o ${COLLECTIONS_LIST_FILE} @@ -111,4 +91,29 @@ else fi +# Delete all previous Atlas Admin API collections from the workspace. +# The current collection is excluded by name — it was either just created (not in the +# initial list) or matched by name in the update case. +deleted=0 +while IFS= read -r row; do + id=$(echo "${row}" | jq -r '.id') + name=$(echo "${row}" | jq -r '.name') + echo "Deleting old collection: ${name} (id: ${id})" + echo "curl --request DELETE --location 'https://api.getpostman.com/collections/${id}' --header 'X-API-Key: **********'" + http_code=$(execute_curl --silent --show-error \ + --write-out "%{http_code}" \ + -o /dev/null \ + --request DELETE \ + --location "https://api.getpostman.com/collections/${id}" \ + --header "X-API-Key: ${POSTMAN_API_KEY}") + if [[ "${http_code}" != "200" ]]; then + echo "[ERROR] Failed to delete old collection: ${name} (id: ${id}), HTTP status: ${http_code}" + else + deleted=$((deleted + 1)) + fi +done < <(jq -c --arg current "${current_collection_name}" \ + '.collections[] | select(.name | contains("MongoDB Atlas Administration API")) | select(.name != $current)' \ + "${COLLECTIONS_LIST_FILE}") +echo "[SUMMARY] Deleted ${deleted} old collection(s)" + popd -0 From b5527838c007fc8b4ae8b54951d405bf92cb8487 Mon Sep 17 00:00:00 2001 From: Yeliz Henden Date: Mon, 25 May 2026 12:00:24 +0100 Subject: [PATCH 3/3] revert the release-postman.yml file --- .github/workflows/release-postman.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release-postman.yml b/.github/workflows/release-postman.yml index 4ea2d369fd..35d90f6905 100644 --- a/.github/workflows/release-postman.yml +++ b/.github/workflows/release-postman.yml @@ -57,4 +57,3 @@ jobs: working-directory: ./tools/postman run: | make upload_collection -