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

CI Approach with GitHub Actions #1175

Merged
merged 4 commits into from
Nov 30, 2022
Merged

CI Approach with GitHub Actions #1175

merged 4 commits into from
Nov 30, 2022

Conversation

kevindew
Copy link
Member

@kevindew kevindew commented Nov 3, 2022

Trello: https://trello.com/c/QrxjshEm/270-move-ruby-gems-from-jenkins-to-github-actions

Edit: I've now closed the RFC aspect of this PR after it being open for a month.

This PR is a proof-of-concept of a GitHub Actions implementation of CI for this app, which has evolved into the final implementation. Unlike most GOV.UK Ruby Gems, this one has more complex needs CI because of the pact contract tests between this gem (consumer) and applications that provide APIs (provider).

Pact refresher

As pact tests are a hard concept to remember this section serves as a quick refresher - feel free to skip.

GOV.UK uses pact contract tests to assert that changes in one codebase remain compatible with a codebase that depends on it. For GDS API Adapters, we can have confidence that an adapter provides methods that will be operational if we can confirm that the way GDS API Adapters expects an API to behave is how it actually behaves.

The way this is achieved is by pact tests that mock how the API is expected to behave. When these tests run, a JSON file is created that stores all these expectations. To confirm the API behaves as expected we run pact:verify, this will use that JSON file to confirm the application behaves as per GDS API Adapters expectations.

The way this works in CI is:

  • When the API (provider) builds it verifies against the pacts of the GDS API Adapters main branch.
  • When GDS API Adapters (consumer) is build it generates new pacts and then runs pact:verify on each provider against this new pacts. Should any of these fail the build will fail.

Approach

The CI process is something of a pipeline, with a number of parallel steps. It is illustrated in the diagram below.

graph LR
    A(Build) --> B[Test Ruby 2.7]
    A --> C[Test Ruby 3]
    A --> D[Test Ruby 3.1]
    B --> E{All pass?}
    C --> E
    D --> E
    E --> |No| F(Exit)
    E --> |Yes| G[Publish pacts]
    G --> H1[Verify Account API pact]
    G --> H2[Verify Asset Manager pact]
    G --> H3[Verify Collections pact]
    G --> H4[Verify Email Alert API pact]
    G --> H5[Verify Imminence pact]
    G --> H6[Verify Link Checker API pact]
    G --> H7[Verify Locations API pact]
    G --> H8[Verify Publishing API pact]
    G --> H9[Verify Whitehall pact]
    H1 --> I{All pass?}
    H2 --> I
    H3 --> I
    H4 --> I
    H5 --> I
    H6 --> I
    H7 --> I
    H8 --> I
    H9 --> I
    I --> |No| J(Exit)
    I --> |Yes| K(Publish Gem)
Loading

Testing gems against Ruby versions is already a well trodden path and publishing the pact is a relatively simple operation (running rake pact:publish:branch). The area that is unusual is how we verify the pact against applications.

To do this we can set up a workflow in each application that these will be run against (example). This workflow will be called when GDS API Adapters builds. The workflow will also be configured to run when the application itself builds - so will be used as both part of an applications standard CI and part of GDS API Adapters CI. As the pact:verify will run when the standard CI process occurs, we will remove this from the default test task (using overrideTestTask) so that we don’t test it twice.

And some rationale for the above:

  • Why aren’t we keeping everything in GDS API Adapters? The previous Jenkinsfile approach seems to have slowly drifted away from how the apps are configured, with the tests being performed against very different dependencies of the apps and needing some manual hacks. If the configuration belongs to the owning app, and a part of a regular process, it seems more likely this will be kept up-to-date.
  • Why run the workflow when the app builds, when it could be part of the regular CI process? If the workflow only runs infrequently it’ll be harder to identify problems with it. If it’s part of a regular build then any breakages will be caught quickly. As a minor aside, it also offers a speed boost since it runs in parallel.
  • Why not have just shared workflow all the apps use to run it? We could do, but the gains seem modest as most of the workflow files comprise of app specific dependencies. A shared workflow file would add more complexity and be less flexible - though it would be nice to have less boilerplate.
  • Why not run pact:verify as both part of regular CI and an extra workflow file? This redundancy of doing them both would likely give the impression that one of these is a mistake. Avoiding the duplication makes it much more explicit how it should behave.
  • Why overrideTestTask when we could remove pact:verify from the default rake task? As pact:verify is part of a build testing this seems like a useful command to have locally so you can still test your app fully with one command. As the tasks that make up testing don't change infrequently in apps, it seems relatively low risk to specify them in the Jenkinsfile

