Skip to content

Commit 183d4ed

Browse files
committed
Add support for creating dev mode app from git source
1 parent 3c9ba96 commit 183d4ed

File tree

15 files changed

+129
-28
lines changed

15 files changed

+129
-28
lines changed

cmd/openrun/app_cmds.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ func printCreateResult(cCtx *cli.Context, createResult types.AppCreateResponse)
229229
if createResult.HttpsUrl != "" {
230230
fmt.Printf("HTTPS Url: %s\n", createResult.HttpsUrl)
231231
}
232+
if createResult.OrigSourceUrl != "" {
233+
fmt.Printf(" Source: %s (created from %s)\n", createResult.SourceUrl, createResult.OrigSourceUrl)
234+
}
232235
approveResult := createResult.ApproveResults[0]
233236
printApproveResult(approveResult)
234237

cmd/openrun/apply_cmd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
func initApplyCommand(commonFlags []cli.Flag, clientConfig *types.ClientConfig) *cli.Command {
1919
flags := make([]cli.Flag, 0, len(commonFlags)+2)
2020
flags = append(flags, commonFlags...)
21+
flags = append(flags, newBoolFlag("dev", "d", "Create apps in development mode", false))
2122
flags = append(flags, newStringFlag("branch", "b", "The branch to checkout if using git source", "main"))
2223
flags = append(flags, newStringFlag("commit", "c", "The commit SHA to checkout if using git source. This takes precedence over branch", ""))
2324
flags = append(flags, newStringFlag("git-auth", "g", "The name of the git_auth entry in server config to use", ""))
@@ -74,6 +75,7 @@ Examples:
7475
values.Add("promote", strconv.FormatBool(cCtx.Bool("promote")))
7576
values.Add("clobber", strconv.FormatBool(cCtx.Bool("clobber")))
7677
values.Add("forceReload", strconv.FormatBool(cCtx.Bool("force-reload")))
78+
values.Add("dev", strconv.FormatBool(cCtx.Bool("dev")))
7779

7880
client := system.NewHttpClient(clientConfig.ServerUri, clientConfig.AdminUser, clientConfig.Client.AdminPassword, clientConfig.Client.SkipCertCheck)
7981
var applyResponse types.AppApplyResponse

internal/app/apptype/builtins.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,18 @@ func CreateConfigBuiltin(nodeConfig types.NodeConfig, allowedEnv []string) func(
467467
return defaultVal, nil
468468
}
469469
return starlark.String(branchStr), nil
470+
} else if key == "_dev" {
471+
// _dev is a special input that returns the current dev status
472+
dev := thread.Local(types.TL_DEV)
473+
if dev == nil {
474+
return defaultVal, nil
475+
}
476+
477+
devBool, ok := dev.(bool)
478+
if !ok {
479+
return nil, fmt.Errorf("dev is not a boolean %v", dev)
480+
}
481+
return starlark.Bool(devBool), nil
470482
}
471483

472484
localVal, ok := nodeConfig[string(key)]

internal/metadata/metadata.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
"strings"
1313
"time"
1414

15-
"github.com/openrundev/openrun/internal/system"
16-
"github.com/openrundev/openrun/internal/types"
1715
"github.com/jackc/pgx/v5"
1816
"github.com/jackc/pgx/v5/pgconn"
1917
_ "github.com/jackc/pgx/v5/stdlib"
2018
"github.com/jackc/pgxlisten"
19+
"github.com/openrundev/openrun/internal/system"
20+
"github.com/openrundev/openrun/internal/types"
2121
_ "modernc.org/sqlite"
2222
)
2323

@@ -460,6 +460,14 @@ func (m *Metadata) GetLinkedApps(ctx context.Context, tx types.Transaction, main
460460
return apps, nil
461461
}
462462

