Skip to content

Latest commit

 

History

History
343 lines (238 loc) · 17.7 KB

File metadata and controls

343 lines (238 loc) · 17.7 KB

Maintainer's Runbook

This documents common maintenance tasks for this codebase, to make ongoing maintenance less dependent on any single individual.

Releasing New Versions

Release a new version using the Release workflow.

  • Click "Run workflow"
  • Select a branch to release from
  • Specify a version number (based on our versioning policy)
  • Click "Run workflow"

Tip

A "Dry Run" option is also available. It's primarily intended for use when testing changes to the Release workflow. It does the release actions which are reversible (e.g. bumping the version, pushing a branch, opening a PR, generating draft release notes) while skipping the one action that's not reversible (actually releasing to rubygems.org). When used, please remember to cleanup afterwards: close the PR and delete the draft release notes.

Important

If there's any question about the readiness to release a new version to end users, please release a release candidate using a version number like 1.2.0.rc1, 1.2.0.rc2, etc. After the release candidate has been thorougly tested, we can cut the final release.

After the workflow completes, review the PR that gets opened (example) and follow its checklist. The release notes can be authored after cutting a release if needed (but it's nice to have them ready to go if possible).

Release Notes

A Claude Code skill is available to help draft release notes:

# Generate notes from most recent release to HEAD
/release-notes 1.1.0

# Generate notes from a specific version
/release-notes 1.1.0 --from 1.0.2

The skill gathers all PRs, categorizes them, identifies new contributors, and drafts release notes following the structure below. Review and refine the output as needed.

Release notes should follow this general structure:

ElasticGraph vX.Y.Z has been released! This release includes...

## New Features

Describe major new features here with a subheading dedicated to each.

## Upgrade notes

Describe how to upgrade ElasticGraph from the prior version.

## What's Changed

<In this section we provide bullet-point lists linking to each PR, but we often combine many PRs into a single bullet point.>

### New Features

...

### Breaking Changes

...

### Performance Optimizations

...

### Bug Fixes

...

### Other Improvements

...

### Dependency Upgrades

The datastore versions we build against have been upgraded:

...

The following Ruby gems have been upgraded:

...

The following GitHub actions have been upgraded:

...

The following NPM packages have been upgraded:

...

The following Python packages have been upgraded:

...

## New Contributors
* List new contributors here; the auto generated release notes provide this

**Full Changelog**: <GitHub compare URL provided by autogenerated release notes>

Important

We're threading the needle here between acknowledging every contribution (we want to acknowledge contributors!) and keeping the release notes at an appropriate level of detail for our user base. Users generally don't care about internal improvements to the ElasticGraph codebase that have zero impact on the experience of using ElasticGraph. That's why we often combine many PRs into a single bullet point like "Various other codebase maintenance tasks".

Note

For a pre-release (e.g. X.Y.Z.rc1), we generally don't bother writing up release notes, since it takes effort and we don't expect users to use pre-releases. Instead, we just use the autogenerated release notes provided by GitHub.

Later, when releasing the final version (e.g. X.Y.Z), be sure to include everything, including things that were actually released in the release candidate.

For a good example of release notes, see the v0.19.2.0 release notes.

Upgrading Elasticsearch/OpenSearch

We want ElasticGraph to stay up-to-date with the latest Elasticsearch/OpenSearch versions. We don't bother keeping up to date with every patch release, but do want to stay current with the latest major/minor releases. However, we always opt for the most recent patch release when upgrading.

In addition, we don't want to bloat our CI build by building against every supported Elasticsearch/OpenSearch version. Instead, we cover a range of versions by building against a minimum version and a maximum version.

To upgrade a version, update the versions in elasticgraph-local/lib/elastic_graph/local/tested_datastore_versions.yaml. Then run:

script/update_ci_yaml

See #545 for an example PR.

Maintaining Time Zones

ElasticGraph maintains a set of valid time zones, which is used to validate client-provided values for the TimeZone scalar type. The set is maintained and validated in a few ways:

  • elasticgraph-graphql/script/dump_time_zones generates valid_time_zones.rb by querying the JVM (in order to match OpenSearch and Elasticsearch since they run on the JVM).
  • A unit test verifies that valid_time_zones.rb is up-to-date.
  • An acceptance test executes a GraphQL query using every time zone, to verify that all time zones accepted by our TimeZone scalar type are in fact handled by our supported Elasticsearch and OpenSearch versions.

The folks who maintain the tzdata database occasionally add new time zones to the database. After that happens, the aforementioned unit test may begin to fail (e.g. once the updated tzdata file has landed on the GitHub actions workers...). Initially, we can just ignore/exclude the new time zone (given that old OpenSearch and Elasticsearch docker images bundle a tzdata file that lacks it). See this PR for an example. Once it's handled by all supported datastore versions, we can stop ignoring it.

Dependabot

We use Dependabot to automatically keep dependencies up-to-date. Our dependabot config configures the cadence of dependabot updates (among other things)--feel free to tweak it as needed.

Dependabot PRs

We have some custom tooling that hooks into Dependabot PRs and updates some other artifacts:

  • script/update_gem_constraints updates constraints in our gemspecs. Dependabot only updates the version in Gemfile/Gemfile.lock, leaving our gemspec constraints untouched. However, it helps avoid surprises for ElasticGraph users if they get the same gem versions our CI runs against, so we want the constraints in our gemspecs to be updated to match.
  • workflows/update-gem-version-artifacts.yaml runs on Dependabot PRs. It runs script/update_gem_constraints, updates rbs_collection.lock.yaml, and pushes a commit to the PR.

Dependabot PRs can be reviewed and merged without the approval of another maintainer. Before merging, please:

  • Review the release notes provided by Dependabot in the PR description. If there are any new features of a dependency that we should take advantage of, please open an issue so we can track that work.
  • Confirm the CI build fully passes. If the build has a non-transient failure and the PR is upgrading multiple dependencies, consider updating .github/dependabot.yml to exclude the culprit from inclusion in a multiple-dependency PR. (It's nice to isolate such a dependency into its own PR.)
  • Review the diff to make sure it looks reasonable.

When merging, please use the "Squash and merge" option as we don't need to keep the two commits in the PR separate. If a Dependabot PR has merge conflicts, comment on the PR with @dependabot recreate rather than @dependabot rebase so that the updates from script/update_gem_constraints get recreated as well.

Triggering Dependabot

Dependabot is configured to run on a regular cadence, but if you ever need to trigger it by hand (e.g. to troubleshoot a problem with it), you can do so from the Dependency Graph--Dependabot page:

  • Click "Recent update jobs" next to a dependabot job
  • Click the "Check for updates" button

Updating GraphiQL

The GraphiQL UI served by elasticgraph-graphiql uses locally vendored assets, packaged into elasticgraph-graphiql/lib/elastic_graph/graphiql/assets.tar.gz. These assets are built from a specified version of the official graphql/graphiql Vite example (examples/graphiql-vite). This ensures the UI can run offline, is not dependent on external CDNs, and uses ElasticGraph project favicons.

The elasticgraph-graphiql/lib/elastic_graph/graphiql.rb application extracts this tarball into a temporary directory at runtime to serve the UI.

To update the graphiql.tar.gz archive (e.g., to a newer version of GraphiQL or to reflect changes in project favicons):

  1. Prerequisites: Ensure you have the following command-line tools installed and available in your system's PATH:

    • git
    • node (Node.js, a recent LTS version is recommended)
    • yarn (Yarn package manager)
    • tar
    • gzip (usually included with tar)
  2. Run the Update Script: Execute the following script from the root of the elasticgraph-fully-local-graphiql project. You can optionally specify a git ref (tag, branch, or commit SHA) from the graphql/graphiql repository using the --ref option.

    # To use a specific version, e.g., a tag graphiql@5.0.3
    elasticgraph-graphiql/script/update_graphiql --ref graphiql@5.0.3
  3. What the Script Does:

    • Clones the specified version of the graphql/graphiql repository into a temporary directory.
    • Modifies the source of the examples/graphiql-vite (App.jsx) to use /graphql as its API endpoint.
    • Installs all necessary Node.js dependencies for the monorepo using yarn install.
    • Builds all packages within the graphql/graphiql monorepo using yarn build.
    • Builds the specific example-graphiql-vite workspace using yarn workspace example-graphiql-vite build.
    • Modifies the resulting dist/index.html to set the title to "ElasticGraph GraphiQL".
    • Copies favicons from this project's config/site/src/assets/favicons/ into the dist/ directory.
    • Creates a graphiql.tar.gz archive from the contents of the modified dist/ directory.
    • Saves this archive to elasticgraph-graphiql/lib/elastic_graph/graphiql/assets.tar.gz.
    • Cleans up the temporary build directory.
  4. Test the updated GraphiQL:

    • Boot locally with bundle exec rake boot_locally.
    • Try out the GraphiQL UI in the browser to confirm it works.
    • Confirm in the network tab that all assets load correctly.
  5. Commit Changes: After the script successfully completes, the elasticgraph-graphiql/lib/elastic_graph/graphiql/assets.tar.gz file will be updated. Review this change and commit it to your version control system.

This process ensures that elasticgraph-graphiql serves a self-contained and consistently branded version of the GraphiQL UI.

Creating a new ElasticGraph Gem

Occasionally, it's useful to create a new gem that's part of the set of ElasticGraph gems provided by this repo. Here's how to do that.

  1. Copy a skeleton from another gem. (elasticgraph-opensearch is a pretty small one, so it's what we'll use here). Be sure to use cp -R so that symlinked files copy properly:
cp -R elasticgraph-opensearch elasticgraph-newgem
  1. Cleanup the lib/spec/sig files that were originally in elasticgraph-opensearch (these will be entirely different for your new gem):
rm -rf elasticgraph-newgem/lib/elastic_graph/opensearch
rm -rf elasticgraph-newgem/spec/unit/elastic_graph/opensearch
rm -rf elasticgraph-newgem/sig/elastic_graph/opensearch
rm -rf elasticgraph-newgem/sig/opensearch.rbs
  1. Use your IDE or similar tool to find and replace elasticgraph-opensearch with elasticgraph-newgem in your gem directory.

  2. Edit the gemspec. Be sure to update the following as needed:

    • name
    • summary
    • metadata.gem_category
    • add_dependency
    • add_development_dependency
  3. Add the gem to git, and then update our dependency diagrams:

git add elasticgraph-newgem
script/update_dependency_diagrams
  1. Write the code, specs and type signatures for the gem. To run the gem's test suite in the way it's run on CI, run:
script/run_gem_specs elasticgraph-newgem
  1. Update rbs_collection.yaml to list the new gem and ignore its type signatures provided by bundler (as they are already available locally in this repo).

  2. Open a PR with the new gem once it's ready for review.

  3. Once that has merged, register the new gem with rubygems.org. We use RubyGems trusted publishing to publish our gems to rubygems.org from a GitHub action. Follow the guide for pushing a new gem. Enter the following details into the "New Pending Trusted Publisher" form:

    • RubyGem name: Whatever the new gem is called (elasticgraph-newgem in the examples above)
    • Trusted publisher type: GitHub Actions
    • Repository owner: block
    • Repository name: elasticgraph
    • Workflow filename: release.yaml
    • Environment: rubygems.org
  4. Publish an ElasticGraph release to verify the new gem can be released successfully. This needs to happen within 12 hours of creating the pending trusted publisher on rubygems.org (as that's how long a new pending trusted publisher is valid for). Use the release process explained at the top of this document, but be sure to use a release candidate version (e.g. 1.2.3.rc1). We don't want to be trying out the publishing of a new gem for the first time when cutting a final release.

READMEs

The project has a root README and a README within each gem directory. Much of the content of the READMEs is generated or validated to ensure accurate documentation.

  • The mermaid dependency diagrams are automatically generated by script/update_dependency_diagrams. CI checks them with script/update_dependency_diagrams --verify.
  • All other README code snippets are validated by script/validate_readme_snippets. Here's how that validation works:
    • A new ElasticGraph project is bootstrapped into tmp/example_project_for_snippet_validation.
    • bash snippets are executed from that project directory.
    • diff snippets are applied to that project directory. Then bundle exec rake is executed to confirm the build still passes.
    • ruby snippets are dumped into a file (either at a temp path, or at the path identified in a comment) and then executed.
    • yaml snippets are parsed as YAML.
    • text snippets (that is, snippets which don't indicate a type) are not validated. (So a simple way to get the build to pass for a failing snippet is to remove the type, so that it's just text).

When updating a README file, you may want to run the validator locally:

script/validate_readme_snippets --file elasticgraph-somegem/README.md

Apollo

elasticgraph-apollo uses https://github.com/apollographql/apollo-federation-subgraph-compatibility to verify compatibility with Apollo. Things to note:

  • Run elasticgraph-apollo/script/test_compatibility to run the compatibility tests (the CI build runs this).
  • Run elasticgraph-apollo/script/boot_eg_apollo_implementation to boot the ElasticGraph compatibility test implementation (can be useful for debugging test_compatibility failures).
  • These scripts require some additional dependencies to be installed (such as docker, node, and npm).
  • To get that to pass locally on a Mac, I had to enable the Use Docker Compose V2 flag in Docker Desktop (under "Preferences -> General"). Without that checked, I got errors like this:
ERROR: for apollo-federation-subgraph-compatibility_router_1  Cannot start service router: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/host_mnt/Users/myron/Development/sq-elasticgraph-ruby/elasticgraph-apollo/vendor/apollo-federation-subgraph-compatibility/supergraph.graphql" to rootfs at "/etc/config/supergraph.graphql" caused: mount through procfd: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type