Skip to content

rubyatscale/code_teams

Repository files navigation

CodeTeams

This gem is a simple, low-dependency, plugin-based manager for teams within a codebase.

Usage

To use code_teams, add YML files in config/teams that start with structure: config/teams/my_team.yml

name: My Team

code_teams leverages a plugin system because every organization's team practices are different. Say your organization uses GitHub and wants to ensure every team YML files has a GitHub owner. To do this, you create a plugin:

class MyGithubPlugin < CodeTeams::Plugin
  extend T::Sig
  extend T::Helpers

  GithubStruct = Struct.new(:team, :members)

  sig { returns(GithubStruct) }
  def github
    raw_github = @team.raw_hash['github'] || {}

    GithubStruct.new(
      raw_github['team'],
      raw_github['members'] || []
    )
  end

  def member?(user)
    github.members.include?(user)
  end

  sig { override.params(teams: T::Array[CodeTeams::Team]).returns(T::Array[String]) }
  def self.validation_errors(teams)
    errors = T.let([], T::Array[String])

    teams.each do |team|
      if self.for(team).github.team.nil?
        errors << missing_key_error_message(team, 'github.team')
      end
    end

    errors
  end
end

After adding the proper GitHub information to the team YML:

name: My Team
github:
  team: '@org/my-team'
  members:
    - member1
    - member2
  1. You can now use the following API to get GitHub information about that team:

    team = CodeTeams.find('My Team')
    members = team.github.members
    github_name = team.github.team

    Alternatively, you can assign an accessor method name that differs from the plugin's class name:

    class MyPlugin < CodeTeams::Plugin
      data_accessor_name :other_name
    
      def other_name
        # ...
      end
    end
    
    # You can then use:
    team.other_name
    # similarly to the Github example above
    # You can then access data in the following manner:
    team.other_name.attribute_name

    However, to avoid confusion, it's recommended to use the naming convention whenever possible so that your accessor name matches your plugin's name

  2. Running team validations (see below) will ensure all teams have a GitHub team specified

    Your plugins can be as simple or as complex as you want. Here are some other things we use plugins for:

    • Identifying which teams own which feature flags
    • Mapping teams to specific portions of the code through code_ownership
    • Allowing teams to protect certain files and require approval on modification of certain files
    • Specifying owned dependencies (Ruby gems, JavaScript packages, and more)
    • Specifying how to get in touch with the team via Slack (their channel and handle)

Configuration

You'll want to ensure that all teams are valid in your CI environment. We recommend running code like this in CI:

require 'code_teams'

errors = CodeTeams.validation_errors(CodeTeams.all)
if errors.any?
  abort <<~ERROR
    Team validation failed with the following errors:
    #{errors.join("\n")}
  ERROR
end

Contributing

Bug reports and pull requests are welcome!

About

A low-dependency gem for declaring and querying engineering teams

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 11

Languages