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

Automatically trigger the sync-ref workflow runs on pushes to git/git #2

Merged
merged 5 commits into from
Sep 14, 2023

Conversation

dscho
Copy link
Member

@dscho dscho commented Aug 31, 2023

The gitgitgadget-git GitHub App is set up to deliver push webhook events. We might just as well put those events to good use by triggering the GitHub workflow whose responsibility it is to synchronize the git/git branches to gitgitgadget/git.

This makes it much easier to mock things in the future, and also
structures the code better.

This commit is best viewed with `--color-moved`.

Signed-off-by: Johannes Schindelin <[email protected]>
In particular, this adds a function to obtain the installation access
token for a given repository. This function will be used e.g. to trigger
GitHub workflow runs.

These functions are slightly edited versions of functions that have been
in use in https://github.com/git-for-windows/gfw-helper-github-app for
quite a while. But the test is new.

Signed-off-by: Johannes Schindelin <[email protected]>
@dscho dscho self-assigned this Aug 31, 2023
@dscho
Copy link
Member Author

dscho commented Aug 31, 2023

I manually triggered this by copying the payload of a push event from the "Advanced" tab of the gitgitgadget-git App and then launching this node.js script:

#!/usr/bin/env node

(async () => {
    const fs = require('fs')

    // Expect a path as command-line parameter that points to a file containing
    // an event copy/pasted from
    // https://github.com/organizations/gitgitgadget/settings/apps/gitgitgadget-git/advanced
    // in the form:
    //
    // Headers
    //
    // Request method: POST
    // [...]
    //
    // Payload
    //
    // {
    //    [...]
    // }

    const path = process.argv[2]
    const contents = fs.readFileSync(path).toString('utf-8')

    const req = {
        headers: {}
    }

    const payloadOffset = contents.indexOf('\n{')
    if (payloadOffset < 0) throw new Error(`Could not find start of payload in ${path}`)
    contents.substring(0, payloadOffset).split(/\r?\n/).forEach(line => {
        const colon = line.indexOf(':')
        if (colon < 0) return

        const key = line.substring(0, colon).toLowerCase()
        const value = line.substring(colon + 1).replace(/^\s+/, '')

        if (key === 'request method') req.method = value
        else req.headers[key] = value
    })
    req.rawBody = contents.substring(payloadOffset + 1)
        // In https://github.com/organizations/gitgitgadget/settings/apps/gitgitgadget-git/advanced,
        // the JSON is pretty-printed, but the actual webhook event avoids any
        // unnecessary white-space in the body
        .replace(/\r?\n\s*("[^"]*":)\s*/g, '$1')
        .replace(/\r?\n\s*/g, '')
    req.body = JSON.parse(req.rawBody)

    const context = {
        log: console.log,
        done: () => {},
        req,
    }

    const localSettings = JSON.parse(fs.readFileSync('local.settings.json'))
    Object.entries(localSettings.Values).forEach(([key, value]) => process.env[key] = value)

    const index = require('./GitGitGadget/index')
    console.log(await index(context, req) || context.res)
})().catch(console.log)

@dscho dscho requested a review from webstech August 31, 2023 14:19
@dscho
Copy link
Member Author

dscho commented Sep 7, 2023

@webstech do you think you'll get a chance to look over this PR?

Copy link
Contributor

@webstech webstech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In trigger-workflow-dispatch.js, are token, and actor expected to be populated outside of testing?

}
}

const waitForWorkflowRun = async (context, owner, repo, workflow_id, after, token, actor) => {
Copy link
Contributor

@webstech webstech Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason token has moved to a different position vs triggerWorkflowDispatch?

Did not expect this to stop the merge ☹️.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's only historical reasons. I fixed it.

The GitHub workflow must have a `workflow_dispatch` trigger for this to
work. The `workflow_id` is the file name of the workflow, e.g.
`sync-ref.yml`.

This function is a slightly edited version of a function that has been
in use in https://github.com/git-for-windows/gfw-helper-github-app for
quite a while. But the test is new.

Signed-off-by: Johannes Schindelin <[email protected]>
…token

When a `workflow_dispatch` should be triggered, we require a token. If
no token was specified (i.e. if `undefined` was passed for the `token`
parameter), let's just automatically get an installation access token
for the GitHub App.

Signed-off-by: Johannes Schindelin <[email protected]>
We added the `sync-ref` GitHub workflow in
gitgitgadget/gitgitgadget-workflows#1
specifically to let it be triggered by `push` webhook events delivered
to GitGitGadget's GitHub App. And this is the commit that teaches the
GitHub App that trick.

Signed-off-by: Johannes Schindelin <[email protected]>
@dscho dscho force-pushed the trigger-sync-ref-workflow-runs branch from 8747931 to 7400342 Compare September 12, 2023 20:19
@dscho
Copy link
Member Author

dscho commented Sep 12, 2023

In trigger-workflow-dispatch.js, are token, and actor expected to be populated outside of testing?

Yes. The idea is to let the GitHub App generate an installation access token, and use that (and then to figure out the actor that was recorded for the workflow that was triggered using this token).

@webstech
Copy link
Contributor

In trigger-workflow-dispatch.js, are token, and actor expected to be populated outside of testing?

Yes. The idea is to let the GitHub App generate an installation access token, and use that (and then to figure out the actor that was recorded for the workflow that was triggered using this token).

Sorry, I did not properly say what I was thinking. token is passed as a parameter to triggerWorkflowDispatch but is only valued in tests. actor is passed as a parameter to waitForWorkflowRun but is never actually valued. In tests, it is set by mocking.

  • should token be a parameter on the trigger function or should the calls be mocked in testing (to allow fuller testing of the code path)? Mocking would be more consistent with setting actor in tests. The app this is based on uses mocking.
  • should actor be a parameter on the wait function or just a local variable?

@dscho
Copy link
Member Author

dscho commented Sep 13, 2023

@webstech it is true that the functions are more generic than they are used here, which is for the reason that they hail from a different project (where I tried to make them generic enough to be able to test locally, using my own token).

So while it is not strictly necessary for the functions to be so generic (and the token and actor parameters could be eliminated), in the interest to make it easier to port improvements back and forth to/from that other project, I would like to keep the functions as-are.

@webstech
Copy link
Contributor

All set for you to merge - I don't appear to have access.

@dscho
Copy link
Member Author

dscho commented Sep 14, 2023

All set for you to merge - I don't appear to have access.

Sorry, my oversight. I fixed it (in all repositories in this org).

@dscho dscho merged commit 323bb7d into main Sep 14, 2023
1 check passed
@dscho dscho deleted the trigger-sync-ref-workflow-runs branch September 14, 2023 07:53
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

Successfully merging this pull request may close these issues.

2 participants