From 1bc017ea5454096f74db02a689f28aef3db77d19 Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:00:28 +0300 Subject: [PATCH 01/10] add pipeline definition --- .gitlab-ci.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..cf9e693 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,24 @@ +stages: + - build + - test + - deploy + +build_job: + stage: build + script: + - echo 'Building' + +test_unit_job: + stage: test + script: + - echo 'Testing 1' + +test_integration_job: + stage: test + script: + - echo 'Testing 2' + +deploy_job: + stage: deploy + script: + - echo 'Deploy' From fd5f2f7d68aa3656a95dd32750340eabc55b28fd Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:05:46 +0300 Subject: [PATCH 02/10] Add reddit app --- reddit/.gitignore | 1 + reddit/Capfile | 15 +++ reddit/Gemfile | 16 +++ reddit/Gemfile.lock | 68 ++++++++++++ reddit/README.md | 22 ++++ reddit/app.rb | 160 +++++++++++++++++++++++++++++ reddit/config.ru | 2 + reddit/config/deploy.rb | 69 +++++++++++++ reddit/config/deploy/production.rb | 61 +++++++++++ reddit/config/deploy/staging.rb | 61 +++++++++++ reddit/helpers.rb | 29 ++++++ reddit/views/create.haml | 14 +++ reddit/views/index.haml | 27 +++++ reddit/views/layout.haml | 46 +++++++++ reddit/views/login.haml | 10 ++ reddit/views/show.haml | 45 ++++++++ reddit/views/signup.haml | 10 ++ 17 files changed, 656 insertions(+) create mode 100644 reddit/.gitignore create mode 100644 reddit/Capfile create mode 100644 reddit/Gemfile create mode 100644 reddit/Gemfile.lock create mode 100644 reddit/README.md create mode 100644 reddit/app.rb create mode 100644 reddit/config.ru create mode 100644 reddit/config/deploy.rb create mode 100644 reddit/config/deploy/production.rb create mode 100644 reddit/config/deploy/staging.rb create mode 100644 reddit/helpers.rb create mode 100644 reddit/views/create.haml create mode 100644 reddit/views/index.haml create mode 100644 reddit/views/layout.haml create mode 100644 reddit/views/login.haml create mode 100644 reddit/views/show.haml create mode 100644 reddit/views/signup.haml diff --git a/reddit/.gitignore b/reddit/.gitignore new file mode 100644 index 0000000..d31f3ca --- /dev/null +++ b/reddit/.gitignore @@ -0,0 +1 @@ +*log diff --git a/reddit/Capfile b/reddit/Capfile new file mode 100644 index 0000000..c85aa52 --- /dev/null +++ b/reddit/Capfile @@ -0,0 +1,15 @@ +# Load DSL and set up stages +require "capistrano/setup" + +# Include default deployment tasks +require "capistrano/deploy" +require "capistrano/scm/git" +install_plugin Capistrano::SCM::Git + +require 'capistrano/bundler' +require 'capistrano/rvm' +require 'capistrano/puma' +install_plugin Capistrano::Puma + +# Load custom tasks from `lib/capistrano/tasks` if you have any defined +Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r } diff --git a/reddit/Gemfile b/reddit/Gemfile new file mode 100644 index 0000000..3ce71c0 --- /dev/null +++ b/reddit/Gemfile @@ -0,0 +1,16 @@ +source 'https://rubygems.org' + +gem 'sinatra', '~> 2.0.1' +gem 'haml' +gem 'bson_ext' +gem 'bcrypt' +gem 'puma' +gem 'mongo' +gem 'json' + +group :development do + gem 'capistrano', require: false + gem 'capistrano-rvm', require: false + gem 'capistrano-bundler', require: false + gem 'capistrano3-puma', require: false +end diff --git a/reddit/Gemfile.lock b/reddit/Gemfile.lock new file mode 100644 index 0000000..f62baeb --- /dev/null +++ b/reddit/Gemfile.lock @@ -0,0 +1,68 @@ +GEM + remote: https://rubygems.org/ + specs: + airbrussh (1.3.0) + sshkit (>= 1.6.1, != 1.7.0) + bcrypt (3.1.11) + bson (4.2.2) + bson_ext (1.5.1) + capistrano (3.9.0) + airbrussh (>= 1.0.0) + i18n + rake (>= 10.0.0) + sshkit (>= 1.9.0) + capistrano-bundler (1.2.0) + capistrano (~> 3.1) + sshkit (~> 1.2) + capistrano-rvm (0.1.2) + capistrano (~> 3.0) + sshkit (~> 1.2) + capistrano3-puma (3.1.1) + capistrano (~> 3.7) + capistrano-bundler + puma (~> 3.4) + haml (5.0.2) + temple (>= 0.8.0) + tilt + i18n (0.8.6) + json (2.1.0) + mongo (2.4.3) + bson (>= 4.2.1, < 5.0.0) + mustermann (1.0.2) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (4.1.0) + puma (3.10.0) + rack (2.0.5) + rack-protection (2.0.2) + rack + rake (12.0.0) + sinatra (2.0.2) + mustermann (~> 1.0) + rack (~> 2.0) + rack-protection (= 2.0.2) + tilt (~> 2.0) + sshkit (1.14.0) + net-scp (>= 1.1.2) + net-ssh (>= 2.8.0) + temple (0.8.0) + tilt (2.0.8) + +PLATFORMS + ruby + +DEPENDENCIES + bcrypt + bson_ext + capistrano + capistrano-bundler + capistrano-rvm + capistrano3-puma + haml + json + mongo + puma + sinatra (~> 2.0.1) + +BUNDLED WITH + 1.16.1 diff --git a/reddit/README.md b/reddit/README.md new file mode 100644 index 0000000..8d173ce --- /dev/null +++ b/reddit/README.md @@ -0,0 +1,22 @@ +# Monolith application + +## Deploy using Capistrano + +#### Requirements for the target host: +* Ruby (>2.2.0) installed via `rvm` +* MongDB +* ports `22` and `9292` should be reachable by you + +#### Steps: +1. Install required gems: +`bundle install` +2. Set env vars: +```bash +export SERVER_IP= # public IP address of the target host +export REPO_NAME= # repo name to fetch the code from, e.g. Artemmkin/reddit +export DEPLOY_USER=deploy # username used to connect via SSH +``` +3. Deploy using capistrano: +```bash +bundle exec cap production deploy:initial +``` diff --git a/reddit/app.rb b/reddit/app.rb new file mode 100644 index 0000000..c28efc2 --- /dev/null +++ b/reddit/app.rb @@ -0,0 +1,160 @@ +require 'sinatra' +require 'json/ext' # for .to_json +require 'haml' +require 'uri' +require 'mongo' +require 'bcrypt' +require './helpers' + + +configure do + db = Mongo::Client.new([ ENV['DATABASE_URL'] || '127.0.0.1:27017' ], database: 'user_posts', heartbeat_frequency: 2) + set :mongo_db, db[:posts] + set :comments_db, db[:comments] + set :users_db, db[:users] + set :bind, '0.0.0.0' + enable :sessions +end + +before do + session[:flashes] = [] if session[:flashes].class != Array +end + + +get '/' do + @title = 'All posts' + begin + @posts = JSON.parse(settings.mongo_db.find.sort(timestamp: -1).to_a.to_json) + rescue + session[:flashes] << { type: 'alert-danger', message: 'Can\'t show blog posts, some problems with database. Refresh?' } + end + @flashes = session[:flashes] + session[:flashes] = nil + haml :index +end + + +get '/new' do + @title = 'New post' + @flashes = session[:flashes] + session[:flashes] = nil + haml :create +end + +post '/new' do + db = settings.mongo_db + if params['link'] =~ URI::regexp + begin + result = db.insert_one title: params['title'], created_at: Time.now.to_i, link: params['link'], votes: 0 + db.find(_id: result.inserted_id).to_a.first.to_json + rescue + session[:flashes] << { type: 'alert-danger', message: 'Can\'t save your post, some problems with the post service' } + else + session[:flashes] << { type: 'alert-success', message: 'Post successuly published' } + end + redirect '/' + else + session[:flashes] << { type: 'alert-danger', message: 'Invalid URL' } + redirect back + end +end + + +get '/signup' do + @title = 'Signup' + @flashes = session[:flashes] + session[:flashes] = nil + haml :signup +end + + +get '/login' do + @title = 'Login' + @flashes = session[:flashes] + session[:flashes] = nil + haml :login +end + + +post '/signup' do + db = settings.users_db + password_salt = BCrypt::Engine.generate_salt + password_hash = BCrypt::Engine.hash_secret(params[:password], password_salt) + u = db.find(_id: params[:username]).to_a.first.to_json + if u == "null" + result = db.insert_one _id: params[:username], salt: password_salt, passwordhash: password_hash + session[:username] = params[:username] + session[:flashes] << { type: 'alert-success', message: 'User created' } + redirect '/' + else + session[:flashes] << { type: 'alert-danger', message: 'User already exists' } + redirect back + end +end + + +post '/login' do + db = settings.users_db + u = db.find(_id: params[:username]).to_a.first.to_json + if u != "null" + user = JSON.parse(u) + if user["passwordhash"] == BCrypt::Engine.hash_secret(params[:password], user["salt"]) + session[:username] = params[:username] + redirect '/' + else + session[:flashes] << { type: 'alert-danger', message: 'Wrong username or password' } + redirect back + end + else + session[:flashes] << { type: 'alert-danger', message: 'Wrong username or password' } + redirect back + end +end + + +get '/logout' do + session[:username] = nil + redirect back +end + + +put '/post/:id/vote/:type' do + if logged_in? + id = object_id(params[:id]) + post = JSON.parse(document_by_id(params[:id])) + post['votes'] += params[:type].to_i + + settings.mongo_db.find(:_id => id). + find_one_and_update('$set' => {:votes => post['votes']}) + document_by_id(id) + else + session[:flashes] << { type: 'alert-danger', message: 'You need to log in before you can vote' } + end + redirect back +end + + +get '/post/:id' do + @title = 'Post' + @post = JSON.parse(document_by_id(params[:id])) + id = object_id(params[:id]) + @comments = JSON.parse(settings.comments_db.find(post_id: "#{id}").to_a.to_json) + @flashes = session[:flashes] + session[:flashes] = nil + haml :show +end + + +post '/post/:id/comment' do + content_type :json + db = settings.comments_db + begin + result = db.insert_one post_id: params[:id], name: session[:username], body: params['body'], created_at: Time.now.to_i + db.find(_id: result.inserted_id).to_a.first.to_json + rescue + session[:flashes] << { type: 'alert-danger', message: 'Can\'t save your comment, some problems with the comment service' } + else + session[:flashes] << { type: 'alert-success', message: 'Comment successuly published' } + end + redirect back +end diff --git a/reddit/config.ru b/reddit/config.ru new file mode 100644 index 0000000..76a6edf --- /dev/null +++ b/reddit/config.ru @@ -0,0 +1,2 @@ +require './app' +run Sinatra::Application diff --git a/reddit/config/deploy.rb b/reddit/config/deploy.rb new file mode 100644 index 0000000..0e535ec --- /dev/null +++ b/reddit/config/deploy.rb @@ -0,0 +1,69 @@ +server ENV['SERVER_IP'], port: 22, user: ENV['DEPLOY_USER'], roles: [:web, :app, :db], primary: true +set :repo_name, ENV['REPO_NAME'] + +set :application, 'reddit' +set :repo_url, "git@github.com:#{fetch(:repo_name)}.git" +set :branch, 'monolith' +set :user, ENV['DEPLOY_USER'] +set :puma_threads, [4, 16] +set :puma_workers, 0 + +set :pty, true +set :use_sudo, false +set :stage, :production +set :deploy_via, :remote_cache +set :deploy_to, "/home/#{fetch(:user)}/#{fetch(:application)}" +set :puma_bind, "tcp://0.0.0.0:9292" +set :puma_state, "#{shared_path}/tmp/pids/puma.state" +set :puma_pid, "#{shared_path}/tmp/pids/puma.pid" +set :puma_access_log, "#{release_path}/log/puma.error.log" +set :puma_error_log, "#{release_path}/log/puma.access.log" +set :ssh_options, { forward_agent: true } +set :puma_preload_app, true +set :puma_worker_timeout, nil +set :puma_init_active_record, false # Change to false when not using ActiveRecord +set :linked_dirs, %w(tmp/pids tmp/sockets log) + +namespace :puma do + desc 'Create Directories for Puma Pids and Socket' + task :make_dirs do + on roles(:app) do + execute "mkdir #{shared_path}/tmp/sockets -p" + execute "mkdir #{shared_path}/tmp/pids -p" + end + end + + before :start, :make_dirs +end + +namespace :deploy do + desc "Make sure local git is in sync with remote." + task :check_revision do + on roles(:app) do + unless `git rev-parse HEAD` == `git rev-parse origin/monolith` + puts "WARNING: HEAD is not the same as origin/monolith" + puts "Run `git push` to sync changes." + exit + end + end + end + + desc 'Initial Deploy' + task :initial do + on roles(:app) do + before 'deploy:restart', 'puma:start' + invoke 'deploy' + end + end + + desc 'Restart application' + task :restart do + on roles(:app), in: :sequence, wait: 5 do + invoke 'puma:restart' + end + end + + before :starting, :check_revision + after :finishing, :cleanup + after :finishing, :restart +end diff --git a/reddit/config/deploy/production.rb b/reddit/config/deploy/production.rb new file mode 100644 index 0000000..4bb7a71 --- /dev/null +++ b/reddit/config/deploy/production.rb @@ -0,0 +1,61 @@ +# server-based syntax +# ====================== +# Defines a single server with a list of roles and multiple properties. +# You can define all roles on a single server, or split them: + +# server "example.com", user: "deploy", roles: %w{app db web}, my_property: :my_value +# server "example.com", user: "deploy", roles: %w{app web}, other_property: :other_value +# server "db.example.com", user: "deploy", roles: %w{db} + + + +# role-based syntax +# ================== + +# Defines a role with one or multiple servers. The primary server in each +# group is considered to be the first unless any hosts have the primary +# property set. Specify the username and a domain or IP for the server. +# Don't use `:all`, it's a meta role. + +# role :app, %w{deploy@example.com}, my_property: :my_value +# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value +# role :db, %w{deploy@example.com} + + + +# Configuration +# ============= +# You can set any configuration variable like in config/deploy.rb +# These variables are then only loaded and set in this stage. +# For available Capistrano configuration variables see the documentation page. +# http://capistranorb.com/documentation/getting-started/configuration/ +# Feel free to add new variables to customise your setup. + + + +# Custom SSH Options +# ================== +# You may pass any option but keep in mind that net/ssh understands a +# limited set of options, consult the Net::SSH documentation. +# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start +# +# Global options +# -------------- +# set :ssh_options, { +# keys: %w(/home/rlisowski/.ssh/id_rsa), +# forward_agent: false, +# auth_methods: %w(password) +# } +# +# The server-based syntax can be used to override options: +# ------------------------------------ +# server "example.com", +# user: "user_name", +# roles: %w{web app}, +# ssh_options: { +# user: "user_name", # overrides user setting above +# keys: %w(/home/user_name/.ssh/id_rsa), +# forward_agent: false, +# auth_methods: %w(publickey password) +# # password: "please use keys" +# } diff --git a/reddit/config/deploy/staging.rb b/reddit/config/deploy/staging.rb new file mode 100644 index 0000000..4bb7a71 --- /dev/null +++ b/reddit/config/deploy/staging.rb @@ -0,0 +1,61 @@ +# server-based syntax +# ====================== +# Defines a single server with a list of roles and multiple properties. +# You can define all roles on a single server, or split them: + +# server "example.com", user: "deploy", roles: %w{app db web}, my_property: :my_value +# server "example.com", user: "deploy", roles: %w{app web}, other_property: :other_value +# server "db.example.com", user: "deploy", roles: %w{db} + + + +# role-based syntax +# ================== + +# Defines a role with one or multiple servers. The primary server in each +# group is considered to be the first unless any hosts have the primary +# property set. Specify the username and a domain or IP for the server. +# Don't use `:all`, it's a meta role. + +# role :app, %w{deploy@example.com}, my_property: :my_value +# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value +# role :db, %w{deploy@example.com} + + + +# Configuration +# ============= +# You can set any configuration variable like in config/deploy.rb +# These variables are then only loaded and set in this stage. +# For available Capistrano configuration variables see the documentation page. +# http://capistranorb.com/documentation/getting-started/configuration/ +# Feel free to add new variables to customise your setup. + + + +# Custom SSH Options +# ================== +# You may pass any option but keep in mind that net/ssh understands a +# limited set of options, consult the Net::SSH documentation. +# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start +# +# Global options +# -------------- +# set :ssh_options, { +# keys: %w(/home/rlisowski/.ssh/id_rsa), +# forward_agent: false, +# auth_methods: %w(password) +# } +# +# The server-based syntax can be used to override options: +# ------------------------------------ +# server "example.com", +# user: "user_name", +# roles: %w{web app}, +# ssh_options: { +# user: "user_name", # overrides user setting above +# keys: %w(/home/user_name/.ssh/id_rsa), +# forward_agent: false, +# auth_methods: %w(publickey password) +# # password: "please use keys" +# } diff --git a/reddit/helpers.rb b/reddit/helpers.rb new file mode 100644 index 0000000..2e5fade --- /dev/null +++ b/reddit/helpers.rb @@ -0,0 +1,29 @@ +helpers do + # a helper method to turn a string ID + # representation into a BSON::ObjectId + def object_id val + begin + BSON::ObjectId.from_string(val) + rescue BSON::ObjectId::Invalid + nil + end + end + + def document_by_id id + id = object_id(id) if String === id + if id.nil? + {}.to_json + else + document = settings.mongo_db.find(:_id => id).to_a.first + (document || {}).to_json + end + end + + def logged_in? + if session[:username].nil? + return false + else + return true + end + end +end diff --git a/reddit/views/create.haml b/reddit/views/create.haml new file mode 100644 index 0000000..68bde5c --- /dev/null +++ b/reddit/views/create.haml @@ -0,0 +1,14 @@ +%h2 Add a new post +- if logged_in? + %form{ action: '/new', method: 'post', role: 'form'} + .form-group + %label{for: 'title'} Title: + %input{name:'title', placeholder: 'cool title', class: 'form-control', id: 'title'} + .form-group + %label{for: 'link'} Link: + %input{name:'link', placeholder: 'awesome link', class: 'form-control', id: 'link'} + .form-group + %input{class: 'btn btn-primary', type: 'submit', value:'Post it!'} +- else + .alert{class: "alert-danger"} + %strong You need to sign in before adding a new post :( diff --git a/reddit/views/index.haml b/reddit/views/index.haml new file mode 100644 index 0000000..bb65bbf --- /dev/null +++ b/reddit/views/index.haml @@ -0,0 +1,27 @@ +- unless @posts.nil? or @posts.empty? + - @posts.each do |post| + %div{ id: 'postlist'} + %div{class: 'panel'} + %div{class: 'panel-heading'} + %div{class: 'text-center'} + %div{class: 'row'} + .col-sm-1 + %form{:action => "/post/#{post['_id']['$oid']}/vote/1", :method => "post", id: "form-upvote" } + %input{:type => "hidden", :name => "_method", :value => "put"} + %button{type: "submit", class: "btn btn-default btn-sm"} + %span{ class: "glyphicon glyphicon-menu-up" } + %h4{class: 'pull-center'} #{post['votes']} + %form{:action => "/post/#{post['_id']['$oid']}/vote/-1", :method => "post", id: "form-downvote"} + %input{:type => "hidden", :name => "_method", :value=> "put"} + %button{type: "submit", class: "btn btn-default btn-sm"} + %span{ class: "glyphicon glyphicon-menu-down" } + .col-sm-8 + %h3{class: 'pull-left'} + %a{href: "/post/#{post['_id']['$oid']}"} #{post['title']} + .col-sm-3 + %h4{class: 'pull-right'} + %small + %em #{Time.at(post['created_at'].to_i).strftime('%d-%m-%Y')} + %br #{Time.at(post['created_at'].to_i).strftime('%H:%M')} + .panel-footer + %a{href: "#{post['link']}", class: 'btn btn-link'} Go to the link diff --git a/reddit/views/layout.haml b/reddit/views/layout.haml new file mode 100644 index 0000000..48b881d --- /dev/null +++ b/reddit/views/layout.haml @@ -0,0 +1,46 @@ +!!! 5 +%html(lang="en") + %head + %meta(charset="utf-8") + %meta(http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1") + %meta(name="viewport" content="width=device-width, initial-scale=1.0") + %title="Monolith Reddit :: #{@title}" + %link{ href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css', integrity: "sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7", type: 'text/css', rel: 'stylesheet', crossorigin: 'anonymous' } + %link{ href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css', integrity: 'sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r', type: 'text/css', rel: 'stylesheet', crossorigin: 'anonymous' } + %script{ href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js', integrity: 'sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS', crossorigin: 'anonymous'} + %script{ src: 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js' } + %body + .navbar.navbar-default.navbar-static-top + .container + .navbar-header + %button.navbar-toggle(type="button" data-toggle="collapse" data-target=".navbar-responsive-collapse") + %span.icon-bar + %span.icon-bar + %span.icon-bar + %a.navbar-brand(href="/") Monolith Reddit + .navbar-collapse.collapse + %ul.nav.navbar-nav.navbar-right + - if logged_in? + %li + %a.nav-link(href="/logout") Logout + - else + %li + %a(href="/signup") Sign up + %li + %a(href="/login") Login + .container + .row + .col-lg-9 + - unless @flashes.nil? or @flashes.empty? + - @flashes.each do |flash| + .alert{class: flash[:type]} + %strong #{flash[:message]} + = yield + .col-lg-3 + .well.sidebar-nav + %h3 Menu + %ul.nav.nav-list + %li + %a(href="/") All posts + %li + %a(href="/new") New post diff --git a/reddit/views/login.haml b/reddit/views/login.haml new file mode 100644 index 0000000..017fe7b --- /dev/null +++ b/reddit/views/login.haml @@ -0,0 +1,10 @@ +%h2 Log In +%form{ action: '/login', method: 'post', role: 'form'} + .form-group + %label{for: 'username'} Username: + %input{name:'username', placeholder: 'Your username', class: 'form-control', id: 'username'} + .form-group + %label{for: 'password'} Password: + %input{name:'password', placeholder: 'Your password', class: 'form-control', id: 'password'} + .form-group + %input{class: 'btn btn-primary', type: 'submit', value:'Log in'} diff --git a/reddit/views/show.haml b/reddit/views/show.haml new file mode 100644 index 0000000..ee3de56 --- /dev/null +++ b/reddit/views/show.haml @@ -0,0 +1,45 @@ +%div{ id: 'postlist'} + %div{class: 'panel'} + %div{class: 'panel-heading'} + %div{class: 'text-center'} + %div{class: 'row'} + .col-sm-1 + %form{action: "#{@post['_id']['$oid']}/vote/1", method: "post"} + %input{:type => "hidden", :name => "_method", :value => "put"} + %button{type: "submit", class: "btn btn-default btn-sm"} + %span{ class: "glyphicon glyphicon-menu-up" } + %h4{class: 'pull-center'} #{@post['votes']} + %form{:action => "#{@post['_id']['$oid']}/vote/-1", :method => "post"} + %input{:type => "hidden", :name => "_method", :value=> "put"} + %button{type: "submit", class: "btn btn-default btn-sm"} + %span{ class: "glyphicon glyphicon-menu-down" } + .col-sm-8 + %h3{class: 'pull-left'} + %a{href: "#{@post['_id']['$oid']}"} #{@post['title']} + .col-sm-3 + %h4{class: 'pull-right'} + %small + %em #{Time.at(@post['created_at'].to_i).strftime('%d-%m-%Y')} + %br #{Time.at(@post['created_at'].to_i).strftime('%H:%M')} + .panel-footer + %a{href: "#{@post['link']}", class: 'btn btn-link'} Go to the link + +- unless @comments.nil? or @comments.empty? + - @comments.each do |comment| + .row + .col-sm-8 + .panel.panel-default + .panel-heading + %strong #{comment['name']} + %span{class: "text-muted pull-right"} + %em #{Time.at(comment['created_at'].to_i).strftime('%H:%M')} #{Time.at(comment['created_at'].to_i).strftime('%d-%m-%Y')} + .panel-body #{comment['body']} +- if logged_in? + %form{action: "/post/#{@post['_id']['$oid']}/comment", method: 'post', role: 'form'} + .col-sm-8 + .form-group + %textarea{name: 'body', class: 'form-control', placeholder: 'put a nice comment :)'} + %button{class: 'btn btn-block btn-primary'} Post my comment +- else + .alert{class: "alert-info"} + %strong Log in or sign up to add a new comment! :) diff --git a/reddit/views/signup.haml b/reddit/views/signup.haml new file mode 100644 index 0000000..44e18b5 --- /dev/null +++ b/reddit/views/signup.haml @@ -0,0 +1,10 @@ +%h2 Sign Up +%form{ action: '/signup', method: 'post', role: 'form'} + .form-group + %label{for: 'username'} Username: + %input{name:'username', placeholder: 'Your username', class: 'form-control', id: 'username'} + .form-group + %label{for: 'password'} Password: + %input{name:'password', placeholder: 'Your password', class: 'form-control', id: 'password'} + .form-group + %input{class: 'btn btn-primary', type: 'submit', value:'Sign up!'} From 4811e16aa54fd5b9fec4fb15c4518e8bf8faff9d Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:10:39 +0300 Subject: [PATCH 03/10] tests --- .gitlab-ci.yml | 12 ++++++++++++ reddit/Gemfile | 9 +++++++++ reddit/simpletest.rb | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 reddit/simpletest.rb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf9e693..cf636c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,17 @@ +image: ruby:2.4.2 + stages: - build - test - deploy +variables: + DATABASE_URL: 'mongodb://mongo/user_posts' + +before_script: + - cd reddit + - bundle install + build_job: stage: build script: @@ -10,7 +19,10 @@ build_job: test_unit_job: stage: test + services: + - mongo:latest script: + - ruby simpletest.rb - echo 'Testing 1' test_integration_job: diff --git a/reddit/Gemfile b/reddit/Gemfile index 3ce71c0..dc2abc0 100644 --- a/reddit/Gemfile +++ b/reddit/Gemfile @@ -7,6 +7,15 @@ gem 'bcrypt' gem 'puma' gem 'mongo' gem 'json' +gem 'sinatra', '~> 2.0.1' +gem 'haml' +gem 'bson_ext' +gem 'bcrypt' +gem 'puma' +gem 'mongo' +gem 'json' +gem 'rack-test' + group :development do gem 'capistrano', require: false diff --git a/reddit/simpletest.rb b/reddit/simpletest.rb new file mode 100644 index 0000000..8fe2726 --- /dev/null +++ b/reddit/simpletest.rb @@ -0,0 +1,18 @@ +require_relative './app' +require 'test/unit' +require 'rack/test' + +set :environment, :test + +class MyAppTest < Test::Unit::TestCase + include Rack::Test::Methods + + def app + Sinatra::Application + end + + def test_get_request + get '/' + assert last_response.ok? + end +end From 481f6045c6d3e8810919466ba659f0cba004d67f Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:20:07 +0300 Subject: [PATCH 04/10] add dev environment --- .gitlab-ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf636c7..59591cb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ image: ruby:2.4.2 stages: - build - test - - deploy + - review variables: DATABASE_URL: 'mongodb://mongo/user_posts' @@ -30,7 +30,10 @@ test_integration_job: script: - echo 'Testing 2' -deploy_job: - stage: deploy +deploy_dev_job: + stage: review script: - echo 'Deploy' + environment: + name: dev + url: http://dev.example.com From 291ebe2c9cf46329ae9544771c31b92dc08da52e Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:42:11 +0300 Subject: [PATCH 05/10] add stage and prod stages --- .gitlab-ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59591cb..c31fc8a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,8 @@ stages: - build - test - review + - stage + - production variables: DATABASE_URL: 'mongodb://mongo/user_posts' @@ -37,3 +39,21 @@ deploy_dev_job: environment: name: dev url: http://dev.example.com + +staging: + stage: stage + when: manual + script: + - echo 'Deploy' + environment: + name: beta + url: http://beta.example.com + +production: + stage: production + when: manual + script: + - echo 'Deploy' + environment: + name: production + url: http://example.com From c1817091da88eb4a74f608131e1f0f93683b27ae Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:43:38 +0300 Subject: [PATCH 06/10] fix yml --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c31fc8a..14adfc4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,8 +46,8 @@ staging: script: - echo 'Deploy' environment: - name: beta - url: http://beta.example.com + name: beta + url: http://beta.example.com production: stage: production @@ -55,5 +55,5 @@ production: script: - echo 'Deploy' environment: - name: production - url: http://example.com + name: production + url: http://example.com From 0f423f43fdc46e9b95e8cc82fafc3e1c633c2a7f Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:46:42 +0300 Subject: [PATCH 07/10] #4 add logout button to profile page --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 14adfc4..81bfaa6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,6 +43,8 @@ deploy_dev_job: staging: stage: stage when: manual + only: + - /^\d+\.\d+\.\d+/ script: - echo 'Deploy' environment: From ec0bfc3b95cb8de79bd73eb703f5f39de965c113 Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 17:56:05 +0300 Subject: [PATCH 08/10] add dynamic enviroments --- .gitlab-ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 81bfaa6..381b3c8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,6 +40,17 @@ deploy_dev_job: name: dev url: http://dev.example.com +branch review: + stage: review + script: echo "Deploy to $CI_ENVIRONMENT_SLUG" + environment: + name: branch/$CI_COMMIT_REF_NAME + url: http://$CI_ENVIRONMENT_SLUG.example.com + only: + - branches + except: + - master + staging: stage: stage when: manual From df071c85441c92c3b27a2f5c4fee50cb05a66887 Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 18:00:34 +0300 Subject: [PATCH 09/10] add docker-compose.yml --- gitlab-ci/docker-compose.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 gitlab-ci/docker-compose.yml diff --git a/gitlab-ci/docker-compose.yml b/gitlab-ci/docker-compose.yml new file mode 100644 index 0000000..936f1d6 --- /dev/null +++ b/gitlab-ci/docker-compose.yml @@ -0,0 +1,15 @@ +web: + image: 'gitlab/gitlab-ce:latest' + restart: always + hostname: 'gitlab.example.com' + environment: + GITLAB_OMNIBUS_CONFIG: | + external_url 'http://51.250.81.47' + ports: + - '80:80' + - '443:443' + - '2222:22' + volumes: + - '/srv/gitlab/config:/etc/gitlab' + - '/srv/gitlab/logs:/var/log/gitlab' + - '/srv/gitlab/data:/var/opt/gitlab' From f00e771a2f7a9bd9f801749c65a2f80fd24b5409 Mon Sep 17 00:00:00 2001 From: FluffyCake19 <39598013+FluffyCake19@users.noreply.github.com> Date: Sat, 15 Oct 2022 18:03:09 +0300 Subject: [PATCH 10/10] changed README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index a9344ca..cf9867f 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,10 @@ docker-4 2. Вынесены настройки в .env Настройка префикса сервисов при сборке docker-compose зависит от папки, в которой расположен docker-compose.yml. Префикс можно задать исопльзуя опцию -p, --project-name NAME + +gitlab-ci-1 +Выполнено: +1. На VM произведена инсталляция Gitlab CI +2. Подготовлен репозиторий с кодом приложения +3. Описаны этапы пайплайна +4. Определены окружения