• Stars
    star
    7,389
  • Rank 5,236 (Top 0.2 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 11 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

πŸ”¬ A Ruby library for carefully refactoring critical paths.

Scientist!

A Ruby library for carefully refactoring critical paths. Build Status

How do I science?

Let's pretend you're changing the way you handle permissions in a large web app. Tests can help guide your refactoring, but you really want to compare the current and refactored behaviors under load.

require "scientist"

class MyWidget
  def allows?(user)
    experiment = Scientist::Default.new "widget-permissions"
    experiment.use { model.check_user?(user).valid? } # old way
    experiment.try { user.can?(:read, model) } # new way

    experiment.run
  end
end

Wrap a use block around the code's original behavior, and wrap try around the new behavior. experiment.run will always return whatever the use block returns, but it does a bunch of stuff behind the scenes:

  • It decides whether or not to run the try block,
  • Randomizes the order in which use and try blocks are run,
  • Measures the durations of all behaviors in seconds,
  • Compares the result of try to the result of use,
  • Swallow and record exceptions raised in the try block when overriding raised, and
  • Publishes all this information.

The use block is called the control. The try block is called the candidate.

Creating an experiment is wordy, but when you include the Scientist module, the science helper will instantiate an experiment and call run for you:

require "scientist"

class MyWidget
  include Scientist

  def allows?(user)
    science "widget-permissions" do |experiment|
      experiment.use { model.check_user(user).valid? } # old way
      experiment.try { user.can?(:read, model) } # new way
    end # returns the control value
  end
end

If you don't declare any try blocks, none of the Scientist machinery is invoked and the control value is always returned.

Making science useful

The examples above will run, but they're not really doing anything. The try blocks don't run yet and none of the results get published. Replace the default experiment implementation to control execution and reporting:

require "scientist/experiment"

class MyExperiment
  include Scientist::Experiment

  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def enabled?
    # see "Ramping up experiments" below
    true
  end

  def raised(operation, error)
    # see "In a Scientist callback" below
    p "Operation '#{operation}' failed with error '#{error.inspect}'"
    super # will re-raise
  end

  def publish(result)
    # see "Publishing results" below
    p result
  end
end

When Scientist::Experiment is included in a class, it automatically sets it as the default implementation via Scientist::Experiment.set_default. This set_default call is skipped if you include Scientist::Experiment in a module.

Now calls to the science helper will load instances of MyExperiment.

Controlling comparison

Scientist compares control and candidate values using ==. To override this behavior, use compare to define how to compare observed values instead:

class MyWidget
  include Scientist

  def users
    science "users" do |e|
      e.use { User.all }         # returns User instances
      e.try { UserService.list } # returns UserService::User instances

      e.compare do |control, candidate|
        control.map(&:login) == candidate.map(&:login)
      end
    end
  end
end

If either the control block or candidate block raises an error, Scientist compares the two observations' classes and messages using ==. To override this behavior, use compare_errors to define how to compare observed errors instead:

class MyWidget
  include Scientist

  def slug_from_login(login)
    science "slug_from_login" do |e|
      e.use { User.slug_from_login login }         # returns String instance or ArgumentError
      e.try { UserService.slug_from_login login }  # returns String instance or ArgumentError

      compare_error_message_and_class = -> (control, candidate) do
        control.class == candidate.class && 
        control.message == candidate.message
      end

      compare_argument_errors = -> (control, candidate) do
        control.class == ArgumentError &&
        candidate.class == ArgumentError &&
        control.message.start_with?("Input has invalid characters") &&
        candidate.message.start_with?("Invalid characters in input") 
      end

      e.compare_errors do |control, candidate|
        compare_error_message_and_class.call(control, candidate) ||
        compare_argument_errors.call(control, candidate)
      end
    end
  end
end

Adding context

Results aren't very useful without some way to identify them. Use the context method to add to or retrieve the context for an experiment:

science "widget-permissions" do |e|
  e.context :user => user

  e.use { model.check_user(user).valid? }
  e.try { user.can?(:read, model) }
end

context takes a Symbol-keyed Hash of extra data. The data is available in Experiment#publish via the context method. If you're using the science helper a lot in a class, you can provide a default context:

class MyWidget
  include Scientist

  def allows?(user)
    science "widget-permissions" do |e|
      e.context :user => user

      e.use { model.check_user(user).valid? }
      e.try { user.can?(:read, model) }
    end
  end

  def destroy
    science "widget-destruction" do |e|
      e.use { old_scary_destroy }
      e.try { new_safe_destroy }
    end
  end

  def default_scientist_context
    { :widget => self }
  end
end

The widget-permissions and widget-destruction experiments will both have a :widget key in their contexts.

Expensive setup

If an experiment requires expensive setup that should only occur when the experiment is going to be run, define it with the before_run method:

# Code under test modifies this in-place. We want to copy it for the
# candidate code, but only when needed:
value_for_original_code = big_object
value_for_new_code      = nil

science "expensive-but-worthwhile" do |e|
  e.before_run do
    value_for_new_code = big_object.deep_copy
  end
  e.use { original_code(value_for_original_code) }
  e.try { new_code(value_for_new_code) }
end

Keeping it clean

Sometimes you don't want to store the full value for later analysis. For example, an experiment may return User instances, but when researching a mismatch, all you care about is the logins. You can define how to clean these values in an experiment:

class MyWidget
  include Scientist

  def users
    science "users" do |e|
      e.use { User.all }
      e.try { UserService.list }

      e.clean do |value|
        value.map(&:login).sort
      end
    end
  end
end

And this cleaned value is available in observations in the final published result:

class MyExperiment
  include Scientist::Experiment

  # ...

  def publish(result)
    result.control.value         # [<User alice>, <User bob>, <User carol>]
    result.control.cleaned_value # ["alice", "bob", "carol"]
  end
end

Note that the #clean method will discard the previous cleaner block if you call it again. If for some reason you need to access the currently configured cleaner block, Scientist::Experiment#cleaner will return the block without further ado. (This probably won't come up in normal usage, but comes in handy if you're writing, say, a custom experiment runner that provides default cleaners.)

The #clean method will not be used for comparison of the results, so in the following example it is not possible to remove the #compare method without the experiment failing:

def user_ids
  science "user_ids" do
    e.use { [1,2,3] }
    e.try { [1,3,2] }
    e.clean { |value| value.sort }
    e.compare { |a, b| a.sort == b.sort }
  end
end

Ignoring mismatches

During the early stages of an experiment, it's possible that some of your code will always generate a mismatch for reasons you know and understand but haven't yet fixed. Instead of these known cases always showing up as mismatches in your metrics or analysis, you can tell an experiment whether or not to ignore a mismatch using the ignore method. You may include more than one block if needed:

def admin?(user)
  science "widget-permissions" do |e|
    e.use { model.check_user(user).admin? }
    e.try { user.can?(:admin, model) }

    e.ignore { user.staff? } # user is staff, always an admin in the new system
    e.ignore do |control, candidate|
      # new system doesn't handle unconfirmed users yet:
      control && !candidate && !user.confirmed_email?
    end
  end
end

The ignore blocks are only called if the values don't match. Unless a compare_errors comparator is defined, two cases are considered mismatches: a) one observation raising an exception and the other not, b) observations raising exceptions with different classes or messages.

Enabling/disabling experiments

Sometimes you don't want an experiment to run. Say, disabling a new codepath for anyone who isn't staff. You can disable an experiment by setting a run_if block. If this returns false, the experiment will merely return the control value. Otherwise, it defers to the experiment's configured enabled? method.

class DashboardController
  include Scientist

  def dashboard_items
    science "dashboard-items" do |e|
      # only run this experiment for staff members
      e.run_if { current_user.staff? }
      # ...
  end
end

Ramping up experiments

As a scientist, you know it's always important to be able to turn your experiment off, lest it run amok and result in villagers with pitchforks on your doorstep. In order to control whether or not an experiment is enabled, you must include the enabled? method in your Scientist::Experiment implementation.

class MyExperiment
  include Scientist::Experiment

  attr_accessor :name, :percent_enabled

  def initialize(name)
    @name = name
    @percent_enabled = 100
  end

  def enabled?
    percent_enabled > 0 && rand(100) < percent_enabled
  end

  # ...

end

This code will be invoked for every method with an experiment every time, so be sensitive about its performance. For example, you can store an experiment in the database but wrap it in various levels of caching such as memcache or per-request thread-locals.

Publishing results

What good is science if you can't publish your results?

You must implement the publish(result) method, and can publish data however you like. For example, timing data can be sent to graphite, and mismatches can be placed in a capped collection in redis for debugging later.

The publish method is given a Scientist::Result instance with its associated Scientist::Observations:

class MyExperiment
  include Scientist::Experiment

  # ...

  def publish(result)

    # Store the timing for the control value,
    $statsd.timing "science.#{name}.control", result.control.duration
    # for the candidate (only the first, see "Breaking the rules" below,
    $statsd.timing "science.#{name}.candidate", result.candidates.first.duration

    # and counts for match/ignore/mismatch:
    if result.matched?
      $statsd.increment "science.#{name}.matched"
    elsif result.ignored?
      $statsd.increment "science.#{name}.ignored"
    else
      $statsd.increment "science.#{name}.mismatched"
      # Finally, store mismatches in redis so they can be retrieved and examined
      # later on, for debugging and research.
      store_mismatch_data(result)
    end
  end

  def store_mismatch_data(result)
    payload = {
      :name            => name,
      :context         => context,
      :control         => observation_payload(result.control),
      :candidate       => observation_payload(result.candidates.first),
      :execution_order => result.observations.map(&:name)
    }

    key = "science.#{name}.mismatch"
    $redis.lpush key, payload
    $redis.ltrim key, 0, 1000
  end

  def observation_payload(observation)
    if observation.raised?
      {
        :exception => observation.exception.class,
        :message   => observation.exception.message,
        :backtrace => observation.exception.backtrace
      }
    else
      {
        # see "Keeping it clean" above
        :value => observation.cleaned_value
      }
    end
  end
end

Testing

When running your test suite, it's helpful to know that the experimental results always match. To help with testing, Scientist defines a raise_on_mismatches class attribute when you include Scientist::Experiment. Only do this in your test suite!

To raise on mismatches:

class MyExperiment
  include Scientist::Experiment
  # ... implementation
end

MyExperiment.raise_on_mismatches = true

Scientist will raise a Scientist::Experiment::MismatchError exception if any observations don't match.

Custom mismatch errors

To instruct Scientist to raise a custom error instead of the default Scientist::Experiment::MismatchError:

class CustomMismatchError < Scientist::Experiment::MismatchError
  def to_s
    message = "There was a mismatch! Here's the diff:"

    diffs = result.candidates.map do |candidate|
      Diff.new(result.control, candidate)
    end.join("\n")

    "#{message}\n#{diffs}"
  end
end
science "widget-permissions" do |e|
  e.use { Report.find(id) }
  e.try { ReportService.new.fetch(id) }

  e.raise_with CustomMismatchError
end

This allows for pre-processing on mismatch error exception messages.

Handling errors

In candidate code

Scientist rescues and tracks all exceptions raised in a try or use block, including some where rescuing may cause unexpected behavior (like SystemExit or ScriptError). To rescue a more restrictive set of exceptions, modify the RESCUES list:

# default is [Exception]
Scientist::Observation::RESCUES.replace [StandardError]

Timeout ⏲️: If you're introducing a candidate that could possibly timeout, use caution. ⚠️ While Scientist rescues all exceptions that occur in the candidate block, it does not protect you from timeouts, as doing so would be complicated. It would likely require running the candidate code in a background job and tracking the time of a request. We feel the cost of this complexity would outweigh the benefit, so make sure that your code doesn't cause timeouts. This risk can be reduced by running the experiment on a low percentage so that users can (most likely) bypass the experiment by refreshing the page if they hit a timeout. See Ramping up experiments below for how details on how to set the percentage for your experiment.

In a Scientist callback

If an exception is raised within any of Scientist's internal helpers, like publish, compare, or clean, the raised method is called with the symbol name of the internal operation that failed and the exception that was raised. The default behavior of Scientist::Default is to simply re-raise the exception. Since this halts the experiment entirely, it's often a better idea to handle this error and continue so the experiment as a whole isn't canceled entirely:

class MyExperiment
  include Scientist::Experiment

  # ...

  def raised(operation, error)
    InternalErrorTracker.track! "science failure in #{name}: #{operation}", error
  end
end

The operations that may be handled here are:

  • :clean - an exception is raised in a clean block
  • :compare - an exception is raised in a compare block
  • :enabled - an exception is raised in the enabled? method
  • :ignore - an exception is raised in an ignore block
  • :publish - an exception is raised in the publish method
  • :run_if - an exception is raised in a run_if block

Designing an experiment

Because enabled? and run_if determine when a candidate runs, it's impossible to guarantee that it will run every time. For this reason, Scientist is only safe for wrapping methods that aren't changing data.

When using Scientist, we've found it most useful to modify both the existing and new systems simultaneously anywhere writes happen, and verify the results at read time with science. raise_on_mismatches has also been useful to ensure that the correct data was written during tests, and reviewing published mismatches has helped us find any situations we overlooked with our production data at runtime. When writing to and reading from two systems, it's also useful to write some data reconciliation scripts to verify and clean up production data alongside any running experiments.

Noise and error rates

Keep in mind that Scientist's try and use blocks run sequentially in random order. As such, any data upon which your code depends may change before the second block is invoked, potentially yielding a mismatch between the candidate and control return values. To calibrate your expectations with respect to false negatives arising from systemic conditions external to your proposed changes, consider starting with an experiment in which both the try and use blocks invoke the control method. Then proceed with introducing a candidate.

Finishing an experiment

As your candidate behavior converges on the controls, you'll start thinking about removing an experiment and using the new behavior.

  • If there are any ignore blocks, the candidate behavior is guaranteed to be different. If this is unacceptable, you'll need to remove the ignore blocks and resolve any ongoing mismatches in behavior until the observations match perfectly every time.
  • When removing a read-behavior experiment, it's a good idea to keep any write-side duplication between an old and new system in place until well after the new behavior has been in production, in case you need to roll back.

Breaking the rules

Sometimes scientists just gotta do weird stuff. We understand.

Ignoring results entirely

Science is useful even when all you care about is the timing data or even whether or not a new code path blew up. If you have the ability to incrementally control how often an experiment runs via your enabled? method, you can use it to silently and carefully test new code paths and ignore the results altogether. You can do this by setting ignore { true }, or for greater efficiency, compare { true }.

This will still log mismatches if any exceptions are raised, but will disregard the values entirely.

Trying more than one thing

It's not usually a good idea to try more than one alternative simultaneously. Behavior isn't guaranteed to be isolated and reporting + visualization get quite a bit harder. Still, it's sometimes useful.

To try more than one alternative at once, add names to some try blocks:

require "scientist"

class MyWidget
  include Scientist

  def allows?(user)
    science "widget-permissions" do |e|
      e.use { model.check_user(user).valid? } # old way

      e.try("api") { user.can?(:read, model) } # new service API
      e.try("raw-sql") { user.can_sql?(:read, model) } # raw query
    end
  end
end

When the experiment runs, all candidate behaviors are tested and each candidate observation is compared with the control in turn.

No control, just candidates

Define the candidates with named try blocks, omit a use, and pass a candidate name to run:

experiment = MyExperiment.new("various-ways") do |e|
  e.try("first-way")  { ... }
  e.try("second-way") { ... }
end

experiment.run("second-way")

The science helper also knows this trick:

science "various-ways", run: "first-way" do |e|
  e.try("first-way")  { ... }
  e.try("second-way") { ... }
end

Providing fake timing data

If you're writing tests that depend on specific timing values, you can provide canned durations using the fabricate_durations_for_testing_purposes method, and Scientist will report these in Scientist::Observation#duration instead of the actual execution times.

science "absolutely-nothing-suspicious-happening-here" do |e|
  e.use { ... } # "control"
  e.try { ... } # "candidate"
  e.fabricate_durations_for_testing_purposes( "control" => 1.0, "candidate" => 0.5 )
end

fabricate_durations_for_testing_purposes takes a Hash of duration values, keyed by behavior names. (By default, Scientist uses "control" and "candidate", but if you override these as shown in Trying more than one thing or No control, just candidates, use matching names here.) If a name is not provided, the actual execution time will be reported instead.

Like Scientist::Experiment#cleaner, this probably won't come up in normal usage. It's here to make it easier to test code that extends Scientist.

Without including Scientist

If you need to use Scientist in a place where you aren't able to include the Scientist module, you can call Scientist.run:

Scientist.run "widget-permissions" do |e|
  e.use { model.check_user(user).valid? }
  e.try { user.can?(:read, model) }
end

Hacking

Be on a Unixy box. Make sure a modern Bundler is available. script/test runs the unit tests. All development dependencies are installed automatically. Scientist requires Ruby 2.3 or newer.

Wrappers

  • RealGeeks/lab_tech is a Rails engine for using this library by controlling, storing, and analyzing experiment results with ActiveRecord.

Alternatives

Maintainers

@jbarnette, @jesseplusplus, @rick, and @zerowidth

More Repositories

1

gitignore

A collection of useful .gitignore templates
160,684
star
2

copilot-docs

Documentation for GitHub Copilot
23,229
star
3

docs

The open-source repo for docs.github.com
JavaScript
14,053
star
4

opensource.guide

πŸ“š Community guides for open source creators
HTML
12,947
star
5

gh-ost

GitHub's Online Schema-migration Tool for MySQL
Go
11,302
star
6

linguist

Language Savant. If your repository's language is being reported incorrectly, send us a pull request!
Ruby
10,684
star
7

semantic

Parsing, analyzing, and comparing source code across many languages
Haskell
8,865
star
8

copilot.vim

Neovim plugin for GitHub Copilot
Vim Script
8,286
star
9

codeql

CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
CodeQL
7,579
star
10

roadmap

GitHub public roadmap
7,393
star
11

personal-website

Code that'll help you kickstart a personal website that showcases your work as a software developer.
HTML
7,243
star
12

markup

Determines which markup library to use to render a content file (e.g. README) on GitHub
Ruby
5,678
star
13

dmca

Repository with text of DMCA takedown notices as received. GitHub does not endorse or adopt any assertion contained in the following notices. Users identified in the notices are presumed innocent until proven guilty. Additional information about our DMCA policy can be found at
DIGITAL Command Language
5,457
star
14

swift-style-guide

**Archived** Style guide & coding conventions for Swift projects
4,770
star
15

gemoji

Emoji images and names.
Ruby
4,280
star
16

training-kit

Open source courseware for Git and GitHub
HTML
4,247
star
17

explore

Community-curated topic and collection pages on GitHub
Ruby
3,840
star
18

mona-sans

Mona Sans, a variable font from GitHub
3,680
star
19

hubot-scripts

DEPRECATED, see https://github.com/github/hubot-scripts/issues/1113 for details - optional scripts for hubot, opt in via hubot-scripts.json
CoffeeScript
3,538
star
20

choosealicense.com

A site to provide non-judgmental guidance on choosing a license for your open source project
Ruby
3,379
star
21

git-sizer

Compute various size metrics for a Git repository, flagging those that might cause problems
Go
3,160
star
22

secure_headers

Manages application of security headers with many safe defaults
Ruby
3,104
star
23

gov-takedowns

Text of government takedown notices as received. GitHub does not endorse or adopt any assertion contained in the following notices.
3,088
star
24

archive-program

The GitHub Archive Program & Arctic Code Vault
3,000
star
25

scripts-to-rule-them-all

Set of boilerplate scripts describing the normalized script pattern that GitHub uses in its projects.
Shell
2,859
star
26

hotkey

Trigger an action on an element with a keyboard shortcut.
JavaScript
2,851
star
27

relative-time-element

Web component extensions to the standard <time> element.
JavaScript
2,799
star
28

janky

Continuous integration server built on top of Jenkins and Hubot
Ruby
2,759
star
29

github-elements

GitHub's Web Component collection.
JavaScript
2,523
star
30

renaming

Guidance for changing the default branch name for GitHub repositories
2,408
star
31

view_component

A framework for building reusable, testable & encapsulated view components in Ruby on Rails.
Ruby
2,370
star
32

VisualStudio

GitHub Extension for Visual Studio
C#
2,365
star
33

glb-director

GitHub Load Balancer Director and supporting tooling.
C
2,255
star
34

SoftU2F

Software U2F authenticator for macOS
Swift
2,201
star
35

accessibilityjs

Client side accessibility error scanner.
JavaScript
2,180
star
36

CodeSearchNet

Datasets, tools, and benchmarks for representation learning of code.
Jupyter Notebook
2,155
star
37

balanced-employee-ip-agreement

GitHub's employee intellectual property agreement, open sourced and reusable
2,126
star
38

github-services

Legacy GitHub Services Integration
Ruby
1,902
star
39

platform-samples

A public place for all platform sample projects.
Shell
1,885
star
40

hubot-sans

Hubot Sans, a variable font from GitHub
Shell
1,832
star
41

pages-gem

A simple Ruby Gem to bootstrap dependencies for setting up and maintaining a local Jekyll environment in sync with GitHub Pages
Ruby
1,782
star
42

india

GitHub resources and information for the developer community in India
Ruby
1,769
star
43

haikus-for-codespaces

EJS
1,753
star
44

site-policy

Collaborative development on GitHub's site policies, procedures, and guidelines
1,743
star
45

government.github.com

Gather, curate, and feature stories of public servants and civic hackers using GitHub as part of their open government innovations
HTML
1,727
star
46

advisory-database

Security vulnerability database inclusive of CVEs and GitHub originated security advisories from the world of open source software.
1,711
star
47

objective-c-style-guide

**Archived** Style guide & coding conventions for Objective-C projects
1,682
star
48

covid19-dashboard

A site that displays up to date COVID-19 stats, powered by fastpages.
Jupyter Notebook
1,644
star
49

lightcrawler

Crawl a website and run it through Google lighthouse
JavaScript
1,471
star
50

rest-api-description

An OpenAPI description for GitHub's REST API
1,372
star
51

feedback

Public feedback discussions for: GitHub for Mobile, GitHub Discussions, GitHub Codespaces, GitHub Sponsors, GitHub Issues and more!
1,359
star
52

developer.github.com

GitHub Developer site
Ruby
1,314
star
53

backup-utils

GitHub Enterprise Backup Utilities
1,190
star
54

brubeck

A Statsd-compatible metrics aggregator
C
1,185
star
55

dev

Press the . key on any repo
1,184
star
56

catalyst

Catalyst is a set of patterns and techniques for developing components within a complex application.
TypeScript
1,183
star
57

codeql-action

Actions for running CodeQL analysis
TypeScript
1,152
star
58

securitylab

Resources related to GitHub Security Lab
C
1,150
star
59

opensourcefriday

🚲 Contribute to the open source community every Friday
HTML
1,143
star
60

graphql-client

A Ruby library for declaring, composing and executing GraphQL queries
Ruby
1,139
star
61

Rebel

Cocoa framework for improving AppKit
Objective-C
1,127
star
62

gh-actions-importer

GitHub Actions Importer helps you plan and automate the migration of Azure DevOps, Bamboo, Bitbucket, CircleCI, GitLab, Jenkins, and Travis CI pipelines to GitHub Actions.
C#
982
star
63

licensed

A Ruby gem to cache and verify the licenses of dependencies
Ruby
942
star
64

.github

Community health files for the @GitHub organization
869
star
65

swordfish

EXPERIMENTAL password management app. Don't use this.
Ruby
740
star
66

details-dialog-element

A modal dialog that's opened with <details>.
JavaScript
739
star
67

stack-graphs

Rust implementation of stack graphs
Rust
725
star
68

codeql-cli-binaries

Binaries for the CodeQL CLI
725
star
69

github-ds

A collection of Ruby libraries for working with SQL on top of ActiveRecord's connection
Ruby
667
star
70

email_reply_parser

Small library to parse plain text email content
Ruby
658
star
71

vulcanizer

GitHub's ops focused Elasticsearch library
Go
657
star
72

github-ospo

Helping open source program offices get started
641
star
73

webauthn-json

πŸ” A small WebAuthn API wrapper that translates to/from pure JSON using base64url.
TypeScript
638
star
74

gh-copilot

Ask for assistance right in your terminal.
637
star
75

rubocop-github

Code style checking for GitHub's Ruby projects
Ruby
616
star
76

safe-settings

JavaScript
606
star
77

codespaces-jupyter

Explore machine learning and data science with Codespaces
Jupyter Notebook
591
star
78

dat-science

Replaced by https://github.com/github/scientist
Ruby
582
star
79

maven-plugins

Official GitHub Maven Plugins
Java
581
star
80

details-menu-element

A menu opened with <details>.
JavaScript
554
star
81

trilogy

Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding.
C
543
star
82

freno

freno: cooperative, highly available throttler service
Go
534
star
83

smimesign

An S/MIME signing utility for use with Git
Go
519
star
84

brasil

Recursos e informaçáes do GitHub para a comunidade de desenvolvedores no Brasil.
Ruby
515
star
85

gh-valet

Valet helps facilitate the migration of Azure DevOps, CircleCI, GitLab CI, Jenkins, and Travis CI pipelines to GitHub Actions.
C#
511
star
86

include-fragment-element

A client-side includes tag.
JavaScript
508
star
87

covid-19-repo-data

Data archive of identifiable COVID-19 related public projects on GitHub
505
star
88

vscode-github-actions

GitHub Actions extension for VS Code
TypeScript
492
star
89

vscode-codeql-starter

Starter workspace to use with the CodeQL extension for Visual Studio Code.
CodeQL
477
star
90

how-engineering-communicates

A community version of the "common API" for how the GitHub Engineering organization communicates
474
star
91

Archimedes

Geometry functions for Cocoa and Cocoa Touch
Objective-C
466
star
92

codeql-go

The CodeQL extractor and libraries for Go.
465
star
93

open-source-survey

The Open Source Survey
431
star
94

synsanity

netfilter (iptables) target for high performance lockless SYN cookies for SYN flood mitigation
C
424
star
95

entitlements-app

The Ruby Gem that Powers Entitlements - GitHub's Identity and Access Management System
Ruby
409
star
96

MVG

MVG = Minimum Viable Governance
379
star
97

issue-metrics

Gather metrics on issues/prs/discussions such as time to first response, count of issues opened, closed, etc.
Python
378
star
98

roskomnadzor

deprecated archive β€” moved to https://github.com/github/gov-takedowns/tree/master/Russia
376
star
99

clipboard-copy-element

Copy element text content or input values to the clipboard.
JavaScript
374
star
100

codespaces-react

JavaScript
364
star