Here is a list of the workflows for apps:

Consequences

For apps with GDS API pact tests:

  • There will be a new GitHub Action workflow added
  • These apps will have their Jenkinsfile test tasks overriden to not include pact:verify
  • A build of one of these will comprise of most testing being done in Jenkins but the pact:verify is done by GitHub actions.
  • A failed pact:verify on a main branch won’t prevent an integration deploy (this scenario seems unlikely)
  • We should configure govuk_saas_config to require the pact_verify check before merging

For GDS API Adapters:

  • It won't be concerned with how apps are configured anymore
  • Contributors outside of GOV.UK won’t be able to get a passing build as their lack of access to GitHub secrets will mean the pact branch can’t be published - this seems low risk as there is little incentive for someone outside GOV.UK to contribute to GDS API Adapters
  • Builds of other projects will be run even when they're not needed (no changes to pacts) - this hasn't been flagged as a past problem so I don't think it's worth adding to the complexity to check it

kevindew added a commit to alphagov/publishing-api that referenced this pull request Nov 3, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions.

For more details see alphagov/gds-api-adapters#1175
@ChrisBAshton
Copy link
Contributor

ChrisBAshton commented Nov 28, 2022

Looks good! ⭐ nice work putting this together. One major suggestion before I come back and do a more thorough review later.

Contributors outside of GOV.UK won’t be able to get a passing build as their lack of access to GitHub secrets will mean the pact branch can’t be published

I've been having a think and I propose a small change to your approach, which would solve the above issue as well as simplify the overall architecture. Essentially, I think we should remove the Pact Broker and use GitHub itself as the broker.

Changes to the consumer

