-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deploy option to enable continuous deployment #1745
base: main
Are you sure you want to change the base?
Conversation
… continuousDeployment for the first time
… primary branch in our db to current branch; add some periods to some messages where it seems appropriate for consistency
Co-authored-by: Mike Bostock <[email protected]>
src/deploy.ts
Outdated
// Disables continuous deployment if there’s no env/source & we can’t link GitHub | ||
if (continuousDeployment) continuousDeployment = await this.maybeLinkGitHub(deployTarget); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fil says: if you enable continuous deployment, it should stay on, and if we can't connect to github for whatever reason (you're not in a repo, or no git remote, or no link in our database), the deploy should just fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, and it feels like a much better way to think about it
workspaceLogin: deployTarget.workspace.login, | ||
projectSlug: deployTarget.project.slug | ||
}); | ||
if (latestCreatedDeployId !== deployTarget.project.latestCreatedDeployId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chatting with fil: there's no guarantee that the new deploy ID is the one you just kicked off; maybe your colleague click the deploy button around the same time. currently, the postProjectBuild method can't return the new deploy ID because it just dispatches a message to the job-manager, which at some point will get around to making a new deploy. two options:
- create deploy id earlier, in api, and pass to job manager (which feels like it might mess with our messaging protocol? i don't know all the reasons it was designed like it is today)
- pass some unique string to the api, which will pass it to the job manager, which will eventually respond with it, which would let us identify that the deploy was our own
but fil thinks this is probably not a blocking issue with this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not planning to do anything about this for now
const deployConfig = await this.getUpdatedDeployConfig(); | ||
const deployTarget = await this.getDeployTarget(deployConfig); | ||
const buildFilePaths = await this.getBuildFilePaths(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fil notes that this could be parallelized: getBuildFilePaths doesn't depend on the previous two; it's filesystem i/o, as opposed to talking to the api. might speed up local deploys a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not gonna worry about this for now; also, buildFilePaths is only relevant for the local deploy path, so it's not as clean to parallelize anymore
src/deploy.ts
Outdated
if (deployTarget.environment.build_environment_id && deployTarget.environment.source) { | ||
// can do cloud build | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fil notes: if we broke our local git configuration, shouldn't we check it? do we want to check if everything is correct? there's a good chance everything will work, but…
if you have erased your .git folder, or you have changed your remotes, or if you're not on the right branch…
should we check that local and remote git refs match?? the user is expecting a cloud deploy of the same application state they are looking at locally!! if they have local unstaged changes, or are on a different branch, they could get surprising results from doing a cloud build.
if observable cloud is configured to pull from the main branch, and you're on toph/onramp locally, what are you expecting to happen when you run yarn deploy
?
and it'll get more confusing with branch previews. how does it work on vercel? on vercel, there's no way to trigger a deploy except to push, so there's no question here. maybe that should be our norm? except you still wanna be able to re-run data loaders, which depend on changing external state not captured by commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe at a minimum we should just check that the local git repo still exists, still has that remote, and is on the same branch. (i.e. move all the tests in the "else" block up above the if/else.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should also verify that the repo hasnt been unlinked on the web side
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done — now validates repo every time and checks that local and remote repos match. i don't check refs yet; not planning to do it in this PR.
src/deploy.ts
Outdated
return true; | ||
} else { | ||
// We only support cloud builds from the root directory so this ignores this.deployOptions.config.root | ||
const isGit = existsSync(".git"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: log cwd when running yarn deploy. you can run yarn deploy from a child directory like src, but i think it still runs in the context of the root directory, in which case this is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tried logging cwd out of curiosity and indeed, as one would hope/expect, yarn deploy runs in the root directory no matter where you call it from.
src/deploy.ts
Outdated
// We only support cloud builds from the root directory so this ignores this.deployOptions.config.root | ||
const isGit = existsSync(".git"); | ||
if (isGit) { | ||
const remotes = (await promisify(exec)("git remote -v", {cwd: this.deployOptions.config.root})).stdout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note that in loader.ts we make our promises "by hand" (and with spawn instead of exec), but in create.ts we already use promisify, so… seems fine!
src/deploy.ts
Outdated
.split("\n") | ||
.filter((d) => d) | ||
.map((d) => d.split(/\s/g)); | ||
const gitHub = remotes.find(([, url]) => url.startsWith("https://github.com/")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fil instead has, i think, the SSH case, which we should also check for:
❯ git remote -v
observable [email protected]:observablehq/pangea.git (fetch)
observable [email protected]:observablehq/pangea.git (push)
origin [email protected]:Fil/pangea.git (fetch)
origin [email protected]:Fil/pangea.git (push)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/deploy.ts
Outdated
.map((d) => d.split(/\s/g)); | ||
const gitHub = remotes.find(([, url]) => url.startsWith("https://github.com/")); | ||
if (gitHub) { | ||
const repoName = formatGitUrl(gitHub[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatGitUrl will also be different in the SSH case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/deploy.ts
Outdated
if (authedRepo) { | ||
// Set branch to current branch | ||
const branch = ( | ||
await promisify(exec)("git rev-parse --abbrev-ref HEAD", {cwd: this.deployOptions.config.root}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think cwd may be wrong here, it should be running in the normal cwd of the command, at the root, since we don't support non-root repos/projects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think it matters for this command but it was unnecessary and conceptually wrong so i removed the cwd option
src/deploy.ts
Outdated
} | ||
} | ||
} else { | ||
this.effects.clack.log.error("No GitHub remote found; cannot enable continuous deployment."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these should exit with a CliError rather than just logging a message and continuing on with a local deploy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. overall, after fil's feedback in last review, i adopted a philosophy of: when a setting is set, don't change it back just because it's not working; instead, exit with an informative error.
src/deploy.ts
Outdated
`Do you want to enable continuous deployment? ${faint( | ||
"This builds in the cloud and redeploys whenever you push to this repository." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunstan says this could note upfront that continuous deployment requires a GitHub repository
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
…ix prettttier thing i missed
…lling back other forcing things to see if i still need them
…ck up to status quo ante; fix polling for auth to respect deployOptions.deployPollInterval, though one could argue its now too narrowly named
…stuff isnt isolated so running the tests changed my email and name. happy to have you as a collaborator, Observable User. removed --global flag... duh...
2fbd17b
to
1a5c9f9
Compare
…init FIRST, duh duh duh
…ult branch after repo is already made, which of course does nothing for the current repo
I think this is ready for review again! PurposeThe idea is that, when a user runs Note that the deploy command ensures you’re currently in the same repo and branch that’s configured in our database. (We could go further and add some info to the API response so we can check that the refs match.) The idea is that you’re trying to deploy the state of the repo you’re in, not just controlling the data app management console from a command line in a repo in some different state. Note that currently there’s no CLI command to change the continuousDeployment setting once set; Fil suggested we could have a separate command to review all settings in deploy.json, but I’m inclined to save that for another PR. ImplementationWhen run manually from the command line (as opposed to in our cloud build environment where we pass in an existing deploy ID), running deploy calls startNewDeploy. It calls getDeployTarget to find out where it’s deploying to; in this PR, I’ve updated getDeployTarget to check the continuousDeployment option; if it’s not present, we prompt the user whether to enable it. Back in startNewDeploy, if continuousDeployment is on, we call validateGitHubLink and then cloudBuild; else we build locally and deploy as usual. (validateGitHubLink checks that you have an authorized and matching repo linked in our database; if not, and you’re in a repo with a GitHub remote, we link it, or prompt you to go to the web (to a new screen added in https://github.com/observablehq/observablehq/pull/18314) to authorize it if necessary.) This adds dependencies on a couple API routes:
|
docs/deploying.md
Outdated
|
||
After deploying an app manually at least once, Observable can handle subsequent deploys for you automatically. You can automate deploys both [on commit](https://observablehq.com/documentation/data-apps/github) (whenever you push a new commit to your project’s default branch) and [on schedule](https://observablehq.com/documentation/data-apps/schedules) (such as daily or weekly). | ||
<!-- TODO: decide whether to primarily use “continuous deployment” or “automatic deploys” --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe CD is the accepted industry term
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review and suggestions #1805
I wonder if we could/should provide a post-commit or post-push hook that would remind the user that their push is going to trigger a build (and where to see the logs etc). (I was just editing a project and could not remember if I had already enabled CD on it.) |
* documentation * reformat and type * simpler * clarify the logic in validateGitHubLink fixes an uncaught Error ('Setting source repository for continuous deployment failed' was never reached)
// the root directory. | ||
private async validateGitHubLink(deployTarget: DeployTargetInfo): Promise<void> { | ||
if (deployTarget.create) throw new Error("Incorrect deploy target state"); | ||
if (!deployTarget.project.build_environment_id) throw new CliError("No build environment configured."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we could add a link to the build settings page maybe?
something like https://observablehq.com/projects/@{user}/{data-app-slug}/settings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I undo my "Request changes" status without giving approval?
Edit: NO.
@Fil You can dismiss your review. |
Running notes