lerentis's changes (#12)

Changes from lerentis's fork.

Co-authored-by: Tobias Trabelsi <lerentis@uploadfilter24.eu>
Reviewed-on: https://gitea.com/gitea/terraform-provider-gitea/pulls/12
This commit is contained in:
techknowlogick
2023-09-06 01:44:01 +00:00
parent 107e741625
commit cc8760c9fd
48 changed files with 1884 additions and 414 deletions

View File

@ -6,9 +6,10 @@ import (
"fmt"
"io/ioutil"
"net/http"
"time"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/logging"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
)
// Config is per-provider, specifies where to connect to gitea
@ -28,8 +29,7 @@ func (c *Config) Client() (interface{}, error) {
return nil, fmt.Errorf("either a token or a username needs to be used")
}
// Configure TLS/SSL
tlsConfig := &tls.Config{}
var tlsConfig tls.Config
// If a CACertFile has been specified, use that for cert validation
if c.CACertFile != "" {
caCert, err := ioutil.ReadFile(c.CACertFile)
@ -43,13 +43,12 @@ func (c *Config) Client() (interface{}, error) {
}
// If configured as insecure, turn off SSL verification
if c.Insecure {
tlsConfig.InsecureSkipVerify = true
}
tlsConfig.InsecureSkipVerify = c.Insecure
t := http.DefaultTransport.(*http.Transport).Clone()
t.TLSClientConfig = tlsConfig
t.TLSClientConfig = &tlsConfig
t.MaxIdleConnsPerHost = 100
t.TLSHandshakeTimeout = 10 * time.Second
httpClient := &http.Client{
Transport: logging.NewTransport("Gitea", t),
@ -60,16 +59,23 @@ func (c *Config) Client() (interface{}, error) {
}
var client *gitea.Client
var err error
if c.Token != "" {
client, _ = gitea.NewClient(c.BaseURL, gitea.SetToken(c.Token), gitea.SetHTTPClient(httpClient))
client, err = gitea.NewClient(c.BaseURL, gitea.SetToken(c.Token), gitea.SetHTTPClient(httpClient))
if err != nil {
return nil, err
}
}
if c.Username != "" {
client, _ = gitea.NewClient(c.BaseURL, gitea.SetBasicAuth(c.Username, c.Password), gitea.SetHTTPClient(httpClient))
client, err = gitea.NewClient(c.BaseURL, gitea.SetBasicAuth(c.Username, c.Password), gitea.SetHTTPClient(httpClient))
if err != nil {
return nil, err
}
}
// Test the credentials by checking we can get information about the authenticated user.
_, _, err := client.GetMyUserInfo()
_, _, err = client.GetMyUserInfo()
return client, err
}

View File

@ -6,7 +6,7 @@ import (
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func dataSourceGiteaOrg() *schema.Resource {

View File

@ -5,7 +5,7 @@ import (
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func dataSourceGiteaRepo() *schema.Resource {

View File

@ -6,7 +6,7 @@ import (
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func dataSourceGiteaUser() *schema.Resource {

View File

@ -4,8 +4,8 @@ import (
"fmt"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccDataSourceGiteaUser_basic(t *testing.T) {

View File

@ -4,12 +4,11 @@ import (
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
func Provider() *schema.Provider {
// The actual provider
return &schema.Provider{
@ -74,13 +73,17 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{
"gitea_org": resourceGiteaOrg(),
// "gitea_team": resourceGiteaTeam(),
// "gitea_repo": resourceGiteaRepo(),
"gitea_user": resourceGiteaUser(),
"gitea_oauth2_app": resourceGiteaOauthApp(),
"gitea_repository": resourceGiteaRepository(),
"gitea_public_key": resourceGiteaPublicKey(),
"gitea_team": resourceGiteaTeam(),
// "gitea_team": resourceGiteaTeam(),
// "gitea_repo": resourceGiteaRepo(),
"gitea_user": resourceGiteaUser(),
"gitea_oauth2_app": resourceGiteaOauthApp(),
"gitea_repository": resourceGiteaRepository(),
"gitea_fork": resourceGiteaFork(),
"gitea_public_key": resourceGiteaPublicKey(),
"gitea_team": resourceGiteaTeam(),
"gitea_git_hook": resourceGiteaGitHook(),
"gitea_token": resourceGiteaToken(),
"gitea_repository_key": resourceGiteaRepositoryKey(),
},
ConfigureFunc: providerConfigure,
@ -118,5 +121,8 @@ func validateAPIURLVersion(value interface{}, key string) (ws []string, es []err
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))
}
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
}

View File

@ -4,30 +4,28 @@ import (
"os"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
var testAccProviders map[string]terraform.ResourceProvider
var testAccProviders map[string]*schema.Provider
var testAccProvider *schema.Provider
func init() {
testAccProvider = Provider().(*schema.Provider)
testAccProviders = map[string]terraform.ResourceProvider{
testAccProvider = Provider()
testAccProviders = map[string]*schema.Provider{
"gitea": testAccProvider,
}
}
func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
if err := Provider().InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvider_impl(t *testing.T) {
var _ terraform.ResourceProvider = Provider()
var _ *schema.Provider = Provider()
}
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("GITEA_TOKEN"); v == "" {
t.Fatal("GITEA_TOKEN must be set for acceptance tests")

View File

@ -0,0 +1,127 @@
package gitea
import (
"fmt"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
forkOwner string = "owner"
forkRepo string = "repo"
forkOrganization string = "organization"
)
func resourceForkCreate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var opts gitea.CreateForkOption
var org string
org = d.Get(forkOrganization).(string)
if org != "" {
opts.Organization = &org
}
repo, _, err := client.CreateFork(d.Get(forkOwner).(string),
d.Get(forkRepo).(string),
opts)
if err == nil {
err = setForkResourceData(repo, d)
}
return err
}
func resourceForkRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
id, err := strconv.ParseInt(d.Id(), 10, 64)
var resp *gitea.Response
if err != nil {
return err
}
repo, resp, err := client.GetRepoByID(id)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
}
err = setForkResourceData(repo, d)
return
}
func resourceForkDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
id, err := strconv.ParseInt(d.Id(), 10, 64)
if err != nil {
return err
}
repo, _, err := client.GetRepoByID(id)
var resp *gitea.Response
resp, err = client.DeleteRepo(repo.Owner.UserName, repo.Name)
if err != nil {
if resp.StatusCode == 404 {
return
} else {
return err
}
}
return
}
func setForkResourceData(repo *gitea.Repository, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d", repo.ID))
return
}
func resourceGiteaFork() *schema.Resource {
return &schema.Resource{
Read: resourceForkRead,
Create: resourceForkCreate,
Delete: resourceForkDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"owner": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The owner or owning organization of the repository to fork",
},
"repo": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The name of the repository to fork",
},
"organization": {
Type: schema.TypeString,
Required: false,
Optional: true,
ForceNew: true,
Description: "The organization that owns the forked repo",
},
},
Description: "`gitea_fork` manages repository fork to the current user or an organisation\n" +
"Forking a repository to a dedicated user is currently unsupported\n" +
"Creating a fork using this resource without an organisation will create the fork in the executors name",
}
}

View File

@ -0,0 +1,120 @@
package gitea
import (
"fmt"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
GitHookUser string = "user"
GitHookRepo string = "repo"
GitHookName string = "name"
GitHookContent string = "content"
)
func resourceGitHookRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
user := d.Get(GitHookUser).(string)
repo := d.Get(GitHookRepo).(string)
name := d.Get(GitHookName).(string)
gitHook, _, err := client.GetRepoGitHook(user, repo, name)
if err != nil {
return err
}
err = setGitHookResourceData(user, repo, gitHook, d)
return
}
func resourceGitHookUpdate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
user := d.Get(GitHookUser).(string)
repo := d.Get(GitHookRepo).(string)
name := d.Get(GitHookName).(string)
opts := gitea.EditGitHookOption{
Content: d.Get(GitHookContent).(string),
}
_, err = client.EditRepoGitHook(user, repo, name, opts)
if err != nil {
return err
}
// Get gitHook ourselves, EditRepoGitHook does not return it
gitHook, _, err := client.GetRepoGitHook(user, repo, name)
if err != nil {
return err
}
err = setGitHookResourceData(user, repo, gitHook, d)
return
}
func resourceGitHookDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
user := d.Get(GitHookUser).(string)
repo := d.Get(GitHookRepo).(string)
name := d.Get(GitHookName).(string)
_, err = client.DeleteRepoGitHook(user, repo, name)
return
}
func setGitHookResourceData(user string, repo string, gitHook *gitea.GitHook, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%s/%s/%s", user, repo, gitHook.Name))
d.Set(GitHookUser, user)
d.Set(GitHookRepo, repo)
d.Set(GitHookName, gitHook.Name)
d.Set(GitHookContent, gitHook.Content)
return
}
func resourceGiteaGitHook() *schema.Resource {
return &schema.Resource{
Read: resourceGitHookRead,
Create: resourceGitHookUpdate, // All hooks already exist, just empty and disabled
Update: resourceGitHookUpdate,
Delete: resourceGitHookDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Name of the git hook to configure",
},
"repo": {
Type: schema.TypeString,
Required: true,
Description: "The repository that this hook belongs too.",
},
"user": {
Type: schema.TypeString,
Required: true,
Description: "The user (or organisation) owning the repo this hook belongs too",
},
"content": {
Type: schema.TypeString,
Required: true,
Description: "Content of the git hook",
},
},
Description: "`gitea_git_hook` manages git hooks on a repository.\n" +
"import is currently not supported\n\n" +
"WARNING: using this resource requires to enable server side hooks" +
"which are known to cause [security issues](https://github.com/go-gitea/gitea/pull/13058)!\n\n" +
"if you want to procede, you need to enable server side hooks as stated" +
" [here](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security)",
}
}