If we consider the current scenario, when a consumer (e.g. gds-api-adapters) is changed, we:

  • Publish all pactfiles (under the git-ignored spec/pacts/*.json) to a new branch on the Pact Broker
  • Check out and bundle each app
  • Run pact tests inside the app, against the published pactfile

Instead, we would now:

  • Commit the generated pactfiles to GitHub (removing them from gitignore)
  • Trigger a GitHub action inside each app's repo (as you've proposed)
  • ...but passing all the necessary arguments to that action (i.e. consumer name, consumer branch, perhaps name of pactfile)
  • The action would fetch the pactfile based on the above args, and run the pact tests against that

Benefits:

  • Knowledge of bundling each app would be contained within the app's repo
  • The action would be generic enough to work with any consumer
  • No pact broker complexity

Changes to provider

Currently, when a provider is changed, we run pact:verify against the master consumer branch on the pact broker.

Instead, we would now need to maintain a hardcoded list of consumers (and potentially pactfile filepaths) in the provider repository. Then, when a change is made to the provider, have CI fetch the pactfiles on that list and run pact:verify against them.

The increased coupling feels like a drawback, though it also acts as documentation (can explicitly see which consumers depend on the provider), giving some semblance of feature parity with the network graph provided by the pact broker. But the main advantage is that we could now retire the pact broker and all its associated infrastructure.

It's a relatively big / controversial change, but feels like only a modest step away from what you're already proposing, so worth considering here. What do you think?

@kevindew
Copy link
Member Author

Thanks for having a look Chris 👍 and thank you for the suggestion.

I somewhat wonder if the idea to get rid of the pact-broker is a tangent from this work rather than directly related, almost like separate questions "can this run on GitHub Actions?" and "Do we need the pact-broker?", so I'm somewhat wondering if pondering that is actually a potential scope creep that could be considered separately?

I'm guessing there is some future pondering needed for the pact broker soon(ish) as it's hosted on the PAAS which is going away.

On the idea itself. I'm imagining one of the pain points of your idea would be that you have increased complications running locally where you both need to clone the repo and risk running out of date pacts. I also think it wouldn't solve the outside contributor issue as I presume we wouldn't allow our repos to clone a fork to test against automatically (though off the top of my head I'm not sure if that'd present a risk).

But yeah, my thought would be: can we defer this concern to be one considered when it comes to Platform Reliability having to think about the future hosting of the Pact Broker?

kevindew added a commit to alphagov/account-api that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/asset-manager that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/collections that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/email-alert-api that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
kevindew added a commit to alphagov/places-manager that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/link-checker-api that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
kevindew added a commit to alphagov/locations-api that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
kevindew added a commit to alphagov/publishing-api that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/whitehall that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
kevindew added a commit to alphagov/whitehall that referenced this pull request Nov 28, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
@kevindew kevindew changed the title CI Approach with GitHub Actions (mini-RFC) CI Approach with GitHub Actions Nov 28, 2022
@kevindew
Copy link
Member Author

kevindew commented Nov 28, 2022

@ChrisBAshton I've now opened up the dependent PRs for this in corresponding repos, which will be needed before I can merge this in.

These are:

and they're all pretty much the same, just tweaked for app differences.

I notice that the previous CI approach is broken (which is presumably blocking @KludgeKML from #1176) because of a database incompatibility with Whitehall, so there may be a need to sort this sooner rather than later.

Copy link
Contributor

@ChrisBAshton ChrisBAshton left a comment

Choose a reason for hiding this comment

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

Code-reviewed - happy with the approach 👍

Comment on lines 15 to 21
- uses: actions/checkout@v3
- name: Checkout GOV.UK Content Schemas
uses: actions/checkout@v3
with:
repository: alphagov/govuk-content-schemas
ref: deployed-to-production
path: vendor/govuk-content-schemas
Copy link
Contributor

Choose a reason for hiding this comment

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

This repo is (recently) retired - can we give this PR an update?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, I've sorted that.

kevindew added a commit to alphagov/publishing-api that referenced this pull request Nov 30, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
where the wider change is being co-ordinated.
kevindew added a commit to alphagov/link-checker-api that referenced this pull request Nov 30, 2022
This moves the pact verification to a GitHub Action and will no longer
be performed by a Jenkins build. This workflow will also be called by
GDS API Adapters as part of it's CI build to assert that newly generated
pacts are valid against this app. To avoid running this same task twice
`pact:verify` is no longer part of the Jenkins test actions and instead
the other rake default steps are included.

For more details see alphagov/gds-api-adapters#1175
This configures this project to use GitHub actions in the same way other
GOV.UK gems are configured [1].

This project will need additional functionality in order to support the
pact tests.

[1]: https://github.com/alphagov/slimmer/blob/f698522c4c014f219cb5faeb2dfbad325e32520a/.github/workflows/ci.yml
This addition is to replicate the similar functionality in the
Jenkinsfile [1].

This functionality is used to publish pact JSON files to the pact
broker, it is tagged with the branch name.

The Jenkinsfile relied on being able to publish the pact JSON files that
were generated by running the tests. This is harder to achieve in a
GitHub action because each matrix runs on a separate machine.

I felt that it was simpler to understand having this step run separately
from the matrix, but to do that we need to generate the pact JSON files.
I therefore added in an extra rake task that can run just the pact tests
to generate them.

[1]: https://github.com/alphagov/gds-api-adapters/blob/2f003aa7a5b808e4bd7d57224545abd6fc606af8/Jenkinsfile#L89-L93
This triggers builds on applications that have a pact with this utility.
It does this by using workflow files that are defined in each of the
repositories which can run the job. These are currently not merged into
the repos while I seek feedback on the approach, hence the non-main
branch.

This is a different approach than the Jenkinsfile takes which clones the
applications and runs the commands directly [1]. The reason for this is
that the configuration for these other apps hasn't aged well (for
example they test against the wrong versions of the databases and need
some manual set-up [2]). Our theory is that if these files are with the
app, and become part of regular builds, they stand a much higher chance
of being maintained.

To implement this I did see if it was possible to use a matrix strategy
so they would be less verbose. However this relied on interpolation in
the workflow name, and this is something that GitHub actions currently
don't support.

[1]: https://github.com/alphagov/gds-api-adapters/blob/2f003aa7a5b808e4bd7d57224545abd6fc606af8/Jenkinsfile#L95-L110
[2]: fdbce25
@kevindew kevindew force-pushed the switch-to-github-actions branch from bcc8e58 to 897ef61 Compare November 30, 2022 10:46
@kevindew kevindew marked this pull request as ready for review November 30, 2022 10:47
This project CI is now done by GitHub Actions.
@kevindew kevindew merged commit e8f8f2c into main Nov 30, 2022
@kevindew kevindew deleted the switch-to-github-actions branch November 30, 2022 11:51
kevindew added a commit that referenced this pull request Jan 31, 2023
This application has a pact with GDS API Adapters and I missed it when
migrating the pact tests to GitHub Actions [1].

[1]: #1175
brucebolt pushed a commit that referenced this pull request Feb 3, 2023
This application has a pact with GDS API Adapters and I missed it when
migrating the pact tests to GitHub Actions [1].

[1]: #1175
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