From 6e637971677de2abfa6aebf618271509fe220c69 Mon Sep 17 00:00:00 2001 From: Tobias Trabelsi Date: Sat, 25 Jun 2022 23:36:24 +0200 Subject: [PATCH 1/2] #3 added team resource and fixed crash in public key state persisting --- Makefile | 2 +- docs/resources/team.md | 50 +++++ examples/main.tf | 8 + examples/provider.tf | 2 +- examples/resources/gitea_team/resource.tf | 10 + gitea/provider.go | 1 + gitea/resource_gitea_public_key.go | 2 +- gitea/resource_gitea_team.go | 262 ++++++++++++++++++++++ gitea/resource_gitea_user.go | 1 - 9 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 docs/resources/team.md create mode 100644 examples/resources/gitea_team/resource.tf create mode 100644 gitea/resource_gitea_team.go diff --git a/Makefile b/Makefile index 2761112..8ae9eeb 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) GOFMT ?= gofmt -s -VERSION = 0.5.0 +VERSION = 0.6.0 test: fmt-check go test -i $(TEST) || exit 1 diff --git a/docs/resources/team.md b/docs/resources/team.md new file mode 100644 index 0000000..a16f48b --- /dev/null +++ b/docs/resources/team.md @@ -0,0 +1,50 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitea_team Resource - terraform-provider-gitea" +subcategory: "" +description: |- + gitea_team manages Team that are part of an organisation. +--- + +# gitea_team (Resource) + +`gitea_team` manages Team that are part of an organisation. + +## Example Usage + +```terraform +resource "gitea_org" "test_org" { + name = "test-org" +} + +resource "gitea_team" "test_team" { + name = "Devs" + organisation = gitea_org.test_org.name + description = "Devs of Test Org" + permission = "write" +} +``` + + +## Schema + +### Required + +- `name` (String) Name of the Team +- `organisation` (String) The organisation which this Team is part of. + +### Optional + +- `can_create_repos` (Boolean) Flag if the Teams members should be able to create Rpositories in the Organisation +- `description` (String) Description of the Team +- `include_all_repositories` (Boolean) Flag if the Teams members should have access to all Repositories in the Organisation +- `permission` (String) Permissions associated with this Team +Can be `none`, `read`, `write`, `admin` or `owner` +- `units` (String) List of types of Repositories that should be allowed to be created from Team members. +Can be `repo.code`, `repo.issues`, `repo.ext_issues`, `repo.wiki`, `repo.pulls`, `repo.releases`, `repo.projects` and/or `repo.ext_wiki` + +### Read-Only + +- `id` (String) The ID of this resource. + + diff --git a/examples/main.tf b/examples/main.tf index c511e41..ff9a3d5 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -46,3 +46,11 @@ resource "gitea_public_key" "test_user_key" { read_only = true username = gitea_user.test.username } + + +resource "gitea_team" "test_team" { + name = "Devs" + organisation = gitea_org.test_org.name + description = "Devs of Test Org" + permission = "write" +} \ No newline at end of file diff --git a/examples/provider.tf b/examples/provider.tf index 44cdeef..b523a8e 100644 --- a/examples/provider.tf +++ b/examples/provider.tf @@ -2,7 +2,7 @@ terraform { required_providers { gitea = { source = "terraform.local/lerentis/gitea" - version = "0.5.0" + version = "0.6.0" } } } diff --git a/examples/resources/gitea_team/resource.tf b/examples/resources/gitea_team/resource.tf new file mode 100644 index 0000000..08ce5d5 --- /dev/null +++ b/examples/resources/gitea_team/resource.tf @@ -0,0 +1,10 @@ +resource "gitea_org" "test_org" { + name = "test-org" +} + +resource "gitea_team" "test_team" { + name = "Devs" + organisation = gitea_org.test_org.name + description = "Devs of Test Org" + permission = "write" +} \ No newline at end of file diff --git a/gitea/provider.go b/gitea/provider.go index 643bbc0..11daf15 100644 --- a/gitea/provider.go +++ b/gitea/provider.go @@ -80,6 +80,7 @@ func Provider() terraform.ResourceProvider { "gitea_oauth2_app": resourceGiteaOauthApp(), "gitea_repository": resourceGiteaRepository(), "gitea_public_key": resourceGiteaPublicKey(), + "gitea_team": resourceGiteaTeam(), }, ConfigureFunc: providerConfigure, diff --git a/gitea/resource_gitea_public_key.go b/gitea/resource_gitea_public_key.go index 611f4b9..8a64ad3 100644 --- a/gitea/resource_gitea_public_key.go +++ b/gitea/resource_gitea_public_key.go @@ -90,7 +90,7 @@ func resourcePublicKeyDelete(d *schema.ResourceData, meta interface{}) (err erro func setPublicKeyResourceData(pubKey *gitea.PublicKey, d *schema.ResourceData) (err error) { d.SetId(fmt.Sprintf("%d", pubKey.ID)) - d.Set(PublicKeyUser, pubKey.Owner.UserName) + d.Set(PublicKeyUser, d.Get(PublicKeyUser).(string)) d.Set(PublicKey, pubKey.Key) d.Set(PublicKeyTitle, pubKey.Title) d.Set(PublicKeyReadOnlyFlag, pubKey.ReadOnly) diff --git a/gitea/resource_gitea_team.go b/gitea/resource_gitea_team.go new file mode 100644 index 0000000..2d98115 --- /dev/null +++ b/gitea/resource_gitea_team.go @@ -0,0 +1,262 @@ +package gitea + +import ( + "fmt" + "strconv" + "strings" + + "code.gitea.io/sdk/gitea" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +const ( + TeamName string = "name" + TeamOrg string = "organisation" + TeamDescription string = "description" + TeamPermissions string = "permission" + TeamCreateRepoFlag string = "can_create_repos" + TeamIncludeAllReposFlag string = "include_all_repositories" + TeamUnits string = "units" +) + +func resourceTeamRead(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + id, err := strconv.ParseInt(d.Id(), 10, 64) + + var resp *gitea.Response + var team *gitea.Team + + team, resp, err = client.GetTeam(id) + + if err != nil { + if resp.StatusCode == 404 { + d.SetId("") + return nil + } else { + return err + } + } + + err = setTeamResourceData(team, d) + + return +} + +func resourceTeamCreate(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + var team *gitea.Team + var units []gitea.RepoUnitType + + if strings.Contains(d.Get(TeamUnits).(string), "repo.code") { + units = append(units, gitea.RepoUnitCode) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.issues") { + units = append(units, gitea.RepoUnitIssues) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_issues") { + units = append(units, gitea.RepoUnitExtIssues) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.wiki") { + units = append(units, gitea.RepoUnitWiki) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.pulls") { + units = append(units, gitea.RepoUnitPulls) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.releases") { + units = append(units, gitea.RepoUnitReleases) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_wiki") { + units = append(units, gitea.RepoUnitExtWiki) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.projects") { + units = append(units, gitea.RepoUnitProjects) + } + + opts := gitea.CreateTeamOption{ + Name: d.Get(TeamName).(string), + Description: d.Get(TeamDescription).(string), + Permission: gitea.AccessMode(d.Get(TeamPermissions).(string)), + CanCreateOrgRepo: d.Get(TeamCreateRepoFlag).(bool), + IncludesAllRepositories: d.Get(TeamIncludeAllReposFlag).(bool), + Units: units, + } + + team, _, err = client.CreateTeam(d.Get(TeamOrg).(string), opts) + + if err != nil { + return + } + + err = setTeamResourceData(team, d) + + return +} + +func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + id, err := strconv.ParseInt(d.Id(), 10, 64) + + var resp *gitea.Response + var team *gitea.Team + + team, resp, err = client.GetTeam(id) + + if err != nil { + if resp.StatusCode == 404 { + resourceTeamCreate(d, meta) + } else { + return err + } + } + + description := d.Get(TeamDescription).(string) + canCreateRepo := d.Get(TeamCreateRepoFlag).(bool) + includeAllRepos := d.Get(TeamIncludeAllReposFlag).(bool) + + var units []gitea.RepoUnitType + + if strings.Contains(d.Get(TeamUnits).(string), "repo.code") { + units = append(units, gitea.RepoUnitCode) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.issues") { + units = append(units, gitea.RepoUnitIssues) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_issues") { + units = append(units, gitea.RepoUnitExtIssues) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.wiki") { + units = append(units, gitea.RepoUnitWiki) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.pulls") { + units = append(units, gitea.RepoUnitPulls) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.releases") { + units = append(units, gitea.RepoUnitReleases) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_wiki") { + units = append(units, gitea.RepoUnitExtWiki) + } + if strings.Contains(d.Get(TeamUnits).(string), "repo.projects") { + units = append(units, gitea.RepoUnitProjects) + } + + opts := gitea.EditTeamOption{ + Name: d.Get(TeamName).(string), + Description: &description, + Permission: gitea.AccessMode(d.Get(TeamPermissions).(string)), + CanCreateOrgRepo: &canCreateRepo, + IncludesAllRepositories: &includeAllRepos, + Units: units, + } + + resp, err = client.EditTeam(id, opts) + + if err != nil { + return err + } + + team, _, _ = client.GetTeam(id) + + err = setTeamResourceData(team, d) + + return +} + +func resourceTeamDelete(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + id, err := strconv.ParseInt(d.Id(), 10, 64) + + var resp *gitea.Response + + resp, err = client.DeleteTeam(id) + + if err != nil { + if resp.StatusCode == 404 { + return + } else { + return err + } + } + + return +} + +func setTeamResourceData(team *gitea.Team, d *schema.ResourceData) (err error) { + d.SetId(fmt.Sprintf("%d", team.ID)) + d.Set(TeamCreateRepoFlag, team.CanCreateOrgRepo) + d.Set(TeamDescription, team.Description) + d.Set(TeamName, team.Name) + d.Set(TeamPermissions, string(team.Permission)) + d.Set(TeamIncludeAllReposFlag, team.IncludesAllRepositories) + d.Set(TeamUnits, d.Get(TeamUnits).(string)) + d.Set(TeamOrg, d.Get(TeamOrg).(string)) + return +} + +func resourceGiteaTeam() *schema.Resource { + return &schema.Resource{ + Read: resourceTeamRead, + Create: resourceTeamCreate, + Update: resourceTeamUpdate, + Delete: resourceTeamDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the Team", + }, + "organisation": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The organisation which this Team is part of.", + }, + "description": { + Type: schema.TypeString, + Required: false, + Optional: true, + Default: "", + Description: "Description of the Team", + }, + "permission": { + Type: schema.TypeString, + Required: false, + Optional: true, + Default: "", + Description: "Permissions associated with this Team\n" + + "Can be `none`, `read`, `write`, `admin` or `owner`", + }, + "can_create_repos": { + Type: schema.TypeBool, + Required: false, + Optional: true, + Default: true, + Description: "Flag if the Teams members should be able to create Rpositories in the Organisation", + }, + "include_all_repositories": { + Type: schema.TypeBool, + Required: false, + Optional: true, + Default: true, + Description: "Flag if the Teams members should have access to all Repositories in the Organisation", + }, + "units": { + Type: schema.TypeString, + Required: false, + Optional: true, + Default: "[repo.code, repo.issues, repo.ext_issues, repo.wiki, repo.pulls, repo.releases, repo.projects, repo.ext_wiki]", + Description: "List of types of Repositories that should be allowed to be created from Team members.\n" + + "Can be `repo.code`, `repo.issues`, `repo.ext_issues`, `repo.wiki`, `repo.pulls`, `repo.releases`, `repo.projects` and/or `repo.ext_wiki`", + }, + }, + Description: "`gitea_team` manages Team that are part of an organisation.", + } +} diff --git a/gitea/resource_gitea_user.go b/gitea/resource_gitea_user.go index 8d05e47..432b24e 100644 --- a/gitea/resource_gitea_user.go +++ b/gitea/resource_gitea_user.go @@ -196,7 +196,6 @@ func resourceUserDelete(d *schema.ResourceData, meta interface{}) (err error) { func setUserResourceData(user *gitea.User, d *schema.ResourceData) (err error) { d.SetId(fmt.Sprintf("%d", user.ID)) - d.Set("id", user.ID) d.Set(userName, user.UserName) d.Set(userEmail, user.Email) d.Set(userFullName, user.FullName) From 680e2dcba284aef77411798ef837deaec8753fff Mon Sep 17 00:00:00 2001 From: Tobias Trabelsi Date: Sun, 26 Jun 2022 00:18:20 +0200 Subject: [PATCH 2/2] #3 teams can now have members --- docs/resources/team.md | 18 ++++++++++-- examples/main.tf | 9 +++--- examples/resources/gitea_team/resource.tf | 19 ++++++++++--- gitea/resource_gitea_team.go | 34 +++++++++++++++++++++++ 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/docs/resources/team.md b/docs/resources/team.md index a16f48b..6434ca7 100644 --- a/docs/resources/team.md +++ b/docs/resources/team.md @@ -17,11 +17,22 @@ resource "gitea_org" "test_org" { name = "test-org" } +resource "gitea_user" "test" { + username = "test" + login_name = "test" + password = "Geheim1!" + email = "test@user.dev" + must_change_password = false + admin = true +} + + resource "gitea_team" "test_team" { - name = "Devs" + name = "Devs" organisation = gitea_org.test_org.name - description = "Devs of Test Org" - permission = "write" + description = "Devs of Test Org" + permission = "write" + members = [gitea_user.test.username] } ``` @@ -38,6 +49,7 @@ resource "gitea_team" "test_team" { - `can_create_repos` (Boolean) Flag if the Teams members should be able to create Rpositories in the Organisation - `description` (String) Description of the Team - `include_all_repositories` (Boolean) Flag if the Teams members should have access to all Repositories in the Organisation +- `members` (List of String) List of Users that should be part of this team - `permission` (String) Permissions associated with this Team Can be `none`, `read`, `write`, `admin` or `owner` - `units` (String) List of types of Repositories that should be allowed to be created from Team members. diff --git a/examples/main.tf b/examples/main.tf index ff9a3d5..79b3707 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -49,8 +49,9 @@ resource "gitea_public_key" "test_user_key" { resource "gitea_team" "test_team" { - name = "Devs" + name = "Devs" organisation = gitea_org.test_org.name - description = "Devs of Test Org" - permission = "write" -} \ No newline at end of file + description = "Devs of Test Org" + permission = "write" + members = [gitea_user.test.username] +} diff --git a/examples/resources/gitea_team/resource.tf b/examples/resources/gitea_team/resource.tf index 08ce5d5..7accce0 100644 --- a/examples/resources/gitea_team/resource.tf +++ b/examples/resources/gitea_team/resource.tf @@ -2,9 +2,20 @@ resource "gitea_org" "test_org" { name = "test-org" } +resource "gitea_user" "test" { + username = "test" + login_name = "test" + password = "Geheim1!" + email = "test@user.dev" + must_change_password = false + admin = true +} + + resource "gitea_team" "test_team" { - name = "Devs" + name = "Devs" organisation = gitea_org.test_org.name - description = "Devs of Test Org" - permission = "write" -} \ No newline at end of file + description = "Devs of Test Org" + permission = "write" + members = [gitea_user.test.username] +} diff --git a/gitea/resource_gitea_team.go b/gitea/resource_gitea_team.go index 2d98115..8bfed82 100644 --- a/gitea/resource_gitea_team.go +++ b/gitea/resource_gitea_team.go @@ -17,6 +17,7 @@ const ( TeamCreateRepoFlag string = "can_create_repos" TeamIncludeAllReposFlag string = "include_all_repositories" TeamUnits string = "units" + TeamMembers string = "members" ) func resourceTeamRead(d *schema.ResourceData, meta interface{}) (err error) { @@ -89,6 +90,17 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) (err error) { return } + users := d.Get(TeamMembers).([]interface{}) + + for _, user := range users { + if user != "" { + _, err = client.AddTeamMember(team.ID, user.(string)) + if err != nil { + return err + } + } + } + err = setTeamResourceData(team, d) return @@ -158,6 +170,17 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) (err error) { return err } + users := d.Get(TeamMembers).([]interface{}) + + for _, user := range users { + if user != "" { + _, err = client.AddTeamMember(team.ID, user.(string)) + if err != nil { + return err + } + } + } + team, _, _ = client.GetTeam(id) err = setTeamResourceData(team, d) @@ -194,6 +217,7 @@ func setTeamResourceData(team *gitea.Team, d *schema.ResourceData) (err error) { d.Set(TeamIncludeAllReposFlag, team.IncludesAllRepositories) d.Set(TeamUnits, d.Get(TeamUnits).(string)) d.Set(TeamOrg, d.Get(TeamOrg).(string)) + d.Set(TeamMembers, d.Get(TeamMembers)) return } @@ -256,6 +280,16 @@ func resourceGiteaTeam() *schema.Resource { Description: "List of types of Repositories that should be allowed to be created from Team members.\n" + "Can be `repo.code`, `repo.issues`, `repo.ext_issues`, `repo.wiki`, `repo.pulls`, `repo.releases`, `repo.projects` and/or `repo.ext_wiki`", }, + "members": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Required: false, + Computed: true, + Description: "List of Users that should be part of this team", + }, }, Description: "`gitea_team` manages Team that are part of an organisation.", }