Heroku - push subtrees to different apps - heroku

I have a two-part app (a Phoenix API and a React front-end) that I want to deploy to Heroku... the back-end and front-end need to run on separate servers, but the current app structure is like so:
app/
|
+ Phoenix/
|
+ React/
|
+ .git/
So both parts of the app are in the same git repo.
Within app/, I created two different Heroku apps - I'll call them phoenix-heroku-app and react-heroku-app. My plan is to use the git subtree method to push these apps up to Heroku, but I'm not sure how to specify where each should go.
When I run heroku apps, this correctly lists
phoenix-heroku-app
react-heroku-app
So they're both there... but when I use a command like
$ git subtree push --prefix Phoenix heroku master
$ git subtree push --prefix React heroku master
what is the syntax to point each of these pushes toward the correct app?

Following #bouteillebleu's suggestion, I was able to handle this like so...
First, I needed to add Heroku endpoints for the two apps in the parent directory -
$ git remote add phoenix-heroku-app https://git.heroku.com/phoenix-heroku-app.git
$ git remote add react-heroku-app https://git.heroku.com/react-heroku-app.git
Then I just needed to run
$ git subtree push --prefix Phoenix phoenix-heroku-app master
$ git subtree push --prefix React react-heroku-app master
and it was good to go.

Related

Why does my Heroku remote repository all of a sudden supposedly contain something that I don't have locally?

