Skip to content

Commit

Permalink
Fixing github_repository_file owner/org handling (#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 <[email protected]>

* Update github/data_source_github_repository_file_test.go

Co-authored-by: Keegan Campbell <[email protected]>

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

Co-authored-by: Keegan Campbell <[email protected]>

* Small docs fixup

* Take into account @vmasutin's suggestion

Signed-off-by: Valery Masiutsin <[email protected]>
Co-authored-by: Keegan Campbell <[email protected]>
  • Loading branch information
vmasutin and kfcampbell authored Jan 18, 2023
1 parent 8b93e4e commit 592edcc
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 := "[email protected]"
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 592edcc

Please sign in to comment.