Skip to content

yiannistri/go-git-providers

 
 

Repository files navigation

go-git-providers

godev build Go Report Card codecov.io LICENSE Contributors Release PRs Welcome

go-git-providers is a general-purpose Go client for interacting with Git providers' APIs (e.g. GitHub, GitLab, Bitbucket).

Features

  • Consistency: Using the same Client interface and high-level structs for multiple backends.
  • Authentication: Personal Access Tokens/OAuth2 Tokens, and unauthenticated.
  • Pagination: List calls automatically return all available pages.
  • Conditional Requests: Asks the Git provider if cached data is up-to-date before requesting, to avoid being rate limited.
  • Reconciling: Support reconciling desired state towards actual state and drift detection.
  • Low-level access: Access the underlying, provider-specific data easily, if needed, and support applying it to the server.
  • Wrapped errors: Data-rich, Go 1.14-errors are consistent across provider, including cases like rate limit, validation, not found, etc.
  • Go modules: The major version is bumped if breaking changes, or major library upgrades are made.
  • Validation-first: Both server and user data is validated prior to manipulation.
  • URL Parsing: HTTPS user, organization and repository URLs can be parsed into machine-readable structs.
  • Enums: Consistent enums are used across providers for similar lists of values.
  • Domain customization: The user can specify their desired domain for the Git provider backend.
  • Context-first: context.Context is the first parameter for every API call.

Operations and Design

The top-level gitprovider.Client has the following sub-clients with their described capabilities:

  • OrganizationsClient operates on organizations the user has access to.

    • Get a specific organization the user has access to.
    • List all top-level organizations the specific user has access to.
    • Children returns the immediate child-organizations for the specific OrganizationRef.
  • {Org,User}RepositoriesClient operates on repositories for organizations and users, respectively.

    • Get returns the repository for the given reference.
    • List all repositories in the given organization or user account.
    • Create creates a repository, with the specified data and options.
    • Reconcile makes sure the given desired state becomes the actual state in the backing Git provider.

The sub-clients above return gitprovider.Organization or gitprovider.{Org,User}Repository interfaces. These object interfaces lets you access their data (through their .Get() function), internal, provider-specific representation (through their .APIObject() function), or sub-resources like deploy keys and teams.

The following object-scoped clients are available:

  • Organization represents an organization in a Git provider.

    • Teams gives access to the TeamsClient for this specific organization.
      • Get a team within the specific organization.
      • List all teams within the specific organization.
  • UserRepository describes a repository owned by an user.

    • DeployKeys gives access to manipulating deploy keys, using this DeployKeyClient.
      • Get a DeployKey by its name.
      • List all deploy keys for the given repository.
      • Create a deploy key with the given specifications.
      • Reconcile makes sure the given desired state becomes the actual state in the backing Git provider.
  • OrgRepository is a superset of UserRepository, and describes a repository owned by an organization.

    • DeployKeys as in UserRepository.
    • TeamAccess returns a TeamsAccessClient for operating on teams' access to this specific repository.
      • Get a team's permission level of this given repository.
      • List the team access control list for this repository.
      • Create adds a given team to the repository's team access control list.
      • Reconcile makes sure the given desired state (req) becomes the actual state in the backing Git provider.

Wait, how do I Delete or Update an object?

That's done on the returned objects themselves, using the following Updatable, Reconcilable and Deletable interfaces implemented by {Org,User}Repository, DeployKey and TeamAccess:

// Updatable is an interface which all objects that can be updated
// using the Client implement.
type Updatable interface {
    // Update will apply the desired state in this object to the server.
    // Only set fields will be respected (i.e. PATCH behaviour).
    // In order to apply changes to this object, use the .Set({Resource}Info) error
    // function, or cast .APIObject() to a pointer to the provider-specific type
    // and set custom fields there.
    //
    // ErrNotFound is returned if the resource does not exist.
    //
    // The internal API object will be overridden with the received server data.
    Update(ctx context.Context) error
}

// Deletable is an interface which all objects that can be deleted
// using the Client implement.
type Deletable interface {
    // Delete deletes the current resource irreversibly.
    //
    // ErrNotFound is returned if the resource doesn't exist anymore.
    Delete(ctx context.Context) error
}

// Reconcilable is an interface which all objects that can be reconciled
// using the Client implement.
type Reconcilable interface {
    // Reconcile makes sure the desired state in this object (called "req" here) becomes
    // the actual state in the backing Git provider.
    //
    // If req doesn't exist under the hood, it is created (actionTaken == true).
    // If req doesn't equal the actual state, the resource will be updated (actionTaken == true).
    // If req is already the actual state, this is a no-op (actionTaken == false).
    //
    // The internal API object will be overridden with the received server data if actionTaken == true.
    Reconcile(ctx context.Context) (actionTaken bool, err error)
}

In order to access the provider-specific, internal object, all resources implement the gitprovider.Object interface:

// Object is the interface all types should implement.
type Object interface {
    // APIObject returns the underlying value that was returned from the server.
    // This is always a pointer to a struct.
    APIObject() interface{}
}

So, how do I set the desired state for an object before running Update or Reconcile?

Using the Get() {Resource}Info or Set({Resource}Info) error methods. An example as follows, for TeamAccess:

// TeamAccess describes a binding between a repository and a team.
type TeamAccess interface {
    // TeamAccess implements the Object interface,
    // allowing access to the underlying object returned from the API.
    Object
    // The deploy key can be updated.
    Updatable
    // The deploy key can be reconciled.
    Reconcilable
    // The deploy key can be deleted.
    Deletable
    // RepositoryBound returns repository reference details.
    RepositoryBound

    // Get returns high-level information about this team access for the repository.
    Get() TeamAccessInfo
    // Set sets high-level desired state for this team access object. In order to apply these changes in
    // the Git provider, run .Update() or .Reconcile().
    Set(TeamAccessInfo) error
}

// TeamAccessInfo contains high-level information about a team's access to a repository.
type TeamAccessInfo struct {
    // Name describes the name of the team. The team name may contain slashes.
    // +required
    Name string `json:"name"`

    // Permission describes the permission level for which the team is allowed to operate.
    // Default: pull.
    // Available options: See the RepositoryPermission enum.
    // +optional
    Permission *RepositoryPermission `json:"permission,omitempty"`
}

Examples

See the following (automatically tested) examples:

Maintainers

In alphabetical order:

Getting Help

If you have any questions about this library:

Your feedback is always welcome!

License

Apache 2.0

About

Git provider client for Go

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 99.9%
  • Makefile 0.1%