diff --git a/bitbucket/resource_repository.go b/bitbucket/resource_repository.go index 3a7af79..8687442 100644 --- a/bitbucket/resource_repository.go +++ b/bitbucket/resource_repository.go @@ -26,16 +26,13 @@ type Repository struct { } `json:"links,omitempty"` } -type ForkRepositoryRequestBody struct { +type RepositoryForkProject struct { + Key string `json:"key,omitempty"` +} + +type RepositoryFork struct { Name string `json:"name,omitempty"` - Slug string `json:"slug,omitempty"` - Description string `json:"description,omitempty"` - Forkable bool `json:"forkable,omitempty"` - Public bool `json:"public,omitempty"` - Links struct { - Clone []CloneUrl `json:"clone,omitempty"` - } `json:"links,omitempty"` - Project Project `json:"project,omitempty"` + Project RepositoryForkProject `json:"project,omitempty"` } func resourceRepository() *schema.Resource { @@ -79,10 +76,15 @@ func resourceRepository() *schema.Resource { Optional: true, Default: false, }, - "origin_slug_to_fork": { + "fork_repository_project": { Type: schema.TypeString, Optional: true, - Default: false, + ForceNew: true, + }, + "fork_repository_slug": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, }, "enable_git_lfs": { Type: schema.TypeBool, @@ -113,19 +115,6 @@ func newRepositoryFromResource(d *schema.ResourceData) (Repo *Repository) { return repo } -func newForkedRepositoryFromResource(d *schema.ResourceData) (Repo *ForkRepositoryRequestBody) { - req := &ForkRepositoryRequestBody{ - Name: d.Get("name").(string), - Slug: d.Get("slug").(string), - Description: d.Get("description").(string), - Forkable: d.Get("forkable").(bool), - Public: d.Get("public").(bool), - Project: Project{Key: d.Get("project").(string)}, - } - - return req -} - func resourceRepositoryUpdate(d *schema.ResourceData, m interface{}) error { client := m.(*BitbucketServerProvider).BitbucketClient project := d.Get("project").(string) @@ -163,9 +152,14 @@ func resourceRepositoryCreate(d *schema.ResourceData, m interface{}) error { repoSlug := determineSlug(d) name := d.Get("name").(string) - forkSlug := d.Get("fork_slug").(string) - if forkSlug != "" { - err := createForkRepository(client, d, project, forkSlug) + forkProject := d.Get("fork_repository_project").(string) + forkRepo := d.Get("fork_repository_slug").(string) + if (forkProject != "" && forkRepo == "") || (forkRepo != "" && forkProject == "") { + return fmt.Errorf("both fork_repository_project and fork_repository_slug need to be specified when forking an existing repository") + } + + if forkProject != "" { + err := createNewRepositoryFromFork(client, d, project, repoSlug, forkProject, forkRepo) if err != nil { return err } @@ -183,34 +177,51 @@ func resourceRepositoryCreate(d *schema.ResourceData, m interface{}) error { return err } - return resourceRepositoryRead(d, m) + if forkProject != "" { + // after forking a repository, run the update loop to update any names/descriptions etc of the forked repo + return resourceRepositoryUpdate(d, m) + } else { + return resourceRepositoryRead(d, m) + } } func createNewRepository(client *BitbucketClient, d *schema.ResourceData, project string) error { repo := newRepositoryFromResource(d) bytedata, err := json.Marshal(repo) + if err != nil { return err } + _, err = client.Post(fmt.Sprintf("/rest/api/1.0/projects/%s/repos", project, ), bytes.NewBuffer(bytedata)) + if err != nil { return err } + return nil } -func createForkRepository(client *BitbucketClient, d *schema.ResourceData, project string, forkSlug string) error { - requestBody := newForkedRepositoryFromResource(d) +func createNewRepositoryFromFork(client *BitbucketClient, d *schema.ResourceData, project string, repository string, forkProject string, forkRepository string) error { + requestBody := &RepositoryFork{ + Name: repository, + Project: RepositoryForkProject{ + Key:forkProject, + }, + } + bytedata, err := json.Marshal(requestBody) if err != nil { return err } - _, err = client.Post(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s", project, forkSlug), bytes.NewBuffer(bytedata)) + + _, err = client.Post(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s", forkProject, forkRepository), bytes.NewBuffer(bytedata)) if err != nil { return err } + return nil } diff --git a/bitbucket/resource_repository_test.go b/bitbucket/resource_repository_test.go index 0cfa7bd..7d46c76 100644 --- a/bitbucket/resource_repository_test.go +++ b/bitbucket/resource_repository_test.go @@ -87,6 +87,59 @@ func TestAccBitbucketRepository_namewithspaces(t *testing.T) { }) } +func TestAccBitbucketRepository_fork(t *testing.T) { + var repo Repository + + config := fmt.Sprintf(` + resource "bitbucketserver_project" "test" { + key = "TEST%v" + name = "Test-%v" + } + + resource "bitbucketserver_repository" "test_repo" { + project = bitbucketserver_project.test.key + name = "test-repo-for-repository-test" + description = "My Repo" + } + + resource "bitbucketserver_repository" "test_fork" { + project = bitbucketserver_repository.test_repo.project + name = "My Fork" + description = "My Repo Forked" + fork_repository_project = bitbucketserver_repository.test_repo.project + fork_repository_slug = bitbucketserver_repository.test_repo.slug + } + `, rand.New(rand.NewSource(time.Now().UnixNano())).Int(), rand.New(rand.NewSource(time.Now().UnixNano())).Int()) + + configModified := strings.ReplaceAll(config, "My Repo Forked", "My Updated Repo Forked") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBitbucketRepositoryDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testAccCheckBitbucketRepositoryExists("bitbucketserver_repository.test_fork", &repo), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "slug", "my-fork"), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "name", "My Fork"), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "description", "My Repo Forked"), + ), + }, + { + Config: configModified, + Check: resource.ComposeTestCheckFunc( + testAccCheckBitbucketRepositoryExists("bitbucketserver_repository.test_fork", &repo), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "slug", "my-fork"), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "name", "My Fork"), + resource.TestCheckResourceAttr("bitbucketserver_repository.test_fork", "description", "My Updated Repo Forked"), + ), + }, + }, + }) +} + func TestAccBitbucketRepository_gitlfs(t *testing.T) { var repo Repository diff --git a/docusaurus/docs/resource_repository.md b/docusaurus/docs/resource_repository.md index cc07a04..e1d6117 100644 --- a/docusaurus/docs/resource_repository.md +++ b/docusaurus/docs/resource_repository.md @@ -15,17 +15,20 @@ resource "bitbucketserver_repository" "test" { } ``` -###### if you want to fork an existing repository in the same project +### Forking an existing repository ```hcl resource "bitbucketserver_repository" "test" { - project = "MYPROJ" - name = "test-01" - description = "Test repository" - origin_slug_to_fork = "MYOLDPROJ" + project = "MYPROJ" + name = "test-01" + description = "Test repository" + fork_repository_project = "MY-ORIGIN-PROJ" + fork_repository_slug = "MY-ORIGIN-REPO" } ``` +> Note: Both `fork_repositiroy_project` and `fork_repository_slug` are required to specified the origin repository to fork. + ## Argument Reference * `project` - Required. Name of the project to create the repository in. @@ -35,7 +38,9 @@ resource "bitbucketserver_repository" "test" { * `forkable` - Optional. Enable/disable forks of this repository. Default `true` * `public` - Optional. Determine if this repository is public. Default `false` * `enable_git_lfs` - Optional. Enable git-lfs for this repository. Default `false` -* `origin_slug_to_fork` - Optional. Use this to fork an expisting repository in the same project. Default `false` +* `fork_repository_project` - Optional. Use this to fork an existing repository from the given project. +* `fork_repository_slug` - Optional. Use this to fork an existing repository from the given repository. + ## Attribute Reference Additional to the above, the following attributes are emitted: