@@ -13,56 +13,102 @@ jobs:
13
13
FLINK_PROFILE : [flink-1.19, flink-1.20]
14
14
15
15
steps :
16
- - name : Delete GHCR image
16
+ - name : Delete GHCR image via GitHub GraphQL API
17
+ env :
18
+ GH_USERNAME : ${{ secrets.PAT_USERNAME }}
19
+ GH_PASSWORD : ${{ secrets.PAT_PASSWORD }}
17
20
run : |
18
21
set -euxo pipefail
19
22
20
- REPO="datasqrl/flink-sql-runner"
23
+ OWNER="datasqrl"
24
+ PACKAGE_NAME="flink-sql-runner"
21
25
TAG="pr-${{ github.event.number }}-${{ matrix.FLINK_PROFILE }}"
22
- IMAGE="ghcr.io/$REPO:$TAG"
23
26
24
- echo "Attempting to delete image: $IMAGE "
27
+ echo "🔐 Authenticating and generating bearer token for GitHub GraphQL API... "
25
28
26
- TOKEN_BASE64="$(echo -n "${{ secrets.PAT_USERNAME }}:${{ secrets.PAT_PASSWORD }}" | base64)"
29
+ # Get GitHub API token using basic auth
30
+ BEARER_TOKEN=$(curl -s -u "$GH_USERNAME:$GH_PASSWORD" \
31
+ -H "Content-Type: application/json" \
32
+ -d '{"scopes":["read:packages", "delete:packages"],"note":"Delete GHCR action"}' \
33
+ https://api.github.com/authorizations | jq -r '.token')
27
34
28
- RAW_RESPONSE=$(curl -sD - \
29
- -H "Authorization: Basic $TOKEN_BASE64" \
30
- -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.docker.distribution.manifest.v2+json" \
31
- "https://ghcr.io/v2/$REPO/manifests/$TAG")
32
-
33
- # Immediately check HTTP status
34
- STATUS_CODE=$(echo "$RAW_RESPONSE" | grep HTTP | awk '{print $2}' | tr -d $'\r')
35
-
36
- if [[ "$STATUS_CODE" -eq 401 ]]; then
37
- echo "ERROR: Unauthorized (401). Check your PAT credentials or GHCR permissions."
38
- exit 1
39
- elif [[ "$STATUS_CODE" -eq 404 ]]; then
40
- echo "ERROR: Image not found (404). Check your image name or tag."
41
- exit 1
42
- elif [[ "$STATUS_CODE" -ge 400 ]]; then
43
- echo "ERROR: Unexpected error occurred. HTTP status: $STATUS_CODE"
35
+ if [[ -z "$BEARER_TOKEN" || "$BEARER_TOKEN" == "null" ]]; then
36
+ echo "❌ Failed to acquire bearer token."
44
37
exit 1
45
38
fi
46
39
47
- HEADERS=$(echo "$RAW_RESPONSE" | sed -n '/^HTTP/,$p' | sed '/^$/q')
48
- DIGEST=$(echo "$HEADERS" | awk '/docker-content-digest:/ { print $2 }' | tr -d $'\r')
40
+ echo "🔍 Searching for GHCR package version with tag: $TAG"
41
+
42
+ QUERY=$(jq -nc --arg owner "$OWNER" --arg name "$PACKAGE_NAME" '
43
+ {
44
+ query: "query($owner:String!, $name:String!) {
45
+ repository(owner: $owner, name: $name) {
46
+ packages(first: 50, packageType: CONTAINER, names: [\"flink-sql-runner\"]) {
47
+ nodes {
48
+ name
49
+ versions(first: 100) {
50
+ nodes {
51
+ id
52
+ version
53
+ tags
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }",
60
+ variables: {
61
+ owner: $owner,
62
+ name: $name
63
+ }
64
+ }')
65
+
66
+ RESPONSE=$(curl -s \
67
+ -H "Authorization: Bearer $BEARER_TOKEN" \
68
+ -H "Content-Type: application/json" \
69
+ -H "Accept: application/vnd.github.package-deletes-preview+json" \
70
+ -d "$QUERY" https://api.github.com/graphql)
49
71
50
- if [[ -z "$DIGEST" ]]; then
51
- echo "ERROR: No digest found. Response headers were:"
52
- echo "$HEADERS"
72
+ echo "GraphQL query result:"
73
+ echo "$RESPONSE" | jq
74
+
75
+ PACKAGE_VERSION_ID=$(echo "$RESPONSE" | jq -r \
76
+ --arg TAG "$TAG" \
77
+ '.data.repository.packages.nodes[].versions.nodes[]
78
+ | select(.tags[]? == $TAG)
79
+ | .id')
80
+
81
+ if [[ -z "$PACKAGE_VERSION_ID" || "$PACKAGE_VERSION_ID" == "null" ]]; then
82
+ echo "❌ No matching package version found for tag $TAG"
53
83
exit 1
54
84
fi
55
85
56
- echo "Found digest: $DIGEST"
86
+ echo "✅ Found package version ID: $PACKAGE_VERSION_ID"
87
+
88
+ DELETE_MUTATION=$(jq -nc --arg id "$PACKAGE_VERSION_ID" '
89
+ {
90
+ query: "mutation($id: ID!) {
91
+ deletePackageVersion(input: {packageVersionId: $id}) {
92
+ success
93
+ }
94
+ }",
95
+ variables: { id: $id }
96
+ }')
97
+
98
+ DELETE_RESPONSE=$(curl -s \
99
+ -H "Authorization: Bearer $BEARER_TOKEN" \
100
+ -H "Content-Type: application/json" \
101
+ -H "Accept: application/vnd.github.package-deletes-preview+json" \
102
+ -d "$DELETE_MUTATION" https://api.github.com/graphql)
103
+
104
+ echo "Delete mutation result:"
105
+ echo "$DELETE_RESPONSE" | jq
57
106
58
- DELETE_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
59
- -X DELETE \
60
- -H "Authorization: Basic $TOKEN_BASE64" \
61
- "https://ghcr.io/v2/$REPO/manifests/$DIGEST")
107
+ SUCCESS=$(echo "$DELETE_RESPONSE" | jq -r '.data.deletePackageVersion.success')
62
108
63
- if [[ "$DELETE_STATUS" -ge 200 && "$DELETE_STATUS" -lt 300 ]]; then
64
- echo "Image deleted successfully (HTTP $DELETE_STATUS). "
109
+ if [[ "$SUCCESS" == "true" ]]; then
110
+ echo "✅ Successfully deleted image with tag $TAG "
65
111
else
66
- echo "ERROR: Failed to delete image. HTTP status $DELETE_STATUS "
112
+ echo "❌ Failed to delete image with tag $TAG "
67
113
exit 1
68
114
fi
0 commit comments