13 Commits

Author SHA1 Message Date
989e7079a5 Merge pull request '#7 fail gracefully if gitea url violates RFC 2606' (#8) from feature/#7-fail-gracefully into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #8
closes #7
2022-08-04 16:56:21 +00:00
edfd4e2e06 #7 fail gracefully if gitea url violates RFC 2606
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-08-04 18:23:41 +02:00
1c8d5146fb Version in README should match released version
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-22 18:33:21 +00:00
0208cbd960 #5 fixed state handling for public keys
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2022-07-08 21:50:09 +02:00
08dffb3e3a Merge pull request '#3 added team resource and fixed crash in public key state persisting' (#4) from feature/tt/#3-team-management into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #4
2022-06-25 22:38:05 +00:00
680e2dcba2 #3 teams can now have members
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-06-26 00:35:28 +02:00
6e63797167 #3 added team resource and fixed crash in public key state persisting
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-06-25 23:36:24 +02:00
787a2b9636 added MIT license
All checks were successful
continuous-integration/drone/push Build is passing
2022-06-25 22:00:22 +02:00
39198a40d6 hopefully fixed drone signing
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2022-06-21 23:12:49 +02:00
26eb2c104a added ssh key management resource
All checks were successful
continuous-integration/drone/push Build is passing
2022-06-21 23:10:25 +02:00
041ad9e393 fixed drone gpg import
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build encountered an error
2022-06-14 23:55:08 +02:00
f9e9235726 added user resource and fixed some typos
Some checks reported errors
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build was killed
2022-06-14 23:24:42 +02:00
f8ea8a9276 re added gitea releases
All checks were successful
continuous-integration/drone/push Build is passing
2022-06-13 21:12:54 +02:00
20 changed files with 1128 additions and 10 deletions

View File

@ -41,7 +41,16 @@ steps:
environment: environment:
GITEA_TOKEN: GITEA_TOKEN:
from_secret: gitea_token from_secret: gitea_token
GPG_PRIVATE_KEY:
from_secret: GPG_PRIVATE_KEY
GPG_FINGERPRINT:
from_secret: GPG_FINGERPRINT
GPG_PRIVATE_KEY_BASE64:
from_secret: GPG_PRIVATE_KEY_BASE64
commands: commands:
- apk add gpg-agent
- gpg-agent --daemon --default-cache-ttl 7200
- echo $GPG_PRIVATE_KEY_BASE64 | base64 -d | gpg --import --batch --no-tty
- goreleaser release - goreleaser release
resources: resources:
limits: limits:

View File

@ -4,6 +4,9 @@ before:
hooks: hooks:
# this is just an example and not a requirement for provider building/publishing # this is just an example and not a requirement for provider building/publishing
- go mod tidy - go mod tidy
gitea_urls:
api: https://git.uploadfilter24.eu/api/v1/
download: https://git.uploadfilter24.eu
builds: builds:
- env: - env:
# goreleaser does not work with CGO, it could also complicate # goreleaser does not work with CGO, it could also complicate
@ -51,6 +54,9 @@ signs:
- "--detach-sign" - "--detach-sign"
- "${artifact}" - "${artifact}"
release: release:
gitea:
owner: lerentis
name: terraform-provider-gitea
extra_files: extra_files:
- glob: 'terraform-registry-manifest.json' - glob: 'terraform-registry-manifest.json'
name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2022 lerentis, https://git.uploadfilter24.eu/lerentis
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -3,7 +3,7 @@ GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
GOFMT ?= gofmt -s GOFMT ?= gofmt -s
VERSION = 0.3.0 VERSION = 0.7.0
test: fmt-check test: fmt-check
go test -i $(TEST) || exit 1 go test -i $(TEST) || exit 1
@ -37,3 +37,5 @@ install: build
@echo ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION} @echo ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION}
@mkdir -p ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64 @mkdir -p ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64
@mv terraform-provider-gitea_${VERSION} ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION} @mv terraform-provider-gitea_${VERSION} ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION}
doc:
tfplugindocs