463+
func (m *Metadata) UpdateSourceUrl(ctx context.Context, tx types.Transaction, app *types.AppEntry) error {
464+
_, err := tx.ExecContext(ctx, system.RebindQuery(m.dbType, `UPDATE apps set source_url = ? where path = ? and domain = ?`), app.SourceUrl, app.Path, app.Domain)
465+
if err != nil {
466+
return fmt.Errorf("error updating app source url: %w", err)
467+
}
468+
return nil
469+
}
470+
463471
func (m *Metadata) UpdateAppMetadata(ctx context.Context, tx types.Transaction, app *types.AppEntry) error {
464472
metadataJson, err := json.Marshal(app.Metadata)
465473
if err != nil {

internal/server/app_apis.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,7 @@ func (s *Server) CreateAppTx(ctx context.Context, currentTx types.Transaction, a
165165

166166
func (s *Server) createApp(ctx context.Context, tx types.Transaction,
167167
appEntry *types.AppEntry, approve, dryRun bool, branch, commit, gitAuth string, applyInfo *types.CreateAppRequest, repoCache *RepoCache) (*types.AppCreateResponse, error) {
168-
if system.IsGit(appEntry.SourceUrl) {
169-
if appEntry.IsDev {
170-
return nil, fmt.Errorf("cannot create dev mode app from git source. For dev mode, manually checkout the git repo and create app from the local path")
171-
}
172-
} else {
168+
if !system.IsGit(appEntry.SourceUrl) {
173169
if appEntry.SourceUrl != types.NO_SOURCE {
174170
// Make sure the source path is absolute
175171
var err error
@@ -258,6 +254,11 @@ func (s *Server) createApp(ctx context.Context, tx types.Transaction,
258254
return nil, fmt.Errorf("App %s audit failed: %s", workEntry.Id, err)
259255
}
260256

257+
// Persist the source url
258+
if err := s.db.UpdateSourceUrl(ctx, tx, workEntry); err != nil {
259+
return nil, err
260+
}
261+
261262
// Persist the metadata so that any git info is saved
262263
if err := s.db.UpdateAppMetadata(ctx, tx, workEntry); err != nil {
263264
return nil, err
@@ -293,6 +294,8 @@ func (s *Server) createApp(ctx context.Context, tx types.Transaction,
293294
HttpsUrl: s.getAppHttpsUrl(appEntry),
294295
DryRun: dryRun,
295296
ApproveResults: results,
297+
OrigSourceUrl: appEntry.Settings.OrigSourceUrl,
298+
SourceUrl: appEntry.SourceUrl,
296299
}
297300

298301
return ret, nil
@@ -756,11 +759,22 @@ func (s *Server) loadSourceFromGit(ctx context.Context, tx types.Transaction, ap
756759
gitAuth = cmp.Or(gitAuth, appEntry.Settings.GitAuthName)
757760
branch = cmp.Or(branch, appEntry.Metadata.VersionMetadata.GitBranch, "main")
758761

759-
repo, folder, message, hash, err := repoCache.CheckoutRepo(appEntry.SourceUrl, branch, commit, gitAuth)
762+
repo, folder, message, hash, err := repoCache.CheckoutRepo(appEntry.SourceUrl, branch, commit, gitAuth, appEntry.IsDev)
760763
if err != nil {
761764
return err
762765
}
763766

767+
if system.IsGit(appEntry.SourceUrl) && appEntry.IsDev {
768+
// Dev app from git, we need to point the app to the local checkout location
769+
sourcePath := repo
770+
if folder != "" {
771+
sourcePath = path.Join(repo, folder)
772+
}
773+
// App metadata points to the local checkout location
774+
appEntry.Settings.OrigSourceUrl = appEntry.SourceUrl
775+
appEntry.SourceUrl = sourcePath
776+
}
777+
764778
// Update the git info into the appEntry, the caller needs to persist it into the app metadata
765779
// This function will persist it into the app_version metadata
766780
appEntry.Metadata.VersionMetadata.GitCommit = hash

internal/server/apply.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const (
2929
APP = "app"
3030
)
3131

32-
func (s *Server) loadApplyInfo(fileName string, data []byte, branch string) ([]*types.CreateAppRequest, error) {
32+
func (s *Server) loadApplyInfo(fileName string, data []byte, branch string, dev bool) ([]*types.CreateAppRequest, error) {
3333
appDefs := make([]*starlarkstruct.Struct, 0)
3434

3535
createAppBuiltin := func(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
@@ -82,6 +82,7 @@ func (s *Server) loadApplyInfo(fileName string, data []byte, branch string) ([]*
8282
}
8383

8484
thread.SetLocal(types.TL_BRANCH, branch)
85+
thread.SetLocal(types.TL_DEV, dev)
8586

8687
options := syntax.FileOptions{}
8788
_, err := starlark.ExecFileOptions(&options, thread, fileName, data, builtins)
@@ -203,7 +204,7 @@ func (s *Server) setupSource(applyPath, branch, commit, gitAuth string, repoCach
203204
}
204205

205206
branch = cmp.Or(branch, "main")
206-
repo, applyFile, _, _, err := repoCache.CheckoutRepo(applyPath, branch, commit, gitAuth)
207+
repo, applyFile, _, _, err := repoCache.CheckoutRepo(applyPath, branch, commit, gitAuth, false)
207208
if err != nil {
208209
return "", "", err
209210
}
@@ -218,7 +219,8 @@ func (s *Server) setupSource(applyPath, branch, commit, gitAuth string, repoCach
218219
}
219220

220221
func (s *Server) Apply(ctx context.Context, inputTx types.Transaction, applyPath string, appPathGlob string, approve, dryRun, promote bool,
221-
reload types.AppReloadOption, branch, commit, gitAuth string, clobber, forceReload bool, lastRunCommitId string, repoCache *RepoCache) (*types.AppApplyResponse, []types.AppPathDomain, error) {
222+
reload types.AppReloadOption, branch, commit, gitAuth string, clobber,
223+
forceReload bool, lastRunCommitId string, repoCache *RepoCache, dev bool) (*types.AppApplyResponse, []types.AppPathDomain, error) {
222224
var tx types.Transaction
223225
var err error
224226
if inputTx.Tx == nil {
@@ -289,7 +291,7 @@ func (s *Server) Apply(ctx context.Context, inputTx types.Transaction, applyPath
289291
return nil, nil, fmt.Errorf("error reading file %s: %w", f, err)
290292
}
291293

292-
fileConfig, err := s.loadApplyInfo(f, fileBytes, branch)
294+
fileConfig, err := s.loadApplyInfo(f, fileBytes, branch, dev)
293295
if err != nil {
294296
return nil, nil, err
295297
}
@@ -365,6 +367,9 @@ func (s *Server) Apply(ctx context.Context, inputTx types.Transaction, applyPath
365367
for _, newApp := range newApps {
366368
s.Trace().Msgf("Applying create app %s", newApp)
367369
applyInfo := applyConfig[newApp]
370+
if dev {
371+
applyInfo.IsDev = dev // Override the dev status from the apply command cli
372+
}
368373
res, err := s.CreateAppTx(ctx, tx, newApp.String(), approve, dryRun, applyInfo, repoCache)
369374
if err != nil {
370375
return nil, nil, err

internal/server/repo_cache.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"cmp"
88
"fmt"
99
"os"
10+
"path"
11+
"path/filepath"
1012

1113
"github.com/go-git/go-git/v5"
1214
"github.com/go-git/go-git/v5/config"
@@ -124,7 +126,7 @@ func latestCommitSHA(repoURL, branch string, auth transport.AuthMethod) (string,
124126
return "", fmt.Errorf("branch %q not found", branch)
125127
}
126128

127-
func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string) (string, string, string, string, error) {
129+
func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string, isDev bool) (string, string, string, string, error) {
128130
gitAuth = cmp.Or(gitAuth, r.server.config.Security.DefaultGitAuth)
129131
authEntry, err := r.server.loadGitKey(gitAuth)
130132
if err != nil {
@@ -137,7 +139,8 @@ func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string) (str
137139
return "", "", "", "", err
138140
}
139141

140-
dir, ok := r.cache[Repo{repo, branch, commit, gitAuth}]
142+
repoKey := Repo{repo, branch, commit, gitAuth}
143+
dir, ok := r.cache[repoKey]
141144
if ok {
142145
return dir.dir, folder, dir.commitMessage, dir.hash, nil
143146
}
@@ -150,7 +153,9 @@ func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string) (str
150153
// No commit id specified, checkout specified branch
151154
cloneOptions.ReferenceName = plumbing.NewBranchReferenceName(branch)
152155
cloneOptions.SingleBranch = true
153-
cloneOptions.Depth = 1
156+
if !isDev {
157+
cloneOptions.Depth = 1
158+
}
154159
}
155160

156161
if gitAuth != "" {
@@ -162,9 +167,19 @@ func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string) (str
162167
cloneOptions.Auth = auth
163168
}
164169

165-
targetPath, err := os.MkdirTemp(r.rootDir, "repo_")
166-
if err != nil {
167-
return "", "", "", "", err
170+
var targetPath string
171+
if isDev {
172+
// We don't have a previous dev checkout for this repo, create a new one
173+
repoName := filepath.Base(repo)
174+
targetPath = getUnusedRepoPath(os.ExpandEnv("$OPENRUN_HOME/app_src/"), repoName)
175+
if err := os.MkdirAll(targetPath, 0744); err != nil {
176+
return "", "", "", "", err
177+
}
178+
} else {
179+
targetPath, err = os.MkdirTemp(r.rootDir, "repo_")
180+
if err != nil {
181+
return "", "", "", "", err
182+
}
168183
}
169184

170185
// Configure the repo to Clone
@@ -215,6 +230,20 @@ func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string) (str
215230
return targetPath, folder, newCommit.Message, newCommit.Hash.String(), nil
216231
}
217232

233+
func getUnusedRepoPath(targetDir, repoName string) string {
234+
if _, err := os.Stat(path.Join(targetDir, repoName)); os.IsNotExist(err) {
235+
return path.Join(targetDir, repoName)
236+
}
237+
count := 2
238+
for {
239+
unusedName := fmt.Sprintf("%s%d", repoName, count)
240+
if _, err := os.Stat(path.Join(targetDir, unusedName)); os.IsNotExist(err) {
241+
return path.Join(targetDir, unusedName)
242+
}
243+
count++
244+
}
245+
}
246+
218247
func (r *RepoCache) Cleanup() {
219248
if r.rootDir != "" {
220249
os.RemoveAll(r.rootDir)

internal/server/router.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import (
1818
"strings"
1919
"time"
2020

21+
"github.com/go-chi/chi"
22+
"github.com/go-chi/chi/middleware"
2123
"github.com/openrundev/openrun/internal/app"
2224
"github.com/openrundev/openrun/internal/system"
2325
"github.com/openrundev/openrun/internal/types"
24-
"github.com/go-chi/chi"
25-
"github.com/go-chi/chi/middleware"
2626
)
2727

2828
const (
@@ -986,10 +986,15 @@ func (h *Handler) apply(r *http.Request) (any, error) {
986986
}
987987
updateOperationInContext(r, genOperationName("apply", promote, approve))
988988

989+
dev, err := parseBoolArg(r.URL.Query().Get("dev"), false)
990+
if err != nil {
991+
return nil, err
992+
}
993+
989994
ret, _, err := h.server.Apply(r.Context(), types.Transaction{}, applyPath, appPathGlob, approve, dryRun, promote,
990995
types.AppReloadOption(r.URL.Query().Get("reload")),
991996
r.URL.Query().Get("branch"), r.URL.Query().Get("commit"), r.URL.Query().Get("gitAuth"),
992-
clobber, forceReload, "", nil)
997+
clobber, forceReload, "", nil, dev)
993998
if err != nil {
994999
return nil, types.CreateRequestError(err.Error(), http.StatusInternalServerError)
9951000
}

internal/server/sync.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func (s *Server) runSyncJob(ctx context.Context, inputTx types.Transaction, entr
242242
}
243243

244244
applyInfo, updatedApps, applyErr := s.Apply(ctx, tx, entry.Path, "all", entry.Metadata.Approve, dryRun, entry.Metadata.Promote, types.AppReloadOption(entry.Metadata.Reload),
245-
entry.Metadata.GitBranch, "", entry.Metadata.GitAuth, entry.Metadata.Clobber, entry.Metadata.ForceReload, lastRunCommitId, repoCache)
245+
entry.Metadata.GitBranch, "", entry.Metadata.GitAuth, entry.Metadata.Clobber, entry.Metadata.ForceReload, lastRunCommitId, repoCache, false)
246246

247247
status := types.SyncJobStatus{
248248
LastExecutionTime: time.Now(),

internal/types/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ type AppCreateResponse struct {
108108
HttpUrl string `json:"http_url"`
109109
HttpsUrl string `json:"https_url"`
110110
ApproveResults []ApproveResult `json:"approve_results"`
111+
OrigSourceUrl string `json:"orig_source_url"`
112+
SourceUrl string `json:"source_url"`
111113
}
112114

113115
type AppDeleteResponse struct {

0 commit comments

Comments
 (0)