Skip to content

Commit

Permalink
fixed merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
sebasslash committed Feb 23, 2022
2 parents 2105081 + aa8c8f7 commit 57f36e6
Show file tree
Hide file tree
Showing 15 changed files with 1,592 additions and 14 deletions.
6 changes: 6 additions & 0 deletions .vscode/settings.json
@@ -0,0 +1,6 @@
{
"go.buildFlags": [
"-tags=integration"
],
"go.testTags": "integration",
}
270 changes: 270 additions & 0 deletions CONTRIBUTING.md
@@ -0,0 +1,270 @@
# Contributing to go-tfe

If you find an issue with this package, please create an issue in GitHub. If you'd like, we welcome any contributions. Fork this repository and submit a pull request.

## Writing Tests

The test suite contains many acceptance tests that are run against the latest version of Terraform Enterprise. You can read more about running the tests against your own Terraform Enterprise environment in [TESTS.md](TESTS.md). Our CI system (Circle) will not test your fork unless you are an authorized employee, so a HashiCorp maintainer will initiate the tests or you and report any missing tests or simple problems. In order to speed up this process, it's not uncommon for your commits to be incorportated into another PR that we can commit test changes to.

## Editor Settings

We've included VSCode settings to assist with configuring the go extension. For other editors that integrate with the [Go Language Server](https://github.com/golang/tools/tree/master/gopls), the main thing to do is to add the `integration` build tags so that the test files are found by the language server. See `.vscode/settings.json` for more details.

## Adding a new Endpoint

Here you will find a scaffold to get you started when building a json:api RESTful endpoint. The comments are meant to guide you but should be replaced with endpoint-specific and type-specific documentation. Additionally, you'll need to add an integration test that covers each method of the main interface.

In general, an interface should cover one RESTful resource, which sometimes involves two or more endpoints. Add all new modules to the tfe package.

