Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: github_organization_project #111

Merged
merged 5 commits into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func Provider() terraform.ResourceProvider {
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_repository": resourceGithubRepository(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
Expand Down
110 changes: 110 additions & 0 deletions github/resource_github_organization_project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package github

import (
"context"
"fmt"
"strconv"

"github.com/google/go-github/github"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceGithubOrganizationProject() *schema.Resource {
return &schema.Resource{
Create: resourceGithubOrganizationProjectCreate,
Read: resourceGithubOrganizationProjectRead,
Update: resourceGithubOrganizationProjectUpdate,
Delete: resourceGithubOrganizationProjectDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"body": {
Type: schema.TypeString,
Optional: true,
},
"url": {
Type: schema.TypeString,
Computed: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about coverage of the remaining fields which are available through PATCH?
https://developer.github.com/v3/projects/#update-a-project
specifically state, organization_permission and public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 It seems that the library that we are using does now support these fields yet?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, understood. Thanks for the detailed answer & research. We shall leave it out for the initial implementation then.

},
}
}

func resourceGithubOrganizationProjectCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Organization).client
o := meta.(*Organization).name
n := d.Get("name").(string)
b := d.Get("body").(string)

options := github.ProjectOptions{Name: n, Body: b}

project, _, err := client.Organizations.CreateProject(context.TODO(), o, &options)
if err != nil {
return err
}
d.SetId(strconv.FormatInt(*project.ID, 10))

return resourceGithubOrganizationProjectRead(d, meta)
}

func resourceGithubOrganizationProjectRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Organization).client
o := meta.(*Organization).name

projectID, err := strconv.ParseInt(d.Id(), 10, 64)
if err != nil {
return err
}

project, resp, err := client.Projects.GetProject(context.TODO(), projectID)
if err != nil {
if resp != nil && resp.StatusCode == 404 {
d.SetId("")
return nil
}
return err
}

d.Set("name", project.GetName())
d.Set("body", project.GetBody())
d.Set("url", fmt.Sprintf("https://github.com/orgs/%s/projects/%d", o, project.GetNumber()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason we should be constructing the URL here instead of reading it from the API? It appears that html_url is the attribute we could use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, but it is not made available in the go-github library? See Project.


return nil
}

func resourceGithubOrganizationProjectUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Organization).client
n := d.Get("name").(string)
b := d.Get("body").(string)

options := github.ProjectOptions{Name: n, Body: b}

projectID, err := strconv.ParseInt(d.Id(), 10, 64)
if err != nil {
return err
}

if _, _, err := client.Projects.UpdateProject(context.TODO(), projectID, &options); err != nil {
return err
}

return resourceGithubOrganizationProjectRead(d, meta)
}

func resourceGithubOrganizationProjectDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Organization).client

projectID, err := strconv.ParseInt(d.Id(), 10, 64)
if err != nil {
return err
}

_, err = client.Projects.DeleteProject(context.TODO(), projectID)
return err
}
132 changes: 132 additions & 0 deletions github/resource_github_organization_project_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package github

import (
"context"
"fmt"
"strconv"
"strings"
"testing"

"github.com/google/go-github/github"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccGithubOrganizationProject_basic(t *testing.T) {
var project github.Project

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccGithubOrganizationProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccGithubOrganizationProjectConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckGithubOrganizationProjectExists("github_organization_project.test", &project),
testAccCheckGithubOrganizationProjectAttributes(&project, &testAccGithubOrganizationProjectExpectedAttributes{
Name: "test-project",
Body: "this is a test project",
}),
),
},
},
})
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind adding a test for import also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test for import in ec08678. Thank you.

func TestAccGithubOrganizationProject_importBasic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccGithubOrganizationProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccGithubOrganizationProjectConfig,
},
{
ResourceName: "github_organization_project.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccGithubOrganizationProjectDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*Organization).client

for _, rs := range s.RootModule().Resources {
if rs.Type != "github_organization_project" {
continue
}

projectID, err := strconv.ParseInt(rs.Primary.ID, 10, 64)
if err != nil {
return err
}

project, res, err := conn.Projects.GetProject(context.TODO(), projectID)
if err == nil {
if project != nil &&
project.GetID() == projectID {
return fmt.Errorf("Organization project still exists")
}
}
if res.StatusCode != 404 {
return err
}
return nil
}
return nil
}

func testAccCheckGithubOrganizationProjectExists(n string, project *github.Project) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not Found: %s", n)
}

projectID, err := strconv.ParseInt(rs.Primary.ID, 10, 64)
if err != nil {
return err
}

conn := testAccProvider.Meta().(*Organization).client
gotProject, _, err := conn.Projects.GetProject(context.TODO(), projectID)
if err != nil {
return err
}
*project = *gotProject
return nil
}
}

type testAccGithubOrganizationProjectExpectedAttributes struct {
Name string
Body string
}

func testAccCheckGithubOrganizationProjectAttributes(project *github.Project, want *testAccGithubOrganizationProjectExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {

if *project.Name != want.Name {
return fmt.Errorf("got project %q; want %q", *project.Name, want.Name)
}
if *project.Body != want.Body {
return fmt.Errorf("got project %q; want %q", *project.Body, want.Body)
}
if !strings.HasPrefix(*project.URL, "https://") {
return fmt.Errorf("got http URL %q; want to start with 'https://'", *project.URL)
}

return nil
}
}

const testAccGithubOrganizationProjectConfig = `
resource "github_organization_project" "test" {
name = "test-project"
body = "this is a test project"
}
`
34 changes: 34 additions & 0 deletions website/docs/r/organization_project.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
layout: "github"
page_title: "GitHub: github_organization_project"
sidebar_current: "docs-github-resource-organization-project"
description: |-
Creates and manages projects for Github organizations
---

# github_organization_project

This resource allows you to create and manage projects for Github organization.

## Example Usage

```hcl
resource "github_organization_project" "project" {
name = "A Organization Project"
body = "This is a organization project."
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the project.

* `body` - (Optional) The body of the project.

## Attributes Reference

The following additional attributes are exported:

* `url` - URL of the project
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
<li<%= sidebar_current("docs-github-resource-issue-label") %>>
<a href="/docs/providers/github/r/issue_label.html">github_issue_label</a>
</li>
<li<%= sidebar_current("docs-github-resource-organization-project") %>>
<a href="/docs/providers/github/r/organization_project.html">github_organization_project</a>
</li>
</ul>
</li>
</ul>
Expand Down