View File

@ -4,14 +4,15 @@ import (
"fmt"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
oauth2KeyName string = "name"
oauth2KeyRedirectURIs string = "redirect_uris"
oauth2KeyClientId string = "client_id"
oauth2KeyClientSecret string = "client_secret"
oauth2KeyName string = "name"
oauth2KeyConfidentialClient string = "confidential_client"
oauth2KeyRedirectURIs string = "redirect_uris"
oauth2KeyClientId string = "client_id"
oauth2KeyClientSecret string = "client_secret"
)
func resourceGiteaOauthApp() *schema.Resource {
@ -37,6 +38,12 @@ func resourceGiteaOauthApp() *schema.Resource {
},
Description: "Accepted redirect URIs",
},
oauth2KeyConfidentialClient: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If set to false, it will be a public client (PKCE will be required)",
},
oauth2KeyClientId: {
Type: schema.TypeString,
Computed: true,
@ -89,9 +96,16 @@ func resourceOauth2AppUpcreate(d *schema.ResourceData, meta interface{}) (err er
return fmt.Errorf("attribute %s must be set and must be a string", oauth2KeyName)
}
confidentialClient, confidentialClientOk := d.Get(oauth2KeyConfidentialClient).(bool)
if !confidentialClientOk {
return fmt.Errorf("attribute %s must be set and must be a bool", oauth2KeyConfidentialClient)
}
opts := gitea.CreateOauth2Option{
Name: name,
RedirectURIs: redirectURIs,
Name: name,
ConfidentialClient: confidentialClient,
RedirectURIs: redirectURIs,
}
var oauth2 *gitea.Oauth2
@ -99,7 +113,7 @@ func resourceOauth2AppUpcreate(d *schema.ResourceData, meta interface{}) (err er
if d.IsNewResource() {
oauth2, _, err = client.CreateOauth2(opts)
} else {
oauth2, err := searchOauth2AppByClientId(client, d.Id())
oauth2, err = searchOauth2AppByClientId(client, d.Id())
if err != nil {
return err
@ -176,9 +190,10 @@ func setOAuth2ResourceData(app *gitea.Oauth2, d *schema.ResourceData) (err error
d.SetId(app.ClientID)
for k, v := range map[string]interface{}{
oauth2KeyName: app.Name,
oauth2KeyRedirectURIs: schema.NewSet(schema.HashString, CollapseStringList(app.RedirectURIs)),
oauth2KeyClientId: app.ClientID,
oauth2KeyName: app.Name,
oauth2KeyConfidentialClient: app.ConfidentialClient,
oauth2KeyRedirectURIs: schema.NewSet(schema.HashString, CollapseStringList(app.RedirectURIs)),
oauth2KeyClientId: app.ClientID,
} {
err = d.Set(k, v)
if err != nil {

View File

@ -2,9 +2,10 @@ package gitea
import (
"fmt"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
@ -15,26 +16,81 @@ const (
orgLocation string = "location"
orgVisibility string = "visibility"
RepoAdminChangeTeamAccess string = "repo_admin_change_team_access"
orgRepos string = "org_repos"
)
// might come in handy if we want to stick to numeric IDs
func searchOrgByClientId(c *gitea.Client, id int64) (res *gitea.Organization, err error) {
page := 1
for {
orgs, _, err := c.AdminListOrgs(gitea.AdminListOrgsOptions{
ListOptions: gitea.ListOptions{
Page: page,
PageSize: 50,
},
})
if err != nil {
return nil, err
}
if len(orgs) == 0 {
return nil, fmt.Errorf("Organisation with ID %d could not be found", id)
}
for _, org := range orgs {
if org.ID == id {
return org, nil
}
}
page += 1
}
}
func getAllOrgRepos(c *gitea.Client, orgName string) (repos []string, err error) {
page := 1
for {
repoBuffer, _, err := c.ListOrgRepos(orgName, gitea.ListOrgReposOptions{
ListOptions: gitea.ListOptions{
Page: page,
PageSize: 50,
},
})
if err != nil {
return nil, err
}
if len(repoBuffer) == 0 {
return repos, nil
}
for _, repo := range repoBuffer {
repos = append(repos, repo.Name)
}
page += 1
}
}
func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var org *gitea.Organization
var resp *gitea.Response
org, resp, err = client.GetOrg(d.Get(orgName).(string))
id, err := strconv.ParseInt(d.Id(), 10, 64)
org, err = searchOrgByClientId(client, id)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
d.SetId("")
return nil
}
err = setOrgResourceData(org, d)
repos, _ := getAllOrgRepos(client, org.UserName)
err = setOrgResourceData(org, d, &repos)
return
}
@ -57,7 +113,8 @@ func resourceOrgCreate(d *schema.ResourceData, meta interface{}) (err error) {
return
}
err = setOrgResourceData(org, d)
repos, _ := getAllOrgRepos(client, org.UserName)
err = setOrgResourceData(org, d, &repos)
return
}
@ -90,7 +147,8 @@ func resourceOrgUpdate(d *schema.ResourceData, meta interface{}) (err error) {
org, resp, err = client.GetOrg(d.Get(orgName).(string))
err = setOrgResourceData(org, d)
repos, _ := getAllOrgRepos(client, org.UserName)
err = setOrgResourceData(org, d, &repos)
return
}
@ -113,7 +171,7 @@ func resourceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) {
return
}
func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData) (err error) {
func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData, repos *[]string) (err error) {
d.SetId(fmt.Sprintf("%d", org.ID))
d.Set("name", org.UserName)
d.Set("full_name", org.FullName)
@ -122,6 +180,7 @@ func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData) (err er
d.Set("website", org.Website)
d.Set("location", org.Location)
d.Set("visibility", org.Visibility)
d.Set("repos", repos)
return
}
@ -133,7 +192,7 @@ func resourceGiteaOrg() *schema.Resource {
Update: resourceOrgUpdate,
Delete: resourceOrgDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"name": {
@ -183,6 +242,13 @@ func resourceGiteaOrg() *schema.Resource {
Default: "public",
Description: "Flag is this organisation should be publicly visible or not.",
},
"repos": {
Type: schema.TypeList,
Required: false,
Computed: true,
Description: "List of all Repositories that are part of this organisation",
Elem: &schema.Schema{Type: schema.TypeString},
},
},
Description: "`gitea_org` manages a gitea organisation.\n\n" +
"Organisations are a way to group repositories and abstract permission management in a gitea instance.",

View File

@ -5,7 +5,7 @@ import (
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (

View File

@ -1,11 +1,15 @@
package gitea
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
@ -34,7 +38,8 @@ const (
repoAllowManualMerge string = "allow_manual_merge"
repoAutodetectManualMerge string = "autodetect_manual_merge"
repoMirror string = "mirror"
migrationCloneAddress string = "migration_clone_addresse"
migrationCloneAddresse string = "migration_clone_addresse"
migrationCloneAddress string = "migration_clone_address"
migrationService string = "migration_service"
migrationServiceAuthName string = "migration_service_auth_username"
migrationServiceAuthPassword string = "migration_service_auth_password"
@ -47,6 +52,34 @@ const (
migrationLFSEndpoint string = "migration_lfs_endpoint"
)
func searchUserByName(c *gitea.Client, name string) (res *gitea.User, err error) {
page := 1
for {
users, _, err := c.AdminListUsers(gitea.AdminListUsersOptions{
ListOptions: gitea.ListOptions{
Page: page,
PageSize: 50,
},
})
if err != nil {
return nil, err
}
if len(users) == 0 {
return nil, fmt.Errorf("User with name %s could not be found", name)
}
for _, user := range users {
if user.UserName == name {
return user, nil
}
}
page += 1
}
}
func resourceRepoRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
@ -78,21 +111,39 @@ func resourceRepoCreate(d *schema.ResourceData, meta interface{}) (err error) {
var repo *gitea.Repository
var resp *gitea.Response
var orgRepo bool
var orgRepo, hasAdmin bool
_, resp, err = client.GetOrg(d.Get(repoOwner).(string))
if resp.StatusCode == 404 {
_, err := searchUserByName(client, d.Get(repoOwner).(string))
if err != nil {
if strings.Contains(err.Error(), "could not be found") {
return errors.New(fmt.Sprintf("Creation of repository cound not proceed as owner %s is not present in gitea", d.Get(repoOwner).(string)))
}
tflog.Warn(context.Background(), "Error query for users. Assuming missing permissions and proceding with user permissions")
hasAdmin = false
} else {
hasAdmin = true
}
orgRepo = false
} else {
orgRepo = true
}
if (d.Get(repoMirror)).(bool) {
var cloneAddr string
if d.Get(migrationCloneAddresse).(string) != "" {
cloneAddr = d.Get(migrationCloneAddresse).(string)
} else {
cloneAddr = d.Get(migrationCloneAddress).(string)
}
if cloneAddr != "" {
opts := gitea.MigrateRepoOption{
RepoName: d.Get(repoName).(string),
RepoOwner: d.Get(repoOwner).(string),
CloneAddr: d.Get(migrationCloneAddress).(string),
CloneAddr: cloneAddr,
Service: gitea.GitServiceType(d.Get(migrationService).(string)),
Mirror: d.Get(repoMirror).(bool),
Private: d.Get(repoPrivateFlag).(bool),
@ -138,12 +189,16 @@ func resourceRepoCreate(d *schema.ResourceData, meta interface{}) (err error) {
if orgRepo {
repo, _, err = client.CreateOrgRepo(d.Get(repoOwner).(string), opts)
} else {
repo, _, err = client.CreateRepo(opts)
if hasAdmin {
repo, _, err = client.AdminCreateRepo(d.Get(repoOwner).(string), opts)
} else {
repo, _, err = client.CreateRepo(opts)
}
}
}
if err != nil {
return
return err
}
err = setRepoResourceData(repo, d)
@ -223,6 +278,7 @@ func respurceRepoDelete(d *schema.ResourceData, meta interface{}) (err error) {
func setRepoResourceData(repo *gitea.Repository, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d", repo.ID))
d.Set("username", repo.Owner.UserName)
d.Set("name", repo.Name)
d.Set("description", repo.Description)
d.Set("full_name", repo.FullName)
@ -239,8 +295,8 @@ func setRepoResourceData(repo *gitea.Repository, d *schema.ResourceData) (err er
d.Set("watchers", repo.Watchers)
d.Set("open_issue_count", repo.OpenIssues)
d.Set("default_branch", repo.DefaultBranch)
d.Set("created", repo.Created)
d.Set("updated", repo.Updated)
d.Set("created", repo.Created.String())
d.Set("updated", repo.Updated.String())
d.Set("permission_admin", repo.Permissions.Admin)
d.Set("permission_push", repo.Permissions.Push)
d.Set("permission_pull", repo.Permissions.Pull)
@ -255,7 +311,7 @@ func resourceGiteaRepository() *schema.Resource {
Update: resourceRepoUpdate,
Delete: respurceRepoDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"username": {
@ -445,6 +501,13 @@ func resourceGiteaRepository() *schema.Resource {
Default: false,
},
"migration_clone_addresse": {
Type: schema.TypeString,
Required: false,
Optional: true,
ForceNew: true,
Description: "DEPRECATED in favor of `migration_clone_address`",
},
"migration_clone_address": {
Type: schema.TypeString,
Required: false,
Optional: true,
@ -513,6 +576,18 @@ func resourceGiteaRepository() *schema.Resource {
Optional: true,
Default: "",
},
"clone_url": {
Type: schema.TypeString,
Computed: true,
},
"html_url": {
Type: schema.TypeString,
Computed: true,
},
"ssh_url": {
Type: schema.TypeString,
Computed: true,
},
},
Description: "`gitea_repository` manages a gitea repository.\n\n" +
"Per default this repository will be initializiled with the provided configuration (gitignore, License etc.).\n" +

View File

@ -0,0 +1,169 @@
package gitea
import (
"fmt"
"strconv"
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
deployKeyRepoId string = "repository"
deployKeyName string = "title"
deployKeyKey string = "key"
deployKeyReadOnly string = "read_only"
)
func resourceRepoKeyIdParts(d *schema.ResourceData) (bool, int64, int64, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
return false, 0, 0, nil
}
repoId, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
return false, 0, 0, err
}
keyId, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil {
return false, 0, 0, err
}
return true, repoId, keyId, err
}
func resourceRepoKeyRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
hasId, repoId, keyId, err := resourceRepoKeyIdParts(d)
if err != nil {
return err
}
if !hasId {
d.SetId("")
return nil
}
repo, resp, err := client.GetRepoByID(repoId)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
}
key, resp, err := client.GetDeployKey(repo.Owner.UserName, repo.Name, keyId)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
} else {
return err
}
}
err = setRepoKeyResourceData(key, repoId, d)
return
}
func resourceRepoKeyCreate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
repo, _, err := client.GetRepoByID(int64(d.Get(deployKeyRepoId).(int)))
if err != nil {
return err
}
dk, _, err := client.CreateDeployKey(repo.Owner.UserName, repo.Name, gitea.CreateKeyOption{
Title: d.Get(deployKeyName).(string),
ReadOnly: d.Get(deployKeyReadOnly).(bool),
Key: d.Get(deployKeyKey).(string),
})
if err != nil {
return err
}
setRepoKeyResourceData(dk, repo.ID, d)
return nil
}
func respurceRepoKeyDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
hasId, repoId, keyId, err := resourceRepoKeyIdParts(d)
if err != nil {
return err
}
if !hasId {
d.SetId("")
return nil
}
repo, resp, err := client.GetRepoByID(repoId)
if err != nil {
if resp.StatusCode == 404 {
d.SetId("")
return nil
}
return err
}
client.DeleteDeployKey(repo.Owner.UserName, repo.Name, keyId)
return nil
}
func setRepoKeyResourceData(dk *gitea.DeployKey, repoId int64, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d/%d", repoId, dk.ID))
d.Set(deployKeyRepoId, repoId)
d.Set(deployKeyReadOnly, dk.ReadOnly)
d.Set(deployKeyKey, dk.Key)
d.Set(deployKeyName, dk.Title)
return
}
func resourceGiteaRepositoryKey() *schema.Resource {
return &schema.Resource{
Read: resourceRepoKeyRead,
Create: resourceRepoKeyCreate,
Delete: respurceRepoKeyDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
deployKeyRepoId: {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
Description: "The ID of the repository where the deploy key belongs to",
},
deployKeyKey: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Armored SSH key to add",
},
deployKeyReadOnly: {
Type: schema.TypeBool,
Required: false,
Optional: true,
Default: true,
ForceNew: true,
Description: "Whether this key has read or read/write access",
},
deployKeyName: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the deploy key",
},
},
Description: "`gitea_repository_key` manages a deploy key for a single gitea_repository.\n\n" +
"Every key needs a unique name and unique key, i.e. no key can be added twice to the same repo",
}
}

View File

@ -1,12 +1,13 @@
package gitea
import (
"errors"
"fmt"
"strconv"
"strings"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
@ -18,6 +19,7 @@ const (
TeamIncludeAllReposFlag string = "include_all_repositories"
TeamUnits string = "units"
TeamMembers string = "members"
TeamRepositories string = "repositories"
)
func resourceTeamRead(d *schema.ResourceData, meta interface{}) (err error) {
@ -39,7 +41,7 @@ func resourceTeamRead(d *schema.ResourceData, meta interface{}) (err error) {
}
}
err = setTeamResourceData(team, d)
err = setTeamResourceData(team, d, meta)
return
}
@ -75,12 +77,14 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) (err error) {
units = append(units, gitea.RepoUnitProjects)
}
includeAllRepos := d.Get(TeamIncludeAllReposFlag).(bool)
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),
IncludesAllRepositories: includeAllRepos,
Units: units,
}
@ -101,7 +105,14 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) (err error) {
}
}
err = setTeamResourceData(team, d)
if !includeAllRepos {
err = setTeamRepositories(team, d, meta, false)
if err != nil {
return err
}
}
err = setTeamResourceData(team, d, meta)
return
}
@ -181,9 +192,16 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) (err error) {
}
}
if !includeAllRepos {
err = setTeamRepositories(team, d, meta, true)
if err != nil {
return err
}
}
team, _, _ = client.GetTeam(id)
err = setTeamResourceData(team, d)
err = setTeamResourceData(team, d, meta)
return
}
@ -208,7 +226,13 @@ func resourceTeamDelete(d *schema.ResourceData, meta interface{}) (err error) {
return
}
func setTeamResourceData(team *gitea.Team, d *schema.ResourceData) (err error) {
func setTeamResourceData(team *gitea.Team, d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
if err := client.CheckServerVersionConstraint(">= 1.19.4"); err != nil {
d.Set(TeamOrg, d.Get(TeamOrg).(string))
} else {
d.Set(TeamOrg, team.Organization.UserName)
}
d.SetId(fmt.Sprintf("%d", team.ID))
d.Set(TeamCreateRepoFlag, team.CanCreateOrgRepo)
d.Set(TeamDescription, team.Description)
@ -216,8 +240,8 @@ func setTeamResourceData(team *gitea.Team, d *schema.ResourceData) (err error) {
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))
d.Set(TeamRepositories, d.Get(TeamRepositories))
return
}
@ -228,7 +252,7 @@ func resourceGiteaTeam() *schema.Resource {
Update: resourceTeamUpdate,
Delete: resourceTeamDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"name": {
@ -290,7 +314,75 @@ func resourceGiteaTeam() *schema.Resource {
Computed: true,
Description: "List of Users that should be part of this team",
},
"repositories": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
Required: false,
Computed: true,
Description: "List of Repositories that should be part of this team",
},
},
Description: "`gitea_team` manages Team that are part of an organisation.",
}
}
func setTeamRepositories(team *gitea.Team, d *schema.ResourceData, meta interface{}, update bool) (err error) {
client := meta.(*gitea.Client)
org := d.Get(TeamOrg).(string)
repositories := make(map[string]bool)
for _, repo := range d.Get(TeamRepositories).([]interface{}) {
if repo != "" {
repositories[repo.(string)] = true
}
}
if update {
page := 1
for {
var existingRepositories []*gitea.Repository
existingRepositories, _, err = client.ListTeamRepositories(team.ID, gitea.ListTeamRepositoriesOptions{
ListOptions: gitea.ListOptions{
Page: page,
PageSize: 50,
},
})
if err != nil {
return errors.New(fmt.Sprintf("[ERROR] Error listeng team repositories: %s", err))
}
if len(existingRepositories) == 0 {
break
}
for _, exr := range existingRepositories {
_, exists := repositories[exr.Name]
if exists {
repositories[exr.Name] = false
} else {
_, err = client.RemoveTeamRepository(team.ID, org, exr.Name)
if err != nil {
return errors.New(fmt.Sprintf("[ERROR] Error removing team repository %q: %s", exr.Name, err))
}
}
}
page += 1
}
}
for repo, flag := range repositories {
if flag {
_, err = client.AddTeamRepository(team.ID, org, repo)
if err != nil {
return errors.New(fmt.Sprintf("[ERROR] Error adding team repository %q: %s", repo, err))
}
}
}
return
}

