Skip to content

Commit fbc961f

Browse files
authored
Merge branch 'master' into flypkgs-builds
2 parents 5f2b45c + 08aa3a4 commit fbc961f

File tree

19 files changed

+537
-71
lines changed

19 files changed

+537
-71
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ out
3737

3838
.direnv/
3939
/ci-preflight-test-results.njson
40+
.tool-versions

CONTRIBUTING.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Development flow
2+
3+
4+
## Building
5+
6+
To build `flyctl`, all you need to do is to run `make build` from the root directory. This will build a binary in the `bin/` directory. Alternatively, you can run `go build .`
7+
8+
To run `flyctl`, you can just run the binary you built using `make build`: `./bin/flyctl`. So for example, to update a machine, you can run `go run . m update -a <app_name> <machine_id>`. Alternatively, you can build and run in the same command by running `go run .`, followed by whatever sub-command you want to run. Just note that this will have a slower startup.
9+
10+
11+
## Testing
12+
13+
We have two different kinds of tests in `flyctl`, unit tests and integration tests (preflight). It's recommend to write a test for any features added or bug fixes, in order to prevent regressions in the future.
14+
15+
16+
### Integration tests
17+
18+
Unit tests are stored in individual files next to the functionality they're testing. For example
19+
20+
`internal/command/secrets/parser_test.go`
21+
is a test for the secrets parsing code
22+
23+
`internal/command/secrets/parser_test.go`.
24+
You can run these tests by running `make test` from the root directory.
25+
26+
27+
### Preflight
28+
29+
The integration tests, called preflight, are different. They exist to test flyctl functionality on production infra, in order to make sure that entire commands and workflows don't break. Those are located in the `test/preflight` directory.
30+
31+
For outside contributors, **please be warned that running preflight tests creates real apps and machines and will cost real money**. We already run preflight by default on all pull requests, so we recommend just opening up a draft PR instead. If you work at Fly and want to work on preflight tests, go ahead and continue reading.
32+
33+
Before running any preflight test, you must first set some specific environment variables. It's recommended to set them up using [direnv](https://direnv.net/docs/installation.html). First, copy the `.direnv/preflight-example` file to `.direnv/preflight`. Next, modify `FLY_PREFLIGHT_TEST_FLY_ORG` to an organization you make specifically for testing. Don't use your `personal` org. Modify `FLY_PREFLIGHT_TEST_FLY_REGIONS` to have two regions, ideally ones not the closest ones. For example, `"iad sin"`. Finally, set `FLY_PREFLIGHT_TEST_ACCESS_TOKEN` to whatever `fly auth token` outputs.
34+
35+
To run preflight tests, you can just run `make preflight-test`. If you want to run a specific preflight test, run `make preflight-test T=<test_name>`
36+
37+
If you're trying to decide whether to write a unit test, or an integration test for your change, I recommend just writing a preflight test. They're usually simpler to write, and there's a lot more examples of how to write them.
38+
39+
40+
41+
## Linting
42+
43+
With the trifecta of the development process nearly complete, let's talk about linting. The linter we run is [golangci-lint](https://golangci-lint.run/). It helps with finding potential bugs in programs, as well as helping you follow standard go conventions. To run it locally, just run `golangci-lint --path-prefix=. run`. If you'd like to run all of our [pre-commit lints](https://pre-commit.com/), then run `pre-commit run --all-files`
44+
45+
# Generating the GraphQL Schema
46+
47+
As of writing this, we host our GraphQL schema on `web`, an internal repo that hosts our GQL based API. Unfortunately, that means that outside contributors can't updated the GraphQL schema used by `flyctl`. While there isn't much of a reason why you may want to do so, we're working on automating update the GQL schema in `flyctl`.
48+
49+
Updating the GraphQL schema from web is a manual process at the moment. To do so, `cd` into `web/`, and run `bundle exec rails graphql:schema:idl && cp ./schema.graphql ../flyctl/gql/schema.graphql`, assuming that `flyctl/` is in the same directory as `web/`
50+
51+
52+
# Cutting a release
53+
54+
If you have write access to this repo, you can ship a prerelease with:
55+
56+
`scripts/bump_version.sh prerel`
57+
58+
or a full release with:
59+
60+
`scripts/bump_version.sh`
61+
62+
63+
# Committing to flyctl
64+
65+
When committing to `flyctl`, there are a few important things to keep in mind:
66+
67+
- Keep commits small and focused, it helps greatly when reviewing larger PRs
68+
- Make sure to use descriptive messages in your commit messages, it also helps future people understand why a change was made.
69+
- PRs are squash merged, so please make sure to use descriptive titles
70+
71+
72+
## Examples
73+
74+
[This is a bad example of a commit](https://github.com/superfly/flyctl/pull/1809/commits/6f167c858dbd7ae1324632dda9e29072ddde8ad7), it has a large diff and no explanation as to why this change is being made. [This is a great one](https://github.com/superfly/flyctl/commit/2636f47fe91cbe37018926cb0d7d2227a6887086), since it's a small commit, and it's reasoning as well as the context behind the change. Good commit messages also help contributors in the future to understand *why* we did something a certain way.
75+
76+
77+
# Further Go reading
78+
79+
Go is a weird language full of a million different pitfalls. If you haven't already, I strongly recommend reading through these articles:
80+
81+
- <https://go.dev/doc/effective_go> (just a generally great resource)
82+
- <https://go.dev/blog/go1.13-errors> (error wrapping specifically is useful for a lot of the functionality we use)

README.md

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -98,42 +98,5 @@ There is a simple Powershell script, `winbuild.ps1`, which will run the code gen
9898
Run `scripts/build-dfly` to build a Docker image from the current branch. Then, use `scripts/dfly` to run it. This assumes you are already
9999
authenticated to Fly in your local environment.
100100

101-
## Cutting a release
102-
103-
If you have write access to this repo, you can ship a prerelease or full release with:
104-
105-
`scripts/bump_version.sh prerel`
106-
107-
or
108-
109-
`scripts/bump_version.sh`
110-
111-
## Running preflight tests
112-
113-
A preflight suite of integration tests is located under the test/preflight/ directory. It uses a flyctl binary and runs real user scenarios, including deploying apps and dbs, and validates expected behavior.
114-
115-
**Warning**: Real apps will be deployed that cost real money. The test fixture does its best to destroy resources it creates, but sometimes it may fail to delete a resource.
116-
117-
The easiest way to run the preflight tests is:
118-
119-
Copy `.direnv/preflight-example` to `.direnv/preflight` and edit following these guidelines:
120-
121-
* Grab your auth token from `~/.fly/config.yml`
122-
* Do not use your "personal" org, create an new org (i.e. `flyctl-tests-YOURNAME`)
123-
* Set 2 regions, ideally not your closest region because it leads
124-
to false positives when --region or primary region handling is buggy.
125-
Run `fly platform regions` for valid ids.
126-
127-
Finally run the tests:
128-
129-
make preflight-test
130-
131-
That builds a flyctl binary (just like running `make`), then runs the preflight tests against that binary.
132-
133-
To run a single test:
134-
135-
```
136-
make preflight-test T=TestAppsV2Example
137-
```
138-
139-
Oh, add more preflight tests at `tests/preflight/*`
101+
## Contributing guide
102+
See [CONTRIBUTING.md](./CONTRIBUTING.mdl)

gql/generated.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gql/schema.graphql

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ enum AccessTokenType {
6868
"""
6969
pat
7070

71+
"""
72+
used for Sentry
73+
"""
74+
sentry
75+
76+
"""
77+
access token
78+
"""
79+
token
80+
7181
"""
7282
token generated for our UI frontend
7383
"""
@@ -190,11 +200,6 @@ type AddOn implements Node {
190200
Status of the add-on
191201
"""
192202
status: String
193-
194-
"""
195-
Token for the add-on
196-
"""
197-
token: String
198203
}
199204

200205
"""
@@ -298,16 +303,11 @@ type AddOnProvider {
298303
selectName: Boolean!
299304
selectRegion: Boolean!
300305
selectReplicaRegions: Boolean!
301-
tosAgreement: String!
306+
tosAgreement: String
302307
tosUrl: String
303308
}
304309

305310
enum AddOnType {
306-
"""
307-
A Logtail log receiver
308-
"""
309-
logtail
310-
311311
"""
312312
A PlanetScale database
313313
"""
@@ -323,6 +323,11 @@ enum AddOnType {
323323
"""
324324
sentry
325325

326+
"""
327+
A Supabase database
328+
"""
329+
supabase
330+
326331
"""
327332
An Upstash Redis database
328333
"""
@@ -435,6 +440,11 @@ input AllocateIPAddressInput {
435440
"""
436441
region: String
437442

443+
"""
444+
The name of the associated service
445+
"""
446+
serviceName: String
447+
438448
"""
439449
The type of IP address to allocate (v4, v6, or private_v6)
440450
"""
@@ -1664,6 +1674,11 @@ input BuildVolumeInput {
16641674
"""
16651675
clientMutationId: String
16661676

1677+
"""
1678+
compute requirements for volume placement (cpu, mem, gpu, ...)
1679+
"""
1680+
computeRequirements: JSON
1681+
16671682
"""
16681683
id of host dedication
16691684
"""
@@ -5872,6 +5887,7 @@ type LimitedAccessToken implements Node {
58725887
id: ID!
58735888
name: String!
58745889
organization: Organization!
5890+
profileParams: JSON
58755891
token: String!
58765892
tokenHeader: String
58775893
user: User!
@@ -5957,6 +5973,27 @@ type LogEntry {
59575973
timestamp: ISO8601DateTime!
59585974
}
59595975

5976+
"""
5977+
Autogenerated input type of LogOut
5978+
"""
5979+
input LogOutInput {
5980+
"""
5981+
A unique identifier for the client performing the mutation.
5982+
"""
5983+
clientMutationId: String
5984+
}
5985+
5986+
"""
5987+
Autogenerated return type of LogOut.
5988+
"""
5989+
type LogOutPayload {
5990+
"""
5991+
A unique identifier for the client performing the mutation.
5992+
"""
5993+
clientMutationId: String
5994+
ok: Boolean!
5995+
}
5996+
59605997
type LoggedCertificate implements Node {
59615998
cert: String!
59625999
id: ID!
@@ -6905,6 +6942,12 @@ type Mutations {
69056942
"""
69066943
input: LockAppInput!
69076944
): LockAppPayload
6945+
logOut(
6946+
"""
6947+
Parameters for LogOut
6948+
"""
6949+
input: LogOutInput!
6950+
): LogOutPayload
69086951
migrateVolume(
69096952
"""
69106953
Parameters for MigrateVolume
@@ -7299,7 +7342,7 @@ type Organization implements Node {
72997342
"""
73007343
Single sign-on link for the given integration type
73017344
"""
7302-
addOnSsoLink: String!
7345+
addOnSsoLink: String
73037346

73047347
"""
73057348
List third party integrations associated with an organization

internal/buildinfo/env_dev.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,25 @@ import (
88
"github.com/superfly/flyctl/internal/version"
99
)
1010

11-
var environment = "development"
11+
var (
12+
buildDate = "<date>"
13+
environment = "development"
14+
)
1215

13-
func loadBuildTime() error {
14-
cachedBuildTime = time.Now()
15-
return nil
16+
func loadBuildTime() (err error) {
17+
// Makefile sets proper values for buildDate but bare `go run .` doesn't
18+
if buildDate == "<date>" {
19+
buildDate = time.Now().Format(time.RFC3339)
20+
}
21+
cachedBuildTime, err = time.Parse(time.RFC3339, buildDate)
22+
return
1623
}
1724

1825
func loadVersion() error {
19-
cachedVersion = version.New(cachedBuildTime, "dev", int(cachedBuildTime.Unix()))
26+
// Makefile sets proper values for branchName but bare `go run .` doesn't
27+
if branchName == "" {
28+
branchName = "dev"
29+
}
30+
cachedVersion = version.New(cachedBuildTime, branchName, int(cachedBuildTime.Unix()))
2031
return nil
2132
}

internal/command/deploy/deploy.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ var CommonFlags = flag.Set{
131131
Description: "Maximum number of machines to update concurrently when using the immediate deployment strategy.",
132132
Default: 16,
133133
},
134+
flag.Int{
135+
Name: "volume-initial-size",
136+
Description: "The initial size in GB for volumes created on first deploy",
137+
Default: 1,
138+
},
134139
flag.VMSizeFlags,
135140
}
136141

@@ -324,6 +329,7 @@ func deployToMachines(
324329
ExcludeRegions: excludeRegions,
325330
OnlyRegions: onlyRegions,
326331
ImmediateMaxConcurrent: flag.GetInt(ctx, "immediate-max-concurrent"),
332+
VolumeInitialSize: flag.GetInt(ctx, "volume-initial-size"),
327333
})
328334
if err != nil {
329335
sentry.CaptureExceptionWithAppInfo(err, "deploy", appCompact)

internal/command/deploy/deploy_first.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,17 @@ func (md *machineDeployment) provisionVolumesOnFirstDeploy(ctx context.Context)
107107
continue
108108
}
109109

110-
fmt.Fprintf(md.io.Out, "Creating 1GB volume '%s' for process group '%s'. Use 'fly vol extend' to increase its size\n", m.Source, groupName)
110+
fmt.Fprintf(
111+
md.io.Out,
112+
"Creating a %d GB volume named '%s' for process group '%s'. "+
113+
"Use 'fly vol extend' to increase its size\n",
114+
md.volumeInitialSize, m.Source, groupName,
115+
)
111116

112117
input := api.CreateVolumeRequest{
113118
Name: m.Source,
114119
Region: groupConfig.PrimaryRegion,
115-
SizeGb: api.Pointer(1),
120+
SizeGb: api.Pointer(md.volumeInitialSize),
116121
Encrypted: api.Pointer(true),
117122
HostDedicationId: md.appConfig.HostDedicationID,
118123
ComputeRequirements: md.machineGuest,

internal/command/deploy/machines.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type MachineDeploymentArgs struct {
5454
ExcludeRegions map[string]interface{}
5555
OnlyRegions map[string]interface{}
5656
ImmediateMaxConcurrent int
57+
VolumeInitialSize int
5758
}
5859

5960
type machineDeployment struct {
@@ -87,6 +88,7 @@ type machineDeployment struct {
8788
excludeRegions map[string]interface{}
8889
onlyRegions map[string]interface{}
8990
immediateMaxConcurrent int
91+
volumeInitialSize int
9092
}
9193

9294
func NewMachineDeployment(ctx context.Context, args MachineDeploymentArgs) (MachineDeployment, error) {
@@ -147,6 +149,10 @@ func NewMachineDeployment(ctx context.Context, args MachineDeploymentArgs) (Mach
147149
if immedateMaxConcurrent < 1 {
148150
immedateMaxConcurrent = 1
149151
}
152+
volumeInitialSize := 1
153+
if args.VolumeInitialSize > 0 {
154+
volumeInitialSize = args.VolumeInitialSize
155+
}
150156

151157
md := &machineDeployment{
152158
apiClient: apiClient,
@@ -172,6 +178,7 @@ func NewMachineDeployment(ctx context.Context, args MachineDeploymentArgs) (Mach
172178
excludeRegions: args.ExcludeRegions,
173179
onlyRegions: args.OnlyRegions,
174180
immediateMaxConcurrent: immedateMaxConcurrent,
181+
volumeInitialSize: volumeInitialSize,
175182
}
176183
if err := md.setStrategy(); err != nil {
177184
return nil, err

0 commit comments

Comments
 (0)