```go
package tfe

import (
"context"
"errors"
"fmt"
"net/url"
)

var ErrInvalidExampleID = errors.New("invalid value for example ID") // move this line to errors.go

// Compile-time proof of interface implementation
var _ ExampleResource = (*example)(nil)

// Example represents all the example methods in the context of an organization
// that the Terraform Cloud/Enterprise API supports.
// If this API is in beta or pre-release state, include that warning here.
type ExampleResource interface {
// Create an example for an organization
Create(ctx context.Context, organization string, options ExampleCreateOptions) (*Example, error)

// List all examples for an organization
List(ctx context.Context, organization string, options *ExampleListOptions) (*ExampleList, error)

// Read an organization's example by ID
Read(ctx context.Context, exampleID string) (*Example, error)

// Read an organization's example by ID with given options
ReadWithOptions(ctx context.Context, exampleID string, options *ExampleReadOptions) (*Example, error)

// Update an example for an organization
Update(ctx context.Context, exampleID string, options ExampleUpdateOptions) (*Example, error)

// Delete an organization's example
Delete(ctx context.Context, exampleID string) error
}

// example implements Example
type example struct {
client *Client
}

// Example represents a TFC/E example resource
type Example struct {
ID string `jsonapi:"primary,tasks"`
Name string `jsonapi:"attr,name"`
URL string `jsonapi:"attr,url"`
OptionalValue *string `jsonapi:"attr,optional-value,omitempty"`

Organization *Organization `jsonapi:"relation,organization"`
}

// ExampleList represents a list of examples
type ExampleList struct {
*Pagination
Items []*Example
}

// ExampleCreateOptions represents the set of options for creating an example
type ExampleCreateOptions struct {
// Type is a public field utilized by JSON:API to
// set the resource type via the field tag.
// It is not a user-defined value and does not need to be set.
// https://jsonapi.org/format/#crud-creating
Type string `jsonapi:"primary,tasks"`

// Required: The name of the example
Name string `jsonapi:"attr,name"`

// Required: The URL to send in the example
URL string `jsonapi:"attr,url"`

// Optional: An optional value that is omitted if empty
OptionalValue *string `jsonapi:"attr,optional-value,omitempty"`
}

func (o *ExampleCreateOptions) valid() error {
if !validString(&o.Name) {
return ErrRequiredName
}

if !validString(&o.URL) {
return ErrInvalidRunTaskURL
}

return nil
}

// Create is used to create a new example for an organization
func (s *example) Create(ctx context.Context, organization string, options ExampleCreateOptions) (*Example, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
}

if err := options.valid(); err != nil {
return nil, err
}

u := fmt.Sprintf("organizations/%s/tasks", url.QueryEscape(organization))
req, err := s.client.newRequest("POST", u, &options)
if err != nil {
return nil, err
}

r := &Example{}
err = s.client.do(ctx, req, r)
if err != nil {
return nil, err
}

return r, nil
}

// A list of relations to include with an example. See available resources:
// https://www.terraform.io/cloud-docs/api-docs/examples#list-examples (replace this URL with the actual documentation URL)
type ExampleIncludeOps string

const (
ExampleOrganization ExampleIncludeOps = "organization"
)

// ExampleListOptions represents the set of options for listing examples
type ExampleListOptions struct {
ListOptions

// A list of relations to include
Include []ExampleIncludeOps `url:"include,omitempty"`
}

// List all the examples for an organization
func (s *example) List(ctx context.Context, organization string, options *ExampleListOptions) (*ExampleList, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
}

u := fmt.Sprintf("organizations/%s/examples", url.QueryEscape(organization))
req, err := s.client.newRequest("GET", u, options)
if err != nil {
return nil, err
}

el := &ExampleList{}
err = s.client.do(ctx, req, el)
if err != nil {
return nil, err
}

return el, nil
}

// Read is used to read an organization's example by ID
func (s *example) Read(ctx context.Context, exampleID string) (*Example, error) {
return s.ReadWithOptions(ctx, exampleID, nil)
}

// ExampleReadOptions represents the set of options for reading an example
type ExampleReadOptions struct {
Include []RunTaskIncludeOps `url:"include,omitempty"`
}

// Read is used to read an organization's example by ID with options
func (s *example) ReadWithOptions(ctx context.Context, exampleID string, options *ExampleReadOptions) (*Example, error) {
if !validStringID(&exampleID) {
return nil, ErrInvalidExampleID
}

u := fmt.Sprintf("examples/%s", url.QueryEscape(exampleID))
req, err := s.client.newRequest("GET", u, options)
if err != nil {
return nil, err
}

e := &Example{}
err = s.client.do(ctx, req, e)
if err != nil {
return nil, err
}

return e, nil
}

// ExampleUpdateOptions represents the set of options for updating an organization's examples
type ExampleUpdateOptions struct {
// Type is a public field utilized by JSON:API to
// set the resource type via the field tag.
// It is not a user-defined value and does not need to be set.
// https://jsonapi.org/format/#crud-creating
Type string `jsonapi:"primary,tasks"`

// Optional: The name of the example, defaults to previous value
Name *string `jsonapi:"attr,name,omitempty"`

// Optional: The URL to send a example payload, defaults to previous value
URL *string `jsonapi:"attr,url,omitempty"`

// Optional: An optional value
OptionalValue *string `jsonapi:"attr,optional-value,omitempty"`
}

func (o *ExampleUpdateOptions) valid() error {
if o.Name != nil && !validString(o.Name) {
return ErrRequiredName
}

if o.URL != nil && !validString(o.URL) {
return ErrInvalidRunTaskURL
}

return nil
}

// Update an existing example for an organization by ID
func (s *example) Update(ctx context.Context, exampleID string, options ExampleUpdateOptions) (*Example, error) {
if !validStringID(&exampleID) {
return nil, ErrInvalidExampleID
}

if err := options.valid(); err != nil {
return nil, err
}

u := fmt.Sprintf("examples/%s", url.QueryEscape(exampleID))
req, err := s.client.newRequest("PATCH", u, &options)
if err != nil {
return nil, err
}

r := &Example{}
err = s.client.do(ctx, req, r)
if err != nil {
return nil, err
}

return r, nil
}

// Delete an existing example for an organization by ID
func (s *example) Delete(ctx context.Context, exampleID string) error {
if !validStringID(&exampleID) {
return ErrInvalidExampleID
}

u := fmt.Sprintf("examples/%s", exampleID)
req, err := s.client.newRequest("DELETE", u, nil)
if err != nil {
return err
}

return s.client.do(ctx, req, nil)
}
```
9 changes: 4 additions & 5 deletions README.md
Expand Up @@ -64,12 +64,11 @@ See the [examples directory](https://github.com/hashicorp/go-tfe/tree/main/examp

## Running tests

See [TESTS.md](https://github.com/hashicorp/go-tfe/tree/main/TESTS.md).
See [TESTS.md](TESTS.md).

## Issues and Contributing

If you find an issue with this package, please report an issue. If you'd like,
we welcome any contributions. Fork this repository and submit a pull request.
See [CONTRIBUTING.md](CONTRIBUTING.md)

## Releases

Expand All @@ -78,12 +77,12 @@ Documentation updates and test fixes that only touch test files don't require a
### Creating a release

1. [Create a new release in GitHub](https://help.github.com/en/github/administering-a-repository/creating-releases) by clicking on "Releases" and then "Draft a new release"
1. Set the `Tag version` to a new tag, using [Semantic Versioning](https://semver.org/) as a guideline.
1. Set the `Tag version` to a new tag, using [Semantic Versioning](https://semver.org/) as a guideline.
1. Set the `Target` as `main`.
1. Set the `Release title` to the tag you created, `vX.Y.Z`
1. Use the description section to describe why you're releasing and what changes you've made. You should include links to merged PRs. Use the following headers in the description of your release:
- BREAKING CHANGES: Use this for any changes that aren't backwards compatible. Include details on how to handle these changes.
- FEATURES: Use this for any large new features added,
- FEATURES: Use this for any large new features added,
- ENHANCEMENTS: Use this for smaller new features added
- BUG FIXES: Use this for any bugs that were fixed.
- NOTES: Use this section if you need to include any additional notes on things like upgrading, upcoming deprecations, or any other information you might want to highlight.
Expand Down
2 changes: 2 additions & 0 deletions TESTS.md
Expand Up @@ -27,6 +27,8 @@ Tests are run against an actual backend so they require a valid backend address
1. `GITHUB_REGISTRY_MODULE_IDENTIFIER` - GitHub registry module repository identifier in the format `username/repository`. Required for running registry module tests.
1. `ENABLE_TFE` - Some tests are only applicable to Terraform Enterprise or Terraform Cloud. By setting `ENABLE_TFE=1` you will enable enterprise only tests and disable cloud only tests. In CI `ENABLE_TFE` is not set so if you are writing enterprise only features you should manually test with `ENABLE_TFE=1` against a Terraform Enterprise instance.
1. `SKIP_PAID` - Some tests depend on paid only features. By setting `SKIP_PAID=1`, you will skip tests that access paid features.
1. `ENABLE_BETA` - Some tests require access to beta features. By setting `ENABLE_BETA=1` you will enable tests that require access to beta features. IN CI `ENABLE_BETA` is not set so if you are writing beta only features you should manually test with `ENABLE_BETA=1` against a Terraform Enterprise instance with those features enabled.
1. `TFC_RUN_TASK_URL` - Run task integration tests require a URL to use when creating run tasks. To learn more about the Run Task API, [read here](https://www.terraform.io/cloud-docs/api-docs/run-tasks)

You can set your environment variables up however you prefer. The following are instructions for setting up environment variables using [envchain](https://github.com/sorah/envchain).
1. Make sure you have envchain installed. [Instructions for this can be found in the envchain README](https://github.com/sorah/envchain#installation).
Expand Down
14 changes: 14 additions & 0 deletions errors.go
Expand Up @@ -72,6 +72,20 @@ var (

ErrInvalidRunID = errors.New("invalid value for run ID")

ErrInvalidRunTaskCategory = errors.New(`category must be "task"`)

ErrInvalidRunTaskID = errors.New("invalid value for run task ID")

ErrInvalidRunTaskURL = errors.New("invalid url for run task URL")

ErrInvalidWorkspaceRunTaskID = errors.New("invalid value for workspace run task ID")

ErrInvalidWorkspaceRunTaskType = errors.New(`invalid value for type, please use "workspace-tasks"`)

ErrInvalidTaskResultID = errors.New("invalid value for task result ID")

ErrInvalidTaskStageID = errors.New("invalid value for task stage ID")

ErrInvalidApplyID = errors.New("invalid value for apply ID")

ErrInvalidOrg = errors.New("invalid value for organization")
Expand Down

0 comments on commit 57f36e6

Please sign in to comment.