diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 00635f9..8190aa5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,2 @@ * @kamilchodola +* @lucasssvaz diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5104149..01f18ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,25 +19,27 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Trigger another workflow uses: benc-uk/workflow-dispatch@v1 with: workflow: to_be_triggered.yml - token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} ref: "${{ inputs.ref || github.ref }}" - name: Wait for the triggered workflow to complete run: | chmod +x scripts/wait-for-workflow.sh - export GITHUB_TOKEN="${{ secrets.REPOSITORY_DISPATCH_TOKEN }}" - export WORKFLOW_ID="to_be_triggered.yml" + export GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" + export WORKFLOW_NAME="to_be_triggered.yml" export RUN_ID="${{ inputs.run_id }}" - export MAX_WAIT_MINUTES="2" + export MAX_WAIT="2" export INTERVAL="5" export TIMEOUT="5" - export ORG_NAME="kamilchodola" - export REPO_NAME="wait-for-workflow-action" + export REPOSITORY="${{ github.repository }}" export REF="${{ inputs.ref || github.ref }}" + export VERBOSE="true" ./scripts/wait-for-workflow.sh + echo "Run ID: $WORKFLOW_RUN_ID" + echo "Conclusion: $WORKFLOW_CONCLUSION" diff --git a/.github/workflows/to_be_triggered.yml b/.github/workflows/to_be_triggered.yml index 58b2c16..0155268 100644 --- a/.github/workflows/to_be_triggered.yml +++ b/.github/workflows/to_be_triggered.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Run a basic shell script run: | diff --git a/LICENSE b/LICENSE index 3a279ed..e7f47b8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2023 Kamil Chodoła +Modified by: Lucas Saavedra Vaz (2024) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8488d46..3f75321 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,29 @@ # Wait for Workflow Action -[![Test WaitForWorkflow](https://github.com/kamilchodola/wait-for-workflow-action/actions/workflows/test.yml/badge.svg)](https://github.com/kamilchodola/wait-for-workflow-action/actions/workflows/test.yml) +[![Test WaitForWorkflow](https://github.com/lucasssvaz/wait-for-workflow-action/actions/workflows/test.yml/badge.svg)](https://github.com/lucasssvaz/wait-for-workflow-action/actions/workflows/test.yml) This GitHub Action waits for a specified workflow to complete before proceeding with the next steps in your workflow. It is useful when you have dependent workflows and want to ensure that one completes successfully before continuing with the next. For example, you might want to ensure that a build or test workflow finishes successfully before starting a deployment workflow. ## Inputs -| Input | Description | Required | Default | -|------------------|-----------------------------------------------------|----------|---------| -| `GITHUB_TOKEN` | GitHub token to access the repository and its APIs | Yes | | -| `workflow_id` | ID of the workflow to wait for | No | | -| `run_id` | If provided will wait for workflow run with specified id | No | | -| `max_wait_minutes`| Maximum time script will wait to workflow run to be found in minutes | No | 5 | -| `interval`| Interval in seconds which will be used for GitHub API calls | No | 10 | -| `timeout`| Maximum time script will wait to workflow run to be finished | No | 30 | -| `org_name` | Organization name where the repository is located | Yes | | -| `repo_name` | Repository name to monitor for the workflow run | Yes | | -| `ref` | Branch reference to watch for the workflow run | No | | +| Input | Description | Required | Default | +|-----------------|---------------------------------------------------------------------------------|----------------------------------|----------------------------| +| `github-token` | GitHub token to access the repository and its APIs | No | `${{ github.token }}` | +| `workflow_name` | File name of the workflow to wait for | Yes (No if `run_id` is provided) | | +| `run_id` | Wait for a specific run ID | No | | +| `max_wait` | Maximum time the script will wait for the workflow run to be found (minutes) | No | `5` | +| `interval` | Interval between checking workflow status (seconds) | No | `10` | +| `timeout` | Maximum time the script will wait for the workflow run to be finished (minutes) | No | `30` | +| `repository` | Repository name with owner | No | `${{ github.repository }}` | +| `ref` | Branch reference to watch for the workflow run | No | `${{ github.ref }}` | +| `verbose` | Enable verbose output | No | `false` | + +## Outputs + +| Output | Description | +|--------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| `run_id` | ID of the workflow run that was waited for | +| `conclusion` | Conclusion of the workflow run. Can be one of the `success`, `failure`, `neutral`, `cancelled`, `skipped`, `timed_out`, or `action_required` | ## How It Works @@ -24,18 +31,15 @@ This action performs the following steps: 1. Retrieves the current time in ISO 8601 format. 2. Loops until the specified workflow is triggered: - - Sends a request to the GitHub API to get the list of workflow runs for the specified workflow ID. + - Sends a request to the GitHub API to get the list of workflow runs for the specified `workflow_name`. - Filters the list of workflow runs based on the provided `ref` (branch) and the run creation time. - Checks if the maximum waiting time has been reached. If so, exits with an error message. - - Sleeps for 30 seconds before checking again if the workflow has been triggered. -3. Once the workflow is triggered, loops until the workflow run is completed: + - Sleeps for `interval` seconds before checking again if the workflow has been triggered. +3. Once the workflow is triggered, sets the `run_id` output and loops until the workflow run is completed: - Sends a request to the GitHub API to get the status of the specified workflow run. - Checks if the status is "completed". If so, proceeds to the next step. - - Sleeps for 30 seconds before checking again if the workflow has been completed. -4. When the workflow run is completed, checks its conclusion: - - If the conclusion is "success", the action exits successfully. - - If the conclusion is anything other than "success", the action exits with an error message. - + - Sleeps for `interval` seconds before checking again if the workflow has been completed. +4. When the workflow run is completed, sets the `conclusion` output to the conclusion of the workflow run. ## Usage @@ -43,33 +47,49 @@ To use this action, add it to your workflow file with the appropriate inputs: ```yaml - name: Wait for Workflow Action - uses: kamilchodola/wait-for-workflow-action@1.1.0 + uses: lucasssvaz/wait-for-workflow-action@v2 with: - GITHUB_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} - workflow_id: 'workflow_name.yml' - max_wait_minutes: '3' - interval: '5' - timeout: '60' - org_name: 'your-organization' - repo_name: 'your-repository' - ref: '${{ github.ref }}' + github-token: ${{ secrets.GITHUB_TOKEN }} + workflow_name: workflow.yml + max_wait: 3 + interval: 5 + timeout: 60 + ref: ${{ github.ref }} ``` -In case, you already have run_id, you can pass it this way: +In case, you already have a workflow run ID, you can pass it this way: ```yaml - name: Wait for Workflow Action - uses: kamilchodola/wait-for-workflow-action@1.1.0 + uses: lucasssvaz/wait-for-workflow-action@v2 with: - GITHUB_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} - workflow_id: 'workflow_name.yml' + github-token: ${{ secrets.GITHUB_TOKEN }} run_id: '123123' - org_name: 'your-organization' - repo_name: 'your-repository' ref: '${{ github.ref }}' ``` +To access the outputs of this action, you can use the `id` specified in the action step: + +```yaml +- name: Wait for Workflow Action + uses: lucasssvaz/wait-for-workflow-action@v2 + id: wait-for-workflow + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + workflow_name: workflow.yml + max_wait: 3 + interval: 5 + timeout: 60 + ref: ${{ github.ref }} + +- name: Get the workflow run ID + run: | + echo "Workflow run ID: ${{ steps.wait-for-workflow.outputs.run_id }}" + echo "Workflow conclusion: ${{ steps.wait-for-workflow.outputs.conclusion }}" +``` + ## Notes +- At least one of the `workflow_name` or `run_id` inputs must be provided. If both are provided, the action will use the `run_id` input. - If the `ref` input is not provided or is left empty, the action will use the current `github.ref` as the branch reference. This is useful when you want to wait for a workflow run on the same branch that triggered the current workflow. -- The maximum wait time is specified in minutes. The default value is 3 minutes if not provided. If the workflow has not been triggered or completed after the specified maximum wait time, the action will exit with an error. You can increase this value if you expect the workflow to take longer to start or complete. Keep in mind that the GitHub Actions runner has a default timeout of 6 hours for a job, so ensure your wait time falls within this limit. +- The maximum wait time is specified in minutes. If the workflow has not been triggered or completed after the specified maximum wait time, the action will exit with an error. You can increase this value if you expect the workflow to take longer to start or complete. Keep in mind that the GitHub Actions runner has a default timeout of 6 hours for a job, so ensure your wait time falls within this limit. diff --git a/action.yml b/action.yml index 783784a..bcaab9d 100644 --- a/action.yml +++ b/action.yml @@ -1,55 +1,60 @@ -name: 'Wait for Workflow Action' +name: "Wait for Workflow Action" branding: - icon: 'clock' - color: 'blue' -description: 'Waits for a specified workflow to complete before proceeding' + icon: "clock" + color: "blue" +description: "Waits for a specified workflow to complete before proceeding" inputs: - GITHUB_TOKEN: - description: 'GitHub token to access the repository' - required: true - workflow_id: - description: 'ID of the workflow to wait for' - required: false + github-token: + description: "GitHub token to access the repository" + default: "${{ github.token }}" + workflow_name: + description: "File name of the workflow to wait for" run_id: - description: 'If provided will wait for workflow run with specified id' - required: false - max_wait_minutes: - description: 'Maximum time script will wait to workflow run to be found in minutes' - required: false - default: '5' + description: "Wait for a specific run ID" + max_wait: + description: "Maximum time the script will wait for the workflow run to be found (minutes)" + default: 5 interval: - description: 'Interval in seconds which will be used for GitHub API calls' - required: false - default: '10' + description: "Interval between checking workflow status (seconds)" + default: 10 timeout: - description: 'Maximum time script will wait to workflow run to be finished' - required: false - default: '30' - org_name: - description: 'GitHub organization name' - required: true - repo_name: - description: 'GitHub repository name' - required: true + description: "Maximum time the script will wait for the workflow run to be finished (minutes)" + default: 30 + repository: + description: "Repository name with owner" + default: "${{ github.repository }}" ref: - description: 'Branch reference (if empty, ref selected for trigger would be taken)' - required: false - default: '' + description: "Branch reference to watch for the workflow run" + default: "${{ github.ref }}" + verbose: + description: "Enable verbose output" + default: false +outputs: + run_id: + description: "ID of the workflow run" + value: ${{ steps.wait-for-workflow.outputs.run_id }} + conclusion: + description: "Conclusion of the workflow run. Can be one of the `success`, `failure`, `neutral`, `cancelled`, `skipped`, `timed_out`, or `action_required`" + value: ${{ steps.wait-for-workflow.outputs.conclusion }} runs: - using: 'composite' + using: "composite" steps: - name: Set execute permissions for script run: chmod +x ${{ github.action_path }}/scripts/wait-for-workflow.sh shell: bash - - run: ${{ github.action_path }}/scripts/wait-for-workflow.sh + - id: wait-for-workflow shell: bash env: - GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} - WORKFLOW_ID: ${{ inputs.workflow_id }} + GITHUB_TOKEN: ${{ inputs.github-token }} + WORKFLOW_NAME: ${{ inputs.workflow_name }} RUN_ID: ${{ inputs.run_id }} - MAX_WAIT_MINUTES: ${{ inputs.max_wait_minutes }} + MAX_WAIT: ${{ inputs.max_wait }} INTERVAL: ${{ inputs.interval }} TIMEOUT: ${{ inputs.timeout }} - ORG_NAME: ${{ inputs.org_name }} - REPO_NAME: ${{ inputs.repo_name }} - REF: ${{ inputs.ref || github.ref }} + REPOSITORY: ${{ inputs.repository }} + REF: ${{ inputs.ref }} + VERBOSE: ${{ inputs.verbose }} + run: | + ${{ github.action_path }}/scripts/wait-for-workflow.sh + echo "run_id=$(echo $WORKFLOW_RUN_ID)" >> $GITHUB_OUTPUT + echo "conclusion=$(echo $WORKFLOW_CONCLUSION)" >> $GITHUB_OUTPUT diff --git a/scripts/wait-for-workflow.sh b/scripts/wait-for-workflow.sh index b91ffee..b67bb0b 100644 --- a/scripts/wait-for-workflow.sh +++ b/scripts/wait-for-workflow.sh @@ -1,7 +1,7 @@ #!/bin/bash # Set the maximum waiting time (in minutes) and initialize the counter -max_wait_minutes="${MAX_WAIT_MINUTES}" +max_wait="${MAX_WAIT}" timeout="${TIMEOUT}" interval="${INTERVAL}" counter=0 @@ -14,33 +14,52 @@ if [[ ! "$REF" =~ ^refs/heads/ ]]; then REF="refs/heads/$REF" fi -echo "ℹ️ Organization: ${ORG_NAME}" -echo "ℹ️ Repository: ${REPO_NAME}" -echo "ℹ️ Reference: $REF" -echo "ℹ️ Maximum wait time: ${max_wait_minutes} minutes" -echo "ℹ️ Timeout for the workflow to complete: ${timeout} minutes" -echo "ℹ️ Interval between checks: ${interval} seconds" +if [ "$VERBOSE" == "true" ]; then + echo "ℹ️ Inputs:" + echo "ℹ️ Run ID: ${RUN_ID}" + echo "ℹ️ Workflow Name: ${WORKFLOW_NAME}" + echo "ℹ️ Repository: ${REPOSITORY}" + echo "ℹ️ Reference: $REF" + echo "ℹ️ Maximum wait time: ${max_wait} minutes" + echo "ℹ️ Timeout for the workflow to complete: ${timeout} minutes" + echo "ℹ️ Interval between checks: ${interval} seconds" + echo "ℹ️ Verbose: ${VERBOSE}" +fi + +# Check if either run_id or workflow_name is provided +if [ -z "${RUN_ID}" ] && [ -z "${WORKFLOW_NAME}" ]; then + echo "❌ Either Run ID or Workflow Name must be provided. Exiting." + exit 1 +fi # If RUN_ID is not empty, use it directly if [ -n "${RUN_ID}" ]; then run_id="${RUN_ID}" - echo "ℹ️ Using provided Run ID: $run_id" + if [ "$VERBOSE" == "true" ]; then + echo "ℹ️ Using provided Run ID: $run_id" + fi else - workflow_id="${WORKFLOW_ID}" # Id of the target workflow - echo "ℹ️ Workflow ID: $workflow_id" + workflow_name="${WORKFLOW_NAME}" # Name of the target workflow + if [ "$VERBOSE" == "true" ]; then + echo "ℹ️ Workflow Name: $workflow_name" + fi # Wait for the workflow to be triggered while true; do - echo "⏳ Waiting for the workflow to be triggered..." + if [ "$VERBOSE" == "true" ] || [ $counter -eq 0 ]; then + echo "⏳ Waiting for the workflow to be triggered..." + fi + response=$(curl -s -H "Accept: application/vnd.github+json" -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos/${ORG_NAME}/${REPO_NAME}/actions/workflows/${workflow_id}/runs") + "https://api.github.com/repos/${REPOSITORY}/actions/workflows/${workflow_name}/runs") if echo "$response" | grep -q "API rate limit exceeded"; then echo "❌ API rate limit exceeded. Please try again later." exit 1 elif echo "$response" | grep -q "Not Found"; then - echo "❌ Invalid input provided (organization, repository, or workflow ID). Please check your inputs." + echo "❌ Invalid input provided (repository or workflow ID). Please check your inputs." exit 1 fi + run_id=$(echo "$response" | \ jq -r --arg ref "$(echo "$REF" | sed 's/refs\/heads\///')" --arg current_time "$current_time" \ '.workflow_runs[] | select(.head_branch == $ref and .created_at >= $current_time) | .id') @@ -51,7 +70,7 @@ else # Increment the counter and check if the maximum waiting time is reached counter=$((counter + 1)) - if [ $((counter * $interval)) -ge $((max_wait_minutes * 60)) ]; then + if [ $((counter * $interval)) -ge $((max_wait * 60)) ]; then echo "❌ Maximum waiting time for the workflow to be triggered has been reached. Exiting." exit 1 fi @@ -60,23 +79,24 @@ else done fi +export WORKFLOW_RUN_ID="${run_id}" + # Wait for the triggered workflow to complete and check its conclusion timeout_counter=0 while true; do - echo "⌛ Waiting for the workflow to complete..." + if [ "$VERBOSE" == "true" ] || [ $timeout_counter -eq 0 ]; then + echo "⌛ Waiting for the workflow to complete..." + fi + run_data=$(curl -s -H "Accept: application/vnd.github+json" -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos/${ORG_NAME}/${REPO_NAME}/actions/runs/$run_id") + "https://api.github.com/repos/${REPOSITORY}/actions/runs/$run_id") status=$(echo "$run_data" | jq -r '.status') if [ "$status" = "completed" ]; then conclusion=$(echo "$run_data" | jq -r '.conclusion') - if [ "$conclusion" != "success" ]; then - echo "❌ The workflow has not completed successfully. Exiting." - exit 1 - else - echo "✅ The workflow completed successfully! Exiting." - break - fi + export WORKFLOW_CONCLUSION="${conclusion}" + echo "✅ The workflow has been completed with result: $conclusion" + break fi # Increment the timeout counter and check if the timeout has been reached