11name : Create PR Preview
2+ description : ' Spins up an Ephemeral Instance for a PR Preview'
23
34inputs :
45 github-token :
56 description : ' Github token used to create PR comments'
67 required : true
78 localstack-api-key :
8- description : ' LocalStack API key used to create the preview environment'
9+ description : ' LocalStack Auth Token used to create the preview environment'
910 required : false
1011 preview-cmd :
1112 description : ' Command(s) used to create a preview of the PR (can use $AWS_ENDPOINT_URL)'
@@ -28,18 +29,6 @@ inputs:
2829runs :
2930 using : composite
3031 steps :
31- - run : >
32- echo "GH_ACTION_ROOT=$(
33- ls -d $(
34- ls -d ./../../_actions/* |
35- grep -i localstack |
36- tail -n1
37- )/setup-localstack/* |
38- grep -v completed |
39- tail -n1
40- )" >> $GITHUB_ENV
41- shell: bash
42-
4332 - name : Initial PR comment
4433 if : inputs.github-token
4534 uses : jenseng/dynamic-uses@5175289a9a87978dcfcb9cf512b821d23b2a53eb # v1
@@ -57,44 +46,96 @@ runs:
5746
5847 - name : Setup preview name
5948 shell : bash
49+ id : preview-name
6050 run : |
6151 prId=$(<pr-id.txt)
6252 repoName=$GITHUB_REPOSITORY
6353 repoNameCleaned=$(echo -n "$repoName" | tr -c '[:alnum:]' '-')
6454 previewName=preview-$repoNameCleaned-$prId
6555 echo "previewName=$previewName" >> $GITHUB_ENV
56+ echo "name=$previewName" >> $GITHUB_OUTPUT
6657
6758 - name : Create preview environment
6859 shell : bash
6960 id : create-instance
7061 run : |
62+ AUTH_HEADER="ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}"
63+ CONTENT_TYPE_HEADER="content-type: application/json"
64+ API_URL_BASE="https://api.localstack.cloud/v1/compute/instances"
65+
66+ source ${{ github.action_path }}/../retry-function.sh
67+
68+ fetch_instances() {
69+ local list_response
70+ list_response=$(curl --fail-with-body -s -X GET \
71+ -H "$AUTH_HEADER" \
72+ -H "$CONTENT_TYPE_HEADER" \
73+ "$API_URL_BASE")
74+ if [ $? -ne 0 ]; then echo "curl command failed while fetching instances. Response: $list_response" >&2; return 1; fi
75+ if ! check_for_api_error "$list_response" "fetch instances"; then return 1; fi
76+ echo "$list_response"
77+ }
78+
79+ if ! list_response=$(retry fetch_instances); then
80+ echo "Error: Failed to fetch instances after multiple retries."
81+ exit 1
82+ fi
83+
7184 autoLoadPod="${AUTO_LOAD_POD:-${{ inputs.auto-load-pod }}}"
7285 extensionAutoInstall="${EXTENSION_AUTO_INSTALL:-${{ inputs.extension-auto-install }}}"
7386 lifetime="${{ inputs.lifetime }}"
7487
75- list_response=$(curl -X GET \
76- -H "ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}" \
77- -H "content-type: application/json" \
78- https://api.localstack.cloud/v1/compute/instances)
79-
8088 instance_exists=$(echo "$list_response" | jq --arg NAME "$previewName" '.[] | select(.instance_name == $NAME)')
8189
90+ delete_instance() {
91+ # We expect a 200 on success or 404 if it's already gone. Other codes are errors.
92+ local response
93+ response=$(curl --fail-with-body -s -w "\n%{http_code}" -X DELETE \
94+ -H "$AUTH_HEADER" \
95+ -H "$CONTENT_TYPE_HEADER" \
96+ "$API_URL_BASE/$previewName")
97+ local exit_code=$?
98+ local http_code=$(echo "$response" | tail -n1)
99+ local body=$(echo "$response" | sed '$d')
100+
101+ if [ $exit_code -ne 0 ]; then echo "curl command failed while deleting instance. Response: $body" >&2; return 1; fi
102+ if ! check_for_api_error "$body" "delete instance"; then return 1; fi
103+
104+ if [ "$http_code" -eq 200 ]; then
105+ echo "Instance '$previewName' deleted successfully."
106+ fi
107+ }
108+
82109 if [ -n "$instance_exists" ]; then
83- del_response=$(curl -X DELETE \
84- -H "ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}" \
85- -H "content-type: application/json" \
86- https://api.localstack.cloud/v1/compute/instances/$previewName)
110+ echo "Found existing instance using '$previewName', trying to delete the old one..."
111+ if ! retry delete_instance; then
112+ echo "Error: Failed to delete existing instance after multiple retries."
113+ exit 1
114+ fi
87115 fi
88116
89- response=$(curl -X POST -d "{\"instance_name\": \"${previewName}\", \"lifetime\": ${lifetime} ,\"env_vars\": {\"AUTO_LOAD_POD\": \"${autoLoadPod}\", \"EXTENSION_AUTO_INSTALL\": \"${extensionAutoInstall}\"}}"\
90- -H "ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}" \
91- -H "content-type: application/json" \
92- https://api.localstack.cloud/v1/compute/instances)
93- endpointUrl=$(echo "$response" | jq -r .endpoint_url)
94- if [ "$endpointUrl" = "null" ] || [ "$endpointUrl" = "" ]; then
95- echo "Unable to create preview environment. API response: $response"
117+ create_instance_func() {
118+ local response
119+ response=$(curl --fail-with-body -s -X POST -d "{\"instance_name\": \"${previewName}\", \"lifetime\": ${lifetime} ,\"env_vars\": {\"AUTO_LOAD_POD\": \"${autoLoadPod}\", \"EXTENSION_AUTO_INSTALL\": \"${extensionAutoInstall}\"}}"\
120+ -H "$AUTH_HEADER" \
121+ -H "$CONTENT_TYPE_HEADER" \
122+ "$API_URL_BASE")
123+ if [ $? -ne 0 ]; then echo "curl command failed while creating instance. Response: $response" >&2; return 1; fi
124+ if ! check_for_api_error "$response" "create instance"; then return 1; fi
125+ if ! echo "$response" | jq -e 'has("endpoint_url") and (.endpoint_url | test(".+"))' > /dev/null; then
126+ echo "Invalid response from instance creation API: $response" >&2; return 1;
127+ fi
128+ echo "$response"
129+ }
130+
131+ echo "Creating preview environment ..."
132+ if ! response=$(retry create_instance_func); then
133+ echo "Error: Failed to create preview environment after multiple retries."
96134 exit 1
97135 fi
136+
137+ endpointUrl=$(echo "$response" | jq -r .endpoint_url)
138+
98139 echo "Created preview environment with endpoint URL: $endpointUrl"
99140
100141 echo $endpointUrl > ./ls-preview-url.txt
@@ -110,16 +151,46 @@ runs:
110151 - name : Run preview deployment
111152 if : ${{ inputs.preview-cmd != '' }}
112153 shell : bash
113- run :
154+ run : |
114155 ${{ inputs.preview-cmd }}
115156
116157 - name : Print logs of ephemeral instance
117158 if : ${{ !cancelled() && steps.create-instance.outcome == 'success' }}
118159 shell : bash
160+ env :
161+ previewName : ${{ steps.preview-name.outputs.name }}
119162 run : |
120- log_response=$(curl -X GET \
121- -H "ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}" \
122- -H "content-type: application/json" \
123- https://api.localstack.cloud/v1/compute/instances/$previewName/logs)
124-
163+ AUTH_HEADER="ls-api-key: ${LOCALSTACK_AUTH_TOKEN:-${LOCALSTACK_API_KEY:-${{ inputs.localstack-api-key }}}}"
164+ CONTENT_TYPE_HEADER="content-type: application/json"
165+ API_URL_BASE="https://api.localstack.cloud/v1/compute/instances"
166+
167+ source ${{ github.action_path }}/../retry-function.sh
168+ fetch_logs() {
169+ local log_response
170+ log_response=$(curl --fail-with-body -s -X GET \
171+ -H "$AUTH_HEADER" \
172+ -H "$CONTENT_TYPE_HEADER" \
173+ "$API_URL_BASE/$previewName/logs")
174+ if [ $? -ne 0 ]; then echo "curl command failed while fetching logs. Response: $log_response" >&2; return 1; fi
175+ if ! check_for_api_error "$log_response" "fetch logs"; then return 1; fi
176+
177+ # A valid log response must be a JSON array.
178+ if ! echo "$log_response" | jq -e 'if type == "array" then true else false end' > /dev/null; then
179+ echo "Invalid response from logs API (expected a JSON array): $log_response" >&2; return 1;
180+ fi
181+
182+ # Check if the logs contain the "Ready." message, indicating the instance is fully started.
183+ if ! echo "$log_response" | jq -e '.[] | select(.content | contains("Ready."))' > /dev/null; then
184+ echo "Instance is not ready yet, waiting for 'Ready.' message in logs..." >&2
185+ return 1
186+ fi
187+
188+ echo "$log_response"
189+ }
190+ echo "Fetching logs for $previewName ..."
191+ if ! log_response=$(retry fetch_logs); then
192+ echo "Error: Failed to fetch logs after multiple retries."
193+ exit 1
194+ fi
195+ echo "$previewName logs:"
125196 echo "$log_response" | jq -r '.[].content'
0 commit comments