Skip to content

Commit

Permalink
Merge pull request #62 from mcncl/master
Browse files Browse the repository at this point in the history
SUP-2785 – Support WAITing for build result
  • Loading branch information
mcncl authored Dec 2, 2024
2 parents 5ba18b2 + 4fa24ec commit 3b5d980
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 19 deletions.
30 changes: 11 additions & 19 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,19 @@ jobs:
- name: Verify that the Docker image for the action builds
run: docker build . --file Dockerfile

- name: Run action with minimal parameters
uses: ./
- uses: mcncl/trigger-pipeline-action@master
id: buildkite
with:
buildkite_api_access_token: ${{ secrets.BUILDKITE_API_ACCESS_TOKEN }}
pipeline: "lzrinc/experimental-pipeline"
message: Triggered from GHA using minimal parameters
branch: master
commit: HEAD
buildkite_api_access_token: ${{ secrets.BUILDKITE_TOKEN }}
pipeline: "testkite/basic-pipeline"
wait: true
wait_interval: 10
wait_timeout: 300

- name: Run action with all parameters
uses: ./
id: tests
with:
buildkite_api_access_token: ${{ secrets.BUILDKITE_API_ACCESS_TOKEN }}
pipeline: "lzrinc/experimental-pipeline"
branch: dev
commit: HEAD
message: ":buildkite::github: 🚀🚀🚀 Triggered from GHA using commit message: ${{ github.event.head_commit.message }}"
build_env_vars: '{"TRIGGERED_FROM_GHA": "true"}'
build_meta_data: '{"FOO": "bar"}'
ignore_pipeline_branch_filter: true
- name: Check Build State
run: |
echo "Build URL: ${{ steps.buildkite.outputs.url }}"
echo "Build State: ${{ steps.buildkite.outputs.state }}"
- name: Verify output
run: echo ${{join(steps.tests.outputs.*, '\n')}}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ steps:
build_meta_data: '{"FOO": "bar"}'
ignore_pipeline_branch_filter: true
send_pull_request: true
wait: true
wait_interval: 10
wait_timeout: 300
```

## Outputs
Expand Down
20 changes: 20 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,30 @@ inputs:
ignore_pipeline_branch_filter:
description: 'Ignore pipeline branch filtering when creating a new build. true or false'
required: false
wait:
description: 'Wait for the build to finish before completing. true or false'
required: false
default: 'false'
wait_interval:
description: 'Interval in seconds between build status checks when waiting'
required: false
default: '10'
wait_timeout:
description: 'Maximum time in seconds to wait for build completion'
required: false
default: '3600'

runs:
using: 'docker'
image: 'Dockerfile'
branding:
icon: 'send'
color: 'green'

outputs:
json:
description: 'The full JSON response from the Buildkite API'
url:
description: 'The URL of the build on Buildkite'
state:
description: 'The final state of the build (when wait=true)'
73 changes: 73 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,68 @@ function get_INPUT_BUILD_ENV_VARS_json() {
echo "$INPUT_BUILD_ENV_VARS"
}

function wait_for_build() {
local BUILD_ID
local ORG_SLUG
local PIPELINE_SLUG
local WAIT_INTERVAL
local WAIT_TIMEOUT
local START_TIME
local CURRENT_TIME
local ELAPSED_TIME
local BUILD_STATE

BUILD_ID="$1"
ORG_SLUG="$2"
PIPELINE_SLUG="$3"
WAIT_INTERVAL="${4:-10}"
WAIT_TIMEOUT="${5:-3600}"

echo "Waiting for build $BUILD_ID to complete..."
START_TIME=$(date +%s)

while true; do
CURRENT_TIME=$(date +%s)
ELAPSED_TIME=$((CURRENT_TIME - START_TIME))

if [ "$ELAPSED_TIME" -gt "$WAIT_TIMEOUT" ]; then
echo "Timeout reached after ${WAIT_TIMEOUT} seconds"
return 1
fi

BUILD_RESPONSE=$(curl \
--fail-with-body \
--silent \
--show-error \
-H "Authorization: Bearer ${INPUT_BUILDKITE_API_ACCESS_TOKEN}" \
"https://api.buildkite.com/v2/organizations/${ORG_SLUG}/pipelines/${PIPELINE_SLUG}/builds/${BUILD_ID}")

BUILD_STATE=$(echo "$BUILD_RESPONSE" | jq -r .state)

case "$BUILD_STATE" in
"passed")
echo "Build passed!"
echo "build_state=$BUILD_STATE" >>"${GITHUB_OUTPUT}"
return 0
;;
"failed"|"canceled"|"skipped"|"blocked")
echo "Build finished with state: $BUILD_STATE"
echo "build_state=$BUILD_STATE" >>"${GITHUB_OUTPUT}"
return 1
;;
"running"|"scheduled"|"waiting"|"waiting_failed")
echo "Build status: $BUILD_STATE. Waiting ${WAIT_INTERVAL} seconds..."
sleep "$WAIT_INTERVAL"
;;
*)
echo "Unknown build state: $BUILD_STATE"
echo "build_state=$BUILD_STATE" >>"${GITHUB_OUTPUT}"
return 1
;;
esac
done
}

if [[ -z "${INPUT_BUILDKITE_API_ACCESS_TOKEN:-}" ]]; then
echo "You must set the buildkite_api_access_token input parameter (e.g. buildkite_api_access_token: \"1234567890\")"
exit 1
Expand Down Expand Up @@ -176,6 +238,17 @@ echo "Build created:"
URL=$(echo "$RESPONSE" | jq --raw-output ".web_url")
echo "$URL"

# Extract build number from response
BUILD_NUMBER=$(echo "$RESPONSE" | jq --raw-output ".number")

# Wait for build if requested
if [[ "${INPUT_WAIT:-false}" == 'true' ]]; then
if ! wait_for_build "$BUILD_NUMBER" "$ORG_SLUG" "$PIPELINE_SLUG" "${INPUT_WAIT_INTERVAL:-10}" "${INPUT_WAIT_TIMEOUT:-3600}"; then
echo "Build did not complete successfully"
exit 1
fi
fi

# Provide JSON and Web URL as outputs for downstream actions
# use environment variable $GITHUB_OUTPUT, or fall back to deprecated set-output command
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
Expand Down
61 changes: 61 additions & 0 deletions tests/entrypoint.bats
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,64 @@ teardown() {

unstub curl
}

@test "Waits for build to complete successfully" {
export INPUT_BUILDKITE_API_ACCESS_TOKEN="123"
export INPUT_PIPELINE="my-org/my-pipeline"
export INPUT_WAIT="true"
export INPUT_WAIT_INTERVAL="1"
export GITHUB_EVENT_NAME="create"

EXPECTED_JSON='{"commit":"a-sha","branch":"a-branch","message":"","author":{"name":"The Pusher","email":"pusher@pusher.com"},"env":{"GITHUB_REPOSITORY":"buildkite/test-repo","SOURCE_REPO_SHA":"a-sha","SOURCE_REPO_REF":"a-branch"}}'
CREATE_RESPONSE='{"web_url": "https://buildkite.com/build-url", "number": "123"}'
STATUS_RESPONSE_RUNNING='{"state": "running"}'
STATUS_RESPONSE_PASSED='{"state": "passed"}'

# Stub curl to handle both the create build call and the status check calls
stub curl \
"--fail-with-body --silent --show-error -X POST -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds -d '$EXPECTED_JSON' : echo '$CREATE_RESPONSE'" \
"--fail-with-body --silent --show-error -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds/123 : echo '$STATUS_RESPONSE_RUNNING'" \
"--fail-with-body --silent --show-error -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds/123 : echo '$STATUS_RESPONSE_PASSED'"

run "${PWD}"/entrypoint.sh

assert_output --partial "Build created:"
assert_output --partial "https://buildkite.com/build-url"
assert_output --partial "Waiting for build 123 to complete..."
assert_output --partial "Build status: running"
assert_output --partial "Build passed!"
assert_success

unstub curl
}

@test "Exits with failure when waited build fails" {
export INPUT_BUILDKITE_API_ACCESS_TOKEN="123"
export INPUT_PIPELINE="my-org/my-pipeline"
export INPUT_WAIT="true"
export INPUT_WAIT_INTERVAL="1"
export GITHUB_EVENT_NAME="create"

EXPECTED_JSON='{"commit":"a-sha","branch":"a-branch","message":"","author":{"name":"The Pusher","email":"pusher@pusher.com"},"env":{"GITHUB_REPOSITORY":"buildkite/test-repo","SOURCE_REPO_SHA":"a-sha","SOURCE_REPO_REF":"a-branch"}}'
CREATE_RESPONSE='{"web_url": "https://buildkite.com/build-url", "number": "123"}'
STATUS_RESPONSE_RUNNING='{"state": "running"}'
STATUS_RESPONSE_FAILED='{"state": "failed"}'

# Stub curl to handle both the create build call and the status check calls
stub curl \
"--fail-with-body --silent --show-error -X POST -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds -d '$EXPECTED_JSON' : echo '$CREATE_RESPONSE'" \
"--fail-with-body --silent --show-error -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds/123 : echo '$STATUS_RESPONSE_RUNNING'" \
"--fail-with-body --silent --show-error -H \"Authorization: Bearer 123\" https://api.buildkite.com/v2/organizations/my-org/pipelines/my-pipeline/builds/123 : echo '$STATUS_RESPONSE_FAILED'"

run "${PWD}"/entrypoint.sh

assert_output --partial "Build created:"
assert_output --partial "https://buildkite.com/build-url"
assert_output --partial "Waiting for build 123 to complete..."
assert_output --partial "Build status: running"
assert_output --partial "Build finished with state: failed"
assert_output --partial "Build did not complete successfully"
assert_failure

unstub curl
}

0 comments on commit 3b5d980

Please sign in to comment.