From 7f3174b0dd38bebef4548038d977e9e7b2957914 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Sun, 24 May 2020 01:36:12 -0400 Subject: [PATCH 1/4] add milestone resource and data source --- ...data_source_github_repository_milestone.go | 66 ++++ ...source_github_repository_milestone_test.go | 92 +++++ github/provider.go | 2 + .../resource_github_repository_milestone.go | 232 +++++++++++++ ...source_github_repository_milestone_test.go | 323 ++++++++++++++++++ .../docs/d/repository_milestone.html.markdown | 35 ++ .../docs/r/repository_milestone.html.markdown | 54 +++ website/github.erb | 6 + 8 files changed, 810 insertions(+) create mode 100644 github/data_source_github_repository_milestone.go create mode 100644 github/data_source_github_repository_milestone_test.go create mode 100644 github/resource_github_repository_milestone.go create mode 100644 github/resource_github_repository_milestone_test.go create mode 100644 website/docs/d/repository_milestone.html.markdown create mode 100644 website/docs/r/repository_milestone.html.markdown diff --git a/github/data_source_github_repository_milestone.go b/github/data_source_github_repository_milestone.go new file mode 100644 index 0000000000..6c517e332c --- /dev/null +++ b/github/data_source_github_repository_milestone.go @@ -0,0 +1,66 @@ +package github + +import ( + "context" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "strconv" +) + +func dataSourceGithubRepositoryMilestone() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGithubRepositoryMilestoneRead, + + Schema: map[string]*schema.Schema{ + "owner": { + Type: schema.TypeString, + Required: true, + }, + "repository": { + Type: schema.TypeString, + Required: true, + }, + "number": { + Type: schema.TypeInt, + Required: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "due_date": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "title": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceGithubRepositoryMilestoneRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*Organization).v3client + ctx := context.Background() + + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) + + number := d.Get("number").(int) + milestone, _, err := conn.Issues.GetMilestone(ctx, owner, repoName, number) + if err != nil { + return err + } + + d.SetId(strconv.FormatInt(milestone.GetID(), 10)) + d.Set("description", milestone.GetDescription()) + d.Set("due_date", milestone.GetDueOn().Format(layoutISO)) + d.Set("state", milestone.GetState()) + d.Set("title", milestone.GetTitle()) + + return nil +} diff --git a/github/data_source_github_repository_milestone_test.go b/github/data_source_github_repository_milestone_test.go new file mode 100644 index 0000000000..0938a52ae4 --- /dev/null +++ b/github/data_source_github_repository_milestone_test.go @@ -0,0 +1,92 @@ +package github + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "regexp" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccGithubRepositoryMilestoneDataSource_noMatchReturnsError(t *testing.T) { + repo := "nonExistentRepo" + owner := "no-user" + number := "1" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckGithubRepositoryMilestoneDataSourceNonExistentConfig(repo, owner, number), + ExpectError: regexp.MustCompile(`Not Found`), + }, + }, + }) +} + +func TestAccGithubRepositoryMilestoneDataSource_existing(t *testing.T) { + repo := acctest.RandomWithPrefix("tf-acc-test") + title := acctest.RandomWithPrefix("ms") + description := acctest.RandomWithPrefix("tf-acc-test-desc") + dueDate := time.Now().UTC().Format(layoutISO) + + rn := "github_repository_milestone.test" + dataSource := "data.github_repository_milestone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckGithubRepositoryMilestoneDataSourceConfig(repo, title, description, dueDate), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSource, "title", rn, "title"), + resource.TestCheckResourceAttrPair(dataSource, "description", rn, "description"), + resource.TestCheckResourceAttrPair(dataSource, "due_date", rn, "due_date"), + resource.TestCheckResourceAttrPair(dataSource, "state", rn, "state"), + resource.TestCheckResourceAttrPair(dataSource, "number", rn, "number"), + resource.TestCheckResourceAttrPair(dataSource, "owner", rn, "owner"), + resource.TestCheckResourceAttrPair(dataSource, "repository", rn, "repository"), + ), + }, + }, + }) +} + +func testAccCheckGithubRepositoryMilestoneDataSourceNonExistentConfig(owner, repo, number string) string { + return fmt.Sprintf(` +data "github_repository_milestone" "test" { + owner = "%s" + repository = "%s" + number = "%s" +} +`, owner, repo, number) +} + +func testAccCheckGithubRepositoryMilestoneDataSourceConfig(repo, title, description, dueDate string) string { + return fmt.Sprintf(` +resource "github_repository" "test" { + name = "%s" +} + +resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "%s" + description = "%s" + due_date = "%s" +} + +data "github_repository_milestone" "test" { + owner = github_repository_milestone.test.owner + repository = github_repository_milestone.test.repository + number = github_repository_milestone.test.number +} +`, repo, title, description, dueDate) +} diff --git a/github/provider.go b/github/provider.go index 5b1a6d7a14..6f96245316 100644 --- a/github/provider.go +++ b/github/provider.go @@ -54,6 +54,7 @@ func Provider() terraform.ResourceProvider { "github_repository_collaborator": resourceGithubRepositoryCollaborator(), "github_repository_deploy_key": resourceGithubRepositoryDeployKey(), "github_repository_file": resourceGithubRepositoryFile(), + "github_repository_milestone": resourceGithubRepositoryMilestone(), "github_repository_project": resourceGithubRepositoryProject(), "github_repository_webhook": resourceGithubRepositoryWebhook(), "github_repository": resourceGithubRepository(), @@ -77,6 +78,7 @@ func Provider() terraform.ResourceProvider { "github_release": dataSourceGithubRelease(), "github_repositories": dataSourceGithubRepositories(), "github_repository": dataSourceGithubRepository(), + "github_repository_milestone": dataSourceGithubRepositoryMilestone(), "github_team": dataSourceGithubTeam(), "github_user": dataSourceGithubUser(), }, diff --git a/github/resource_github_repository_milestone.go b/github/resource_github_repository_milestone.go new file mode 100644 index 0000000000..30be4bfa92 --- /dev/null +++ b/github/resource_github_repository_milestone.go @@ -0,0 +1,232 @@ +package github + +import ( + "context" + "fmt" + "github.com/google/go-github/v31/github" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "log" + "net/http" + "strconv" + "strings" + "time" +) + +func resourceGithubRepositoryMilestone() *schema.Resource { + return &schema.Resource{ + Create: resourceGithubRepositoryMilestoneCreate, + Read: resourceGithubRepositoryMilestoneRead, + Update: resourceGithubRepositoryMilestoneUpdate, + Delete: resourceGithubRepositoryMilestoneDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 3 || parts[0] == "" || parts[1] == "" || parts[2] == "" { + return nil, fmt.Errorf("Invalid ID format, must be provided as OWNER/REPOSITORY/NUMBER") + } + d.Set("owner", parts[0]) + d.Set("repository", parts[1]) + number, err := strconv.Atoi(parts[2]) + if err != nil { + return nil, err + } + d.Set("number", number) + d.SetId(fmt.Sprintf("%s/%s/%d", parts[0], parts[1], number)) + + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "title": { + Type: schema.TypeString, + Required: true, + }, + "owner": { + Type: schema.TypeString, + Required: true, + }, + "repository": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "due_date": { + Type: schema.TypeString, + Optional: true, + Description: "in yyyy-mm-dd format", + }, + "state": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "open", "closed", + }, true), + Default: "open", + }, + "number": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +const ( + layoutISO = "2006-01-02" +) + +func resourceGithubRepositoryMilestoneCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*Organization).v3client + ctx := context.Background() + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) + + milestone := &github.Milestone{ + Title: github.String(d.Get("title").(string)), + } + + if v, ok := d.GetOk("description"); ok && len(v.(string)) > 0 { + milestone.Description = github.String(v.(string)) + } + if v, ok := d.GetOk("due_date"); ok && len(v.(string)) > 0 { + dueDate, err := time.Parse(layoutISO, v.(string)) + if err != nil { + return err + } + date := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 7, 0, 0, 0, time.UTC) + milestone.DueOn = &date + } + if v, ok := d.GetOk("state"); ok && len(v.(string)) > 0 { + milestone.State = github.String(v.(string)) + } + + log.Printf("[DEBUG] Creating milestone for repository: %s/%s", owner, repoName) + milestone, _, err := conn.Issues.CreateMilestone(ctx, owner, repoName, milestone) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("%s/%s/%d", owner, repoName, milestone.GetNumber())) + + return resourceGithubRepositoryMilestoneRead(d, meta) +} + +func resourceGithubRepositoryMilestoneRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*Organization).v3client + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) + number, err := parseMilestoneNumber(d.Id()) + if err != nil { + return err + } + + log.Printf("[DEBUG] Reading milestone for repository: %s/%s", owner, repoName) + milestone, _, err := conn.Issues.GetMilestone(ctx, owner, repoName, number) + if err != nil { + if ghErr, ok := err.(*github.ErrorResponse); ok { + if ghErr.Response.StatusCode == http.StatusNotModified { + return nil + } + if ghErr.Response.StatusCode == http.StatusNotFound { + log.Printf("[WARN] Removing milestone for %s/%s from state because it no longer exists in GitHub", + owner, repoName) + d.SetId("") + return nil + } + } + return err + } + + d.Set("title", milestone.GetTitle()) + d.Set("description", milestone.GetDescription()) + d.Set("number", milestone.GetNumber()) + d.Set("state", milestone.GetState()) + if dueOn := milestone.GetDueOn(); !dueOn.IsZero() { + d.Set("due_date", milestone.GetDueOn().Format(layoutISO)) + } + + return nil +} + +func resourceGithubRepositoryMilestoneUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*Organization).v3client + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) + number, err := parseMilestoneNumber(d.Id()) + if err != nil { + return err + } + + milestone := &github.Milestone{} + if d.HasChanges("title") { + _, n := d.GetChange("title") + milestone.Title = github.String(n.(string)) + } + + if d.HasChanges("description") { + _, n := d.GetChange("description") + milestone.Description = github.String(n.(string)) + } + + if d.HasChanges("due_date") { + _, n := d.GetChange("due_date") + dueDate, err := time.Parse(layoutISO, n.(string)) + if err != nil { + return err + } + date := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 7, 0, 0, 0, time.UTC) + milestone.DueOn = &date + } + + if d.HasChanges("state") { + _, n := d.GetChange("state") + milestone.State = github.String(n.(string)) + } + + log.Printf("[DEBUG] Updating milestone for repository: %s/%s", owner, repoName) + _, _, err = conn.Issues.EditMilestone(ctx, owner, repoName, number, milestone) + if err != nil { + return err + } + + return resourceGithubRepositoryMilestoneRead(d, meta) +} + +func resourceGithubRepositoryMilestoneDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*Organization).v3client + ctx := context.WithValue(context.Background(), ctxId, d.Id()) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) + number, err := parseMilestoneNumber(d.Id()) + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting milestone for repository: %s/%s", owner, repoName) + _, err = conn.Issues.DeleteMilestone(ctx, owner, repoName, number) + if err != nil { + return err + } + + return nil +} + +func parseMilestoneNumber(id string) (int, error) { + parts := strings.Split(id, "/") + if len(parts) != 3 { + return -1, fmt.Errorf("ID not properly formatted: %s", id) + } + number, err := strconv.Atoi(parts[2]) + if err != nil { + return -1, err + } + return number, nil +} diff --git a/github/resource_github_repository_milestone_test.go b/github/resource_github_repository_milestone_test.go new file mode 100644 index 0000000000..f6c7d74aa1 --- /dev/null +++ b/github/resource_github_repository_milestone_test.go @@ -0,0 +1,323 @@ +package github + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + "github.com/google/go-github/v31/github" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccGithubRepositoryMilestone_basic(t *testing.T) { + var milestone github.Milestone + title := acctest.RandomWithPrefix("tf-acc-test") + repoName := acctest.RandomWithPrefix("tf-acc-test-repo") + rn := "github_repository_milestone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGithubRepositoryMilestoneConfig(repoName, title), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), + resource.TestCheckResourceAttr(rn, "title", title), + resource.TestCheckResourceAttr(rn, "description", ""), + resource.TestCheckResourceAttr(rn, "state", "open"), + resource.TestCheckResourceAttr(rn, "number", "1"), + ), + }, + { + ResourceName: rn, + ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccGithubRepositoryMilestone_update(t *testing.T) { + var milestone github.Milestone + title := acctest.RandomWithPrefix("tf-acc-test") + repoName := acctest.RandomWithPrefix("tf-acc-test-repo") + dueDate := time.Now().UTC().Format(layoutISO) + description := acctest.RandomWithPrefix("tf-acc-test-desc") + rn := "github_repository_milestone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGithubRepositoryMilestoneConfig(repoName, title), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), + resource.TestCheckResourceAttr(rn, "title", title), + resource.TestCheckResourceAttr(rn, "description", ""), + resource.TestCheckResourceAttr(rn, "state", "open"), + resource.TestCheckResourceAttr(rn, "number", "1"), + ), + }, + { + ResourceName: rn, + ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGithubRepositoryMilestoneConfigUpdate(repoName, title, description, dueDate), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), + resource.TestCheckResourceAttr(rn, "title", title), + resource.TestCheckResourceAttr(rn, "description", description), + resource.TestCheckResourceAttr(rn, "due_date", dueDate), + resource.TestCheckResourceAttr(rn, "state", "open"), + resource.TestCheckResourceAttr(rn, "number", "1"), + ), + }, + }, + }) +} + +func TestAccGithubRepositoryMilestone_multiple(t *testing.T) { + var milestone1, milestone2 github.Milestone + titleOne := acctest.RandomWithPrefix("tf-acc-test-ms") + titleTwo := acctest.RandomWithPrefix("tf-acc-test-ms-two") + + repoName := acctest.RandomWithPrefix("tf-acc-test-repo") + dueDate := time.Now().UTC().Format(layoutISO) + descriptionOne := acctest.RandomWithPrefix("tf-acc-test-desc") + descriptionTwo := acctest.RandomWithPrefix("tf-acc-test-desc-two") + + rn := "github_repository_milestone.test" + rnTwo := "github_repository_milestone.test_two" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGithubRepositoryMultipleMilestoneConfig(repoName, titleOne, descriptionOne, titleTwo, descriptionTwo, dueDate), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone1), + resource.TestCheckResourceAttr(rn, "title", titleOne), + resource.TestCheckResourceAttr(rn, "description", descriptionOne), + resource.TestCheckResourceAttr(rn, "due_date", dueDate), + resource.TestCheckResourceAttr(rn, "state", "closed"), + resource.TestCheckResourceAttrSet(rn, "number"), + testAccCheckGithubRepositoryMilestoneExists(rnTwo, &milestone2), + resource.TestCheckResourceAttr(rnTwo, "title", titleTwo), + resource.TestCheckResourceAttr(rnTwo, "description", descriptionTwo), + resource.TestCheckResourceAttr(rn, "due_date", dueDate), + resource.TestCheckResourceAttr(rnTwo, "state", "open"), + resource.TestCheckResourceAttrSet(rnTwo, "number"), + ), + }, + { + ResourceName: rn, + ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: rnTwo, + ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rnTwo), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGithubRepositoryMilestoneConfigUpdate(repoName, titleOne, descriptionOne, dueDate), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone1), + resource.TestCheckResourceAttr(rn, "title", titleOne), + resource.TestCheckResourceAttr(rn, "description", descriptionOne), + resource.TestCheckResourceAttr(rn, "due_date", dueDate), + resource.TestCheckResourceAttr(rn, "state", "open"), + resource.TestCheckResourceAttrSet(rn, "number"), + ), + }, + }, + }) +} + +func TestAccGithubRepositoryMilestone_disappears(t *testing.T) { + var milestone github.Milestone + + title := acctest.RandomWithPrefix("tf-acc-test") + repoName := acctest.RandomWithPrefix("tf-acc-test-repo") + rn := "github_repository_milestone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGithubRepositoryMilestoneConfig(title, repoName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), + testAccCheckGithubRepositoryMilestoneDisappears(rn), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckGithubRepositoryMilestoneExists(rn string, milestone *github.Milestone) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("not Found: %s", rn) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no Milestone ID is set") + } + + conn := testAccProvider.Meta().(*Organization).v3client + number, err := parseMilestoneNumber(rs.Primary.ID) + if err != nil { + return err + } + parts := strings.Split(rs.Primary.ID, "/") + owner := parts[0] + repoName := parts[1] + + m, _, err := conn.Issues.GetMilestone(context.TODO(), owner, repoName, number) + if err != nil { + return err + } + *milestone = *m + return nil + } +} + +func testAccCheckGithubRepositoryMilestoneDisappears(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + conn := testAccProvider.Meta().(*Organization).v3client + number, err := parseMilestoneNumber(rs.Primary.ID) + if err != nil { + return err + } + parts := strings.Split(rs.Primary.ID, "/") + owner := parts[0] + repoName := parts[1] + + _, err = conn.Issues.DeleteMilestone(context.TODO(), owner, repoName, number) + return err + } +} + +func testAccCheckGithubRepositoryMilestoneDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*Organization).v3client + + for _, rs := range s.RootModule().Resources { + if rs.Type != "github_repository_milestone" { + continue + } + + number, err := parseMilestoneNumber(rs.Primary.ID) + if err != nil { + return err + } + parts := strings.Split(rs.Primary.ID, "/") + owner := parts[0] + repoName := parts[1] + + milestone, resp, err := conn.Issues.GetMilestone(context.TODO(), owner, repoName, number) + if err != nil { + if resp.StatusCode != 404 { + return err + } + } + if milestone != nil { + return fmt.Errorf("milestone still exists") + } + + return nil + } + + return nil +} + +func testAccGithubRepositoryMilestoneImportStateIdFunc(rn string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return "", fmt.Errorf("Not found: %s", rn) + } + + return fmt.Sprintf("%s/%s/%s", rs.Primary.Attributes["owner"], rs.Primary.Attributes["repository"], rs.Primary.Attributes["number"]), nil + } +} + +func testAccGithubRepositoryMilestoneConfig(repoName, title string) string { + return fmt.Sprintf(` +resource "github_repository" "test" { + name = "%s" +} + +resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "%s" +} +`, repoName, title) +} + +func testAccGithubRepositoryMilestoneConfigUpdate(repoName, title, description, dueDate string) string { + return fmt.Sprintf(` +resource "github_repository" "test" { + name = "%s" +} + +resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "%s" + description = "%s" + due_date = "%s" +} +`, repoName, title, description, dueDate) +} + +func testAccGithubRepositoryMultipleMilestoneConfig(repoName, titleOne, descriptionOne, titleTwo, descriptionTwo, dueDate string) string { + return fmt.Sprintf(` +resource "github_repository" "test" { + name = "%s" +} + +resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "%s" + description = "%s" + due_date = "%s" + state = "closed" +} + +resource "github_repository_milestone" "test_two" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "%s" + description = "%s" + due_date = "%s" + state = "open" +} +`, repoName, titleOne, descriptionOne, dueDate, titleTwo, descriptionTwo, dueDate) +} diff --git a/website/docs/d/repository_milestone.html.markdown b/website/docs/d/repository_milestone.html.markdown new file mode 100644 index 0000000000..fe177f4b68 --- /dev/null +++ b/website/docs/d/repository_milestone.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "github" +page_title: "GitHub: github_repository_milestone" +description: |- + Get information on a GitHub Repository Milestone. +--- + +# github_repository_milestone + +Use this data source to retrieve information about a specific GitHub milestone in a repository. + +## Example Usage + +```hcl +data "github_repository_milestone" "example" { + owner = "example-owner" + repository = "example-repository" + number = 1 +} +``` + +## Argument Reference + + * `owner` - (Required) Owner of the repository. + + * `repository` - (Required) Name of the repository to retrieve the milestone from. + + * `number` - (Required) The number of the milestone. + +## Attributes Reference + + * `description` - Description of the milestone. + * `due_date` - The milestone due date (in ISO-8601 `yyyy-mm-dd` format). + * `state` - State of the milestone. + * `title` - Title of the milestone. diff --git a/website/docs/r/repository_milestone.html.markdown b/website/docs/r/repository_milestone.html.markdown new file mode 100644 index 0000000000..7a5cb263da --- /dev/null +++ b/website/docs/r/repository_milestone.html.markdown @@ -0,0 +1,54 @@ +--- +layout: "github" +page_title: "GitHub: github_repository_milestone" +description: |- + Provides a GitHub repository milestone resource. +--- + +# github_repository_milestone + +Provides a GitHub respository milestone resource. + +This resource allows you to create and manage milestones for a Github Repository within an organization or user account. + +## Example Usage + +```hcl +# Create a milestone for a repository +resource "github_repository_milestone" "example" { + owner = "example-owner" + repository = "example-repository" + title = "v1.1.0" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `owner` - (Required) The owner of the Github Repository. + +* `repository` - (Required) The name of the Github Repository. + +* `title` - (Required) The title of the milestone. + +* `description` - (Optional) A description of the milestone. + +* `due_date` - (Optional) The milestone due date. In `yyyy-mm-dd` format. + +* `state` - (Optional) The state of the milestone. Either `open` or `closed`. Default: `open` + + +## Attributes Reference + +The following additional attributes are exported: + +* `number` - The number of the milestone. + +## Import + +A GitHub Repository Milestone can be imported using an ID made up of `owner/repository/number`, e.g. + +``` +$ terraform import github_repository_milestone.example example-owner/example-repository/1 +``` diff --git a/website/github.erb b/website/github.erb index 653560070d..e6c09f5d08 100644 --- a/website/github.erb +++ b/website/github.erb @@ -43,6 +43,9 @@
  • github_repository
  • +
  • + github_repository_milestone +
  • github_team
  • @@ -97,6 +100,9 @@
  • github_repository_file
  • +
  • + github_repository_milestone +
  • github_repository_project
  • From 0ef7d40d3fe67a87c25599fa06756489970a061b Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Sun, 24 May 2020 01:46:31 -0400 Subject: [PATCH 2/4] fix misspell --- website/docs/r/repository_milestone.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/repository_milestone.html.markdown b/website/docs/r/repository_milestone.html.markdown index 7a5cb263da..f012d81f04 100644 --- a/website/docs/r/repository_milestone.html.markdown +++ b/website/docs/r/repository_milestone.html.markdown @@ -7,7 +7,7 @@ description: |- # github_repository_milestone -Provides a GitHub respository milestone resource. +Provides a GitHub repository milestone resource. This resource allows you to create and manage milestones for a Github Repository within an organization or user account. From c7118b746961c2b179e78c33036f8d66c7143dad Mon Sep 17 00:00:00 2001 From: Jeremy Udit Date: Sun, 22 Nov 2020 15:27:50 -0500 Subject: [PATCH 3/4] rebase and fix build errors - update to go-github v32 - use `Owner` instead of `Organization` --- github/data_source_github_repository_milestone.go | 2 +- github/resource_github_repository_milestone.go | 15 ++++++++------- .../resource_github_repository_milestone_test.go | 8 ++++---- go.mod | 1 + go.sum | 3 +++ 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/github/data_source_github_repository_milestone.go b/github/data_source_github_repository_milestone.go index 6c517e332c..54c4628845 100644 --- a/github/data_source_github_repository_milestone.go +++ b/github/data_source_github_repository_milestone.go @@ -44,7 +44,7 @@ func dataSourceGithubRepositoryMilestone() *schema.Resource { } func dataSourceGithubRepositoryMilestoneRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*Organization).v3client + conn := meta.(*Owner).v3client ctx := context.Background() owner := d.Get("owner").(string) diff --git a/github/resource_github_repository_milestone.go b/github/resource_github_repository_milestone.go index 30be4bfa92..01b26f03cf 100644 --- a/github/resource_github_repository_milestone.go +++ b/github/resource_github_repository_milestone.go @@ -3,14 +3,15 @@ package github import ( "context" "fmt" - "github.com/google/go-github/v31/github" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "log" "net/http" "strconv" "strings" "time" + + "github.com/google/go-github/v32/github" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceGithubRepositoryMilestone() *schema.Resource { @@ -81,7 +82,7 @@ const ( ) func resourceGithubRepositoryMilestoneCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*Organization).v3client + conn := meta.(*Owner).v3client ctx := context.Background() owner := d.Get("owner").(string) repoName := d.Get("repository").(string) @@ -117,7 +118,7 @@ func resourceGithubRepositoryMilestoneCreate(d *schema.ResourceData, meta interf } func resourceGithubRepositoryMilestoneRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*Organization).v3client + conn := meta.(*Owner).v3client ctx := context.WithValue(context.Background(), ctxId, d.Id()) owner := d.Get("owner").(string) @@ -156,7 +157,7 @@ func resourceGithubRepositoryMilestoneRead(d *schema.ResourceData, meta interfac } func resourceGithubRepositoryMilestoneUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*Organization).v3client + conn := meta.(*Owner).v3client ctx := context.WithValue(context.Background(), ctxId, d.Id()) owner := d.Get("owner").(string) repoName := d.Get("repository").(string) @@ -201,7 +202,7 @@ func resourceGithubRepositoryMilestoneUpdate(d *schema.ResourceData, meta interf } func resourceGithubRepositoryMilestoneDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*Organization).v3client + conn := meta.(*Owner).v3client ctx := context.WithValue(context.Background(), ctxId, d.Id()) owner := d.Get("owner").(string) repoName := d.Get("repository").(string) diff --git a/github/resource_github_repository_milestone_test.go b/github/resource_github_repository_milestone_test.go index f6c7d74aa1..207dacd4f6 100644 --- a/github/resource_github_repository_milestone_test.go +++ b/github/resource_github_repository_milestone_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/google/go-github/v31/github" + "github.com/google/go-github/v32/github" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" @@ -185,7 +185,7 @@ func testAccCheckGithubRepositoryMilestoneExists(rn string, milestone *github.Mi return fmt.Errorf("no Milestone ID is set") } - conn := testAccProvider.Meta().(*Organization).v3client + conn := testAccProvider.Meta().(*Owner).v3client number, err := parseMilestoneNumber(rs.Primary.ID) if err != nil { return err @@ -209,7 +209,7 @@ func testAccCheckGithubRepositoryMilestoneDisappears(rn string) resource.TestChe if !ok { return fmt.Errorf("Not found: %s", rn) } - conn := testAccProvider.Meta().(*Organization).v3client + conn := testAccProvider.Meta().(*Owner).v3client number, err := parseMilestoneNumber(rs.Primary.ID) if err != nil { return err @@ -224,7 +224,7 @@ func testAccCheckGithubRepositoryMilestoneDisappears(rn string) resource.TestChe } func testAccCheckGithubRepositoryMilestoneDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*Organization).v3client + conn := testAccProvider.Meta().(*Owner).v3client for _, rs := range s.RootModule().Resources { if rs.Type != "github_repository_milestone" { diff --git a/go.mod b/go.mod index 439d7644fa..7598170951 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.25.1 + github.com/google/go-github/v31 v31.0.0 github.com/google/go-github/v32 v32.1.0 github.com/hashicorp/terraform v0.12.24 github.com/hashicorp/terraform-plugin-sdk v1.7.0 diff --git a/go.sum b/go.sum index e860703a7b..0c7bf1d69d 100644 --- a/go.sum +++ b/go.sum @@ -204,6 +204,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo= +github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= github.com/google/go-github/v32 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo= github.com/google/go-github/v32 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= From 94c06b9e96c654ccc117ffa9e66499a1c7e62dd2 Mon Sep 17 00:00:00 2001 From: Jeremy Udit Date: Mon, 23 Nov 2020 08:36:33 -0500 Subject: [PATCH 4/4] update test suite --- ...source_github_repository_milestone_test.go | 136 +++---- .../resource_github_repository_milestone.go | 2 +- ...source_github_repository_milestone_test.go | 344 +++--------------- 3 files changed, 104 insertions(+), 378 deletions(-) diff --git a/github/data_source_github_repository_milestone_test.go b/github/data_source_github_repository_milestone_test.go index 0938a52ae4..577bd9b426 100644 --- a/github/data_source_github_repository_milestone_test.go +++ b/github/data_source_github_repository_milestone_test.go @@ -2,91 +2,73 @@ package github import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "regexp" "testing" - "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) -func TestAccGithubRepositoryMilestoneDataSource_noMatchReturnsError(t *testing.T) { - repo := "nonExistentRepo" - owner := "no-user" - number := "1" - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckGithubRepositoryMilestoneDataSourceNonExistentConfig(repo, owner, number), - ExpectError: regexp.MustCompile(`Not Found`), - }, - }, - }) -} +func TestAccGithubRepositoryMilestoneDataSource(t *testing.T) { -func TestAccGithubRepositoryMilestoneDataSource_existing(t *testing.T) { - repo := acctest.RandomWithPrefix("tf-acc-test") - title := acctest.RandomWithPrefix("ms") - description := acctest.RandomWithPrefix("tf-acc-test-desc") - dueDate := time.Now().UTC().Format(layoutISO) - - rn := "github_repository_milestone.test" - dataSource := "data.github_repository_milestone.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccCheckGithubRepositoryMilestoneDataSourceConfig(repo, title, description, dueDate), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSource, "title", rn, "title"), - resource.TestCheckResourceAttrPair(dataSource, "description", rn, "description"), - resource.TestCheckResourceAttrPair(dataSource, "due_date", rn, "due_date"), - resource.TestCheckResourceAttrPair(dataSource, "state", rn, "state"), - resource.TestCheckResourceAttrPair(dataSource, "number", rn, "number"), - resource.TestCheckResourceAttrPair(dataSource, "owner", rn, "owner"), - resource.TestCheckResourceAttrPair(dataSource, "repository", rn, "repository"), - ), - }, - }, - }) -} + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) -func testAccCheckGithubRepositoryMilestoneDataSourceNonExistentConfig(owner, repo, number string) string { - return fmt.Sprintf(` -data "github_repository_milestone" "test" { - owner = "%s" - repository = "%s" - number = "%s" -} -`, owner, repo, number) -} + t.Run("queries a repository milestone", func(t *testing.T) { -func testAccCheckGithubRepositoryMilestoneDataSourceConfig(repo, title, description, dueDate string) string { - return fmt.Sprintf(` -resource "github_repository" "test" { - name = "%s" -} + config := fmt.Sprintf(` -resource "github_repository_milestone" "test" { - owner = split("/", "${github_repository.test.full_name}")[0] - repository = github_repository.test.name - title = "%s" - description = "%s" - due_date = "%s" -} + resource "github_repository" "test" { + name = "tf-acc-test-%s" + } -data "github_repository_milestone" "test" { - owner = github_repository_milestone.test.owner - repository = github_repository_milestone.test.repository - number = github_repository_milestone.test.number -} -`, repo, title, description, dueDate) + resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "v1.0.0" + description = "General Availability" + due_date = "2020-11-22" + state = "closed" + } + + data "github_repository_milestone" "test" { + owner = github_repository_milestone.test.owner + repository = github_repository_milestone.test.repository + number = github_repository_milestone.test.number + } + + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository_milestone.test", "state", + "closed", + ), + ) + + 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) { + testCase(t, individual) + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + + }) } diff --git a/github/resource_github_repository_milestone.go b/github/resource_github_repository_milestone.go index 01b26f03cf..7c3c4f6466 100644 --- a/github/resource_github_repository_milestone.go +++ b/github/resource_github_repository_milestone.go @@ -99,7 +99,7 @@ func resourceGithubRepositoryMilestoneCreate(d *schema.ResourceData, meta interf if err != nil { return err } - date := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 7, 0, 0, 0, time.UTC) + date := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 23, 39, 0, 0, time.UTC) milestone.DueOn = &date } if v, ok := d.GetOk("state"); ok && len(v.(string)) > 0 { diff --git a/github/resource_github_repository_milestone_test.go b/github/resource_github_repository_milestone_test.go index 207dacd4f6..08e9a12693 100644 --- a/github/resource_github_repository_milestone_test.go +++ b/github/resource_github_repository_milestone_test.go @@ -1,323 +1,67 @@ package github import ( - "context" "fmt" - "strings" "testing" - "time" - "github.com/google/go-github/v32/github" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccGithubRepositoryMilestone_basic(t *testing.T) { - var milestone github.Milestone - title := acctest.RandomWithPrefix("tf-acc-test") - repoName := acctest.RandomWithPrefix("tf-acc-test-repo") - rn := "github_repository_milestone.test" +func TestAccGithubRepositoryMilestone(t *testing.T) { - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, - Steps: []resource.TestStep{ - { - Config: testAccGithubRepositoryMilestoneConfig(repoName, title), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), - resource.TestCheckResourceAttr(rn, "title", title), - resource.TestCheckResourceAttr(rn, "description", ""), - resource.TestCheckResourceAttr(rn, "state", "open"), - resource.TestCheckResourceAttr(rn, "number", "1"), - ), - }, - { - ResourceName: rn, - ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccGithubRepositoryMilestone_update(t *testing.T) { - var milestone github.Milestone - title := acctest.RandomWithPrefix("tf-acc-test") - repoName := acctest.RandomWithPrefix("tf-acc-test-repo") - dueDate := time.Now().UTC().Format(layoutISO) - description := acctest.RandomWithPrefix("tf-acc-test-desc") - rn := "github_repository_milestone.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, - Steps: []resource.TestStep{ - { - Config: testAccGithubRepositoryMilestoneConfig(repoName, title), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), - resource.TestCheckResourceAttr(rn, "title", title), - resource.TestCheckResourceAttr(rn, "description", ""), - resource.TestCheckResourceAttr(rn, "state", "open"), - resource.TestCheckResourceAttr(rn, "number", "1"), - ), - }, - { - ResourceName: rn, - ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccGithubRepositoryMilestoneConfigUpdate(repoName, title, description, dueDate), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), - resource.TestCheckResourceAttr(rn, "title", title), - resource.TestCheckResourceAttr(rn, "description", description), - resource.TestCheckResourceAttr(rn, "due_date", dueDate), - resource.TestCheckResourceAttr(rn, "state", "open"), - resource.TestCheckResourceAttr(rn, "number", "1"), - ), - }, - }, - }) -} - -func TestAccGithubRepositoryMilestone_multiple(t *testing.T) { - var milestone1, milestone2 github.Milestone - titleOne := acctest.RandomWithPrefix("tf-acc-test-ms") - titleTwo := acctest.RandomWithPrefix("tf-acc-test-ms-two") - - repoName := acctest.RandomWithPrefix("tf-acc-test-repo") - dueDate := time.Now().UTC().Format(layoutISO) - descriptionOne := acctest.RandomWithPrefix("tf-acc-test-desc") - descriptionTwo := acctest.RandomWithPrefix("tf-acc-test-desc-two") - - rn := "github_repository_milestone.test" - rnTwo := "github_repository_milestone.test_two" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, - Steps: []resource.TestStep{ - { - Config: testAccGithubRepositoryMultipleMilestoneConfig(repoName, titleOne, descriptionOne, titleTwo, descriptionTwo, dueDate), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone1), - resource.TestCheckResourceAttr(rn, "title", titleOne), - resource.TestCheckResourceAttr(rn, "description", descriptionOne), - resource.TestCheckResourceAttr(rn, "due_date", dueDate), - resource.TestCheckResourceAttr(rn, "state", "closed"), - resource.TestCheckResourceAttrSet(rn, "number"), - testAccCheckGithubRepositoryMilestoneExists(rnTwo, &milestone2), - resource.TestCheckResourceAttr(rnTwo, "title", titleTwo), - resource.TestCheckResourceAttr(rnTwo, "description", descriptionTwo), - resource.TestCheckResourceAttr(rn, "due_date", dueDate), - resource.TestCheckResourceAttr(rnTwo, "state", "open"), - resource.TestCheckResourceAttrSet(rnTwo, "number"), - ), - }, - { - ResourceName: rn, - ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rn), - ImportState: true, - ImportStateVerify: true, - }, - { - ResourceName: rnTwo, - ImportStateIdFunc: testAccGithubRepositoryMilestoneImportStateIdFunc(rnTwo), - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccGithubRepositoryMilestoneConfigUpdate(repoName, titleOne, descriptionOne, dueDate), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone1), - resource.TestCheckResourceAttr(rn, "title", titleOne), - resource.TestCheckResourceAttr(rn, "description", descriptionOne), - resource.TestCheckResourceAttr(rn, "due_date", dueDate), - resource.TestCheckResourceAttr(rn, "state", "open"), - resource.TestCheckResourceAttrSet(rn, "number"), - ), - }, - }, - }) -} - -func TestAccGithubRepositoryMilestone_disappears(t *testing.T) { - var milestone github.Milestone - - title := acctest.RandomWithPrefix("tf-acc-test") - repoName := acctest.RandomWithPrefix("tf-acc-test-repo") - rn := "github_repository_milestone.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckGithubRepositoryMilestoneDestroy, - Steps: []resource.TestStep{ - { - Config: testAccGithubRepositoryMilestoneConfig(title, repoName), - Check: resource.ComposeTestCheckFunc( - testAccCheckGithubRepositoryMilestoneExists(rn, &milestone), - testAccCheckGithubRepositoryMilestoneDisappears(rn), - ), - ExpectNonEmptyPlan: true, - }, - }, - }) -} - -func testAccCheckGithubRepositoryMilestoneExists(rn string, milestone *github.Milestone) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[rn] - if !ok { - return fmt.Errorf("not Found: %s", rn) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("no Milestone ID is set") - } - - conn := testAccProvider.Meta().(*Owner).v3client - number, err := parseMilestoneNumber(rs.Primary.ID) - if err != nil { - return err - } - parts := strings.Split(rs.Primary.ID, "/") - owner := parts[0] - repoName := parts[1] - - m, _, err := conn.Issues.GetMilestone(context.TODO(), owner, repoName, number) - if err != nil { - return err - } - *milestone = *m - return nil - } -} - -func testAccCheckGithubRepositoryMilestoneDisappears(rn string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[rn] - if !ok { - return fmt.Errorf("Not found: %s", rn) - } - conn := testAccProvider.Meta().(*Owner).v3client - number, err := parseMilestoneNumber(rs.Primary.ID) - if err != nil { - return err - } - parts := strings.Split(rs.Primary.ID, "/") - owner := parts[0] - repoName := parts[1] - - _, err = conn.Issues.DeleteMilestone(context.TODO(), owner, repoName, number) - return err - } -} + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) -func testAccCheckGithubRepositoryMilestoneDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*Owner).v3client + t.Run("creates a repository milestone", func(t *testing.T) { - for _, rs := range s.RootModule().Resources { - if rs.Type != "github_repository_milestone" { - continue - } - - number, err := parseMilestoneNumber(rs.Primary.ID) - if err != nil { - return err - } - parts := strings.Split(rs.Primary.ID, "/") - owner := parts[0] - repoName := parts[1] + config := fmt.Sprintf(` - milestone, resp, err := conn.Issues.GetMilestone(context.TODO(), owner, repoName, number) - if err != nil { - if resp.StatusCode != 404 { - return err + resource "github_repository" "test" { + name = "tf-acc-test-%s" } - } - if milestone != nil { - return fmt.Errorf("milestone still exists") - } - return nil - } - - return nil -} + resource "github_repository_milestone" "test" { + owner = split("/", "${github_repository.test.full_name}")[0] + repository = github_repository.test.name + title = "v1.0.0" + description = "General Availability" + due_date = "2020-11-22" + state = "closed" + } -func testAccGithubRepositoryMilestoneImportStateIdFunc(rn string) resource.ImportStateIdFunc { - return func(s *terraform.State) (string, error) { - rs, ok := s.RootModule().Resources[rn] - if !ok { - return "", fmt.Errorf("Not found: %s", rn) + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository_milestone.test", "state", + "closed", + ), + ) + + 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, + }, + }, + }) } - return fmt.Sprintf("%s/%s/%s", rs.Primary.Attributes["owner"], rs.Primary.Attributes["repository"], rs.Primary.Attributes["number"]), nil - } -} + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) -func testAccGithubRepositoryMilestoneConfig(repoName, title string) string { - return fmt.Sprintf(` -resource "github_repository" "test" { - name = "%s" -} + t.Run("with an individual account", func(t *testing.T) { + testCase(t, individual) + }) -resource "github_repository_milestone" "test" { - owner = split("/", "${github_repository.test.full_name}")[0] - repository = github_repository.test.name - title = "%s" -} -`, repoName, title) -} - -func testAccGithubRepositoryMilestoneConfigUpdate(repoName, title, description, dueDate string) string { - return fmt.Sprintf(` -resource "github_repository" "test" { - name = "%s" -} - -resource "github_repository_milestone" "test" { - owner = split("/", "${github_repository.test.full_name}")[0] - repository = github_repository.test.name - title = "%s" - description = "%s" - due_date = "%s" -} -`, repoName, title, description, dueDate) -} + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) -func testAccGithubRepositoryMultipleMilestoneConfig(repoName, titleOne, descriptionOne, titleTwo, descriptionTwo, dueDate string) string { - return fmt.Sprintf(` -resource "github_repository" "test" { - name = "%s" -} - -resource "github_repository_milestone" "test" { - owner = split("/", "${github_repository.test.full_name}")[0] - repository = github_repository.test.name - title = "%s" - description = "%s" - due_date = "%s" - state = "closed" -} - -resource "github_repository_milestone" "test_two" { - owner = split("/", "${github_repository.test.full_name}")[0] - repository = github_repository.test.name - title = "%s" - description = "%s" - due_date = "%s" - state = "open" -} -`, repoName, titleOne, descriptionOne, dueDate, titleTwo, descriptionTwo, dueDate) + }) }