github.com/mistwind/reviewdog@v0.0.0-20230322024206-9cfa11856d58/doghouse/server/storage/installation.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  
     6  	"cloud.google.com/go/datastore"
     7  )
     8  
     9  // GitHubInstallation represents GitHub Apps Installation data.
    10  // Installation is per org or user account, not repository.
    11  type GitHubInstallation struct {
    12  	InstallationID int64  // https://github.com/settings/installations/<InstallationID>
    13  	AccountName    string // https://github/<AccountName>. Org or user account.
    14  	AccountID      int64  // GitHub ID of <AccountName>.
    15  }
    16  
    17  // GitHubInstallationStore represents GitHubInstallation storage interface.
    18  type GitHubInstallationStore interface {
    19  	// Put upserts GitHub InstallationID entity. If InstallationID is not
    20  	// updated, the whole entity won't be saved.
    21  	Put(ctx context.Context, inst *GitHubInstallation) error
    22  	// Get get GitHubInstallation entity by account name.
    23  	// - If the entity is found, return inst with ok is true.
    24  	// - If the entity is not found, ok is false.
    25  	// - If error occurs, it returns err.
    26  	Get(ctx context.Context, accountName string) (ok bool, inst *GitHubInstallation, err error)
    27  }
    28  
    29  // GitHubInstallationDatastore is store of GitHubInstallation by Datastore of
    30  // Google Appengine.
    31  type GitHubInstallationDatastore struct{}
    32  
    33  func (g *GitHubInstallationDatastore) newKey(accountName string) *datastore.Key {
    34  	const kind = "GitHubInstallation"
    35  	return datastore.NameKey(kind, accountName, nil)
    36  }
    37  
    38  // Put save GitHubInstallation. It reduces datastore write call as much as possible.
    39  func (g *GitHubInstallationDatastore) Put(ctx context.Context, inst *GitHubInstallation) error {
    40  	d, err := datastoreClient(ctx)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	_, err = d.RunInTransaction(ctx, func(t *datastore.Transaction) error {
    45  		var foundInst GitHubInstallation
    46  		var ok bool
    47  		err := t.Get(g.newKey(inst.AccountName), &foundInst)
    48  		if err != datastore.ErrNoSuchEntity {
    49  			ok = true
    50  		}
    51  		if err != nil {
    52  			return err
    53  		}
    54  		// Insert if not found or installation ID is different.
    55  		if !ok || foundInst.InstallationID != inst.InstallationID {
    56  			_, err = t.Put(g.newKey(inst.AccountName), inst)
    57  			return err
    58  		}
    59  		return nil // Do nothing.
    60  	})
    61  	return err
    62  }
    63  
    64  func (g *GitHubInstallationDatastore) Get(ctx context.Context, accountName string) (ok bool, inst *GitHubInstallation, err error) {
    65  	key := g.newKey(accountName)
    66  	inst = new(GitHubInstallation)
    67  	d, err := datastoreClient(ctx)
    68  	if err != nil {
    69  		return false, nil, err
    70  	}
    71  	if err := d.Get(ctx, key, inst); err != nil {
    72  		if err == datastore.ErrNoSuchEntity {
    73  			return false, nil, nil
    74  		}
    75  		return false, nil, err
    76  	}
    77  	return true, inst, nil
    78  }