github.com/reviewdog/reviewdog@v0.17.5-0.20240516205324-0cd103a83d58/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  	defer d.Close()
    45  	_, err = d.RunInTransaction(ctx, func(t *datastore.Transaction) error {
    46  		var foundInst GitHubInstallation
    47  		var ok bool
    48  		err := t.Get(g.newKey(inst.AccountName), &foundInst)
    49  		if err != datastore.ErrNoSuchEntity {
    50  			ok = true
    51  		}
    52  		if err != nil {
    53  			return err
    54  		}
    55  		// Insert if not found or installation ID is different.
    56  		if !ok || foundInst.InstallationID != inst.InstallationID {
    57  			_, err = t.Put(g.newKey(inst.AccountName), inst)
    58  			return err
    59  		}
    60  		return nil // Do nothing.
    61  	})
    62  	return err
    63  }
    64  
    65  func (g *GitHubInstallationDatastore) Get(ctx context.Context, accountName string) (ok bool, inst *GitHubInstallation, err error) {
    66  	key := g.newKey(accountName)
    67  	inst = new(GitHubInstallation)
    68  	d, err := datastoreClient(ctx)
    69  	if err != nil {
    70  		return false, nil, err
    71  	}
    72  	defer d.Close()
    73  	if err := d.Get(ctx, key, inst); err != nil {
    74  		if err == datastore.ErrNoSuchEntity {
    75  			return false, nil, nil
    76  		}
    77  		return false, nil, err
    78  	}
    79  	return true, inst, nil
    80  }