From 73756dd859d183b339797003f5c12ac05018327b Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Fri, 26 Jul 2019 13:46:50 +0100 Subject: [PATCH 01/11] Move backend routes to /api and add proxy for dev --- api/config/routes.rb | 36 +++++++++++++++++++----------------- web/package.json | 1 + web/public/config.js | 4 ++-- web/src/setupProxy.js | 6 ++++++ 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 web/src/setupProxy.js diff --git a/api/config/routes.rb b/api/config/routes.rb index 824f884..f428b9f 100644 --- a/api/config/routes.rb +++ b/api/config/routes.rb @@ -32,26 +32,28 @@ devise_for :admin_users, ActiveAdmin::Devise.config ActiveAdmin.routes(self) - put '/retros/:id/archive', to: 'retros#archive' - patch '/retros/:id/password', to: 'retros#update_password', as: :retro_update_password + scope '/api' do + put '/retros/:id/archive', to: 'retros#archive' + patch '/retros/:id/password', to: 'retros#update_password', as: :retro_update_password - get '/config', to: 'config#show' + get '/config', to: 'config#show' - resources :oauth_sessions, path: 'sessions', only: [:create] - resources :users, only: [:create] + resources :oauth_sessions, path: 'sessions', only: [:create] + resources :users, only: [:create] - resources :retros, only: [:index, :create, :show, :update] do - resources :archives, only: [:index, :show] - resources :settings, only: [:index] - resources :action_items, only: [:create, :destroy, :update] - resources :items, only: [:create, :update, :destroy] do - patch 'done', to: :done, controller: 'items' - post 'vote', to: :vote, controller: 'items' - end - resource :discussion, only: [:create, :destroy, :update] do - post 'transitions', controller: 'transitions' - end + resources :retros, only: [:index, :create, :show, :update] do + resources :archives, only: [:index, :show] + resources :settings, only: [:index] + resources :action_items, only: [:create, :destroy, :update] + resources :items, only: [:create, :update, :destroy] do + patch 'done', to: :done, controller: 'items' + post 'vote', to: :vote, controller: 'items' + end + resource :discussion, only: [:create, :destroy, :update] do + post 'transitions', controller: 'transitions' + end - resources :sessions, only: [:new, :create] + resources :sessions, only: [:new, :create] + end end end diff --git a/web/package.json b/web/package.json index e298459..8c27d66 100644 --- a/web/package.json +++ b/web/package.json @@ -6,6 +6,7 @@ "actioncable": "^5.2.2", "foundation-sites": "6.5.3", "grapnel": "^0.7.0", + "http-proxy-middleware": "^0.19.1", "material-ui": "^0.20.2", "mixpanel-browser": "^2.26.0", "node-sass": "^4.12.0", diff --git a/web/public/config.js b/web/public/config.js index 7c34f32..b0ca2e5 100644 --- a/web/public/config.js +++ b/web/public/config.js @@ -10,8 +10,8 @@ window.Retro = { "useRevManifest": false, "hotModule": true, "useWebpackDevMiddleware": true, - "api_base_url": "http://localhost:4000", - "websocket_url": "ws://localhost:4000/cable", + "api_base_url": "/api", + "websocket_url": "/cable", "enable_analytics": false, "contact": "mailto:postfacto@example.com", "terms": "https://loripsum.net/api", diff --git a/web/src/setupProxy.js b/web/src/setupProxy.js new file mode 100644 index 0000000..98b9db3 --- /dev/null +++ b/web/src/setupProxy.js @@ -0,0 +1,6 @@ +const proxy = require("http-proxy-middleware"); + +module.exports = app => { + app.use(proxy("/cable", { target: "http://localhost:4000", ws: true })); + app.use(proxy("/api", { target: "http://localhost:4000" })); +}; From 875b1995ef8a26f346f9518841a8b52911f5f703 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Fri, 26 Jul 2019 13:57:53 +0100 Subject: [PATCH 02/11] Fix links in API tests --- .../requests/oauth_sessions_request_spec.rb | 16 ++++----- api/spec/requests/retros_request_spec.rb | 33 ++++++++++--------- api/spec/requests/settings_request_spec.rb | 4 +-- api/spec/requests/users_request_spec.rb | 26 +++++++-------- web/src/setupProxy.js | 8 ++--- 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/api/spec/requests/oauth_sessions_request_spec.rb b/api/spec/requests/oauth_sessions_request_spec.rb index 7cae070..42278b8 100644 --- a/api/spec/requests/oauth_sessions_request_spec.rb +++ b/api/spec/requests/oauth_sessions_request_spec.rb @@ -47,7 +47,7 @@ end it 'returns user details' do - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response.status).to eq(200) @@ -76,7 +76,7 @@ end it 'returns user details' do - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response.status).to eq(200) @@ -85,7 +85,7 @@ end it 'returns a token' do - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response.status).to eq(200) @@ -107,7 +107,7 @@ end it 'responds with an expiring token' do - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json data = JSON.parse(response.body) jwt = JWT.decode(data['auth_token'], nil, false) @@ -129,7 +129,7 @@ end it 'returns 404' do - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response.status).to eq(404) end @@ -143,7 +143,7 @@ end it 'returns 500' do - post '/sessions', params: { access_token: 'invalid-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'invalid-access-token' }, as: :json expect(response.status).to eq(500) end @@ -155,7 +155,7 @@ .with('the-access-token') .and_raise(GoogleClient::InvalidUserDomain.new) - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response).to be_forbidden end @@ -168,7 +168,7 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/sessions', params: { access_token: 'the-access-token' }, as: :json + post '/api/sessions', params: { access_token: 'the-access-token' }, as: :json expect(response).to be_not_found end end diff --git a/api/spec/requests/retros_request_spec.rb b/api/spec/requests/retros_request_spec.rb index 6b3634f..326304a 100644 --- a/api/spec/requests/retros_request_spec.rb +++ b/api/spec/requests/retros_request_spec.rb @@ -49,9 +49,11 @@ context 'when auth header is provided' do let(:user) { User.create!(email: 'test@test.io', name: 'random') } before do - post '/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, - params: { retro: { name: 'the new retro', slug: 'my-retro-url', password: 'the-password' } }, - as: :json + post '/api/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, + params: { + retro: { name: 'the new retro', slug: 'my-retro-url', password: 'the-password' } + }, + as: :json end it 'returns the retro' do @@ -78,14 +80,15 @@ expect(retro.action_items.count).to eq 2 expect do - post '/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, params: { retro: { name: 'the second retro' } } + post '/api/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, + params: { retro: { name: 'the second retro' } } end.to_not change { [Item.count, ActionItem.count] } end end context 'when auth header is not provided' do it 'responds with forbidden' do - post '/retros', params: { retro: { name: 'the new retro', password: 'the-password' } }, as: :json + post '/api/retros', params: { retro: { name: 'the new retro', password: 'the-password' } }, as: :json expect(response).to be_forbidden end @@ -96,9 +99,9 @@ it 'returns unprocessable entity with error message' do # Create retro with same slug - post '/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, - params: { retro: { name: 'the new retro', slug: retro.slug, password: 'the-password' } }, - as: :json + post '/api/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, + params: { retro: { name: 'the new retro', slug: retro.slug, password: 'the-password' } }, + as: :json expect(response).to have_http_status(:unprocessable_entity) end @@ -112,7 +115,7 @@ before do user.retros.create(name: 'Felicity Frog') user.retros.create(name: 'Frog Felicity') - get '/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, as: :json + get '/api/retros', headers: { 'X-AUTH-TOKEN': token_for(user) }, as: :json end it 'returns a list of retros' do @@ -126,7 +129,7 @@ let(:user) { User.create!(email: 'test@test.io', name: 'random') } before do - get '/retros', headers: { 'X-AUTH-TOKEN': 'not-a-valid-token' }, as: :json + get '/api/retros', headers: { 'X-AUTH-TOKEN': 'not-a-valid-token' }, as: :json end it 'returns 403 Forbidden' do @@ -136,7 +139,7 @@ context 'when auth header is not provided' do before do - get '/retros', as: :json + get '/api/retros', as: :json end it 'returns 403 Forbidden' do @@ -162,7 +165,7 @@ end it 'returns the retro with the given slug' do - status = get "/retros/#{retro.slug}", headers: { HTTP_AUTHORIZATION: token }, as: :json + status = get "/api/retros/#{retro.slug}", headers: { HTTP_AUTHORIZATION: token }, as: :json expect(status).to eq(200) data = JSON.parse(response.body) @@ -204,7 +207,7 @@ context 'when not authenticated' do context 'public retro' do it 'returns 200 OK when the slug is used' do - status = get "/retros/#{retro.slug}", as: :json + status = get "/api/retros/#{retro.slug}", as: :json expect(status).to eq(200) end @@ -217,7 +220,7 @@ it 'returns 403 Forbidden' do retro.update(is_private: true) - status = get "/retros/#{retro.slug}", as: :json + status = get "/api/retros/#{retro.slug}", as: :json expect(status).to eq(403) end end @@ -226,7 +229,7 @@ context 'when such a retro with that slug does not exist' do it 'responds with a http 404 json string' do headers = { HTTP_AUTHORIZATION: token } - get "/retros/#{retro.id}", headers: headers, as: :json + get "/api/retros/#{retro.id}", headers: headers, as: :json expect(response).to have_http_status(:not_found) expect(response.content_type).to eq('application/json') diff --git a/api/spec/requests/settings_request_spec.rb b/api/spec/requests/settings_request_spec.rb index c289e1a..2fab8b3 100644 --- a/api/spec/requests/settings_request_spec.rb +++ b/api/spec/requests/settings_request_spec.rb @@ -39,7 +39,7 @@ describe 'GET /' do context 'when auth header is provided' do it 'returns the updated retro' do - get "/retros/#{retro.id}/settings", headers: { HTTP_AUTHORIZATION: token }, as: :json + get "/api/retros/#{retro.id}/settings", headers: { HTTP_AUTHORIZATION: token }, as: :json expect(response.status).to eq(200) @@ -53,7 +53,7 @@ context 'when not authenticated' do it 'returns forbidden' do - get "/retros/#{retro.id}/settings", headers: {}, as: :json + get "/api/retros/#{retro.id}/settings", headers: {}, as: :json expect(response.status).to eq(403) end diff --git a/api/spec/requests/users_request_spec.rb b/api/spec/requests/users_request_spec.rb index e2c3f75..ea62502 100644 --- a/api/spec/requests/users_request_spec.rb +++ b/api/spec/requests/users_request_spec.rb @@ -42,8 +42,8 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', - full_name: 'Felicity Toad' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', + full_name: 'Felicity Toad' }, as: :json expect(response).to be_created @@ -62,8 +62,8 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', - full_name: 'Felicity Toad' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', + full_name: 'Felicity Toad' }, as: :json data = JSON.parse(response.body) jwt = JWT.decode(data['auth_token'], nil, false) @@ -89,8 +89,8 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', - full_name: 'Felicity Toad' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', + full_name: 'Felicity Toad' }, as: :json data = JSON.parse(response.body) jwt = JWT.decode(data['auth_token'], nil, false) @@ -110,8 +110,8 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token', company_name: 'Irrelevant', - full_name: 'Irrelevant' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Irrelevant', + full_name: 'Irrelevant' }, as: :json expect(response.status).to eq(300) end @@ -127,7 +127,7 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token' }, as: :json + post '/api/users', params: { access_token: 'the-access-token' }, as: :json expect(response).to be_created expect(User.last.company_name).to be_nil @@ -140,8 +140,8 @@ .with('the-access-token') .and_raise(GoogleClient::InvalidUserDomain.new) - post '/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', - full_name: 'Felicity Toad' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', + full_name: 'Felicity Toad' }, as: :json expect(response).to be_forbidden end @@ -155,8 +155,8 @@ expect(GOOGLE_CLIENT).to receive(:get_user!).with('the-access-token').and_return(google_user_data) - post '/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', - full_name: 'Felicity Toad' }, as: :json + post '/api/users', params: { access_token: 'the-access-token', company_name: 'Felicity Corps', + full_name: 'Felicity Toad' }, as: :json expect(response).to be_created end diff --git a/web/src/setupProxy.js b/web/src/setupProxy.js index 98b9db3..7778b0c 100644 --- a/web/src/setupProxy.js +++ b/web/src/setupProxy.js @@ -1,6 +1,6 @@ -const proxy = require("http-proxy-middleware"); +const proxy = require('http-proxy-middleware'); -module.exports = app => { - app.use(proxy("/cable", { target: "http://localhost:4000", ws: true })); - app.use(proxy("/api", { target: "http://localhost:4000" })); +module.exports = (app) => { + app.use(proxy('/cable', {target: 'http://localhost:4000', ws: true})); + app.use(proxy('/api', {target: 'http://localhost:4000'})); }; From 54be35065c68f123368fbbd11ecc3f4441adba6b Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Fri, 26 Jul 2019 15:09:31 +0100 Subject: [PATCH 03/11] E2E test with client merged into server --- api/.gitignore | 10 +++++++ api/app/controllers/static_controller.rb | 35 ++++++++++++++++++++++++ api/config/routes.rb | 4 +++ e2e.sh | 22 ++++++--------- e2e/spec/spec_helper.rb | 2 +- 5 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 api/app/controllers/static_controller.rb diff --git a/api/.gitignore b/api/.gitignore index 279621b..ee5c85a 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -26,3 +26,13 @@ vendor /.idea postfacto-api.iml db/schema.rb + +# Ignore public client files +/public +!/public/404.html +!/public/422.html +!/public/500.html +!/public/apple-touch-icon-precomposed.png +!/public/apple-touch-icon.png +!/public/favicon.ico +!/public/robots.txt diff --git a/api/app/controllers/static_controller.rb b/api/app/controllers/static_controller.rb new file mode 100644 index 0000000..03fca2d --- /dev/null +++ b/api/app/controllers/static_controller.rb @@ -0,0 +1,35 @@ +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +class StaticController < ApplicationController + def home + render file: 'public/index.html', layout: false + end +end diff --git a/api/config/routes.rb b/api/config/routes.rb index f428b9f..94dbc7f 100644 --- a/api/config/routes.rb +++ b/api/config/routes.rb @@ -56,4 +56,8 @@ resources :sessions, only: [:new, :create] end end + + # pushstate routing + get '/' => 'static#home', as: 'home', constraints: { format: :html } + get '*url' => 'static#home', constraints: { format: :html } end diff --git a/e2e.sh b/e2e.sh index de88ada..aa726b7 100755 --- a/e2e.sh +++ b/e2e.sh @@ -6,7 +6,7 @@ BASE_DIR="$(dirname "$0")" export RAILS_ENV="test" export USE_MOCK_GOOGLE=true -export BASE_WEB_URL="http://localhost:3000" +export BASE_WEB_URL="http://localhost:4000" export RETRO_ADMIN_BASE_URL="http://localhost:4000/admin" export GOOGLE_AUTH_ENDPOINT="http://localhost:3100/auth" @@ -68,6 +68,13 @@ fi npm --prefix="$BASE_DIR/mock-google-server" start & register_spawned $! +# Create static content + +echo 'Building frontend in E2E test mode...' +rm -rf "$BASE_DIR/api/public" +npm --prefix="$BASE_DIR/web" run build +cp -a "$BASE_DIR/web/build/." "$BASE_DIR/api/public" + # Launch API pushd "$BASE_DIR/api" >/dev/null @@ -80,19 +87,6 @@ pushd "$BASE_DIR/api" >/dev/null ( tail -f -n10 "$API_LOG" & ) | grep -q 'Listening' || true popd >/dev/null -# Launch static content - -echo 'Building frontend in E2E test mode...' -npm --prefix="$BASE_DIR/web" run build - -echo 'Launching frontend...' -echo > "$WEB_LOG" -npm --prefix="$BASE_DIR/web" run serve-built >> "$WEB_LOG" 2>&1 & -register_spawned $! - -echo 'Waiting for frontend...' -( tail -f -n10 "$WEB_LOG" & ) | grep -q 'Accepting connections' - # Run tests pushd "$BASE_DIR/e2e" >/dev/null diff --git a/e2e/spec/spec_helper.rb b/e2e/spec/spec_helper.rb index bd200cc..c481d59 100644 --- a/e2e/spec/spec_helper.rb +++ b/e2e/spec/spec_helper.rb @@ -45,7 +45,7 @@ ) end -RETRO_APP_BASE_URL = ENV['BASE_WEB_URL'] || 'http://localhost:3000' +RETRO_APP_BASE_URL = ENV['BASE_WEB_URL'] || 'http://localhost:4000' RETRO_ADMIN_BASE_URL = ENV['BASE_ADMIN_URL'] || 'http://localhost:4000/admin' Capybara.run_server = false From b10798a2f4bac765654f6a4ab08a29a979b492b2 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Thu, 1 Aug 2019 14:59:05 +0100 Subject: [PATCH 04/11] CORS no longer required in dev/test environments Only in production when the CLIENT_ORIGIN is set. --- api/config.ru | 13 ------------- api/config/environments/development.rb | 7 ------- api/config/environments/test.rb | 7 ------- 3 files changed, 27 deletions(-) diff --git a/api/config.ru b/api/config.ru index 95adb80..f7ba0b5 100644 --- a/api/config.ru +++ b/api/config.ru @@ -3,16 +3,3 @@ require_relative 'config/environment' run Rails.application - -require 'rack/cors' -unless ENV['RAILS_ENV'] == 'production' - use Rack::Cors do - # allow all origins in development - allow do - origins '*' - resource '*', - headers: :any, - methods: [:get, :patch, :post, :delete, :put, :options] - end - end -end diff --git a/api/config/environments/development.rb b/api/config/environments/development.rb index 6fd204b..e56eb5f 100644 --- a/api/config/environments/development.rb +++ b/api/config/environments/development.rb @@ -84,13 +84,6 @@ # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker - config.middleware.insert_before 0, Rack::Cors do - allow do - origins 'http://localhost:3000' - resource '*', headers: :any, methods: [:get, :post, :patch, :delete, :options, :put] - end - end - config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true diff --git a/api/config/environments/test.rb b/api/config/environments/test.rb index 7548a6a..867237c 100644 --- a/api/config/environments/test.rb +++ b/api/config/environments/test.rb @@ -69,13 +69,6 @@ config.action_cable.allowed_request_origins = [/.*/] - config.middleware.insert_before 0, Rack::Cors do - allow do - origins 'http://localhost:3000' - resource '*', headers: :any, methods: [:get, :post, :patch, :delete, :options, :put] - end - end - # Raises error for missing translations # config.action_view.raise_on_missing_translations = true From 22cb8dd29d28385f4bd1f82a914311ffd2ac8a3b Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Mon, 5 Aug 2019 15:22:08 +0100 Subject: [PATCH 05/11] Move client files in backend to client/ not public/ --- api/.gitignore | 9 +-------- api/app/controllers/static_controller.rb | 2 +- api/client/.gitkeep | 0 api/config/application.rb | 9 +++++++++ e2e.sh | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 api/client/.gitkeep diff --git a/api/.gitignore b/api/.gitignore index ee5c85a..53983f3 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -28,11 +28,4 @@ postfacto-api.iml db/schema.rb # Ignore public client files -/public -!/public/404.html -!/public/422.html -!/public/500.html -!/public/apple-touch-icon-precomposed.png -!/public/apple-touch-icon.png -!/public/favicon.ico -!/public/robots.txt +/client diff --git a/api/app/controllers/static_controller.rb b/api/app/controllers/static_controller.rb index 03fca2d..ad59722 100644 --- a/api/app/controllers/static_controller.rb +++ b/api/app/controllers/static_controller.rb @@ -30,6 +30,6 @@ # class StaticController < ApplicationController def home - render file: 'public/index.html', layout: false + render file: 'client/index.html', layout: false end end diff --git a/api/client/.gitkeep b/api/client/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/config/application.rb b/api/config/application.rb index fc73585..a7d30fc 100644 --- a/api/config/application.rb +++ b/api/config/application.rb @@ -52,5 +52,14 @@ class Application < Rails::Application # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. config.autoload_paths << Rails.root.join('lib', 'configurations') + if ENV['RAILS_ENV'] != 'production' || ENV['RAILS_SERVE_STATIC_FILES'].present? + config.middleware.insert_after( + ActionDispatch::Static, + ActionDispatch::Static, + Rails.root.join('client').to_s, + index: config.public_file_server.index_name, + headers: config.public_file_server.headers || {} + ) + end end end diff --git a/e2e.sh b/e2e.sh index aa726b7..91c102f 100755 --- a/e2e.sh +++ b/e2e.sh @@ -71,9 +71,9 @@ register_spawned $! # Create static content echo 'Building frontend in E2E test mode...' -rm -rf "$BASE_DIR/api/public" +rm -rf "$BASE_DIR/api/client/*" npm --prefix="$BASE_DIR/web" run build -cp -a "$BASE_DIR/web/build/." "$BASE_DIR/api/public" +cp -a "$BASE_DIR/web/build/." "$BASE_DIR/api/client" # Launch API From 559b72d257b526ebac11f094487696edaf0f5457 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Tue, 6 Aug 2019 11:54:15 +0100 Subject: [PATCH 06/11] Allow configuration to specify websocket port for client --- web/src/Application.jsx | 4 +-- web/src/Application.test.jsx | 12 +++++++- .../components/retro-show/show_retro_page.jsx | 28 +++++++++++++------ .../retro-show/show_retro_page.test.jsx | 10 +++++++ web/src/helpers/websockets.js | 10 +++++++ web/src/helpers/websockets.test.js | 23 +++++++++++++++ 6 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 web/src/helpers/websockets.js create mode 100644 web/src/helpers/websockets.test.js diff --git a/web/src/Application.jsx b/web/src/Application.jsx index bc764db..7140b26 100644 --- a/web/src/Application.jsx +++ b/web/src/Application.jsx @@ -45,6 +45,7 @@ import {retrieveConfig} from './redux/actions/api_actions'; import makeReduxStore from './redux/store'; import RetroClient from './api/retro_client'; import AnalyticsClient from './helpers/analytics_client'; +import {websocketUrl} from './helpers/websockets'; const muiTheme = getMuiTheme({ fontFamily: 'Karla', @@ -96,7 +97,6 @@ class Application extends React.Component { render() { const {config} = this.props; - const {websocket_url} = config; return ( @@ -104,7 +104,7 @@ class Application extends React.Component { - + diff --git a/web/src/Application.test.jsx b/web/src/Application.test.jsx index e65113a..d3aa114 100755 --- a/web/src/Application.test.jsx +++ b/web/src/Application.test.jsx @@ -3,11 +3,13 @@ import {mount} from 'enzyme'; import './spec_helper'; import EnhancedApplication from './Application'; +import SessionWebsocket from './components/session_websocket'; describe('Application', () => { + const websocket_url = 'ws://websocket/url'; + it('renders without crashing', () => { const api_base_url = 'https://example.com'; - const websocket_url = 'ws://websocket/url'; const enable_analytics = false; global.Retro = {config: {api_base_url, enable_analytics}}; @@ -26,4 +28,12 @@ describe('Application', () => { expect(app).toExist(); app.unmount(); }); + + it('passes the URL to the websocket', () => { + const config = {websocket_url, websocket_port: 1111}; + + const app = mount(); + + expect(app.find(SessionWebsocket).prop('url')).toBe('ws://websocket:1111/url'); + }); }); diff --git a/web/src/components/retro-show/show_retro_page.jsx b/web/src/components/retro-show/show_retro_page.jsx index 8c63637..f1303e8 100644 --- a/web/src/components/retro-show/show_retro_page.jsx +++ b/web/src/components/retro-show/show_retro_page.jsx @@ -48,22 +48,34 @@ import EmptyPage from '../shared/empty_page'; import {DEFAULT_TOGGLE_STYLE} from '../shared/constants'; import { - archiveRetro, createRetroActionItem, createRetroItem, deleteRetroActionItem, - deleteRetroItem, doneRetroActionItem, - doneRetroItem, editRetroActionItem, extendTimer, + archiveRetro, + createRetroActionItem, + createRetroItem, + deleteRetroActionItem, + deleteRetroItem, + doneRetroActionItem, + doneRetroItem, + editRetroActionItem, + extendTimer, getRetro, - getRetroArchive, highlightRetroItem, - nextRetroItem, undoneRetroItem, unhighlightRetroItem, updateRetroItem, + getRetroArchive, + highlightRetroItem, + nextRetroItem, + undoneRetroItem, + unhighlightRetroItem, + updateRetroItem, voteRetroItem, } from '../../redux/actions/api_actions'; import { clearDialog, - currentRetroSendArchiveEmailUpdated, currentRetroUpdated, + currentRetroSendArchiveEmailUpdated, + currentRetroUpdated, forceRelogin, showDialog, signOut, } from '../../redux/actions/main_actions'; import {retroArchives, retroLogin, retroSettings} from '../../redux/actions/router_actions'; +import {websocketUrl} from '../../helpers/websockets'; function getItemArchiveTime(item) { if (!item.archived_at) { @@ -319,7 +331,7 @@ class ShowRetroPage extends React.Component { return ( - + {this.renderArchiveConfirmationDialog()}
@@ -392,7 +404,7 @@ class ShowRetroPage extends React.Component { return ( - + {this.renderArchiveConfirmationDialog()}
diff --git a/web/src/components/retro-show/show_retro_page.test.jsx b/web/src/components/retro-show/show_retro_page.test.jsx index 7e75e42..a136e9c 100644 --- a/web/src/components/retro-show/show_retro_page.test.jsx +++ b/web/src/components/retro-show/show_retro_page.test.jsx @@ -36,10 +36,12 @@ import Dialog from 'material-ui/Dialog'; import '../../spec_helper'; import {ShowRetroPage} from './show_retro_page'; +import RetroWebsocket from './retro_websocket'; const config = { title: 'Retro', api_base_url: 'https://example.com', + websocket_port: 1234, websocket_url: 'ws://websocket/url', contact: '', terms: '', @@ -248,6 +250,10 @@ describe('ShowRetroPage', () => { it('does not display a dialog by default', () => { expect(dom.find(Dialog)).toHaveProp({open: false}); }); + + it('passes the retro URL to RetroWebsocket', () => { + expect(dom.find(RetroWebsocket).prop('url')).toBe('ws://websocket:1234/url'); + }); }); describe('on mobile', () => { @@ -296,5 +302,9 @@ describe('ShowRetroPage', () => { it('does not display a back button', () => { expect(dom.find('.retro-back')).not.toExist(); }); + + it('passes the retro URL to RetroWebsocket', () => { + expect(dom.find(RetroWebsocket).prop('url')).toBe('ws://websocket:1234/url'); + }); }); }); diff --git a/web/src/helpers/websockets.js b/web/src/helpers/websockets.js new file mode 100644 index 0000000..7f74d09 --- /dev/null +++ b/web/src/helpers/websockets.js @@ -0,0 +1,10 @@ +// eslint-disable-next-line import/prefer-default-export +export const websocketUrl = (config) => { + if (config.websocket_port) { + const a = document.createElement('a'); + a.href = config.websocket_url; + a.port = config.websocket_port; + return a.href; + } + return config.websocket_url; +}; diff --git a/web/src/helpers/websockets.test.js b/web/src/helpers/websockets.test.js new file mode 100644 index 0000000..1a03ce2 --- /dev/null +++ b/web/src/helpers/websockets.test.js @@ -0,0 +1,23 @@ +import {websocketUrl} from './websockets'; + +describe('websocketUrl', () => { + const path = '/path/to/hell'; + + describe('without an explicit port', () => { + it('returns the websocket_url', () => { + expect(websocketUrl({websocket_url: path})).toEqual(path); + }); + }); + + describe('with an explicit port', () => { + const port = 4321; + + it('includes the port in the url', () => { + const config = {websocket_url: path, websocket_port: port}; + + const websocketUrlResult = websocketUrl(config); + + expect(websocketUrlResult).toMatch(new RegExp(`:${port}${path}$`)); + }); + }); +}); From 04dc434e00ba42e202a4223501bd63fe8c28cc51 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Tue, 6 Aug 2019 16:21:26 +0100 Subject: [PATCH 07/11] Force SSL usage in production and handle websocket handshakes --- api/Gemfile | 1 + api/Gemfile.lock | 3 +++ api/config.ru | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/api/Gemfile b/api/Gemfile index fe7bc7d..946c2ef 100644 --- a/api/Gemfile +++ b/api/Gemfile @@ -45,6 +45,7 @@ gem 'jbuilder' gem 'premailer-rails', '>= 1.10.2' gem 'puma' gem 'rack-cors', require: 'rack/cors' +gem 'rack-ssl' gem 'rest-client' gem 'uglifier' gem 'jwt' diff --git a/api/Gemfile.lock b/api/Gemfile.lock index fe8af66..690c76c 100644 --- a/api/Gemfile.lock +++ b/api/Gemfile.lock @@ -189,6 +189,8 @@ GEM puma (3.12.0) rack (2.0.7) rack-cors (1.0.2) + rack-ssl (1.4.1) + rack rack-test (1.1.0) rack (>= 1.0, < 3) rails (5.2.3) @@ -339,6 +341,7 @@ DEPENDENCIES pry-byebug puma rack-cors + rack-ssl rails (>= 5.2.2.1) redis (~> 3.3.3) rest-client diff --git a/api/config.ru b/api/config.ru index f7ba0b5..b2fc72d 100644 --- a/api/config.ru +++ b/api/config.ru @@ -1,5 +1,44 @@ +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# # This file is used by Rack-based servers to start the application. require_relative 'config/environment' +if ENV['RAILS_ENV'] == 'production' + require 'rack/ssl' + + use Rack::SSL, + exclude: (lambda do |env| + env['HTTP_CONNECTION'] == 'Upgrade' && env['HTTP_UPGRADE'] == 'websocket' + end) +end + run Rails.application From dbcc4f080a111f32f8ba9f72aed048fa14b843be Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Wed, 7 Aug 2019 10:34:10 +0100 Subject: [PATCH 08/11] Update deployment configuration for changes --- deployment/heroku/config/config.js | 4 ++-- deployment/pcf/config/config.js | 6 +++--- deployment/pws/config/config.js | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/deployment/heroku/config/config.js b/deployment/heroku/config/config.js index b7ea72a..1cd1862 100644 --- a/deployment/heroku/config/config.js +++ b/deployment/heroku/config/config.js @@ -5,11 +5,11 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.herokuapp.com", + "api_base_url": "https://{{api-app-name}}.herokuapp.com/api", "websocket_url": "wss://{{api-app-name}}.herokuapp.com/cable", "contact": "", "terms": "", "privacy": "" } -} +}; diff --git a/deployment/pcf/config/config.js b/deployment/pcf/config/config.js index 4351108..f250d1e 100644 --- a/deployment/pcf/config/config.js +++ b/deployment/pcf/config/config.js @@ -34,10 +34,10 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.{{pcf-url}}", - "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}:443/cable", + "api_base_url": "https://{{api-app-name}}.{{pcf-url}}/api", + "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}/cable", "contact": "", "terms": "", "privacy": "" } -} +}; diff --git a/deployment/pws/config/config.js b/deployment/pws/config/config.js index 08ed01b..f7e22ba 100644 --- a/deployment/pws/config/config.js +++ b/deployment/pws/config/config.js @@ -5,10 +5,11 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.{{pcf-url}}", - "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}:4443/cable", + "api_base_url": "https://{{api-app-name}}.{{pcf-url}}/api", + "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}/cable", + "websocket_port": 4443, "contact": "", "terms": "", "privacy": "" } -} +}; From 7f28624fa4031261035d1133f85a3d8278457be2 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Wed, 7 Aug 2019 11:10:03 +0100 Subject: [PATCH 09/11] Exclude test databases/client files from package --- package.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.sh b/package.sh index d81e1a0..b4ef48a 100755 --- a/package.sh +++ b/package.sh @@ -25,6 +25,8 @@ chmod u+x package/pws/*.sh mkdir package/pws/assets +rm -rf api/client/* +rm -rf api/db/*.sqlite3 rm -rf api/tmp/* cp -r api package/pws/assets/api cp -r web/build package/pws/assets/web From 1d2f5347cda7e729a32ae040dd1e36fdfa6f5caf Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Thu, 15 Aug 2019 14:40:29 +0100 Subject: [PATCH 10/11] Update deployment scripts for new topology - Introduce migrate script for pre-4.x installs --- .gitignore | 5 +- deployment/README.md | 71 ++++++++++----- deployment/deploy-cf.sh | 61 +++++++++---- deployment/deploy-heroku.sh | 52 ++++------- deployment/heroku/assets/web/static.json | 6 -- .../heroku/{assets/api => config}/Procfile | 1 + deployment/heroku/config/config.js | 5 +- deployment/migrate-cf.sh | 52 +++++++++++ deployment/migrate-heroku.sh | 51 +++++++++++ deployment/pcf/config/config.js | 5 +- deployment/pcf/config/manifest-web.yml | 6 -- .../config/{manifest-api.yml => manifest.yml} | 1 - deployment/pws/config/config.js | 5 +- deployment/pws/config/manifest-web.yml | 6 -- .../config/{manifest-api.yml => manifest.yml} | 1 - deployment/upgrade-cf.sh | 58 ++++++++---- deployment/upgrade-heroku.sh | 53 ++++------- package.sh | 89 +++++++++++++------ test-package.sh | 22 +++-- 19 files changed, 357 insertions(+), 193 deletions(-) delete mode 100644 deployment/heroku/assets/web/static.json rename deployment/heroku/{assets/api => config}/Procfile (99%) create mode 100644 deployment/migrate-cf.sh create mode 100644 deployment/migrate-heroku.sh delete mode 100644 deployment/pcf/config/manifest-web.yml rename deployment/pcf/config/{manifest-api.yml => manifest.yml} (86%) delete mode 100644 deployment/pws/config/manifest-web.yml rename deployment/pws/config/{manifest-api.yml => manifest.yml} (86%) diff --git a/.gitignore b/.gitignore index 395ba90..f611813 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ -package +last-release/ +package/ +tmp/ package.zip +last-release.zip .idea/ .DS_Store node_modules/ diff --git a/deployment/README.md b/deployment/README.md index 08b7665..48ee036 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -1,6 +1,6 @@ # Deployment -So you're ready to set Postfacto up, choose names for your web and API apps. We'll refer to these names as `api-app-name` and `web-app-name` from now on. +So you're ready to set Postfacto up, choose a name for your app. We'll refer to this as `app-name` from now on. ## Pivotal Web Services @@ -13,19 +13,27 @@ So you're ready to set Postfacto up, choose names for your web and API apps. We' 1. Run the PWS deployment script from the `pws` directory: ```bash - ./deploy.sh + ./deploy.sh ``` -1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `api-app-name.cfapps.io/admin` +1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `.cfapps.io/admin` 1. Create a retro for yourself by clicking on 'Retros' and the 'New Retro' -1. Log in to your retro at `web-app-name.cfapps.io/retros/you-retro-slug` +1. Log in to your retro at `.cfapps.io/retros/your-retro-slug` 1. Share the URL and password with your team and then run a retro! ### Upgrading a deployment 1. Presuming the steps in the Initial deployment section have been completed, run the upgrade script from the `pws` directory: - ```bash - ./upgrade.sh - ``` + ```bash + ./upgrade.sh + ``` + +### Migrating a deployment + +1. If you'd previously deployed a version of Postfacto prior to 4.0, run the migration script from the `pws` directory: + ```bash + ./migrate.sh + ``` + **Note** that the admin panel will move from `.cfapps.io/admin` to `.cfapps.io/admin` and the API app will be deleted ## Pivotal Cloud Foundry @@ -37,20 +45,27 @@ So you're ready to set Postfacto up, choose names for your web and API apps. We' 1. Run the PCF deployment script from the `pcf` directory: ```bash - ./deploy.sh + ./deploy.sh ``` -1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `api-app-name.{{pcf-url}}/admin` +1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `./admin` 1. Create a retro for yourself by clicking on 'Retros' and the 'New Retro' -1. Log in to your retro at `web-app-name.{{pcf-url}}/retros/you-retro-slug` +1. Log in to your retro at `./retros/your-retro-slug` 1. Share the URL and password with your team and then run a retro! ### Upgrading a deployment 1. Presuming the steps in the Initial deployment section have been completed, run the upgrade script from the `pcf` directory: - ```bash - ./upgrade.sh - ``` + ```bash + ./upgrade.sh + ``` +### Migrating a deployment + +1. If you'd previously deployed a version of Postfacto prior to 4.0, run the migration script from the `pcf` directory: + ```bash + ./migrate.sh + ``` + **Note** that the admin panel will move from `./admin` to `./admin` and the API app will be deleted ## Heroku @@ -59,20 +74,28 @@ So you're ready to set Postfacto up, choose names for your web and API apps. We' 1. Install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) 1. Run the Heroku deployment script from the `heroku` directory: - ```bash - ./deploy.sh - ``` -1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `api-app-name.herokuapp.com/admin` + ```bash + ./deploy.sh + ``` +1. Log in to the admin dashboard (email: `email@example.com` and password: `password`) to check everything has worked at `.herokuapp.com/admin` 1. Create a retro for yourself by clicking on 'Retros' and the 'New Retro' -1. Log in to your retro at `web-app-name.herokuapp.com/retros/you-retro-slug` +1. Log in to your retro at `.herokuapp.com/retros/your-retro-slug` 1. Share the URL and password with your team and then run a retro! ### Upgrading a deployment 1. Presuming the steps in the Initial deployment section have been completed, run the upgrade script from the `heroku` directory: - ```bash - ./upgrade.sh - ``` + ```bash + ./upgrade.sh + ``` + +### Migrating a deployment + +1. If you'd previously deployed a version of Postfacto prior to 4.0, run the migration script from the `heroku` directory: + ```bash + ./migrate.sh + ``` + **Note** that the admin panel will move from `.herokuapp.com/admin` to `.herokuapp.com/admin` and the API app will be deleted ## Configuration @@ -80,13 +103,13 @@ So you're ready to set Postfacto up, choose names for your web and API apps. We' In order for users to sign-up and create their own retros using the web UI, Postfacto needs Google OAuth setup. For deployments that do not want to setup Google OAuth, you will need to create your retros through the admin console of your server via -`api-app-name.cfapps.io/admin` or `api-app-name.{{pcf-url}}/admin`. +`.cfapps.io/admin` or `./admin`. 1. Go to [Google Cloud Console](https://console.cloud.google.com) and create a new project 1. Go to APIs & Services > Credentials > Create Credentials > OAuth client ID > Web application 1. Choose a name for your app -1. In `Authorized JavaScript Origins`, set it to the public URL of your `web-app-name`. For example: if deploying to PWS, your public URL will be `https://{{web-app-name}}.{{pcf-url}}` +1. In `Authorized JavaScript Origins`, set it to the public URL of your `app-name`. For example: if deploying to PWS, your public URL will be `https://.` 1. You can leave redirect blank 1. Take note of your `client-id` that is generated 1. Add `"google_oauth_client_id": {{client-id}}` to the `config.js` for your installation. @@ -100,5 +123,5 @@ If you'd like to have your instance send analytics data to the Postfacto team so You can customise this window with the `SESSION_TIME` env variable to the `env` on deploy. To set a session time of 1 hour for example: ```bash -SESSION_TIME=60 ./deploy web-app api-app +SESSION_TIME=60 ./deploy ``` diff --git a/deployment/deploy-cf.sh b/deployment/deploy-cf.sh index f25eff0..3a3beeb 100644 --- a/deployment/deploy-cf.sh +++ b/deployment/deploy-cf.sh @@ -1,30 +1,55 @@ #!/bin/bash - -set -e - +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "usage: ./deploy.sh " + echo "This will deploy the app to a CF foundation of your choosing" + exit 1 +fi # The directory in which this script is located SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" "$SCRIPT_DIR/mixpanel.sh" "CF $(basename "${BASH_SOURCE[0]}")" "$@" -WEB_HOST=$1 -API_HOST=$2 -APP_DOMAIN=${3:-cfapps.io} +APP_HOST=$1 SESSION_TIME=${SESSION_TIME:-'""'} -ASSETS_DIR="$SCRIPT_DIR"/assets -CONFIG_DIR="$SCRIPT_DIR"/config +ASSETS_DIR="$SCRIPT_DIR/../assets" +CONFIG_DIR="$SCRIPT_DIR/config" cf target \ || (echo 'You need to have the CF CLI installed and be logged in' \ && exit 1) -cf push -f "$CONFIG_DIR"/manifest-api.yml -p "$ASSETS_DIR"/api --var api-app-name=$API_HOST --var web-app-name=$WEB_HOST --var pcf-url=${APP_DOMAIN} --var session-time=$SESSION_TIME -cf run-task $API_HOST 'ADMIN_EMAIL=email@example.com ADMIN_PASSWORD=password rake admin:create_user' - -sed \ - -e "s/{{api-app-name}}/${API_HOST}/" \ - -e "s/{{pcf-url}}/${APP_DOMAIN}/" \ - <"$CONFIG_DIR"/config.js \ - >"$ASSETS_DIR"/web/config.js - -cf push -f "$CONFIG_DIR"/manifest-web.yml -p "$ASSETS_DIR"/web --var api-app-name=$API_HOST --var web-app-name=$WEB_HOST +cp "$CONFIG_DIR/config.js" "$ASSETS_DIR/client/config.js" +cf push -f "$CONFIG_DIR"/manifest.yml -p "$ASSETS_DIR" --var api-app-name=$APP_HOST --var session-time=$SESSION_TIME +cf run-task $APP_HOST 'ADMIN_EMAIL=email@example.com ADMIN_PASSWORD=password rake admin:create_user' diff --git a/deployment/deploy-heroku.sh b/deployment/deploy-heroku.sh index 5381d7c..908a7a7 100644 --- a/deployment/deploy-heroku.sh +++ b/deployment/deploy-heroku.sh @@ -29,12 +29,11 @@ # # along with this program. If not, see . # +set -euo pipefail -set -e - -if [ $# -ne 2 ]; then - echo "usage: ./deploy_heroku.sh " - echo "This will deploy the web frontend and api to a .herokuapp.com host of your choosing" +if [ $# -lt 1 ]; then + echo "usage: ./deploy.sh " + echo "This will deploy the app to a .herokuapp.com host of your choosing" exit 1 fi @@ -42,47 +41,30 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" "$SCRIPT_DIR/mixpanel.sh" "Heroku $(basename "${BASH_SOURCE[0]}")" "$@" -WEB_HOST=$1 -API_HOST=$2 +APP_HOST=$1 SESSION_TIME=${SESSION_TIME:-'""'} -ASSETS_DIR="$SCRIPT_DIR"/assets -CONFIG_DIR="$SCRIPT_DIR"/config +ASSETS_DIR="$SCRIPT_DIR/../assets" +CONFIG_DIR="$SCRIPT_DIR/config" +# Prepare assets +cp "$CONFIG_DIR/config.js" "$ASSETS_DIR/client" +cp "$CONFIG_DIR/Procfile" "$ASSETS_DIR" ################### # Deploy the API ################### -pushd "$ASSETS_DIR"/api - heroku create ${API_HOST} --buildpack https://github.com/heroku/heroku-buildpack-ruby.git#v200 - heroku addons:create heroku-postgresql:hobby-dev -a ${API_HOST} - heroku addons:create heroku-redis:hobby-dev -a ${API_HOST} - heroku config:set WEBSOCKET_PORT=4443 CLIENT_ORIGIN=https://${WEB_HOST}.herokuapp.com SESSION_TIME=${SESSION_TIME} -a ${API_HOST} - - rm -rf .git # blow away any existent git directory from a previous run - git init . - git add . - git commit -m "Packaging for initial Heroku deployment" - git push --set-upstream https://git.heroku.com/${API_HOST}.git master - heroku run rake admin:create_user ADMIN_EMAIL=email@example.com ADMIN_PASSWORD=password -a ${API_HOST} -popd - -########################### -# Deploy the web frontend -########################### - -pushd "$ASSETS_DIR"/web - sed \ - -e "s/{{api-app-name}}/${API_HOST}/" \ - <"$CONFIG_DIR"/config.js \ - >"$ASSETS_DIR"/web/public_html/config.js - - heroku create ${WEB_HOST} --buildpack https://github.com/heroku/heroku-buildpack-static +pushd "$ASSETS_DIR" + heroku create ${APP_HOST} --buildpack https://github.com/heroku/heroku-buildpack-ruby.git#v200 + heroku addons:create heroku-postgresql:hobby-dev -a ${APP_HOST} + heroku addons:create heroku-redis:hobby-dev -a ${APP_HOST} + heroku config:set WEBSOCKET_PORT=4443 SESSION_TIME=${SESSION_TIME} -a ${APP_HOST} rm -rf .git # blow away any existent git directory from a previous run git init . git add . git commit -m "Packaging for initial Heroku deployment" - git push --set-upstream https://git.heroku.com/${WEB_HOST}.git master + git push --set-upstream https://git.heroku.com/${APP_HOST}.git master + heroku run rake admin:create_user ADMIN_EMAIL=email@example.com ADMIN_PASSWORD=password -a ${APP_HOST} -x popd diff --git a/deployment/heroku/assets/web/static.json b/deployment/heroku/assets/web/static.json deleted file mode 100644 index 836e74b..0000000 --- a/deployment/heroku/assets/web/static.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "routes": { - "/**": "index.html" - }, - "https_only": true -} diff --git a/deployment/heroku/assets/api/Procfile b/deployment/heroku/config/Procfile similarity index 99% rename from deployment/heroku/assets/api/Procfile rename to deployment/heroku/config/Procfile index 7b8a5dc..51b9bf6 100644 --- a/deployment/heroku/assets/api/Procfile +++ b/deployment/heroku/config/Procfile @@ -1,3 +1,4 @@ + # # Postfacto, a free, open-source and self-hosted retro tool aimed at helping # remote teams. diff --git a/deployment/heroku/config/config.js b/deployment/heroku/config/config.js index 1cd1862..381dac5 100644 --- a/deployment/heroku/config/config.js +++ b/deployment/heroku/config/config.js @@ -5,8 +5,9 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.herokuapp.com/api", - "websocket_url": "wss://{{api-app-name}}.herokuapp.com/cable", + "api_base_url": "/api", + "websocket_url": "/cable", + "enable_analytics": false, "contact": "", "terms": "", "privacy": "" diff --git a/deployment/migrate-cf.sh b/deployment/migrate-cf.sh new file mode 100644 index 0000000..890f0d3 --- /dev/null +++ b/deployment/migrate-cf.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "usage: ./migrate.sh " + echo "This will migrate the app on a CF foundation of your choosing" + exit 1 +fi + +WEB_HOST=$1 +API_HOST=$2 +SESSION_TIME=${SESSION_TIME:-'""'} + +# The directory in which this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +"$SCRIPT_DIR/mixpanel.sh" "CF $(basename "${BASH_SOURCE[0]}")" "$@" + +cf unset-env $WEB_HOST 'FORCE_HTTPS' + +ENABLE_ANALYTICS=false "$SCRIPT_DIR/upgrade.sh" $WEB_HOST + +cf delete $API_HOST -f -r diff --git a/deployment/migrate-heroku.sh b/deployment/migrate-heroku.sh new file mode 100644 index 0000000..914526e --- /dev/null +++ b/deployment/migrate-heroku.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "usage: ./migrate.sh " + echo "This will migrate the app on a .herokuapp.com host of your choosing" + exit 1 +fi + +WEB_HOST=$1 +API_HOST=$2 +SESSION_TIME=${SESSION_TIME:-'""'} + +# The directory in which this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +"$SCRIPT_DIR/mixpanel.sh" "Heroku $(basename "${BASH_SOURCE[0]}")" "$@" + +ENABLE_ANALYTICS=false "$SCRIPT_DIR/upgrade.sh" ${API_HOST} + +heroku apps:delete -a ${WEB_HOST} -c ${WEB_HOST} +heroku apps:rename -a ${API_HOST} ${WEB_HOST} diff --git a/deployment/pcf/config/config.js b/deployment/pcf/config/config.js index f250d1e..f51e28b 100644 --- a/deployment/pcf/config/config.js +++ b/deployment/pcf/config/config.js @@ -34,8 +34,9 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.{{pcf-url}}/api", - "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}/cable", + "api_base_url": "/api", + "websocket_url": "/cable", + "enable_analytics": false, "contact": "", "terms": "", "privacy": "" diff --git a/deployment/pcf/config/manifest-web.yml b/deployment/pcf/config/manifest-web.yml deleted file mode 100644 index 7690f4e..0000000 --- a/deployment/pcf/config/manifest-web.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -applications: -- name: ((web-app-name)) - memory: 64M - env: - FORCE_HTTPS: true diff --git a/deployment/pcf/config/manifest-api.yml b/deployment/pcf/config/manifest.yml similarity index 86% rename from deployment/pcf/config/manifest-api.yml rename to deployment/pcf/config/manifest.yml index c5e4d95..bf149aa 100644 --- a/deployment/pcf/config/manifest-api.yml +++ b/deployment/pcf/config/manifest.yml @@ -10,6 +10,5 @@ applications: - postfacto-db - postfacto-redis env: - CLIENT_ORIGIN: https://((web-app-name)).((pcf-url)) WEBSOCKET_PORT: 443 SESSION_TIME: ((session-time)) diff --git a/deployment/pws/config/config.js b/deployment/pws/config/config.js index f7e22ba..6dd2245 100644 --- a/deployment/pws/config/config.js +++ b/deployment/pws/config/config.js @@ -5,9 +5,10 @@ window.Retro = { "scripts": ["application.js"], "stylesheets": ["application.css"], "useRevManifest": true, - "api_base_url": "https://{{api-app-name}}.{{pcf-url}}/api", - "websocket_url": "wss://{{api-app-name}}.{{pcf-url}}/cable", + "api_base_url": "/api", + "websocket_url": "/cable", "websocket_port": 4443, + "enable_analytics": false, "contact": "", "terms": "", "privacy": "" diff --git a/deployment/pws/config/manifest-web.yml b/deployment/pws/config/manifest-web.yml deleted file mode 100644 index 7690f4e..0000000 --- a/deployment/pws/config/manifest-web.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -applications: -- name: ((web-app-name)) - memory: 64M - env: - FORCE_HTTPS: true diff --git a/deployment/pws/config/manifest-api.yml b/deployment/pws/config/manifest.yml similarity index 86% rename from deployment/pws/config/manifest-api.yml rename to deployment/pws/config/manifest.yml index 5636d3b..a292d00 100644 --- a/deployment/pws/config/manifest-api.yml +++ b/deployment/pws/config/manifest.yml @@ -10,6 +10,5 @@ applications: - postfacto-db - postfacto-redis env: - CLIENT_ORIGIN: https://((web-app-name)).((pcf-url)) WEBSOCKET_PORT: 4443 SESSION_TIME: ((session-time)) diff --git a/deployment/upgrade-cf.sh b/deployment/upgrade-cf.sh index e166b65..da37237 100644 --- a/deployment/upgrade-cf.sh +++ b/deployment/upgrade-cf.sh @@ -1,29 +1,55 @@ #!/bin/bash - -set -e +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "usage: ./upgrade.sh " + echo "This will upgrade the app on a CF foundation of your choosing" + exit 1 +fi # The directory in which this script is located SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" "$SCRIPT_DIR/mixpanel.sh" "CF $(basename "${BASH_SOURCE[0]}")" "$@" -WEB_HOST=$1 -API_HOST=$2 -APP_DOMAIN=${3:-cfapps.io} +APP_HOST=$1 SESSION_TIME=${SESSION_TIME:-'""'} -ASSETS_DIR="$SCRIPT_DIR"/assets -CONFIG_DIR="$SCRIPT_DIR"/config +ASSETS_DIR="$SCRIPT_DIR/../assets" +CONFIG_DIR="$SCRIPT_DIR/config" cf target \ || (echo 'You need to have the CF CLI installed and be logged in' \ && exit 1) -cf push -f "$CONFIG_DIR"/manifest-api.yml -p "$ASSETS_DIR"/api --var api-app-name=$API_HOST --var web-app-name=$WEB_HOST --var pcf-url=${APP_DOMAIN} --var session-time=$SESSION_TIME - -sed \ - -e "s/{{api-app-name}}/${API_HOST}/" \ - -e "s/{{pcf-url}}/${APP_DOMAIN}/" \ - <"$CONFIG_DIR"/config.js \ - >"$ASSETS_DIR"/web/config.js - -cf push -f "$CONFIG_DIR"/manifest-web.yml -p "$ASSETS_DIR"/web --var api-app-name=$API_HOST --var web-app-name=$WEB_HOST +cp "$CONFIG_DIR/config.js" "$ASSETS_DIR/client/config.js" +cf push -f "$CONFIG_DIR/manifest.yml" -p "$ASSETS_DIR" --var api-app-name=$APP_HOST --var session-time=$SESSION_TIME diff --git a/deployment/upgrade-heroku.sh b/deployment/upgrade-heroku.sh index 442ec7a..fc36397 100644 --- a/deployment/upgrade-heroku.sh +++ b/deployment/upgrade-heroku.sh @@ -29,12 +29,11 @@ # # along with this program. If not, see . # +set -euo pipefail -set -e - -if [ $# -ne 2 ]; then - echo "usage: ./upgrade_heroku.sh " - echo "This will upgrade an existing Postfacto deployment to a .herokuapp.com host of your choosing" +if [ $# -lt 1 ]; then + echo "usage: ./upgrade_heroku.sh " + echo "This will upgrade an existing Postfacto deployment on a .herokuapp.com host of your choosing" exit 1 fi @@ -42,51 +41,31 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" "$SCRIPT_DIR/mixpanel.sh" "Heroku $(basename "${BASH_SOURCE[0]}")" "$@" -WEB_HOST=$1 -API_HOST=$2 +APP_HOST=$1 -ASSETS_DIR="$SCRIPT_DIR"/assets -CONFIG_DIR="$SCRIPT_DIR"/config +ASSETS_DIR="$SCRIPT_DIR/../assets" +CONFIG_DIR="$SCRIPT_DIR/config" -if ! heroku apps:info -a "$WEB_HOST" 2>/dev/null; then - echo "Web host ${WEB_HOST} does not exist! Aborting." +if ! heroku apps:info -a "$APP_HOST" 2>/dev/null; then + echo "App host ${APP_HOST} does not exist! Aborting." exit 1 fi -if ! heroku apps:info -a "$API_HOST" 2>/dev/null; then - echo "API host ${API_HOST} does not exist! Aborting." - exit 1 -fi ################### -# Upgrade the API +# Upgrade the app ################### +cp "$CONFIG_DIR/config.js" "$ASSETS_DIR/client" +cp "$CONFIG_DIR/Procfile" "$ASSETS_DIR" -pushd "$ASSETS_DIR"/api +pushd "$ASSETS_DIR" BUILDPACK='https://github.com/heroku/heroku-buildpack-ruby.git#v200' - if [[ ! $(heroku buildpacks -a ${API_HOST}) =~ ${BUILDPACK} ]]; then - heroku buildpacks:set -a ${API_HOST} ${BUILDPACK} + if [[ ! $(heroku buildpacks -a ${APP_HOST}) =~ ${BUILDPACK} ]]; then + heroku buildpacks:set -a ${APP_HOST} ${BUILDPACK} fi rm -rf .git # blow away any existent git directory from a previous run git init . git add . git commit -m "Packaging for Heroku upgrade" - git push --force --set-upstream https://git.heroku.com/${API_HOST}.git master -popd - -########################### -# Upgrade the web frontend -########################### - -pushd "$ASSETS_DIR"/web - sed \ - -e "s/{{api-app-name}}/${API_HOST}/" \ - <"$CONFIG_DIR"/config.js \ - >"$ASSETS_DIR"/web/public_html/config.js - - rm -rf .git # blow away any existent git directory from a previous run - git init . - git add . - git commit -m "Packaging for Heroku upgrade" - git push --force --set-upstream https://git.heroku.com/${WEB_HOST}.git master + git push --force --set-upstream https://git.heroku.com/${APP_HOST}.git master popd diff --git a/package.sh b/package.sh index b4ef48a..5e95a28 100755 --- a/package.sh +++ b/package.sh @@ -1,62 +1,97 @@ #!/bin/bash +# +# Postfacto, a free, open-source and self-hosted retro tool aimed at helping +# remote teams. +# +# Copyright (C) 2016 - Present Pivotal Software, Inc. +# +# This program is free software: you can redistribute it and/or modify +# +# it under the terms of the GNU Affero General Public License as +# +# published by the Free Software Foundation, either version 3 of the +# +# License, or (at your option) any later version. +# +# +# +# This program is distributed in the hope that it will be useful, +# +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# +# GNU Affero General Public License for more details. +# +# +# +# You should have received a copy of the GNU Affero General Public License +# +# along with this program. If not, see . +# +set -euo pipefail + +rm -rf package.zip +for DIR in package tmp +do + if [[ -d $DIR ]]; then + rm -rf $DIR + fi +done -set -e +# BUILD FRONT-END -if [[ -d "package" ]]; then - rm -r package +if [[ ! $* =~ '--skip-build' ]]; then + pushd web + npm run build + cp ../humans.txt build + popd fi -mkdir package +# CREATE APP -# BUILD FRONT-END +mkdir tmp +cp -r api/. tmp +rm -rf tmp/client/* +rm -rf tmp/db/*.sqlite3 +rm -rf tmp/log/*.log +rm -rf tmp/spec +rm -rf tmp/tmp/* +cp -r web/build/. tmp/client -pushd web - npm run build - cp ../humans.txt build -popd +# BUILD PACKAGES + +mkdir -p package/assets +cp -r tmp/. package/assets +rm -rf tmp # PWS cp -r deployment/pws package cp -r deployment/deploy-cf.sh package/pws/deploy.sh +cp -r deployment/migrate-cf.sh package/pws/migrate.sh cp -r deployment/upgrade-cf.sh package/pws/upgrade.sh cp -r deployment/mixpanel.sh package/pws/mixpanel.sh chmod u+x package/pws/*.sh -mkdir package/pws/assets - -rm -rf api/client/* -rm -rf api/db/*.sqlite3 -rm -rf api/tmp/* -cp -r api package/pws/assets/api -cp -r web/build package/pws/assets/web - # PCF cp -r deployment/pcf package cp -r deployment/deploy-cf.sh package/pcf/deploy.sh +cp -r deployment/migrate-cf.sh package/pcf/migrate.sh cp -r deployment/upgrade-cf.sh package/pcf/upgrade.sh cp -r deployment/mixpanel.sh package/pcf/mixpanel.sh chmod u+x package/pcf/*.sh -mkdir package/pcf/assets - -rm -rf api/tmp/* -cp -r api package/pcf/assets/api -cp -r web/build package/pcf/assets/web - # Heroku cp -r deployment/heroku package cp -r deployment/deploy-heroku.sh package/heroku/deploy.sh +cp -r deployment/migrate-heroku.sh package/heroku/migrate.sh cp -r deployment/upgrade-heroku.sh package/heroku/upgrade.sh cp -r deployment/mixpanel.sh package/heroku/mixpanel.sh chmod u+x package/heroku/*.sh -rm -rf api/tmp/* -cp -r api/* package/heroku/assets/api -cp -r web/build package/heroku/assets/web/public_html - # Docs cp deployment/README.md package diff --git a/test-package.sh b/test-package.sh index fe48027..70a600b 100755 --- a/test-package.sh +++ b/test-package.sh @@ -62,7 +62,6 @@ NOW=$(date +%s) OLD_WEB="postfacto-old-web-${NOW}" OLD_API="postfacto-old-api-${NOW}" NEW_WEB="postfacto-new-web-${NOW}" -NEW_API="postfacto-new-api-${NOW}" if [[ ! $* =~ --skip-cf ]]; then @@ -95,15 +94,15 @@ then popd pushd "$SCRIPT_DIR/package/pcf" - echo 'Upgrading old version on Cloud Foundry' - ENABLE_ANALYTICS=false ./upgrade.sh $OLD_WEB $OLD_API 'apps.pcfone.io' + echo 'Migrating old version on Cloud Foundry' + ENABLE_ANALYTICS=false ./migrate.sh $OLD_WEB $OLD_API echo 'Deploying new version to Cloud Foundry' - ENABLE_ANALYTICS=false ./deploy.sh $NEW_WEB $NEW_API 'apps.pcfone.io' + ENABLE_ANALYTICS=false ./deploy.sh $NEW_WEB popd echo 'Cleaning up Cloud Foundry' - for APP in $OLD_WEB $OLD_API $NEW_WEB $NEW_API + for APP in $OLD_WEB $NEW_WEB do cf delete $APP -f -r done @@ -132,18 +131,23 @@ then popd pushd "$SCRIPT_DIR/package/heroku" - echo 'Upgrading old version on Heroku' - ENABLE_ANALYTICS=false ./upgrade.sh $OLD_WEB $OLD_API + echo 'Migrating old version on Heroku' + ENABLE_ANALYTICS=false ./migrate.sh $OLD_WEB $OLD_API echo 'Deploying new version to Heroku' - ENABLE_ANALYTICS=false ./deploy.sh $NEW_WEB $NEW_API + ENABLE_ANALYTICS=false ./deploy.sh $NEW_WEB popd echo 'Cleaning up Heroku' - for APP in $OLD_WEB $OLD_API $NEW_WEB $NEW_API + for APP in $OLD_WEB $NEW_WEB do heroku apps:delete -a $APP -c $APP done + + if [[ $(heroku apps) =~ $OLD_API ]]; then + echo "$OLD_API was not deleted by the upgrade" + exit 1 + fi fi echo 'Cleaning up working directory' From 07fe4f8ac1885ec33074384adf394778a7908e60 Mon Sep 17 00:00:00 2001 From: Jonathan Sharpe Date: Sat, 17 Aug 2019 21:32:40 +0100 Subject: [PATCH 11/11] Copy Postgres data across to a fresh DB when migrating on Heroku This works around #183 by avoiding reuse of the old Ruby app. Note that we don't copy over the Redis data; this is only used to sync websockets and considered ephemeral. --- deployment/README.md | 2 ++ deployment/migrate-heroku.sh | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/deployment/README.md b/deployment/README.md index 48ee036..16f9d32 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -91,6 +91,8 @@ So you're ready to set Postfacto up, choose a name for your app. We'll refer to ### Migrating a deployment + > ⚠️ **Warning**: the Heroku migration will attempt to migrate your data to a new database instance and delete the old one. Take a look at what the script is doing and make sure you understand the implications before running it. + 1. If you'd previously deployed a version of Postfacto prior to 4.0, run the migration script from the `heroku` directory: ```bash ./migrate.sh diff --git a/deployment/migrate-heroku.sh b/deployment/migrate-heroku.sh index 914526e..ca9b788 100644 --- a/deployment/migrate-heroku.sh +++ b/deployment/migrate-heroku.sh @@ -45,7 +45,11 @@ SESSION_TIME=${SESSION_TIME:-'""'} SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" "$SCRIPT_DIR/mixpanel.sh" "Heroku $(basename "${BASH_SOURCE[0]}")" "$@" -ENABLE_ANALYTICS=false "$SCRIPT_DIR/upgrade.sh" ${API_HOST} +heroku addons:create heroku-postgresql:hobby-dev -a ${WEB_HOST} +heroku pg:copy DATABASE ${WEB_HOST}::DATABASE -a ${API_HOST} --confirm ${API_HOST} +heroku addons:create heroku-redis:hobby-dev -a ${WEB_HOST} +heroku config:set WEBSOCKET_PORT=4443 SESSION_TIME=${SESSION_TIME} -a ${WEB_HOST} -heroku apps:delete -a ${WEB_HOST} -c ${WEB_HOST} -heroku apps:rename -a ${API_HOST} ${WEB_HOST} +ENABLE_ANALYTICS=false "$SCRIPT_DIR/upgrade.sh" ${WEB_HOST} + +heroku apps:delete -a ${API_HOST} -c ${API_HOST}