Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
186 commits
Select commit Hold shift + click to select a range
db813b3
wip deployer script
jeromegn Jul 15, 2024
8d8957d
add app name and org slug speicifiers
jeromegn Jul 15, 2024
f34c9e9
generate full config beforehand, if DEPLOY_NOW env is defined, run fl…
jeromegn Jul 17, 2024
ed94877
fix manifest return, don't specify region when deploying
jeromegn Jul 17, 2024
a38be4e
support more env vars to configure the deployer, adjust fly launch ge…
jeromegn Jul 18, 2024
d889fee
fix spacing and types, set vm size options in config
jeromegn Jul 19, 2024
8726038
add elixir and nodejs
jeromegn Jul 26, 2024
108f41a
adds a build step, a diff artifact and finally generates files on dis…
jeromegn Jul 29, 2024
836015d
send metadata about the deploy steps before starting
jeromegn Aug 1, 2024
03d828c
fly pg creation from deployer
jeromegn Aug 2, 2024
0897f2d
trying to allow multiple ruby versions, but failing. wip commit
jeromegn Aug 4, 2024
9a4c268
Use dev envs for elixir and nodejs
lubien Aug 6, 2024
c01b275
Fix support for [build.image]
lubien Aug 6, 2024
449886e
Fix typo
lubien Aug 6, 2024
fc9b7ff
Maybe fix secrets setting
lubien Aug 7, 2024
97a3062
merged main and tested more frameworks
jeromegn Aug 12, 2024
a98b4ab
add launch sessions subcommands, adjust deploy script to use them
jeromegn Aug 12, 2024
07d5b9c
create all extensions from a launch manifest
jeromegn Aug 13, 2024
8087cac
update fly config after tweak form resolves, use org slug from final …
jeromegn Aug 14, 2024
d5ba0b0
merged master
jeromegn Aug 14, 2024
fa7c154
add runtime to plan for rails, node, and bun
rubys Aug 14, 2024
3153d0b
extract ruby version from .ruby-version or Gemfile
rubys Aug 14, 2024
7897948
Merge remote-tracking branch 'origin/plan-runtime' into deployer
jeromegn Aug 14, 2024
d69cec8
defer the running of bundle install in the rails scanner to the callback
rubys Aug 14, 2024
6a4c627
merged rails-defer-bundle-install
jeromegn Aug 14, 2024
8588928
use launch plan subcommands, install dependencies
jeromegn Aug 14, 2024
432f560
wip installing deps for more frameworks
jeromegn Aug 19, 2024
306980e
Scan composer file for php version, fallback to artisan version if ca…
Aug 19, 2024
bbf0353
fix trailing spaces, fix gofmt error
Aug 19, 2024
e723e40
Merge remote-tracking branch 'origin/detect_php_from_composer_json' i…
jeromegn Aug 20, 2024
63261c5
write manifest to fix, switch customization opt-out instead of opt-in…
jeromegn Aug 20, 2024
a62607a
don't log everything, re-order steps, always do JSON for artifacts
jeromegn Aug 28, 2024
6fcadd1
add DEPLOY_ONLY env to prevent all the planning of a launch
jeromegn Sep 11, 2024
fae836f
fix conditional to skip extensions when using DEPLOY_ONLY
jeromegn Sep 13, 2024
65e4ff4
trying to make the deployer testable via the CI
jeromegn Sep 13, 2024
5c83bc7
use the correct restart policy
jeromegn Sep 13, 2024
225ceb8
on eof, don't panic, try to attach stdout and stderr
jeromegn Sep 13, 2024
9e1c271
attempt to wait for container
jeromegn Sep 16, 2024
2bfae94
check for nil error from container wait channel
jeromegn Sep 16, 2024
ad9f3ce
attempt not to loop endlessly when everything is done
jeromegn Sep 16, 2024
c438f89
write all to stdout
jeromegn Sep 16, 2024
337096e
build just once
jeromegn Sep 16, 2024
97d67a6
I wanted github.sha to tag the docker image, not github.ref
jeromegn Sep 16, 2024
155aa32
first, pull the deployer image
jeromegn Sep 16, 2024
c69aa93
upgrade docker module, successfully build and deploy the deploy-node …
jeromegn Sep 16, 2024
79413c0
moved a few tests around, start parsing logs and testing the deployer…
jeromegn Sep 16, 2024
35b2db7
merged master
jeromegn Sep 17, 2024
f93cdba
ignore .fly
jeromegn Sep 17, 2024
50f0928
always generate git diff
jeromegn Sep 17, 2024
45210ba
abstracted the deployer run to be reusable
jeromegn Sep 17, 2024
8bfb0d2
run deployer tests during preflight
jeromegn Sep 17, 2024
39171ae
add launch test
jeromegn Sep 17, 2024
0ad2e56
disable depot
jeromegn Sep 18, 2024
6f6c089
go mod tidy
jeromegn Sep 18, 2024
7adf153
add go-example test
jeromegn Sep 18, 2024
ef780b9
refactor deployer tests to make them more succinct
jeromegn Sep 18, 2024
cd59492
more readable tests
jeromegn Sep 25, 2024
d62e134
Merge remote-tracking branch 'origin/master' into deployer
jeromegn Sep 25, 2024
b032feb
fix node scanner
jeromegn Sep 27, 2024
1434718
possibly fix weird setup where override fly.toml should clear a templ…
jeromegn Sep 27, 2024
7fc099c
Deployer: open pr on launch (#3953)
lubien Sep 30, 2024
30c2e94
bomb if plan propose doesn't detect anything
jeromegn Sep 30, 2024
717395f
fix color output for error message when no framework is detected
jeromegn Sep 30, 2024
3b939c0
even if opting out of gha, return the source info
jeromegn Sep 30, 2024
811cfac
test for opt out gha
jeromegn Sep 30, 2024
ff17b7d
download correct default node.js to save some time
jeromegn Sep 30, 2024
42e59ff
try to cache deployer build
jeromegn Sep 30, 2024
fb0063d
setup buildx
jeromegn Sep 30, 2024
f2379ac
use local context for build
jeromegn Sep 30, 2024
a5e56bf
Run deployer tests in separate workflow (#3977)
jeromegn Oct 1, 2024
bc093bc
adjust logs when not detecting runtime or Dockerfile
jeromegn Oct 1, 2024
3057043
synchronously write to stdout/stderr
jeromegn Oct 2, 2024
9ec4879
Custom config for deployer monorepos (#3976)
lubien Oct 7, 2024
25e2811
Merge remote-tracking branch 'origin/master' into deployer
jeromegn Oct 11, 2024
79b1003
add rails 8 test, fix rvm install and usage, better ruby version dete…
jeromegn Oct 11, 2024
6e12d09
use bash_profile instead of profile since we're using a bash login shell
jeromegn Oct 12, 2024
68e01e2
install rvm after mise...
jeromegn Oct 12, 2024
1329ad0
set node.js for nextjs, nuxt and redwood projects
jeromegn Oct 14, 2024
2f3878e
install a default node.js version if anything needs it
jeromegn Oct 15, 2024
14739e4
switch to node 20 by default
jeromegn Oct 15, 2024
a46108d
maybe delete the container more proactively
jeromegn Oct 15, 2024
11ed89f
run deployer tests as root
jeromegn Oct 15, 2024
0044e78
also install gotessplit as root
jeromegn Oct 15, 2024
b2eacad
add a cleanup env var, mostly useful in tests
jeromegn Oct 15, 2024
84665ab
detect a Dockerfile first and foremost
jeromegn Oct 16, 2024
ede91b5
Deployer: skip installing dependencies in some cases (#4019)
jeromegn Oct 21, 2024
c0c1983
ensure flushing of stdout and stderr before exit
jeromegn Oct 21, 2024
2b205e0
sleep 1 second after flushing just to be sure all log lines are ingested
jeromegn Oct 21, 2024
7e16e26
Add node yarn test and fix yarn installation for node > 18 (#4023)
jeromegn Oct 22, 2024
2c8bb4c
removing a few warnings that don't apply to deployers
jeromegn Oct 22, 2024
3a32452
use a depot builder scoped by app so they don't share cache and all t…
jeromegn Oct 22, 2024
8efd9b6
validate existence of fly.toml earlier when deploy-only
jphenow Oct 23, 2024
47466bb
exit after error
jphenow Oct 23, 2024
9ada865
Deployer: actually support Bun (#4042)
jeromegn Oct 29, 2024
c270001
explicitly disallow upstash replicas if no upstash regions provided
jeromegn Oct 30, 2024
8ea62fb
soft skip extensions in tests so the step still shows up in logs
jeromegn Oct 30, 2024
86705ae
fix python version detection from Pipfile, add django fixture
jeromegn Oct 30, 2024
735eb3d
query from slug directly if supplied
jeromegn Oct 31, 2024
6de1bfb
don't prompt for bucket name on tigris if using the --yes flag
jeromegn Oct 31, 2024
64878e3
fix go deployments when missing go.sum
jeromegn Nov 1, 2024
ec683eb
upgrade default deno to 2.0.4, try to detect more deno apps, add test…
jeromegn Nov 1, 2024
ec2751c
attempt at accepting customize from file (#4046)
jeromegn Nov 5, 2024
c542022
add static site fixture
jeromegn Nov 5, 2024
a6fc203
Merge remote-tracking branch 'origin/master' into deployer
lubien Dec 9, 2024
c76b965
Deployers phoenix improvements (#4113)
lubien Dec 17, 2024
3a28913
Port https://github.com/superfly/flyctl/pull/4247 into deployer branc…
clouvet Mar 18, 2025
bcffc53
Deploy image ref (#4471)
lubien Jul 9, 2025
178c73b
Deployer update now (#4593)
lubien Oct 7, 2025
a9b3996
deploy fix: use image ref directly if image resolver fails (#4596)
lubien Oct 9, 2025
610c773
Pass builder ID through fly deploy --image build strategy (#4601)
wjordan Oct 17, 2025
f87a793
Deployer experiment early git push (#4610)
lubien Oct 17, 2025
66e95e7
require uiex in all plan commands (#4625)
lubien Oct 29, 2025
9767ed6
files from diff (#4626)
lubien Oct 31, 2025
f0f255c
Merge remote-tracking branch 'origin/deployer' into jphenow/deployer-…
jphenow Nov 11, 2025
c5fd74c
dump a bunch of things we'll pull elsewhere
jphenow Nov 11, 2025
6f62134
drop some more we know we're moving
jphenow Nov 11, 2025
381742d
go back on some test changes we can keep as well
jphenow Nov 11, 2025
e50ac44
try that
jphenow Nov 11, 2025
46e17d6
remove more that probably doesn't belong here
jphenow Nov 11, 2025
a600e26
Rollback test changes we don't need now
jphenow Nov 11, 2025
936ea91
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Nov 12, 2025
59431b7
perhaps a fix
jphenow Nov 13, 2025
f9a69f8
see if mix/match helps
jphenow Nov 13, 2025
1f0ec4d
another brief shot from the hip to see if it helps with this odd tran…
jphenow Nov 13, 2025
724d50a
I can't see why we need to force that nil
jphenow Nov 13, 2025
45f5cd2
try out removing sessions
jphenow Nov 13, 2025
a8e3c87
could it be a small name grab tweak
jphenow Nov 13, 2025
e56f704
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Nov 13, 2025
a4a19b7
how many more things are there
jphenow Nov 13, 2025
3ce76e7
another hipshot
jphenow Nov 13, 2025
1af960e
no way
jphenow Nov 13, 2025
b5fafe8
reverts
jphenow Nov 14, 2025
e72b6a4
bring this back to more similarish
jphenow Nov 14, 2025
cee05cd
just handle that we match them now
jphenow Nov 14, 2025
1a0862d
handle nils
jphenow Nov 14, 2025
dcc010b
segfault and launch test compat
jphenow Nov 14, 2025
b7a03dc
fix another segfault
jphenow Nov 14, 2025
455c3d1
Merge remote-tracking branch 'origin/master' into jphenow/deployer-me…
jphenow Nov 14, 2025
cc43103
these appear to be gone
jphenow Nov 14, 2025
502a516
another nil check apparently
jphenow Nov 14, 2025
966d524
right on back
jphenow Nov 14, 2025
26d18a8
see if this helps windows build
jphenow Nov 17, 2025
c520abe
try this for a sec; should maybe revert
jphenow Nov 17, 2025
35a2d07
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Nov 17, 2025
ce43108
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Nov 17, 2025
3817455
fix: use index-based iteration for CPU/Memory compute overrides
jphenow Nov 17, 2025
cf35575
fix: add MachineGuest nil check in CPU/Memory compute overrides
jphenow Nov 17, 2025
bf171e7
quit the double preflight life
jphenow Nov 17, 2025
647a4b0
Upgrade mise version to v2025.11.6
lubien Nov 18, 2025
650deb4
Add error handling to NewMPGService and related functions
lubien Nov 18, 2025
af74a53
Add trigger configuration to Django basic deployment test
lubien Nov 18, 2025
13d0118
allow setting org on manifest
jphenow Nov 22, 2025
0a987b2
fix rails fixture tests
jphenow Nov 25, 2025
14f69c0
fix deno fixture test
jphenow Nov 25, 2025
7d6f5b4
it contains multitudes of database
jphenow Nov 25, 2025
936f1c1
Add debug logging to diagnose silent manifest creation failure
jphenow Nov 28, 2025
6e4e013
Fix error handling in plan commands
jphenow Nov 28, 2025
da45f32
https://github.com/superfly/flyctl/blob/a6da01fd0840f18fb5c57c66e6335…
jphenow Dec 1, 2025
6fd4ac7
roll this back for now from old PR
jphenow Dec 1, 2025
dee9c9f
disable dead flag for now
jphenow Dec 1, 2025
427388f
Fix Rails SQLite Dockerfile generation
jphenow Dec 1, 2025
ada5624
edge case of setting binrails above messes with multi-test runs when …
jphenow Dec 2, 2025
ce5c42a
needless maybe
jphenow Dec 2, 2025
cfb2e37
dump silly md
jphenow Dec 2, 2025
a8570ac
revert some experimentation that now seems unnecessary
jphenow Dec 2, 2025
7299ca3
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Dec 2, 2025
b016594
undo some more things we probably didn't need
jphenow Dec 2, 2025
164c868
remove a thing that shouldn't be there anyways
jphenow Dec 2, 2025
07b5a70
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Dec 2, 2025
d490d4a
I found a bug where our deployer fixture has a port 8080, but doesn't…
jphenow Dec 3, 2025
d1f02a1
gitignore
jphenow Dec 3, 2025
a660ad1
See if we maybe just don't need to load the app config because it bus…
jphenow Dec 4, 2025
03aaa23
Add precedence logic for --app/--region flags in generate step
jphenow Dec 4, 2025
232341b
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Dec 5, 2025
28d0fe1
Keep some of the previous functionality
jphenow Dec 5, 2025
858d87d
clearer, more succinct error/canenterui handling
jphenow Dec 5, 2025
c3aebf6
better fallback and more common first-check on main.ts for deno
jphenow Dec 5, 2025
6ca4cee
clearer conditional flow management
jphenow Dec 5, 2025
bb8087b
fix regex escaping
jphenow Dec 5, 2025
69c5b6b
warn python folks when we have wsgi and not gunicorn
jphenow Dec 5, 2025
571c4f1
some backstop stuff in case folks wind up in this more internal-usage…
jphenow Dec 5, 2025
365bb02
safer npm install
jphenow Dec 5, 2025
de5055f
make decisions using semver instead of string comparisons
jphenow Dec 5, 2025
0d1dcf4
Merge branch 'master' into jphenow/deployer-mergeable
jphenow Dec 5, 2025
5b3762e
Fix malformed regex in Deno scanner
jphenow Dec 5, 2025
5f14339
some localized feedback tweaks and tests
jphenow Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
schedule:
- cron: '21 */2 * * *'
push:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -36,6 +37,8 @@ jobs:
overwrite: true

preflight:
# Only run preflight on master pushes, scheduled runs, or pull requests
if: ${{ github.event_name == 'schedule' || github.ref == 'refs/heads/master' || github.event_name == 'pull_request' }}
needs: test_build
uses: ./.github/workflows/preflight.yml
secrets: inherit
6 changes: 3 additions & 3 deletions .github/workflows/preflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
go-version-file: 'go.mod'
check-latest: true
- name: Get go version
id: go-version
Expand All @@ -49,8 +49,8 @@ jobs:
FLY_PREFLIGHT_TEST_ACCESS_TOKEN: ${{ secrets.FLYCTL_PREFLIGHT_CI_FLY_API_TOKEN }}
FLY_PREFLIGHT_TEST_FLY_ORG: flyctl-ci-preflight
FLY_PREFLIGHT_TEST_FLY_REGIONS: ${{ inputs.region }}
FLY_PREFLIGHT_TEST_NO_PRINT_HISTORY_ON_FAIL: "true"
FLY_FORCE_TRACE: "true"
FLY_PREFLIGHT_TEST_NO_PRINT_HISTORY_ON_FAIL: 'true'
FLY_FORCE_TRACE: 'true'
run: |
(test -e master-build/flyctl) && mv master-build/flyctl bin/flyctl
chmod +x bin/flyctl
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ out
# generated release meta
release.json

.fly
CLAUDE.md
.claude/settings.local.json
7 changes: 6 additions & 1 deletion internal/command/deploy/deploy_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ func determineImage(ctx context.Context, app *flaps.App, appConfig *appconfig.Co
img, err = resolver.ResolveReference(ctx, io, opts)
if err != nil {
tracing.RecordError(span, err, "failed to resolve reference for prebuilt docker image")
return
img = &imgsrc.DeploymentImage{
ID: imageRef,
Tag: imageRef,
}
terminal.Debugf("Failed to resolve reference for prebuilt docker image, using imageRef %s: %v\n", img.String(), err)
err = nil
}

span.AddEvent("using pre-built docker image")
Expand Down
12 changes: 6 additions & 6 deletions internal/command/extensions/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,17 @@ func ProvisionExtension(ctx context.Context, params ExtensionParams) (extension
if override := params.OverrideName; override != nil {
name = *override
} else {
if name == "" {
name = flag.GetString(ctx, "name")
}
name = flag.GetString(ctx, "name")

if name == "" {
if provider.NameSuffix != "" && targetApp.Name != "" {
name = targetApp.Name + "-" + provider.NameSuffix
}
err = prompt.String(ctx, &name, "Choose a name, use the default, or leave blank to generate one:", name, false)
if err != nil {
return
if !flag.GetYes(ctx) {
err = prompt.String(ctx, &name, "Choose a name, use the default, or leave blank to generate one:", name, false)
if err != nil {
return
}
}
}
}
Expand Down
70 changes: 61 additions & 9 deletions internal/command/launch/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,20 @@ func New() (cmd *cobra.Command) {
Name: "yaml",
Description: "Generate configuration in YAML format",
},
// don't try to generate a name
flag.Bool{
Name: "no-create",
Description: "Do not create an app, only generate configuration files",
Name: "force-name",
Description: "Force app name supplied by --name",
Default: false,
Hidden: true,
},
// like reuse-app, but non-legacy!
flag.Bool{
Name: "no-create-app",
Description: "Do not create an app",
Default: false,
Hidden: true,
Aliases: []string{"no-create"},
},
flag.String{
Name: "auto-stop",
Expand Down Expand Up @@ -337,6 +348,46 @@ func run(ctx context.Context) (err error) {
return err
}

planStep := plan.GetPlanStep(ctx)

if launchManifest != nil && planStep != "generate" {
// we loaded a manifest...
cache = &planBuildCache{
appConfig: launchManifest.Config,
sourceInfo: nil,
appNameValidated: true,
warnedNoCcHa: true,
}
}

// For "generate" step, allow command-line flags to override manifest values.
// This is necessary because buildManifest() is skipped when loading a manifest from file.
// The "generate" step specifically needs this because it's called after propose/create steps,
// and the deployer wrapper needs to be able to override specific values without re-proposing.
if launchManifest != nil && planStep == "generate" {
// Override org if --org flag was provided
if orgRequested := flag.GetOrg(ctx); orgRequested != "" {
launchManifest.Plan.OrgSlug = orgRequested
}

// Override app name if --app flag was provided
// This allows explicit override while preserving manifest value by default
if appRequested := flag.GetApp(ctx); appRequested != "" && flag.IsSpecified(ctx, "app") {
launchManifest.Plan.AppName = appRequested
}

// Override region if --region flag was provided
if regionRequested := flag.GetRegion(ctx); regionRequested != "" && flag.IsSpecified(ctx, "region") {
launchManifest.Plan.RegionCode = regionRequested
}

// Initialize PlanSource if nil (happens when loading from JSON because fields are unexported)
// This prevents nil pointer dereference in PlanSummary and other code that accesses PlanSource
if launchManifest.PlanSource == nil {
launchManifest.PlanSource = newDefaultPlanSource("from manifest")
}
}

// "--from" arg handling
parentCtx := ctx
ctx, parentConfig, err := setupFromTemplate(ctx)
Expand All @@ -350,19 +401,20 @@ func run(ctx context.Context) (err error) {
recoverableErrors := recoverableErrorBuilder{canEnterUi: canEnterUi}

if launchManifest == nil {

launchManifest, cache, err = buildManifest(ctx, parentConfig, &recoverableErrors)
if err != nil {
var recoverableErr recoverableInUiError
if errors.As(err, &recoverableErr) && canEnterUi {
} else {
if !errors.As(err, &recoverableErr) || !canEnterUi {
return err
}
}

if flag.GetBool(ctx, "manifest") {
manifestFlag := flag.GetBool(ctx, "manifest")
manifestPath := flag.GetString(ctx, "manifest-path")

if manifestFlag {
var jsonEncoder *json.Encoder
if manifestPath := flag.GetString(ctx, "manifest-path"); manifestPath != "" {
if manifestPath != "" {
file, err := os.OpenFile(manifestPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return err
Expand All @@ -374,7 +426,8 @@ func run(ctx context.Context) (err error) {
jsonEncoder = json.NewEncoder(io.Out)
}
jsonEncoder.SetIndent("", " ")
return jsonEncoder.Encode(launchManifest)
encodeErr := jsonEncoder.Encode(launchManifest)
return encodeErr
}
}

Expand Down Expand Up @@ -419,7 +472,6 @@ func run(ctx context.Context) (err error) {
family = state.sourceInfo.Family
}

planStep := plan.GetPlanStep(ctx)
if planStep == "" {
colorize := io.ColorScheme()

Expand Down
15 changes: 15 additions & 0 deletions internal/command/launch/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ func TestValidatePostgresFlags(t *testing.T) {
}
}

func TestNewDefaultPlanSource(t *testing.T) {
source := "test source"
planSource := newDefaultPlanSource(source)

assert.NotNil(t, planSource)
assert.Equal(t, source, planSource.appNameSource)
assert.Equal(t, source, planSource.regionSource)
assert.Equal(t, source, planSource.orgSource)
assert.Equal(t, source, planSource.computeSource)
assert.Equal(t, source, planSource.postgresSource)
assert.Equal(t, source, planSource.redisSource)
assert.Equal(t, source, planSource.tigrisSource)
assert.Equal(t, source, planSource.sentrySource)
}

func TestParseMountOptions(t *testing.T) {
tests := []struct {
name string
Expand Down
73 changes: 61 additions & 12 deletions internal/command/launch/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ func (state *launchState) Launch(ctx context.Context) error {
}
}

if planStep != "generate" {
// Override internal port if requested using --internal-port flag
if n := flag.GetInt(ctx, "internal-port"); n > 0 {
state.appConfig.SetInternalPort(n)
}
}

// if the user specified a command, set it in the app config
if flag.GetString(ctx, "command") != "" {
if state.appConfig.Processes == nil {
Expand Down Expand Up @@ -276,17 +283,30 @@ func (state *launchState) updateComputeFromDeprecatedGuestFields(ctx context.Con
return nil
}

// isComputeValid checks if a compute configuration is valid and can be safely modified
func isComputeValid(c *appconfig.Compute) bool {
return c != nil && c.MachineGuest != nil
}

// updateConfig populates the appConfig with the plan's values
func (state *launchState) updateConfig(ctx context.Context) {
state.appConfig.AppName = state.Plan.AppName
state.appConfig.PrimaryRegion = state.Plan.RegionCode
if state.env != nil {
state.appConfig.SetEnvVariables(state.env)
appConfig := state.appConfig
env := state.env
plan := state.Plan

if plan == nil {
return
}

state.appConfig.Compute = state.Plan.Compute
appConfig.AppName = plan.AppName
appConfig.PrimaryRegion = plan.RegionCode
if env != nil {
appConfig.SetEnvVariables(env)
}

appConfig.Compute = plan.Compute

if state.Plan.HttpServicePort != 0 {
if plan.HttpServicePort != 0 {
autostop := fly.MachineAutostopStop
autostopFlag := flag.GetString(ctx, "auto-stop")

Expand All @@ -296,8 +316,11 @@ func (state *launchState) updateConfig(ctx context.Context) {
autostop = fly.MachineAutostopSuspend

// if any compute has a GPU or more than 2GB of memory, set autostop to stop
for _, compute := range state.appConfig.Compute {
if compute.MachineGuest != nil && compute.MachineGuest.GPUKind != "" {
for _, compute := range appConfig.Compute {
if !isComputeValid(compute) {
continue
}
if compute.MachineGuest.GPUKind != "" {
autostop = fly.MachineAutostopStop
break
}
Expand All @@ -312,18 +335,44 @@ func (state *launchState) updateConfig(ctx context.Context) {
}
}

if state.appConfig.HTTPService == nil {
state.appConfig.HTTPService = &appconfig.HTTPService{
if appConfig.HTTPService == nil {
appConfig.HTTPService = &appconfig.HTTPService{
ForceHTTPS: true,
AutoStartMachines: fly.Pointer(true),
AutoStopMachines: fly.Pointer(autostop),
MinMachinesRunning: fly.Pointer(0),
Processes: []string{"app"},
}
}
state.appConfig.HTTPService.InternalPort = state.Plan.HttpServicePort
appConfig.HTTPService.InternalPort = plan.HttpServicePort
} else {
state.appConfig.HTTPService = nil
appConfig.HTTPService = nil
}

// Apply plan-level compute overrides to all compute configurations
// Only set fields that haven't already been set (defensive against updateComputeFromDeprecatedGuestFields)
if plan.CPUKind != "" {
for i := range appConfig.Compute {
if isComputeValid(appConfig.Compute[i]) && appConfig.Compute[i].CPUKind == "" {
appConfig.Compute[i].CPUKind = plan.CPUKind
}
}
}

if plan.CPUs != 0 {
for i := range appConfig.Compute {
if isComputeValid(appConfig.Compute[i]) && appConfig.Compute[i].CPUs == 0 {
appConfig.Compute[i].CPUs = plan.CPUs
}
}
}

if plan.MemoryMB != 0 {
for i := range appConfig.Compute {
if isComputeValid(appConfig.Compute[i]) && appConfig.Compute[i].MemoryMB == 0 {
appConfig.Compute[i].MemoryMB = plan.MemoryMB
}
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions internal/command/launch/launch_databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,18 @@ func (state *launchState) createManagedPostgres(ctx context.Context) error {
retry.Delay(2*time.Second),
retry.MaxDelay(30*time.Second),
retry.DelayType(retry.BackOffDelay),
retry.OnRetry(func(n uint, err error) {
// Log network-related errors and periodic status updates
if containsNetworkError(err.Error()) {
s.Stop()
fmt.Fprintf(io.Out, "Retrying status check due to network issue: %v\n", err)
s = spinner.Run(io, colorize.Yellow("Provisioning your Managed Postgres cluster..."))
} else if n%10 == 0 && n > 0 { // Log every 10th attempt to show progress
s.Stop()
fmt.Fprintf(io.Out, "Still waiting for cluster to be ready (attempt %d)...\n", n+1)
s = spinner.Run(io, colorize.Yellow("Provisioning your Managed Postgres cluster..."))
}
}),
)

// Stop the spinner
Expand Down
13 changes: 8 additions & 5 deletions internal/command/launch/launch_frameworks.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/superfly/flyctl/helpers"
"github.com/superfly/flyctl/internal/appconfig"
"github.com/superfly/flyctl/internal/appsecrets"
"github.com/superfly/flyctl/internal/command/launch/plan"
"github.com/superfly/flyctl/internal/flag"
"github.com/superfly/flyctl/internal/flapsutil"
"github.com/superfly/flyctl/internal/flyutil"
Expand All @@ -35,11 +36,13 @@ func (state *launchState) setupGitHubActions(ctx context.Context, appName string
gh, err := exec.LookPath("gh")

if err != nil {
io := iostreams.FromContext(ctx)
colorize := io.ColorScheme()
fmt.Fprintln(io.Out, "Run", colorize.Purple("`fly tokens create deploy -x 999999h`"), "to create a token and set it as the FLY_API_TOKEN secret in your GitHub repository settings")
fmt.Fprintln(io.Out, "See https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions")
fmt.Fprintln(io.Out)
if plan.GetPlanStep(ctx) == "" {
io := iostreams.FromContext(ctx)
colorize := io.ColorScheme()
fmt.Fprintln(io.Out, "Run", colorize.Purple("`fly tokens create deploy -x 999999h`"), "to create a token and set it as the FLY_API_TOKEN secret in your GitHub repository settings")
fmt.Fprintln(io.Out, "See https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions")
fmt.Fprintln(io.Out)
}
} else {
apiClient := flyutil.ClientFromContext(ctx)

Expand Down
Loading
Loading