mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-14 05:29:56 +09:00
Adds terraform/opentofu state registry with locking. Implements: https://github.com/go-gitea/gitea/issues/33644. I also checked [encrypted state](https://opentofu.org/docs/language/state/encryption), it works out of the box. Docs PR: https://gitea.com/gitea/docs/pulls/357 --------- Co-authored-by: Andras Elso <elso.andras@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package terraform
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
packages_model "code.gitea.io/gitea/models/packages"
|
|
"code.gitea.io/gitea/modules/json"
|
|
"code.gitea.io/gitea/modules/util"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
const LockFile = "terraform.lock"
|
|
|
|
// LockInfo is the metadata for a terraform lock.
|
|
type LockInfo struct {
|
|
ID string `json:"ID"`
|
|
Operation string `json:"Operation"`
|
|
Info string `json:"Info"`
|
|
Who string `json:"Who"`
|
|
Version string `json:"Version"`
|
|
Created time.Time `json:"Created"`
|
|
Path string `json:"Path"`
|
|
}
|
|
|
|
func (l *LockInfo) IsLocked() bool {
|
|
return l.ID != ""
|
|
}
|
|
|
|
func ParseLockInfo(r io.Reader) (*LockInfo, error) {
|
|
var lock LockInfo
|
|
err := json.NewDecoder(r).Decode(&lock)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// ID is required. Rest is less important.
|
|
if lock.ID == "" {
|
|
return nil, util.NewInvalidArgumentErrorf("terraform lock is missing an ID")
|
|
}
|
|
return &lock, nil
|
|
}
|
|
|
|
// GetLock returns the terraform lock for the given package.
|
|
// Lock is empty if no lock exists.
|
|
func GetLock(ctx context.Context, packageID int64) (LockInfo, error) {
|
|
var lock LockInfo
|
|
locks, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypePackage, packageID, LockFile)
|
|
if err != nil {
|
|
return lock, err
|
|
}
|
|
if len(locks) == 0 || locks[0].Value == "" {
|
|
return lock, nil
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(locks[0].Value), &lock)
|
|
return lock, err
|
|
}
|
|
|
|
// SetLock sets the terraform lock for the given package.
|
|
func SetLock(ctx context.Context, packageID int64, lock *LockInfo) error {
|
|
jsonBytes, err := json.Marshal(lock)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return updateLock(ctx, packageID, string(jsonBytes), builder.Eq{"value": ""})
|
|
}
|
|
|
|
// RemoveLock removes the terraform lock for the given package.
|
|
func RemoveLock(ctx context.Context, packageID int64) error {
|
|
return updateLock(ctx, packageID, "", builder.Neq{"value": ""})
|
|
}
|
|
|
|
func updateLock(ctx context.Context, refID int64, value string, cond builder.Cond) error {
|
|
pp := packages_model.PackageProperty{RefType: packages_model.PropertyTypePackage, RefID: refID, Name: LockFile}
|
|
ok, err := db.GetEngine(ctx).Get(&pp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ok {
|
|
n, err := db.GetEngine(ctx).Where("ref_type=? AND ref_id=? AND name=?", packages_model.PropertyTypePackage, refID, LockFile).And(cond).Cols("value").Update(&packages_model.PackageProperty{Value: value})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n == 0 {
|
|
return errors.New("failed to update lock state")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
_, err = packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, refID, LockFile, value)
|
|
return err
|
|
}
|