Skip to content

Commit

Permalink
Fixing github_repository_file owner/org handling (integrations#1494)
Browse files Browse the repository at this point in the history
* Fixing `github_repository_file` owner handling, if `full_name` is
passed, split it into `owner` and `repo`, use user as an `owner`
otherwise

Signed-off-by: Valery Masiutsin <val.masiutsin@gmail.com>

* Update github/data_source_github_repository_file_test.go

Co-authored-by: Keegan Campbell <me@kfcampbell.com>

* Update website/docs/d/repository_file.html.markdown

Co-authored-by: Keegan Campbell <me@kfcampbell.com>

* Small docs fixup

* Take into account @vmasutin's suggestion

Signed-off-by: Valery Masiutsin <val.masiutsin@gmail.com>
Co-authored-by: Keegan Campbell <me@kfcampbell.com>
  • Loading branch information
vmasutin and kfcampbell committed Jan 18, 2023
1 parent bab1ce9 commit a655e2a
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 7 deletions.
16 changes: 14 additions & 2 deletions github/data_source_github_repository_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"strings"

"github.com/google/go-github/v49/github"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
Expand Down Expand Up @@ -64,12 +65,23 @@ func dataSourceGithubRepositoryFile() *schema.Resource {
}

func dataSourceGithubRepositoryFileRead(d *schema.ResourceData, meta interface{}) error {

client := meta.(*Owner).v3client
owner := meta.(*Owner).name
ctx := context.WithValue(context.Background(), ctxId, d.Id())

owner := meta.(*Owner).name
repo := d.Get("repository").(string)

// checking if repo has a slash in it, which means that full_name was passed
// split and replace owner and repo
parts := strings.Split(repo, "/")
if len(parts) == 2 {
log.Printf("[DEBUG] repo has a slash, extracting owner from: %s", repo)
owner = parts[0]
repo = parts[1]

log.Printf("[DEBUG] owner: %s repo:%s", owner, repo)
}

file := d.Get("file").(string)
branch := d.Get("branch").(string)
if err := checkRepositoryBranchExists(client, owner, repo, branch); err != nil {
Expand Down
195 changes: 193 additions & 2 deletions github/data_source_github_repository_file_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package github

import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/url"
"testing"

"github.com/google/go-github/v49/github"
"github.com/stretchr/testify/assert"

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

func TestAccGithubRepositoryFileDataSource(t *testing.T) {

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

t.Run("read files", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
Expand Down Expand Up @@ -85,6 +91,191 @@ func TestAccGithubRepositoryFileDataSource(t *testing.T) {
t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}

func TestDataSourceGithubRepositoryFileRead(t *testing.T) {
// helper function to simplify marshalling.
marshal := func(t *testing.T, msg interface{}) string {
data, err := json.MarshalIndent(msg, "", " ")
if err != nil {
t.Fatalf("cant encode to json: %v", err)
}

return string(data)
}

sha := "some-test-sha"
committerName := "some-test-user"
committerEmail := "some-test-user@github.com"
commitMessage := "test commit message"

enc := "base64"
fileContent := "here-goes-content-of-our-glorious-config.json"
b64FileContent := base64.StdEncoding.EncodeToString([]byte(fileContent))

fileName := "test-file.json"
branch := "main"

// setting up some org/owner info
owner := "test-owner"
org := "test-org"
repo := "test-repo"

// preparing mashalled objects
branchRespBody := marshal(t, &github.Branch{Name: &branch})
repoContentRespBody := marshal(t, &github.RepositoryContent{
Encoding: &enc,
Content: &b64FileContent,
SHA: &sha,
})
repoCommitRespBody := marshal(t, &github.RepositoryCommit{
SHA: &sha,
Committer: &github.User{
Name: &committerName,
Email: &committerEmail,
},
Commit: &github.Commit{
Message: &commitMessage,
},
})

t.Run("extracting org and repo if full_name is passed", func(t *testing.T) {
// test setup
repositoryFullName := fmt.Sprintf("%s/%s", org, repo)
expectedID := fmt.Sprintf("%s/%s", repo, fileName)
expectedRepo := "test-repo"

ts := githubApiMock([]*mockResponse{
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/branches/%s", org, repo, branch),
ResponseBody: branchRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/contents/%s?ref=%s", org, repo, fileName, branch),
ResponseBody: repoContentRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/commits/%s", org, repo, sha),
ResponseBody: repoCommitRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/commits", org, repo),
ResponseBody: repoCommitRespBody,
StatusCode: http.StatusOK,
},
})
defer ts.Close()

httpCl := http.DefaultClient
httpCl.Transport = http.DefaultTransport

client := github.NewClient(httpCl)
u, _ := url.Parse(ts.URL + "/")
client.BaseURL = u

meta := &Owner{
name: owner,
v3client: client,
}

testSchema := map[string]*schema.Schema{
"repository": {Type: schema.TypeString},
"file": {Type: schema.TypeString},
"branch": {Type: schema.TypeString},
"commit_sha": {Type: schema.TypeString},
"content": {Type: schema.TypeString},
"id": {Type: schema.TypeString},
}

schema := schema.TestResourceDataRaw(t, testSchema, map[string]interface{}{
"repository": repositoryFullName,
"file": fileName,
"branch": branch,
"commit_sha": sha,
"content": "",
"id": "",
})

// actual call
err := dataSourceGithubRepositoryFileRead(schema, meta)

// assertions
assert.Nil(t, err)
assert.Equal(t, expectedRepo, schema.Get("repository"))
assert.Equal(t, fileContent, schema.Get("content"))
assert.Equal(t, expectedID, schema.Get("id"))
})
t.Run("using user as owner if just name is passed", func(t *testing.T) {
// test setup
repositoryFullName := repo
expectedID := fmt.Sprintf("%s/%s", repo, fileName)
expectedRepo := "test-repo"

ts := githubApiMock([]*mockResponse{
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/branches/%s", owner, repo, branch),
ResponseBody: branchRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/contents/%s?ref=%s", owner, repo, fileName, branch),
ResponseBody: repoContentRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/commits/%s", owner, repo, sha),
ResponseBody: repoCommitRespBody,
StatusCode: http.StatusOK,
},
{
ExpectedUri: fmt.Sprintf("/repos/%s/%s/commits", owner, repo),
ResponseBody: repoCommitRespBody,
StatusCode: http.StatusOK,
},
})
defer ts.Close()

httpCl := http.DefaultClient
httpCl.Transport = http.DefaultTransport

client := github.NewClient(httpCl)
u, _ := url.Parse(ts.URL + "/")
client.BaseURL = u

meta := &Owner{
name: owner,
v3client: client,
}

testSchema := map[string]*schema.Schema{
"repository": {Type: schema.TypeString},
"file": {Type: schema.TypeString},
"branch": {Type: schema.TypeString},
"commit_sha": {Type: schema.TypeString},
"content": {Type: schema.TypeString},
"id": {Type: schema.TypeString},
}

schema := schema.TestResourceDataRaw(t, testSchema, map[string]interface{}{
"repository": repositoryFullName,
"file": fileName,
"branch": branch,
"commit_sha": sha,
"content": "",
"id": "",
})

// actual call
err := dataSourceGithubRepositoryFileRead(schema, meta)

// assertions
assert.Nil(t, err)
assert.Equal(t, expectedRepo, schema.Get("repository"))
assert.Equal(t, fileContent, schema.Get("content"))
assert.Equal(t, expectedID, schema.Get("id"))
})
}
6 changes: 3 additions & 3 deletions website/docs/d/repository_file.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ data "github_repository_file" "foo" {

The following arguments are supported:

* `repository` - (Required) The repository to create the file in.
* `repository` - (Required) The repository to read the file from. If an unqualified repo name (without an owner) is passed, the owner will be inferred from the owner of the token used to execute the plan. If a name of the type "owner/repo" (with a slash in the middle) is passed, the owner will be as specified and not the owner of the token.

* `file` - (Required) The path of the file to manage.

* `branch` - (Optional) Git branch (defaults to `main`).
The branch must already exist, it will not be created if it does not already exist.
* `branch` - (Optional) Git branch (if omitted, the default repository branch is used, which is usually `main`)
The branch must already exist; it will not be created if it does not already exist.

## Attributes Reference

Expand Down

0 comments on commit a655e2a

Please sign in to comment.