I created an app on Heroku using the CLI:
heroku apps:create --region eu myapp
Then in my app's GitHub repository I created a GitHub action to deploy the app on Heroku by pushing a subtree of the repository:
git remote add heroku https://heroku:${{ secrets.HEROKU_API_KEY }}#git.heroku.com/myapp.git
git subtree push --prefix path/to/myapp heroku main
Then I triggered the action, and it worked perfectly just as intended; the app got deployed on Heroku.
Next, I edited a line of the app's source on GitHub, committed and triggered the pipeline just to test that the action works (as it was configured to trigger on pushes to main). The action triggered but then failed with a git error saying that the remote (Heroku remote repository) contains some work that I don't have "locally" (in the GitHub repository where the action was triggered from). I did not push anything to the Heroku remote repository in between, and nobody else has access to the remote either. I just created the app as described. How can the remote have something that I do not have locally?
EDIT1:
After further inspection it looks like the git subtree push command produces a different kind of git log when issued from the GitHub actions workflow agent vs. when issued from my local system. The former produces a git log where all of the commits up to that point are somehow squashed into one, whereas the latter produces a full git log including all the commits normally up to that point. Therefore the last commits' hashes are different even though the files are "in the same state" at that point.
Does the discrepancy come from differing git config --list or is there something more to this? And what would I need to change in the GitHub workflow's git config to make it not ruin the last commit's hash by doing this not-asked-for squashing? (Assuming the last commit's hash is the issue here.)
Here's the git config that the GitHub workflow agent appears to use:
$ git config --list
safe.directory=*
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=https://github.com/mynick/myreponame
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
gc.auto=0
http.https://github.com/.extraheader=AUTHORIZATION: basic ***
branch.main.remote=origin
branch.main.merge=refs/heads/main

Heroku can't find package.json during build although I have it

When I push my node app to heroku master I get this log
remote: Building source:
remote:
remote: -----> App not compatible with buildpack: https://codon-
buildpacks.s3.amazonaws.com/buildpacks/heroku/nodejs.tgz
remote: Node.js: package.json not found in application root
I can't find the reason why this would happen as I clearly have in my root directory. I checked using git ls-files and it appears.
Is it possible that my application root is not the same as my repository root? How would one config that?
It seems that when I push to heroku master, heroku pushes the main branch of my local repository to heroku instead of the branch I'm currently in. So what I had to do was pushing with:
git push heroku mybranchname:master
so that my branch (not the master) gets pushed
One common issue is not having added the files to git.
You might be having package.json in your root directory on you device, without adding it to git, heroku can't find it.
Please check status to confirm and add if not added already
git status
git add .
then followed by the usual
git push heroku master assuming you are on the master branch.
Hope this helps.
I think just pushing a branch and not the master should fix it. If you do not have a branch, I suggest you create one and push with that.

Building a dev environment in Heroku for Phoenix

I'm trying to set up Phoenix 1.2 so that I have two Heroku environments: one for dev/testing (which will keep the this-app-12345.herokuapp.com url), and a standard production environment.
Currently, I set up my app the usual way:
mix phoenix.new my_app
cd my_app
mix ecto.create
mix ecto.migrate
git init && git add . && git commit -m "Initial commit"
heroku create
This gives me a Heroku instance:
Creating app... done, ⬢ first-instance-12345
https://first-instance-12345.herokuapp.com/ | https://git.heroku.com/first-instance-12345.git
I then add the buildpacks, change the config/ files and run git push heroku master and everything works.
Now I'd like to create another Heroku instance, to which I can also deploy. If I run heroku create again, I get:
Creating app... done, ⬢ second-instance-23456
https://second-instance-23456.herokuapp.com/ | https://git.heroku.com/second-instance-23456.git
If I replace the url in prod.exs with the new instance...
config :my_app, MyApp.Endpoint,
http: [port: {:system, "PORT"}],
url: [scheme: "https", host: "second-instance-23456.herokuapp.com", port: 443], force_ssl: [rewrite_on: [:x_forwarded_proto]],
...and then commit and run git push heroku master, it will still deploy to first-instance-12345.herokuapp.com, which isn't what I want.
Re-running buildpacks doesn't help either.
$ heroku buildpacks:add https://github.com/HashNuke/heroku-buildpack-elixir
▸ The buildpack https://github.com/HashNuke/heroku-buildpack-elixir is already set on your app.
$ heroku buildpacks:add https://github.com/gjaldon/phoenix-static-buildpack
▸ The buildpack https://github.com/gjaldon/phoenix-static-buildpack is already set on your app.
Is there a standard method (or any method) to get Phoenix to deploy to multiple heroku environments? (And hopefully specify which one/s on deploy)
The standard way to deploy an app to multiple Heroku apps is to add multiple remotes to the repo and push to the one you want to deploy to. Making that change to config/prod.exs will have no effect on where the app is deployed.
Here's how to add the two remotes:
$ git remote add first https://git.heroku.com/first-instance-12345.git
$ git remote add second https://git.heroku.com/second-instance-23456.git
Now you can deploy to the first one using:
$ git push first master
and to the second using:
$ git push second master
Certainly the best way to do so is to have two different instances as #dogbert wrote.
Also remember about changing Procfile for heroku, because you want to run app using different environments eg.
# Procfile for prod
web: MIX_ENV=prod mix phoenix.server
# Procfile for dev
web: MIX_ENV=dev mix phoenix.server
For both environments you would need to apply migrations:
heroku run MIX_ENV=<env> ecto.migrate

Managing Heroku Multiple environments with existing app

I've got an app, that has 'heroku' configured as a remote, to one application.
Let's call this app 'MyAppDev'
However, I have another app, called 'MyAppLive'
I want to configure deployment like this:
git push staging
push to MyAppDev
git push production
push to MyAppLive
How can I do this?
Also, what about environment variables?
Both apps have MongoLab, so I'd like the MyAppDev app to use it's own db....
Here are the steps that you'd need to follow
git remote rm heroku - this will remove the heroku remote from your application
git remote add production <production apps heroku git repo url> - this will add a new remote named 'production' pointing at the production apps git repo url (you can get this from the My Apps page on heroku.com
git remote add staging <staging apps heroku git repo url>
This now means you can do git push production master or git push staging master to push your codebase to either repo.
NOTE If you need to push branches to Heroku you need to push them into the master branch of Heroku.
eg. assuming a staging branch locally you would do;
git push staging staging:master
To push your locally staging branch into master of the staging remote.
Any addons you use would need to be duplicated to the staging application.
Config variables can either be done manually via heroku config:set or you can use the plugin detailed at the bottom of this page https://devcenter.heroku.com/articles/config-vars which allows you to push and pull your Heroku variables into a .env file suitable for running with Foreman locally. Becareful about overriding variables though - I tend to do my variables manually as I don't typically have many.

GIt Deployment + Configuration Files + Heroku

I'm using Heroku to host a Rails app, which means using Git to deploy to Heroku. Because of the "pure Git workflow" on Heroku, anything that needs to go upstream to the server has to be configured identically on my local box.
However I need to have certain configuration files be different depending on whether I'm in the local setup or deployed on Heroku. Again, because of the deployment method Heroku uses I can't use .gitignore and a template (as I have seen suggested many times, and have used in other projects).
What I need is for git to somehow track changes on a file, but selectively tell git not to override certain files when pulling from a particular repo -- basically to make certain changes one-way only.
Can this be done? I'd appreciate any suggestions!
You can have config vars persistently stored ON each heroku app's local setup so they do not have to be in your code at all! so the same code can run on multiple heroku sites but with different configuration. It very simple, easy, elegant...
It's the approach we used. (We used it for the SAME thing... we have multiple clones of the SAME app at Heroku, but we want only ONE source at github, in our dev local directory we do the PUSH to ORIGIN (github), then when we have it the way we like it, we CD to the prod local directory, which goes to the SAME github repository, and we ONLY PULL from GITHUB into this directory, never push (eg, all pushes to github come from our dev directory, the prod directory is just a staging area for the other heroku app.)
By having the different configs ON the different HEROKU sites (as explained below), the EXACT SAME CODE works on BOTH heroku sites.
So our workflow is: (the key is that BOTH directories point to SAME github repo)
cd myDEVdir
*....develop away....*
git add .
git commit -am "another day, another push"
git push origin *(to our SINGLE github repo)*
git push heroku *(test it out on heroku #1)*
cd ../myPRODdir
git pull *(grabs SAME code as used on other site *)
git push heroku *(now the SAME code runs on Heroku #2)*
that's it!
Now here's how you keep your site-specific config vars ON the heroku site:
http://docs.heroku.com/config-vars
on your local command line, for EACH of your two local directories, do:
$ heroku config:add FIRST_CONFIGVAR=fooheroku1
Adding config vars:
FIRST_CONFIGVAR => fooheroku1
$ heroku config:add SECOND_CONFIGVAR=barheroku1
Adding config vars:
SECOND_CONFIGVAR => barheroku1
to see the ones you have defined:
$ heroku config
FIRST_CONFIGVAR => fooheroku1
SECOND_CONFIGVAR => barheroku1
then cd to your other directory myPRODdir and do the SAME thing, only set the same remote heroku vars to fooheroku2 and barheroku2.
then in your rails app you simple refer to them like so:
a = ENV['FIRST_CONFIGVAR']
One app will read 'fooheroku1' the other app will read 'fooheroku2'
And finally, on your LOCAL directory myDEVdir, where you run in DEV mode, put the same config commands in your config/environment/development.rb file your 'dev' version of the config vars will be set to whatever they should be:
ENV['FIRST_CONFIGVAR'] = "foodev"
ENV['SECOND_CONFIGVAR'] = "bardev"
Easy, elegant. Thanks, Heroku!
Here are a few solutions:
1) If you want to ignore files only on heroku, use slugignore
2) If your changes are minor, stay DRY and use universal config files, inserting switches for server-specific behavior
if Rails.env == "production"
#production server code
elsif Rails.env == "development"
#development server code
else
#test server code
end
3) If your changes are major, write one config file and add a "smudge file" to config/initializers for each additional server. Basically, you would have separate files using the technique in (2).
4) If your changes are SWEEPING (unlikely), then maintain separate branches for each server.
5) This script can do exactly what you requested, but may be overkill.
I hope that helped.

Resources