Skip to content

Commit

Permalink
Add bulletproof automerger
Browse files Browse the repository at this point in the history
commit-id:c2d84b0c
  • Loading branch information
leoluk committed Nov 17, 2021
1 parent 482e8a3 commit 986bf28
Show file tree
Hide file tree
Showing 15 changed files with 1,736 additions and 32 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ trim_trailing_whitespace = true
[*.md]
max_line_length = 0
trim_trailing_whitespace = false

[{go.mod,go.sum,*.go}]
indent_style = tab
indent_size = 4
25 changes: 25 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,28 @@ At minimum each entry should have
- Logo: (logo should be uploaded under assets/mainnet/<mint address>/\*.<png/svg>)
- Link to the official homepage of token:
- Coingecko ID if available (https://www.coingecko.com/api/documentations/v3#/coins/get_coins__id_):

## Auto merge requirements

Your pull request will be automatically merged if the following conditions are met:

- Your pull request **only adds new tokens** to the list. Any modification to existing
tokens will require manual review to prevent unwanted modifications.

- Your pull request does **not touch unrelated code**. In particular, reformatting changes to unrelated
code will cause the auto merge to reject your PR.

- Any **asset files added correspond to the token address** you are adding. Asset files
must be PNG, JPG or SVG files.

- Your change is **valid JSON** and **conforms to the schema**. If your change failed validation,
read the error message carefully and update your PR accordingly.

- No other tokens shares the **same name, symbol or address**.

For example, this change would be rejected due to unrelated changes:

<img src=https://i.imgur.com/qB9RNO4.png width=600px>

The bot runs **every 30 minutes** and bulk-merges all open pull requests to prevent conflicts.
This means that you need to wait up to 30 minutes for your pull request to be merged or reprocessed.
37 changes: 8 additions & 29 deletions .github/workflows/automerge.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
name: Automerge

on:
pull_request_target:
push:
Expand All @@ -18,30 +16,11 @@ jobs:
auto-merge:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v1
with:
node-version: 12
- run: yarn
- run: yarn test

- name: Get changes
id: git_diff
uses: swmd/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- uses: actions-ecosystem/action-add-labels@v1
if: ${{ steps.git_diff.outputs.valid == 'VALID' }}
with:
labels: automerge

# - name: Merge pull request
# if: ${{ steps.git_diff.outputs.valid == 'VALID' }}
# uses: 'pascalgn/[email protected]'
# env:
# GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- uses: LouisBrunner/[email protected]
if: always()
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: Automerge / auto-merge (pull_request_target)
conclusion: neutral
output: |
{"summary": "Disregard - please see new automerge" }
24 changes: 24 additions & 0 deletions .github/workflows/automerge_new.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: AutomergeCron

on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: actions/setup-go@v2
with:
go-version: '^1.17.3'

# Required for automerge to clone from the local working copy
- run: git checkout -b work

- run: cd automerge && go build -o ~/automerge github.com/solana-labs/token-list/automerge

- run: ~/automerge -v=1
env:
GITHUB_APP_PEM: "${{ secrets.GITHUB_APP_PEM }}"

- run: git push -f origin automerge-pending:automerge-pending
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ jobs:
- run: yarn
- run: yarn test
- run: go install cuelang.org/go/cmd/[email protected]
- run: PATH=$PATH:~/go/bin cd src/tokens && ./validate.sh
- run: PATH=$PATH:~/go/bin ./validate.sh
89 changes: 89 additions & 0 deletions automerge/auth/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package auth

import (
"context"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/google/go-github/v40/github"
"golang.org/x/oauth2"
"k8s.io/klog/v2"
"time"
)

var ErrInvalidKey = errors.New("invalid key")

// signJWTFromPEM returns a signed JWT from a PEM-encoded private key.
func signJWTFromPEM(key []byte, appId int64) (string, error) {
// decode PEM
block, _ := pem.Decode(key)
if block == nil {
return "", ErrInvalidKey
}

// parse key
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}

// sign
return signJWT(privateKey, appId)
}

func signJWT(privateKey *rsa.PrivateKey, appId int64) (string, error) {
// sign
token := jwt.NewWithClaims(jwt.SigningMethodRS256,
jwt.MapClaims{
"exp": time.Now().Add(10 * time.Minute).Unix(),
"iat": time.Now().Unix(),
"iss": fmt.Sprintf("%d", appId),
})

tokenString, err := token.SignedString(privateKey)
if err != nil {
return "", err
}

return tokenString, nil
}

func GetInstallationToken(privateKey []byte, appId int64) (string, error) {
token, err := signJWTFromPEM(privateKey, appId)
if err != nil {
klog.Exitf("failed to sign JWT: %v", err)
}

// get installation access token for app
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc := oauth2.NewClient(ctx, ts)
client := github.NewClient(tc)
is, _, err := client.Apps.ListInstallations(ctx, nil)
if err != nil {
klog.Exitf("failed to list installations: %v", err)
}

for _, i := range is {
if i.GetAppID() == appId {
klog.Infof("installation id: %v", i.GetID())
klog.Infof("installed on %s: %s", i.GetTargetType(), i.GetAccount().GetLogin())
}

// Get an installation token
it, _, err := client.Apps.CreateInstallationToken(ctx, i.GetID(), nil)
if err != nil {
klog.Exitf("failed to create installation token: %v", err)
}

return it.GetToken(), nil
}

return "", errors.New("no installation found")
}
Loading

0 comments on commit 986bf28

Please sign in to comment.