DEPRECATED
==========

RockPaperScissors
=================

RockPaperScissors a system for collecting software project health metrics such
as time between releases, code churn, test coverage, etc. It's also gamified so
teams can compare their progress and are encouraged to follow best practices in
order to gain higher levels and score points.

Twitch has a number of other metrics collections systems but this one is
targeted just for developer tools (e.g. Jenkins, GitHub, Skadi) and a bit more
flexible in what it records in order to be able to do more kinds of ad hoc and
contextual analysis later.

Wiki page in Jira: http://link.twitch.tv/dta-rps-wiki

Slide Deck: http://link.twitch.tv/dta-rps-preso

Design Doc: http://link.twitch.tv/dta-rps-design

Slack Channel: #RPS

## Local Development Quick Start

Building/testing with Manta (assumes you've already installed Manta):

```
manta -v -f build.json
```

This will build binaries for Linux 64bit Intel platforms. It's also pretty slow
on laptops.

Inside .manta, you will find the following artifacts:

Artifact                          | Description
--------------------------------- | -----------
aws_lambda                        | AWS Lambda handlers and dependencies
aws_lambda_venv/coverage_html     | test coverage browser for Python code
\*.html                           | test coverage browser for each Go package
rockpaperscissors                 | actual service binary
rockpaperscissors.alpine          | statically compiled with musl libc library for running under Alpine Linux
publishevent                      | CLI tool for publishing an event to the event bus
rpstool                           | CLI tool for rockpaperscissors APIs
test_report.xml                   | JUnit style test report

If you would rather build in the host environment, you may use:

```
./scripts/build.sh output
```

This is the same script that manta runs and will output the same artifacts into
a directory named `output`. See the `setup` portion of the `build.json` file for
what dependencies need to be installed into your host environment in order to
build. The `scripts/install_build_tools.sh` script should install the right
depedencies for your macOS development host but we sometimes forget to update
it.

`rockpaperscissors` is the main "service" binary. Best practice to is run it
like so:

```
go run ./cmd/rockpaperscissors/main.go -enable-ingest-queue-consumer=false -enable-events-datastore-writes=false
```

The extra flags will turn off a background task that updates GitHub statistics
and disables accidentally making changes to the events datastore.

The `rockpaperscissors` service requires AWS credentials to access it's
datastores in the `twitch-core-services` account. You may need to set AWS
environment variables to get it to start correctly. It does honor the
`AWS_PROFILE` environment variable if you have credentials stored in profile
files.

By default, it logs to standard error and listens to TCP port 8000. You can go
to http://localhost:8000/ in your browser and get the web UI. It also serves a
JSON/REST API and a gRPC API on the same port. You can go to
http://localhost:8000/api/swagger/ to get documentation about the JSON/REST API
and actually try it out right there. Most of that API you can do by crafting
URLs under http://localhost:8000/api/v1/.

While the `rockpaperscissors` service is running locally, you can use rpstool to
talk to it with if you use the `--rps-addr=localhost:8000` flag with it.

## Python Lambda Bundles

`aws_lambda/event_store.py` contains an AWS lambda function written in Python.
This handler listens a Kinesis stream and writes the events it receives there to
a DynamoDB table. Generated protobuf code for Python isn't checked into source
control but is generated by the build script.

`aws_lambda/github_webhook_handler.py` contains an AWS lambda function written
in Python. This handler is connected to an AWS API Gateway to receive GitHub
webhooks and publish events based on those to the Kinesis.

`aws_lambda/blueprint_ingest.py` contains an AWS lambda function written in
Python. This handler also listens to the Kinesis stream looking for
`GitHub-push` events that show a `*.blueprint` file changed in a repository's
"default" branch (usually "master"). When it sees such an event, it adds a
request to an AWS SQS queue to "ingest" that blueprint to update its project
metadata.

`aws_lambda/github_stats.py` contains an AWS lambda function written in Python.
This handler also lists to the Kinesis stream looking for `GitHub-push` events
to the "default branch" (usually "master" for most repositories) and puts a
request in an AWS SQS queue to schedule an ingestion of code change stats by
querying GitHub.

`aws_lambda/jira_scraper.py` contains an AWS lambda function written in Python.
It simply contacts JIRA to do some queries about open production bugs.

## Go Packages

Package                        | Description
------------------------------ | -----------
./client/blueprint             | Utility functions for reading and parsing blueprint files.
./client/event                 | Client library for event service
./client/eventpublisher        | Client library for publishing events to the event bus
./client/metric                | Client library for the metric service
./client/projectmetadata       | Client library for the project metadata service
./client/web                   | standard HTTP server providing a javascript based client/UI
./cmd/publishevent             | CLI to publish an event to the event bus
./cmd/rockpaperscissors        | Main rockpaperscissors server binary
./cmd/rpstool                  | CLI for rockpaperscissors APIs
./internal/api/event           | gRPC service implementing event API
./internal/api/metric          | gRPC service implementing metric API
./internal/api/projectmetadata | gRPC service implementing project metadata API
./internal/api/swagger         | HTTP handlers for serving generated swagger-ui
./internal/codecov             | Parser for Codecov coverage reports
./internal/elasticache         | AWS ElastiCache client that supports auto-discovery
./internal/github              | creates github clients, uses OAuth token in Sandstorm
./internal/ingestqueueconsumer | background poller that consumes "ingest" requests from SQS
./internal/metrics             | metrics calculators, has a registry/plugin system
./internal/mocks/...           | Generated packages used for mocking in unit tests
./internal/sandstorm           | simple wrapper to lookup secrets in Sandstorm
./internal/taskmanager         | Manager for background "task" goroutines
./internal/testutil            | Convenience functions used in go tests
./proto                        | Proto schema definitions and generated go code

## Docker images

The Docker image for rockpaperscissors is:
`docker-registry.internal.justin.tv/dta/rockpaperscissors`

When Jenkins does a build from the `master` branch, it will also make and
publishing a Docker image tagged with the Git commit ID it built at.

You can start a Jenkins-built Docker image in a container listening on port
8080:
```
docker run -p 8080:8000 --rm --name rockpaperscissors \
  docker-registry.internal.justin.tv/dta/rockpaperscissors:$(git rev-parse --verify HEAD)
```

To locally build an image:
```
manta -f build.json && docker build .
```

## Provisioning with Terraform

There is a helper script at `./scripts/terraform_apply.sh` that assumes you
have `terraform_apply` installed and have a configured AWS profile named
`twitch-core-services`. The first argument is the environment to work with
and the rest are passed to `terraform_apply` so `-p` and `-f` work as you'd
expect.

There are 3 main blocks of Terraform configs in the `terraform` tree:
* terraform/beanstalk_app
* terraform/development
* terraform/production

There is one "beanstalk_app" that is provisioned. That simply gives the service
a name and environments are created within it.

```
./scripts/terraform_apply.sh beanstalk_app
```

The "production" config creates:
* a "production" Beanstalk environment
* a "staging" Beanstalk environment
* Kinesis stream to receive events
* an events DynamoDB table
* a Lambda function to listen to that stream and write events to that table
* a projects DynamoDB table
* API Gateway to receive for GitHub webhooks
* a Lambda function to receive GitHub webhooks connected to API Gateway
* a Lambda function to look for GitHub events where blueprints are modified
* a Lambda function to query JIRA
* a CloudWatch scheduled event to tickle the JIRA Lambda every hour
* a Lambda function to look for GitHub pushes for stats collection
* an SQS queue to hold blueprint and GitHub stats "ingestion" requests
* an S3 bucket for storing large events
* CloudWatch alarms to monitor the resources
* SNS Topic to report alerts to PagerDuty
* IAM roles/policies for it all.

The staging and production environments share the same datastores and are
configured almost exactly the same except for the name.

```
./scripts/terraform_apply.sh production
```

The development config creates the same set of resources as the production
config but only has one "development" Beanstalk environment. It also uses a
different set of roles, VPCs, and subnets.

```
./scripts/terraform_apply.sh development
```

## Deploying

When git commits are pushed to the `master` branch in the
`dta/rockpaperscissors` respository in our GitHub Enterprise instance, Jenkins
will, after building the AWS Lambda function packages and Docker image, also
deploy those to the "development" environment.

Production and staging deployments are done through Skadi.

### Deploying Manually

The regular AWS console or command line tools can be used to to deploy a Lambda
function package or Beanstalk version created for the development environment
to a production environment.

For example, you may deploy the latest Git commit (assuming it's been built by
Jenkins) to production using the `eb` command line tool:
```
eb deploy rockpaperscissors-production \
  --profile twitch-core-services \
  --version $(git rev-parse --verify HEAD)
```

Same but for a production Lambda function (all function use the same zip package):
```
aws --profile twitch-core-services lambda update-function-code \
  --function-name rockpaperscissors-production \
  --publish \
  --s3-bucket core-devtools-deploy-artifact \
  --s3-key dta/rockpaperscissors/$(git rev-parse --verify HEAD).zip
```

## API and Clients

RockPaperScissors has a gRPC-based API that listens on the same port as it's
web UI. Service definitions are in the `proto/*_service.proto` files.

The endpoints are:

Address                                     | Description
------------------------------------------- | -----------
rockpaperscissors-dev.internal.justin.tv:80 | Development instance
rockpaperscissors.internal.justin.tv:80     | Production instance

Any data stored in the development instance is not guaranteed to persist and may
be cleared at any time.

At this stage, this API should be considered in draft and may change. Also,
currently, the API doesn't have authentication or authorization but will be
implemented soon.

Go client packages for the API are under `./client`.

In addition to the gRPC-based API, there is a Kinesis stream of events that are
ingested into the datastore. You may publish your own development-related events
to this stream and subscribe to it to receive development-related events. Each
event is a protobuffer; see `proto/event.proto` for the fields.

A Go library for publishing to the event stream is provided in
`./client/eventpublisher`.