View File

@ -17,7 +17,7 @@ terraform {
required_providers { required_providers {
gitea = { gitea = {
source = "Lerentis/gitea" source = "Lerentis/gitea"
version = "0.3.0" version = "0.7.0"
} }
} }
} }

View File

@ -0,0 +1,52 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "gitea_public_key Resource - terraform-provider-gitea"
subcategory: ""
description: |-
gitea_public_key manages ssh key that are associated with users.
---
# gitea_public_key (Resource)
`gitea_public_key` manages ssh key that are associated with users.
## Example Usage
```terraform
resource "gitea_user" "test" {
username = "test"
login_name = "test"
password = "Geheim1!"
email = "test@user.dev"
must_change_password = false
}
resource "gitea_public_key" "test_user_key" {
title = "test"
key = file("${path.module}/id_ed25519.pub")
username = gitea_user.test.username
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `key` (String, Sensitive) An armored SSH key to add
- `title` (String) Title of the key to add
- `username` (String) User to associate with the added key
### Optional
- `read_only` (Boolean) Describe if the key has only read access or read/write
### Read-Only
- `created` (String)
- `fingerprint` (String)
- `id` (String) The ID of this resource.
- `type` (String)

62
docs/resources/team.md Normal file
View File

@ -0,0 +1,62 @@
---
# 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_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"
organisation = gitea_org.test_org.name
description = "Devs of Test Org"
permission = "write"
members = [gitea_user.test.username]
}
```
<!-- schema generated by tfplugindocs -->
## 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
- `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.
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.

60
docs/resources/user.md Normal file
View File

@ -0,0 +1,60 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "gitea_user Resource - terraform-provider-gitea"
subcategory: ""
description: |-
gitea_user manages a native gitea user.
If you are using OIDC or other kinds of authentication mechanisms you can still try to managessh keys or other ressources this way
---
# gitea_user (Resource)
`gitea_user` manages a native gitea user.
If you are using OIDC or other kinds of authentication mechanisms you can still try to managessh keys or other ressources this way
## Example Usage
```terraform
resource "gitea_user" "test" {
username = "test"
login_name = "test"
password = "Geheim1!"
email = "test@user.dev"
must_change_password = false
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `email` (String) E-Mail Address of the user
- `login_name` (String) The login name can differ from the username
- `password` (String, Sensitive) Password to be set for the user
- `username` (String) Username of the user to be created
### Optional
- `active` (Boolean) Flag if this user should be active or not
- `admin` (Boolean) Flag if this user should be an administrator or not
- `allow_create_organization` (Boolean)
- `allow_git_hook` (Boolean)
- `allow_import_local` (Boolean)
- `description` (String) A description of the user
- `force_password_change` (Boolean) Flag if the user defined password should be overwritten or not
- `full_name` (String) Full name of the user
- `location` (String)
- `max_repo_creation` (Number)
- `must_change_password` (Boolean) Flag if the user should change the password after first login
- `prohibit_login` (Boolean) Flag if the user should not be allowed to log in (bot user)
- `restricted` (Boolean)
- `send_notification` (Boolean) Flag to send a notification about the user creation to the defined `email`
- `visibility` (String) Visibility of the user. Can be `public`, `limited` or `private`
### Read-Only
- `id` (String) The ID of this resource.

3
examples/.gitignore vendored
View File

@ -2,4 +2,5 @@
.terraform.lock.hcl .terraform.lock.hcl
terraform.tfstate terraform.tfstate
terraform.tfstate.backup terraform.tfstate.backup
*.tfvars *.tfvars
id_ed25519

View File

@ -23,5 +23,35 @@ resource "gitea_org" "test_org" {
resource "gitea_repository" "org_repo" { resource "gitea_repository" "org_repo" {
username = gitea_org.test_org.name username = gitea_org.test_org.name
name = "org-test-repo" name = "org-test-repo"
} }
data "gitea_user" "me" {
username = "lerentis"
}
resource "gitea_user" "test" {
username = "test"
login_name = "test"
password = "Geheim1!"
email = "test@user.dev"
must_change_password = false
admin = true
}
resource "gitea_public_key" "test_user_key" {
title = "test"
key = file("${path.module}/resources/gitea_public_key/id_ed25519.pub")
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"
members = [gitea_user.test.username]
}

13
examples/provider.tf Normal file
View File

@ -0,0 +1,13 @@
terraform {
required_providers {
gitea = {
source = "terraform.local/lerentis/gitea"
version = "0.7.0"
}
}
}
provider "gitea" {
base_url = var.gitea_url
token = var.gitea_token
}

View File

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINn6hAP48oKz6MVWjYvn0fne2YeaOv/zC6zuvFXlJKf2 test@dev.local

View File

@ -0,0 +1,14 @@
resource "gitea_user" "test" {
username = "test"
login_name = "test"
password = "Geheim1!"
email = "test@user.dev"
must_change_password = false
}
resource "gitea_public_key" "test_user_key" {
title = "test"
key = file("${path.module}/id_ed25519.pub")
username = gitea_user.test.username
}

View File

@ -0,0 +1,21 @@
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"
organisation = gitea_org.test_org.name
description = "Devs of Test Org"
permission = "write"
members = [gitea_user.test.username]
}

View File

@ -0,0 +1,7 @@
resource "gitea_user" "test" {
username = "test"
login_name = "test"
password = "Geheim1!"
email = "test@user.dev"
must_change_password = false
}

View File

@ -76,9 +76,11 @@ func Provider() terraform.ResourceProvider {
"gitea_org": resourceGiteaOrg(), "gitea_org": resourceGiteaOrg(),
// "gitea_team": resourceGiteaTeam(), // "gitea_team": resourceGiteaTeam(),
// "gitea_repo": resourceGiteaRepo(), // "gitea_repo": resourceGiteaRepo(),
// "gitea_user": resourceGiteaUser(), "gitea_user": resourceGiteaUser(),
"gitea_oauth2_app": resourceGiteaOauthApp(), "gitea_oauth2_app": resourceGiteaOauthApp(),
"gitea_repository": resourceGiteaRepository(), "gitea_repository": resourceGiteaRepository(),
"gitea_public_key": resourceGiteaPublicKey(),
"gitea_team": resourceGiteaTeam(),
}, },
ConfigureFunc: providerConfigure, ConfigureFunc: providerConfigure,
@ -116,5 +118,8 @@ func validateAPIURLVersion(value interface{}, key string) (ws []string, es []err
if strings.HasSuffix(v, "/api/v1") || strings.HasSuffix(v, "/api/v1/") { if strings.HasSuffix(v, "/api/v1") || strings.HasSuffix(v, "/api/v1/") {
es = append(es, fmt.Errorf("terraform-gitea-provider base URL format is incorrect; Please leave out API Path %s", v)) es = append(es, fmt.Errorf("terraform-gitea-provider base URL format is incorrect; Please leave out API Path %s", v))
} }
if strings.Contains(v, "localhost") && strings.Contains(v, ".") {
es = append(es, fmt.Errorf("terraform-gitea-provider base URL violates RFC 2606; Please do not define a subdomain for localhost!"))
}
return return
} }

View File

@ -17,8 +17,6 @@ const (
RepoAdminChangeTeamAccess string = "repo_admin_change_team_access" RepoAdminChangeTeamAccess string = "repo_admin_change_team_access"
) )
type VisibleType string
func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) { func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client) client := meta.(*gitea.Client)
@ -97,7 +95,7 @@ func resourceOrgUpdate(d *schema.ResourceData, meta interface{}) (err error) {
return return
} }
func respurceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) { func resourceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client) client := meta.(*gitea.Client)
var resp *gitea.Response var resp *gitea.Response
@ -133,7 +131,7 @@ func resourceGiteaOrg() *schema.Resource {
Read: resourceOrgRead, Read: resourceOrgRead,
Create: resourceOrgCreate, Create: resourceOrgCreate,
Update: resourceOrgUpdate, Update: resourceOrgUpdate,
Delete: respurceOrgDelete, Delete: resourceOrgDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough, State: schema.ImportStatePassthrough,
}, },

View File

@ -0,0 +1,155 @@
package gitea
import (
"fmt"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
const (
PublicKeyUser string = "username"
PublicKey string = "key"
PublicKeyReadOnlyFlag string = "read_only"
PublicKeyTitle string = "title"
PublicKeyId string = "id"
PublicKeyFingerprint string = "fingerprint"
PublicKeyCreated string = "created"
PublicKeyType string = "type"
)
func resourcePublicKeyRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
id, err := strconv.ParseInt(d.Id(), 10, 64)
var resp *gitea.Response
var pubKey *gitea.PublicKey
pubKey, resp, err = client.GetPublicKey(id)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
}
err = setPublicKeyResourceData(pubKey, d)
return
}
func resourcePublicKeyCreate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var pubKey *gitea.PublicKey
opts := gitea.CreateKeyOption{
Title: d.Get(PublicKeyTitle).(string),
Key: d.Get(PublicKey).(string),
ReadOnly: d.Get(PublicKeyReadOnlyFlag).(bool),
}
pubKey, _, err = client.AdminCreateUserPublicKey(d.Get(PublicKeyUser).(string), opts)
err = setPublicKeyResourceData(pubKey, d)
return
}
func resourcePublicKeyUpdate(d *schema.ResourceData, meta interface{}) (err error) {
// update = recreate
resourcePublicKeyDelete(d, meta)
resourcePublicKeyCreate(d, meta)
return
}
func resourcePublicKeyDelete(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.AdminDeleteUserPublicKey(d.Get(PublicKeyUser).(string), int(id))
if err != nil {
if resp.StatusCode == 404 {
return
} else {
return err
}
}
return
}
func setPublicKeyResourceData(pubKey *gitea.PublicKey, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d", pubKey.ID))
d.Set(PublicKeyUser, d.Get(PublicKeyUser).(string))
d.Set(PublicKey, d.Get(PublicKey).(string))
d.Set(PublicKeyTitle, pubKey.Title)
d.Set(PublicKeyReadOnlyFlag, d.Get(PublicKeyReadOnlyFlag).(bool))
d.Set(PublicKeyCreated, pubKey.Created)
d.Set(PublicKeyFingerprint, pubKey.Fingerprint)
d.Set(PublicKeyType, pubKey.KeyType)
return
}
func resourceGiteaPublicKey() *schema.Resource {
return &schema.Resource{
Read: resourcePublicKeyRead,
Create: resourcePublicKeyCreate,
Update: resourcePublicKeyUpdate,
Delete: resourcePublicKeyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"title": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Title of the key to add",
},
"key": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Sensitive: true,
Description: "An armored SSH key to add",
},
"read_only": {
Type: schema.TypeBool,
Required: false,
Optional: true,
Default: false,
Description: "Describe if the key has only read access or read/write",
},
"username": {
Type: schema.TypeString,
Required: true,
Optional: false,
ForceNew: true,
Description: "User to associate with the added key",
},
"fingerprint": {
Type: schema.TypeString,
Computed: true,
},
"created": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
},
Description: "`gitea_public_key` manages ssh key that are associated with users.",
}
}

View File

@ -0,0 +1,296 @@
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"
TeamMembers string = "members"
)
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
}
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
}
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
}
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)
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))
d.Set(TeamMembers, d.Get(TeamMembers))
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`",
},
"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.",
}
}

View File

@ -0,0 +1,364 @@
package gitea
import (
"fmt"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
const (
userName string = "username"
userLoginName string = "login_name"
userEmail string = "email"
userFullName string = "full_name"
userPassword string = "password"
userMustChangePassword string = "must_change_password"
userSendNotification string = "send_notification"
userVisibility string = "visibility"
userDescription string = "description"
userLocation string = "location"
userActive string = "active"
userAdmin string = "admin"
userAllowGitHook string = "allow_git_hook"
userAllowLocalImport string = "allow_import_local"
userMaxRepoCreation string = "max_repo_creation"
userPhorbitLogin string = "prohibit_login"
userAllowCreateOrgs string = "allow_create_organization"
userRestricted string = "restricted"
userForcePasswordChange string = "force_password_change"
)
func resourceUserRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
id, err := strconv.ParseInt(d.Id(), 10, 64)
var resp *gitea.Response
var user *gitea.User
user, resp, err = client.GetUserByID(id)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
}
err = setUserResourceData(user, d)
return
}
func resourceUserCreate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var user *gitea.User
visibility := gitea.VisibleType(d.Get(userVisibility).(string))
changePassword := d.Get(userMustChangePassword).(bool)
opts := gitea.CreateUserOption{
SourceID: 0,
LoginName: d.Get(userLoginName).(string),
Username: d.Get(userName).(string),
FullName: d.Get(userFullName).(string),
Email: d.Get(userEmail).(string),
Password: d.Get(userPassword).(string),
MustChangePassword: &changePassword,
SendNotify: d.Get(userSendNotification).(bool),
Visibility: &visibility,
}
user, _, err = client.AdminCreateUser(opts)
if err != nil {
return
}
d.SetId(fmt.Sprintf("%d", user.ID))
err = resourceUserUpdate(d, meta)
return
}
func resourceUserUpdate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
id, err := strconv.ParseInt(d.Id(), 10, 64)
var resp *gitea.Response
var user *gitea.User
user, resp, err = client.GetUserByID(id)
if err != nil {
if resp.StatusCode == 404 {
resourceUserCreate(d, meta)
} else {
return err
}
}
mail := d.Get(userEmail).(string)
fullName := d.Get(userFullName).(string)
description := d.Get(userDescription).(string)
changePassword := d.Get(userMustChangePassword).(bool)
location := d.Get(userLocation).(string)
active := d.Get(userActive).(bool)
admin := d.Get(userAdmin).(bool)
allowHook := d.Get(userAllowGitHook).(bool)
allowImport := d.Get(userAllowLocalImport).(bool)
maxRepoCreation := d.Get(userMaxRepoCreation).(int)
accessDenied := d.Get(userPhorbitLogin).(bool)
allowOrgs := d.Get(userAllowCreateOrgs).(bool)
restricted := d.Get(userRestricted).(bool)
visibility := gitea.VisibleType(d.Get(userVisibility).(string))
if d.Get(userForcePasswordChange).(bool) {
opts := gitea.EditUserOption{
SourceID: 0,
LoginName: d.Get(userLoginName).(string),
Email: &mail,
FullName: &fullName,
Password: d.Get(userPassword).(string),
Description: &description,
MustChangePassword: &changePassword,
Location: &location,
Active: &active,
Admin: &admin,
AllowGitHook: &allowHook,
AllowImportLocal: &allowImport,
MaxRepoCreation: &maxRepoCreation,
ProhibitLogin: &accessDenied,
AllowCreateOrganization: &allowOrgs,
Restricted: &restricted,
Visibility: &visibility,
}
_, err = client.AdminEditUser(d.Get(userName).(string), opts)
if err != nil {
return err
}
} else {
opts := gitea.EditUserOption{
SourceID: 0,
LoginName: d.Get(userLoginName).(string),
Email: &mail,
FullName: &fullName,
Description: &description,
MustChangePassword: &changePassword,
Location: &location,
Active: &active,
Admin: &admin,
AllowGitHook: &allowHook,
AllowImportLocal: &allowImport,
MaxRepoCreation: &maxRepoCreation,
ProhibitLogin: &accessDenied,
AllowCreateOrganization: &allowOrgs,
Restricted: &restricted,
Visibility: &visibility,
}
_, err = client.AdminEditUser(d.Get(userName).(string), opts)
if err != nil {
return err
}
}
user, _, err = client.GetUserByID(id)
err = setUserResourceData(user, d)
return
}
func resourceUserDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var resp *gitea.Response
resp, err = client.AdminDeleteUser(d.Get(userName).(string))
if err != nil {
if resp.StatusCode == 404 {
return
} else {
return err
}
}
return
}
func setUserResourceData(user *gitea.User, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d", user.ID))
d.Set(userName, user.UserName)
d.Set(userEmail, user.Email)
d.Set(userFullName, user.FullName)
d.Set(userAdmin, user.IsAdmin)
d.Set("created", user.Created)
d.Set("avatar_url", user.AvatarURL)
d.Set("last_login", user.LastLogin)
d.Set("language", user.Language)
d.Set(userLoginName, d.Get(userLoginName).(string))
d.Set(userMustChangePassword, d.Get(userMustChangePassword).(bool))
d.Set(userSendNotification, d.Get(userSendNotification).(bool))
d.Set(userVisibility, d.Get(userVisibility).(string))
d.Set(userDescription, d.Get(userDescription).(string))
d.Set(userLocation, d.Get(userLocation).(string))
d.Set(userActive, d.Get(userActive).(bool))
d.Set(userAllowGitHook, d.Get(userAllowGitHook).(bool))
d.Set(userAllowLocalImport, d.Get(userAllowLocalImport).(bool))
d.Set(userMaxRepoCreation, d.Get(userMaxRepoCreation).(int))
d.Set(userPhorbitLogin, d.Get(userPhorbitLogin).(bool))
d.Set(userAllowCreateOrgs, d.Get(userAllowCreateOrgs).(bool))
d.Set(userRestricted, d.Get(userRestricted).(bool))
d.Set(userForcePasswordChange, d.Get(userForcePasswordChange).(bool))
return
}
func resourceGiteaUser() *schema.Resource {
return &schema.Resource{
Read: resourceUserRead,
Create: resourceUserCreate,
Update: resourceUserUpdate,
Delete: resourceUserDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"username": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Username of the user to be created",
},
"login_name": {
Type: schema.TypeString,
Optional: false,
Required: true,
Description: "The login name can differ from the username",
},
"email": {
Type: schema.TypeString,
Optional: false,
Required: true,
Description: "E-Mail Address of the user",
},
"full_name": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Required: false,
Description: "Full name of the user",
},
"password": {
Type: schema.TypeString,
Optional: false,
Required: true,
Sensitive: true,
Description: "Password to be set for the user",
},
"must_change_password": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
Description: "Flag if the user should change the password after first login",
},
"send_notification": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
Description: "Flag to send a notification about the user creation to the defined `email`",
},
"visibility": {
Type: schema.TypeString,
Optional: true,
Required: false,
Default: "public",
Description: "Visibility of the user. Can be `public`, `limited` or `private`",
},
"description": {
Type: schema.TypeString,
Optional: true,
Required: false,
Default: "",
Description: "A description of the user",
},
"location": {
Type: schema.TypeString,
Optional: true,
Required: false,
Default: "",
},
"active": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
Description: "Flag if this user should be active or not",
},
"admin": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: false,
Description: "Flag if this user should be an administrator or not",
},
"allow_git_hook": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
},
"allow_import_local": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
},
"max_repo_creation": {
Type: schema.TypeInt,
Optional: true,
Required: false,
Default: -1,
},
"prohibit_login": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: false,
Description: "Flag if the user should not be allowed to log in (bot user)",
},
"allow_create_organization": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: true,
},
"restricted": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: false,
},
"force_password_change": {
Type: schema.TypeBool,
Optional: true,
Required: false,
Default: false,
Description: "Flag if the user defined password should be overwritten or not",
},
},
Description: "`gitea_user` manages a native gitea user.\n\n" +
"If you are using OIDC or other kinds of authentication mechanisms you can still try to manage" +
"ssh keys or other ressources this way",
}
}