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

Add Project Card Support #460

Merged
merged 1 commit into from
Nov 23, 2020
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 @@ -50,6 +50,7 @@ func Provider() terraform.ResourceProvider {
"github_organization_block": resourceOrganizationBlock(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_project_card": resourceGithubProjectCard(),
"github_project_column": resourceGithubProjectColumn(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
Expand Down
160 changes: 160 additions & 0 deletions github/resource_github_project_card.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package github

import (
"context"
"log"
"net/http"
"strconv"
"strings"

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

func resourceGithubProjectCard() *schema.Resource {
return &schema.Resource{
Create: resourceGithubProjectCardCreate,
Read: resourceGithubProjectCardRead,
Update: resourceGithubProjectCardUpdate,
Delete: resourceGithubProjectCardDelete,
Importer: &schema.ResourceImporter{
State: resourceGithubProjectCardImport,
},
Schema: map[string]*schema.Schema{
"column_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"note": {
Type: schema.TypeString,
Required: true,
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
"card_id": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceGithubProjectCardCreate(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

columnIDStr := d.Get("column_id").(string)
columnID, err := strconv.ParseInt(columnIDStr, 10, 64)
if err != nil {
return unconvertibleIdErr(columnIDStr, err)
}

log.Printf("[DEBUG] Creating project card note in column ID: %d", columnID)
client := meta.(*Owner).v3client
options := github.ProjectCardOptions{Note: d.Get("note").(string)}
ctx := context.Background()
card, _, err := client.Projects.CreateProjectCard(ctx, columnID, &options)
if err != nil {
return err
}

d.Set("card_id", card.GetID())
d.SetId(card.GetNodeID())

return resourceGithubProjectCardRead(d, meta)
}

func resourceGithubProjectCardRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
nodeID := d.Id()
cardID := d.Get("card_id").(int)
ctx := context.WithValue(context.Background(), ctxId, d.Id())
if !d.IsNewResource() {
ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string))
}

log.Printf("[DEBUG] Reading project card: %s", nodeID)
card, _, err := client.Projects.GetProjectCard(ctx, int64(cardID))
if err != nil {
if err, ok := err.(*github.ErrorResponse); ok {
if err.Response.StatusCode == http.StatusNotFound {
log.Printf("[WARN] Removing project card %s from state because it no longer exists in GitHub", d.Id())
d.SetId("")
return nil
}
}
return err
}

// FIXME: Remove URL parsing if a better option becomes available
columnURL := card.GetColumnURL()
columnIDStr := strings.TrimPrefix(columnURL, client.BaseURL.String()+`projects/columns/`)
if err != nil {
return unconvertibleIdErr(columnIDStr, err)
}

d.Set("note", card.GetNote())
d.Set("column_id", columnIDStr)
d.Set("card_id", card.GetID())

return nil
}

func resourceGithubProjectCardUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
cardID := d.Get("card_id").(int)

log.Printf("[DEBUG] Updating project Card: %s", d.Id())
options := github.ProjectCardOptions{
Note: d.Get("note").(string),
}
ctx := context.WithValue(context.Background(), ctxId, d.Id())
_, _, err := client.Projects.UpdateProjectCard(ctx, int64(cardID), &options)
if err != nil {
return err
}

return resourceGithubProjectCardRead(d, meta)
}

func resourceGithubProjectCardDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
ctx := context.WithValue(context.Background(), ctxId, d.Id())

log.Printf("[DEBUG] Deleting project Card: %s", d.Id())
cardID := d.Get("card_id").(int)
_, err := client.Projects.DeleteProjectCard(ctx, int64(cardID))
if err != nil {
return err
}

return nil
}

func resourceGithubProjectCardImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
anGie44 marked this conversation as resolved.
Show resolved Hide resolved

cardIDStr := d.Id()
cardID, err := strconv.ParseInt(cardIDStr, 10, 64)
if err != nil {
return []*schema.ResourceData{d}, unconvertibleIdErr(cardIDStr, err)
}

log.Printf("[DEBUG] Importing project card with card ID: %d", cardID)
client := meta.(*Owner).v3client
ctx := context.Background()
card, _, err := client.Projects.GetProjectCard(ctx, cardID)
if card == nil || err != nil {
return []*schema.ResourceData{d}, err
}

d.SetId(card.GetNodeID())
d.Set("card_id", cardID)

return []*schema.ResourceData{d}, nil

}
68 changes: 68 additions & 0 deletions github/resource_github_project_card_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package github

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccGithubProjectCard(t *testing.T) {

randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

t.Run("creates a project card", func(t *testing.T) {

config := fmt.Sprintf(`

resource "github_organization_project" "project" {
name = "tf-acc-%s"
body = "This is an organization project."
}

resource "github_project_column" "column" {
project_id = github_organization_project.project.id
name = "Backlog"
}

resource "github_project_card" "card" {
column_id = github_project_column.column.column_id
note = "## Unaccepted 👇"
}

`, randomID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"github_project_card.card", "note",
),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})

})
}
7 changes: 7 additions & 0 deletions github/resource_github_project_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func resourceGithubProjectColumn() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
"column_id": {
Type: schema.TypeInt,
Computed: true,
},
"etag": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -67,7 +71,9 @@ func resourceGithubProjectColumnCreate(d *schema.ResourceData, meta interface{})
if err != nil {
return err
}

d.SetId(strconv.FormatInt(column.GetID(), 10))
d.Set("column_id", column.GetID())

return resourceGithubProjectColumnRead(d, meta)
}
Expand Down Expand Up @@ -102,6 +108,7 @@ func resourceGithubProjectColumnRead(d *schema.ResourceData, meta interface{}) e

d.Set("name", column.GetName())
d.Set("project_id", projectID)
d.Set("column_id", column.GetID())
return nil
}

Expand Down
45 changes: 45 additions & 0 deletions website/docs/r/project_card.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
layout: "github"
page_title: "GitHub: github_project_card"
description: |-
Creates and manages project cards for GitHub projects
---

# github_project_card

This resource allows you to create and manage cards for GitHub projects.

## Example Usage

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

resource "github_project_column" "column" {
project_id = github_organization_project.project.id
name = "Backlog"
}

resource "github_project_card" "card" {
column_id = github_project_column.column.column_id
note = "## Unaccepted 👇"
}
```

## Argument Reference

The following arguments are supported:

* `column_id` - (Required) The ID of the card.

* `note` - (Required) The note contents of the card. Markdown supported.

## Import

A GitHub Project Card can be imported using its [Card ID](https://developer.github.com/v3/projects/cards/#get-a-project-card):

```
$ terraform import github_project_card.card 01234567
```
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@
<li>
<a href="/docs/providers/github/r/organization_webhook.html">github_organization_webhook</a>
</li>
<li>
<a href="/docs/providers/github/r/project_card.html">github_project_card</a>
</li>
<li>
<a href="/docs/providers/github/r/project_column.html">github_project_column</a>
</li>
Expand Down