View File

@ -0,0 +1,151 @@
package gitea
import (
"fmt"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
TokenUsername string = "username"
TokenName string = "name"
TokenHash string = "token"
TokenLastEight string = "last_eight"
)
func searchTokenById(c *gitea.Client, id int64) (res *gitea.AccessToken, err error) {
page := 1
for {
tokens, _, err := c.ListAccessTokens(gitea.ListAccessTokensOptions{
ListOptions: gitea.ListOptions{
Page: page,
PageSize: 50,
},
})
if err != nil {
return nil, err
}
if len(tokens) == 0 {
return nil, fmt.Errorf("Token with ID %d could not be found", id)
}
for _, token := range tokens {
if token.ID == id {
return token, nil
}
}
page += 1
}
}
func resourceTokenCreate(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var opt gitea.CreateAccessTokenOption
opt.Name = d.Get(TokenName).(string)
token, _, err := client.CreateAccessToken(opt)
if err != nil {
return err
}
err = setTokenResourceData(token, d)
return
}
func resourceTokenRead(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var token *gitea.AccessToken
id, err := strconv.ParseInt(d.Id(), 10, 64)
token, err = searchTokenById(client, id)
if err != nil {
return err
}
err = setTokenResourceData(token, d)
return
}
func resourceTokenDelete(d *schema.ResourceData, meta interface{}) (err error) {
client := meta.(*gitea.Client)
var resp *gitea.Response
resp, err = client.DeleteAccessToken(d.Get(TokenName).(string))
if err != nil {
if resp.StatusCode == 404 {
return
} else {
return err
}
}
return
}
func setTokenResourceData(token *gitea.AccessToken, d *schema.ResourceData) (err error) {
d.SetId(fmt.Sprintf("%d", token.ID))
d.Set(TokenName, token.Name)
if token.Token != "" {
d.Set(TokenHash, token.Token)
}
d.Set(TokenLastEight, token.TokenLastEight)
return
}
func resourceGiteaToken() *schema.Resource {
return &schema.Resource{
Read: resourceTokenRead,
Create: resourceTokenCreate,
Delete: resourceTokenDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"username": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The owner of the Access Token",
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The name of the Access Token",
},
"token": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
Description: "The actual Access Token",
},
"last_eight": {
Type: schema.TypeString,
Computed: true,
},
},
Description: "`gitea_token` manages gitea Access Tokens.\n\n" +
"Due to upstream limitations (see https://gitea.com/gitea/go-sdk/issues/610) this resource\n" +
"can only be used with username/password provider configuration.\n\n" +
"WARNING:\n" +
"Tokens will be stored in the terraform state!",
}
}

View File

@ -5,7 +5,7 @@ import (
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (