Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Wait and Get Workflow Output #260

Closed
nibanks opened this issue Sep 14, 2023 · 8 comments
Closed

Question: Wait and Get Workflow Output #260

nibanks opened this issue Sep 14, 2023 · 8 comments

Comments

@nibanks
Copy link

nibanks commented Sep 14, 2023

Hello! While reading the docs here, it's not clear to me if this will wait on the result of the other repo's workflow or if it returns the results of that workflow execution. Does it? If so, how does that work? It'd be great if you could add some docs. If it doesn't work, is there any way to accomplish it?

@peter-evans
Copy link
Owner

Hi @nibanks

The way that GitHub have designed this API means that there is no response other than 200 Ok, which just means the dispatch message was sent. It doesn't even mean that a workflow was actually triggered. Whether or not the dispatch triggers a workflow or not is up to the user to make sure the workflow exists in the default branch of the target repo.

So, unfortunately, there is no simple way to wait for a response from the dispatch. If you need that kind of behaviour you would need to build it yourself, perhaps with some shared storage and polling the result.

@nibanks
Copy link
Author

nibanks commented Sep 14, 2023

Thanks for the quick response. How easy is it to use the GitHub rest API to try to find the workflow that should have been started from this trigger? And then poll its status?

@peter-evans
Copy link
Owner

Sorry, I don't know. If you come up with a good solution please let me know! 😄

@nibanks
Copy link
Author

nibanks commented Sep 14, 2023

So, I have come up with a solution. In the workflow that gets triggered, I have two separate jobs:

  1. Just has a special name that I can use to uniquely identify the run (via sha)
  2. A completion job that is run at the end.

Then I have this script that uses the gh CLI to find and wait on the workflow: https://github.com/microsoft/msquic/pull/3853/files#diff-45852c4dd2e80af80f14c6a831add8f04c7bf165c7e9d15deeb937c042811979.

@nibanks
Copy link
Author

nibanks commented Sep 15, 2023

Ultimately, I was able to refactor everything into one simple PowerShell script: run-workflow.ps1. I eliminated the need for the completion job, but still need the "name" job for identification. So, I'm not sure how feasible a "standard" solution will be.

@ansonngch-Sephora
Copy link

Hello @peter-evans are we able to make this available in your repo please?

@peter-evans
Copy link
Owner

@ansonngch-Sephora At the moment I'm not interested in maintaining and supporting a solution for this. However, I can pin this issue so people can find @nibanks solution more easily.

@peter-evans peter-evans pinned this issue Sep 29, 2023
@pmerwin
Copy link

pmerwin commented Dec 13, 2023

I wrote this as POC, would you be interested in adding it?

I was thinking the ' Wait for Workflow Completion ' could be added to your action ?

` - name: Trigger Cypress Workflow
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.GH_TOKEN }}
repository: adept-at/lib-cypress-canary
event-type: trigger-skill-preview
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "repo": "${{ github.repository }}", "run_id": "${{ github.run_id }}", "run_attempt": "${{ github.run_attempt }}", "target_url": "${{ github.event.deployment_status.target_url }}"}'
# Wait for the Cypress workflow to complete
- name: Wait for Workflow Completion
run: |
echo "const https = require('https');
const MAX_ATTEMPTS = 8;
let attempt = 0;
const current_time = new Date();
console.log('Current Time: ', current_time.toISOString());
const thirtySecsLater = new Date(current_time.getTime() + 30000);

      async function checkWorkflowStatus() {
        const options = {
          hostname: 'api.github.com',
          path: '/repos/adept-at/lib-cypress-canary/actions/runs',
          method: 'GET',
          headers: {
            'Authorization': 'token ' + process.env.GITHUB_TOKEN,
            'Accept': 'application/vnd.github.v3+json',
            'User-Agent': 'Node.js Script'
          }
        };

        return new Promise((resolve, reject) => {
          https.get(options, (res) => {
            let data = '';
            res.on('data', (chunk) => {
              data += chunk;
            });
            res.on('end', () => {
              const response = JSON.parse(data);
              if (!response.workflow_runs) {
                console.error('Unexpected response structure:', response);
                reject('Invalid API response');
                return;
              }
              console.log('Response:', response.workflow_runs[0].status);
              const workflowRuns = response.workflow_runs.filter(run =>
                new Date(run.created_at) > new Date(current_time) &&
                new Date(run.created_at) < new Date(thirtySecsLater) &&
                run.event === 'repository_dispatch' &&
                run.display_title === 'trigger-skill-preview'
              );
              if (workflowRuns.length > 0) {
                const status = workflowRuns[0].status;
                const conclusion = workflowRuns[0].conclusion;
                console.log('Status of the matching workflow run: ', status);

                // Check if the workflow run is completed
                if (status === 'completed') {
                    console.log('Completed matching workflow run: ', status, conclusion);
                    resolve({ status, conclusion });  // Resolving both status and conclusion
                } else {
                    console.log('Workflow run is not completed yet');
                    resolve({ status, conclusion: null }); // Conclusion is null if not completed
                }
            } else {
                console.log('No workflow runs found');
                reject('No workflow runs found');  // Reject if no workflow runs are found
            }

            });
          }).on('error', (e) => {
            console.error(e);
            reject(e);
          });
        });
      }

      async function waitForWorkflowCompletion() {
        let res = {};
        while (attempt < MAX_ATTEMPTS) {
           try {
              res = await checkWorkflowStatus();
            } catch (error) {
              console.error('Error checking workflow status:', error);
            }
            // ... handle status and conclusion ...
          if (res && res.status === 'completed' && res.conclusion === 'success') {
            console.log('Workflow completed and test passed!');
            break
          } else if (res && res.status === 'completed' && res.conclusion === 'failure') {
            console.log('Workflow status is failed...');
            process.exit(1);
          } else if (res?.status !== '') {
            console.log('Workflow status is ' + res?.status + '. Waiting for completion...');
          } else {
            console.log('Workflow status is unknown. Waiting for completion...');
          }
          attempt++;
          console.log('Attempt: ' + attempt);
          await new Promise(resolve => setTimeout(resolve, 60000)); // 60 seconds
        }

        if (attempt === MAX_ATTEMPTS) {
          console.log('Max attempts reached without completion. Exiting.');
          process.exit(1);
        }
      }
      waitForWorkflowCompletion();" > script.js
      node script.js
env:
  GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants