Skip to content

Commit 534f002

Browse files
author
Rene Schach
authored
New resource github_repository_autolink_reference (#924)
* Add resource github_repository_autolink_reference * Add resource to provider main file * Use correct resource name, thanks to @mrwacky42
1 parent 9f305fb commit 534f002

File tree

5 files changed

+341
-0
lines changed

5 files changed

+341
-0
lines changed

github/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func Provider() terraform.ResourceProvider {
9898
"github_organization_webhook": resourceGithubOrganizationWebhook(),
9999
"github_project_card": resourceGithubProjectCard(),
100100
"github_project_column": resourceGithubProjectColumn(),
101+
"github_repository_autolink_reference": resourceGithubRepositoryAutolinkReference(),
101102
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
102103
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
103104
"github_repository_environment": resourceGithubRepositoryEnvironment(),
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"regexp"
8+
"strconv"
9+
"strings"
10+
11+
"github.com/google/go-github/v39/github"
12+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
13+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
14+
)
15+
16+
func resourceGithubRepositoryAutolinkReference() *schema.Resource {
17+
return &schema.Resource{
18+
Create: resourceGithubRepositoryAutolinkReferenceCreate,
19+
Read: resourceGithubRepositoryAutolinkReferenceRead,
20+
Delete: resourceGithubRepositoryAutolinkReferenceDelete,
21+
22+
Importer: &schema.ResourceImporter{
23+
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
24+
parts := strings.Split(d.Id(), "/")
25+
if len(parts) != 2 {
26+
return nil, fmt.Errorf("Invalid ID specified. Supplied ID must be written as <repository>/<autolink_reference_id>")
27+
}
28+
d.Set("repository", parts[0])
29+
d.SetId(parts[1])
30+
return []*schema.ResourceData{d}, nil
31+
},
32+
},
33+
34+
SchemaVersion: 1,
35+
Schema: map[string]*schema.Schema{
36+
"repository": {
37+
Type: schema.TypeString,
38+
Required: true,
39+
ForceNew: true,
40+
Description: "The repository name",
41+
},
42+
"key_prefix": {
43+
Type: schema.TypeString,
44+
Required: true,
45+
Description: "This prefix appended by a number will generate a link any time it is found in an issue, pull request, or commit",
46+
},
47+
"target_url_template": {
48+
Type: schema.TypeString,
49+
Required: true,
50+
Description: "The template of the target URL used for the links; must be a valid URL and contain `<num>` for the reference number",
51+
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^http[s]?:\/\/[a-z0-9-.]*\/.*?<num>.*?$`), "must be a valid URL and contain <num> token"),
52+
},
53+
"etag": {
54+
Type: schema.TypeString,
55+
Computed: true,
56+
},
57+
},
58+
}
59+
}
60+
61+
func resourceGithubRepositoryAutolinkReferenceCreate(d *schema.ResourceData, meta interface{}) error {
62+
client := meta.(*Owner).v3client
63+
64+
owner := meta.(*Owner).name
65+
repoName := d.Get("repository").(string)
66+
keyPrefix := d.Get("key_prefix").(string)
67+
targetURLTemplate := d.Get("target_url_template").(string)
68+
ctx := context.Background()
69+
70+
opts := &github.AutolinkOptions{
71+
KeyPrefix: &keyPrefix,
72+
URLTemplate: &targetURLTemplate,
73+
}
74+
75+
log.Printf("[DEBUG] Creating repository autolink reference: %s -> %s (%s/%s)", keyPrefix, targetURLTemplate, owner, repoName)
76+
autolinkRef, _, err := client.Repositories.AddAutolink(ctx, owner, repoName, opts)
77+
if err != nil {
78+
return err
79+
}
80+
d.SetId(strconv.FormatInt(autolinkRef.GetID(), 10))
81+
82+
return resourceGithubRepositoryAutolinkReferenceRead(d, meta)
83+
}
84+
85+
func resourceGithubRepositoryAutolinkReferenceRead(d *schema.ResourceData, meta interface{}) error {
86+
client := meta.(*Owner).v3client
87+
88+
owner := meta.(*Owner).name
89+
repoName := d.Get("repository").(string)
90+
autolinkRefID, err := strconv.ParseInt(d.Id(), 10, 64)
91+
if err != nil {
92+
return unconvertibleIdErr(d.Id(), err)
93+
}
94+
ctx := context.WithValue(context.Background(), ctxId, d.Id())
95+
if !d.IsNewResource() {
96+
ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string))
97+
}
98+
99+
log.Printf("[DEBUG] Reading repository autolink reference: %s (%s/%s)", d.Id(), owner, repoName)
100+
autolinkRef, _, err := client.Repositories.GetAutolink(ctx, owner, repoName, autolinkRefID)
101+
if err != nil {
102+
return err
103+
}
104+
105+
// Set resource fields
106+
d.SetId(strconv.FormatInt(autolinkRef.GetID(), 10))
107+
d.Set("repository", repoName)
108+
d.Set("key_prefix", autolinkRef.KeyPrefix)
109+
d.Set("target_url_template", autolinkRef.URLTemplate)
110+
111+
return nil
112+
}
113+
114+
func resourceGithubRepositoryAutolinkReferenceDelete(d *schema.ResourceData, meta interface{}) error {
115+
client := meta.(*Owner).v3client
116+
117+
owner := meta.(*Owner).name
118+
repoName := d.Get("repository").(string)
119+
autolinkRefID, err := strconv.ParseInt(d.Id(), 10, 64)
120+
if err != nil {
121+
return unconvertibleIdErr(d.Id(), err)
122+
}
123+
ctx := context.WithValue(context.Background(), ctxId, d.Id())
124+
125+
log.Printf("[DEBUG] Deleting repository autolink reference: %s (%s/%s)", d.Id(), owner, repoName)
126+
_, err = client.Repositories.DeleteAutolink(ctx, owner, repoName, autolinkRefID)
127+
return err
128+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
)
10+
11+
func TestAccGithubRepositoryAutolinkReference(t *testing.T) {
12+
13+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
14+
15+
t.Run("creates repository autolink reference without error", func(t *testing.T) {
16+
17+
config := fmt.Sprintf(`
18+
resource "github_repository" "oof" {
19+
name = "oof-%s"
20+
description = "Test autolink creation"
21+
}
22+
23+
resource "github_repository_autolink_reference" "autolink" {
24+
repository = github_repository.oof.name
25+
26+
key_prefix = "OOF-"
27+
target_url_template = "https://awesome.com/find/OOF-<num>"
28+
}
29+
`, randomID)
30+
31+
check := resource.ComposeTestCheckFunc(
32+
resource.TestCheckResourceAttr(
33+
"github_repository_autolink_reference.autolink", "key_prefix", "OOF-",
34+
),
35+
resource.TestCheckResourceAttr(
36+
"github_repository_autolink_reference.autolink", "target_url_template", "https://awesome.com/find/OOF-<num>",
37+
),
38+
)
39+
40+
testCase := func(t *testing.T, mode string) {
41+
resource.Test(t, resource.TestCase{
42+
PreCheck: func() { skipUnlessMode(t, mode) },
43+
Providers: testAccProviders,
44+
Steps: []resource.TestStep{
45+
{
46+
Config: config,
47+
Check: check,
48+
},
49+
},
50+
})
51+
}
52+
53+
t.Run("with an anonymous account", func(t *testing.T) {
54+
t.Skip("anonymous account not supported for this operation")
55+
})
56+
57+
t.Run("with an individual account", func(t *testing.T) {
58+
testCase(t, individual)
59+
})
60+
61+
t.Run("with an organization account", func(t *testing.T) {
62+
testCase(t, organization)
63+
})
64+
65+
})
66+
67+
t.Run("imports repository autolink reference without error", func(t *testing.T) {
68+
69+
config := fmt.Sprintf(`
70+
resource "github_repository" "oof" {
71+
name = "oof-%s"
72+
description = "Test autolink creation"
73+
}
74+
75+
resource "github_repository_autolink_reference" "autolink" {
76+
repository = github_repository.oof.name
77+
78+
key_prefix = "OOF-"
79+
target_url_template = "https://awesome.com/find/OOF-<num>"
80+
}
81+
`, randomID)
82+
83+
testCase := func(t *testing.T, mode string) {
84+
resource.Test(t, resource.TestCase{
85+
PreCheck: func() { skipUnlessMode(t, mode) },
86+
Providers: testAccProviders,
87+
Steps: []resource.TestStep{
88+
{
89+
Config: config,
90+
},
91+
{
92+
ResourceName: "github_repository_autolink_reference.autolink",
93+
ImportState: true,
94+
ImportStateVerify: true,
95+
ImportStateIdPrefix: fmt.Sprintf("oof-%s/", randomID),
96+
},
97+
},
98+
})
99+
}
100+
101+
t.Run("with an anonymous account", func(t *testing.T) {
102+
t.Skip("anonymous account not supported for this operation")
103+
})
104+
105+
t.Run("with an individual account", func(t *testing.T) {
106+
testCase(t, individual)
107+
})
108+
109+
t.Run("with an organization account", func(t *testing.T) {
110+
testCase(t, organization)
111+
})
112+
113+
})
114+
115+
t.Run("deletes repository autolink reference without error", func(t *testing.T) {
116+
117+
config := fmt.Sprintf(`
118+
resource "github_repository" "oof" {
119+
name = "oof-%s"
120+
description = "Test autolink creation"
121+
}
122+
123+
resource "github_repository_autolink_reference" "autolink" {
124+
repository = github_repository.oof.name
125+
126+
key_prefix = "OOF-"
127+
target_url_template = "https://awesome.com/find/OOF-<num>"
128+
}
129+
`, randomID)
130+
131+
testCase := func(t *testing.T, mode string) {
132+
resource.Test(t, resource.TestCase{
133+
PreCheck: func() { skipUnlessMode(t, mode) },
134+
Providers: testAccProviders,
135+
Steps: []resource.TestStep{
136+
{
137+
Config: config,
138+
Destroy: true,
139+
},
140+
},
141+
})
142+
}
143+
144+
t.Run("with an anonymous account", func(t *testing.T) {
145+
t.Skip("anonymous account not supported for this operation")
146+
})
147+
148+
t.Run("with an individual account", func(t *testing.T) {
149+
testCase(t, individual)
150+
})
151+
152+
t.Run("with an organization account", func(t *testing.T) {
153+
testCase(t, organization)
154+
})
155+
})
156+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
layout: "github"
3+
page_title: "GitHub: github_repository_autolink_reference"
4+
description: |-
5+
Creates and manages autolink references for a single repository
6+
---
7+
8+
# github_repository_autolink_reference
9+
10+
This resource allows you to create and manage an autolink reference for a single repository.
11+
12+
## Example Usage
13+
14+
```hcl
15+
resource "github_repository" "repo" {
16+
name = "oof"
17+
description = "GitHub repo managed by Terraform"
18+
19+
private = false
20+
}
21+
22+
resource "github_repository_autolink_reference" "auto" {
23+
repository = github_repository.repo.name
24+
25+
key_prefix = "TICKET-"
26+
27+
target_url_template = "https://hello.there/TICKET?query=<num>"
28+
}
29+
```
30+
31+
## Argument Reference
32+
33+
The following arguments are supported:
34+
35+
* `repository` - (Required) The repository of the autolink reference.
36+
37+
* `key_prefix` - (Required) This prefix appended by a number will generate a link any time it is found in an issue, pull request, or commit.
38+
39+
* `target_url_template` - (Required) The template of the target URL used for the links; must be a valid URL and contain `<num>` for the reference number
40+
41+
## Attributes Reference
42+
43+
The following additional attributes are exported:
44+
45+
* `etag` - An etag representing the autolink reference object.
46+
47+
## Import
48+
49+
Autolink references can be imported using the `name` of the repository, combined with the `id` of the autolink reference and a `/` character for separating components, e.g.
50+
51+
```sh
52+
terraform import github_repository_autolink_reference.auto oof/123
53+
```

website/github.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@
115115
<li>
116116
<a href="/docs/providers/github/r/repository.html">github_repository</a>
117117
</li>
118+
<li>
119+
<a href="/docs/providers/github/r/repository_autolink_reference.html">github_repository_autolink_reference</a>
120+
</li>
118121
<li>
119122
<a href="/docs/providers/github/r/repository_collaborator.html">github_repository_collaborator</a>
120123
</li>

0 commit comments

Comments
 (0)