Compare commits

...

100 Commits

Author SHA1 Message Date
Adam Townsend 1822004460 use the hostname of the artifacts repository
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-19 07:58:59 -08:00
Adam Townsend b9345f9cb5 removed extra line
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-12-18 20:19:55 -08:00
Adam Townsend 166c68570d v1.0.1
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 20:16:52 -08:00
Adam Townsend 28fc8b3b86 updated Gemfile with falcon instead of puma
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 20:15:33 -08:00
Adam Townsend 2c7a18c374 create the directory before syncingit
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-12-18 18:38:18 -08:00
Adam Townsend 0a3f6c5fab try with ssh-agent
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 18:11:28 -08:00
Adam Townsend ca29051dc2 try to rsync with the user/key pair
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 17:50:42 -08:00
Adam Townsend 0b51b52b84 echo the file to see what's in there/how to handle it
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-12-18 17:45:55 -08:00
Adam Townsend 4659942800 use user/key pair
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-12-18 17:33:09 -08:00
Adam Townsend 6d0f594bba set file in the stage it is used in
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 17:15:30 -08:00
Adam Townsend 4ca73cc3ca use artifacts key
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 16:59:52 -08:00
Adam Townsend 1f96facbf2 use the ZIP FILE variable not ZIP_FILE text
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 15:57:02 -08:00
Adam Townsend e362cef9ba added SHA256 and sync both the sig and the zip
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 15:51:41 -08:00
Adam Townsend 25d94bbfc2 attempt to use rsync to sync data to artifact repo jail
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-12-18 13:09:52 -08:00
Adam Townsend 40e3703650 get the actual version, not the line
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-10-24 18:11:12 -07:00
Adam Townsend 21eeb9db72 use version instead of date
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-10-24 18:01:15 -07:00
Adam Townsend 2cbe5f85b0 moved bundle-audit inside test group, added version file 2023-10-24 17:53:56 -07:00
bucky b62d45d0d8 Merge pull request 'prod-artifact-when-good' (#34) from prod-artifact-when-good into master
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
Reviewed-on: #34
2023-10-23 15:54:27 -07:00
Adam Townsend 0dc792b0bf added try catch wrappers around other parts. if they fail, don't build
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
the deliverable
2023-10-23 15:48:42 -07:00
Adam Townsend 5f4209dbe8 testing skipping building the artifact at the end (and cleanup of it)
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-10-23 15:10:16 -07:00
Adam Townsend fbba67a9bd install, not clean, since it changed the bundle location
Gitea Bucky/url-shortener/pipeline/head This commit looks good Details
2023-10-23 15:05:20 -07:00
Adam Townsend 5cd296cb70 when is outside the steps
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-10-23 15:03:45 -07:00
Adam Townsend 7c0f6eb603 limit building deployment artifact
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
+ added buildArtifact variable and set it to true
+ in auditing stage, if there's an error, set buildArtifact to false
+ in build artifact stage, if buildArtifact is true, build  it
2023-10-23 14:58:02 -07:00
Adam Townsend de3dcc48ab removed the when, and removed unnecessary rm command
Gitea Bucky/url-shortener/pipeline/head There was a failure building this commit Details
2023-10-23 12:31:29 -07:00
Adam Townsend 958091e000 see if we can access the buildResult status to use it 2023-10-23 11:32:02 -07:00
Adam Townsend 35583e404e move the local path in the build prod artifact stage to make the tests
quicker
2023-10-23 07:43:30 -07:00
Adam Townsend 0e9342fab6 only build the production environment when the previous steps all executed successfully 2023-10-23 07:41:52 -07:00
bucky ca4182d798 Merge pull request 'added bundle config to only use prod gems and bundle clean to remove unnecessary gems from the current poject' (#33) from build-deployment-artifact into master
Reviewed-on: #33

closes bucky/url-shortener#32
2023-10-23 07:31:15 -07:00
Adam Townsend 7d04c46728 added bundle config to only use prod gems and bundle clean to remove unnecessary gems from the current poject 2023-10-23 07:18:31 -07:00
Adam Townsend 4490ed3e7c output something from the bundler audit to see in the reports 2023-10-22 16:22:18 -07:00
bucky 30c1192e27 Merge pull request 'audit' (#31) from audit into master
Reviewed-on: #31

closes bucky/url-shortener#30
2023-10-22 16:06:15 -07:00
Adam Townsend 6e30705810 rubocop autofixed quotes 2023-10-22 15:57:57 -07:00
Adam Townsend d7c9105995 added audit checks, this should help keep things secure 2023-10-22 15:51:16 -07:00
Adam Townsend a732eb2a61 added bundle-audit and ruby_audit gems 2023-10-22 15:48:40 -07:00
bucky c29d53a33b Merge pull request 'rubocop' (#29) from rubocop into master
Reviewed-on: #29

closes bucky/url-shortener#28
2023-10-22 15:11:23 -07:00
Adam Townsend 3fd8e8c630 wrap the string in single quotes 2023-10-22 15:00:59 -07:00
Adam Townsend 950c358ae5 another try 2023-10-22 14:55:06 -07:00
Adam Townsend f81199e31b maybe this will clean up a few things 2023-10-22 14:15:27 -07:00
Adam Townsend bf1fefd1bc still worknig on env file, and adding logic to not build if the tests fail 2023-10-22 14:05:51 -07:00
Adam Townsend c51a6782d9 another shot at cleaning up the .env.rb file 2023-10-22 13:50:58 -07:00
Adam Townsend 795447e029 attempting to clean up the .env.rb file 2023-10-22 13:43:12 -07:00
Adam Townsend 7caf25c4d0 don't kill it if linting breaks, mark it as unstable 2023-10-22 13:32:39 -07:00
Adam Townsend 3fa1de5e4e install bundled gems in /vendor, and use bundle exec to run them 2023-10-22 13:27:07 -07:00
Adam Townsend f86da2ed6f forgot to wrap the steps in a steps block 2023-10-22 13:19:30 -07:00
Adam Townsend 282a07c5fb added rubocop linting section with output for reports and clean up
rubocop config
2023-10-22 13:16:20 -07:00
Adam Townsend bf6ed14b5e custom parts for rubocop to run. don't worry about block length in many
parts. hide extension suggestions
2023-10-22 13:15:09 -07:00
Adam Townsend 7d35133e43 require capybara and rspec parts needed for tests to run instead of
including them. rubocop autofixed formatting
2023-10-22 13:14:23 -07:00
Adam Townsend c505012b00 rubocop added frozen string literal comment 2023-10-22 13:14:02 -07:00
Adam Townsend 4f54124519 rubocop autofixed formatting 2023-10-22 13:13:27 -07:00
Adam Townsend 18e8eac2ab rubocop autofixed formatting 2023-10-22 13:12:48 -07:00
Adam Townsend 5abf07d0c7 rubocop formatting fixes 2023-10-22 13:07:07 -07:00
Adam Townsend 48ffdf560b frozen string literal for rubocop 2023-10-22 13:06:12 -07:00
Adam Townsend e0392f2483 added rubocop 2023-10-22 13:05:43 -07:00
Adam Townsend 15a5017c86 set up to run with only the freebsd and ruby labeled agent(s) 2023-10-18 13:08:41 -07:00
Adam Townsend dd5caa4056 updated README, swapped Falcon for Puma for now, and ignored more files 2023-10-17 21:53:12 -07:00
Adam Townsend 360ddbe6d2 include the branch name in the zip, so it can be identified a little easier later 2023-10-17 21:45:14 -07:00
bucky b3b886f0b3 Merge pull request 'simplify-secret' (#27) from simplify-secret into master
Reviewed-on: #27
2023-10-17 21:43:19 -07:00
Adam Townsend 93aa007c14 removed secret.rb, it's no longer needed 2023-10-17 21:40:39 -07:00
Adam Townsend 4e32f4a60d use the escaped quotes for it to work correctly 2023-10-17 21:39:15 -07:00
Adam Townsend 2759880a53 remove env. 2023-10-17 21:37:45 -07:00
Adam Townsend 7bc1a852db swap quotes on the db name 2023-10-17 21:36:56 -07:00
Adam Townsend 00119f9723 use env.DB_NAME to access the environment variable 2023-10-17 21:32:30 -07:00
Adam Townsend ff2a0e867d swap the quotes because single quotes doesn't exec the ruby command 2023-10-17 21:30:53 -07:00
Adam Townsend 1fae85ff9d moved the init step into one shell command to load it all, and don't use
the secret.rb file
2023-10-17 21:26:23 -07:00
bucky 10fe82ab6a Merge pull request 'archive-deliverable' (#26) from archive-deliverable into master
Reviewed-on: #26
2023-10-17 18:12:37 -07:00
Adam Townsend 9812a92d59 remove ls 2023-10-17 18:09:17 -07:00
Adam Townsend e8b12c307a include ruby version 2023-10-17 18:06:36 -07:00
Adam Townsend ae00ac8672 forgot the .rb 2023-10-17 18:04:29 -07:00
Adam Townsend bf92201721 removed some unnecessary lines, and check what's in the current
directory
2023-10-17 18:02:40 -07:00
Adam Townsend 1f2e3d41dd syntax error extra - in there 2023-10-17 18:00:46 -07:00
Adam Townsend f31b6da49c include the .env file and remove the scret.rb file 2023-10-17 17:58:40 -07:00
Adam Townsend f32d153b69 simplified things? 2023-10-17 17:46:24 -07:00
Adam Townsend 15d9ade2cf remove EXPORT 2023-10-17 17:42:17 -07:00
Adam Townsend 4587c35806 just set it in the script 2023-10-17 17:40:23 -07:00
Adam Townsend 340614dadc echo outside catch error 2023-10-17 17:37:35 -07:00
Adam Townsend 8a0fef63b2 another try 2023-10-17 17:35:37 -07:00
Adam Townsend 8691d19e8d dump the zip file, let's see how it's working? 2023-10-17 17:32:50 -07:00
Adam Townsend 35d196bdc2 another shot accessing the new env var 2023-10-17 17:28:41 -07:00
Adam Townsend e2c3cb7035 access the ZIP_FILE variable properly? 2023-10-17 17:25:02 -07:00
Adam Townsend a69b3e4226 missed quote 2023-10-17 17:22:00 -07:00
Adam Townsend 36285b060b better try to set the environment 2023-10-17 17:19:31 -07:00
Adam Townsend a0a9e84b91 another try 2023-10-17 17:14:33 -07:00
Adam Townsend 01d9f9a21c another shot at setting the zip file name 2023-10-17 17:12:16 -07:00
Adam Townsend 621a777a46 update env vars
+ removed the app session secret. it's used where it is set
+ added zip file to make it easier to name the zip and reuse the name
2023-10-17 17:05:15 -07:00
Adam Townsend 6fbecd78a4 clean out unnecessary files a little easier 2023-10-17 10:39:17 -07:00
bucky 873b86a809 Merge pull request 'remove db files as well' (#25) from archive-deliverable into master
Reviewed-on: #25
2023-10-16 17:41:38 -07:00
Adam Townsend 47393a5ead remove db files as well 2023-10-16 17:30:11 -07:00
bucky 69c56ae31a Merge pull request 'archive-deliverable' (#24) from archive-deliverable into master
Reviewed-on: #24
2023-10-16 17:28:43 -07:00
Adam Townsend b2cdf60a32 Revert "simplify it a little"
This reverts commit 91f45965a0.
2023-10-16 17:23:50 -07:00
Adam Townsend 91f45965a0 simplify it a little 2023-10-16 17:18:06 -07:00
Adam Townsend 3097cb69aa clean the workspace when done 2023-10-16 17:04:23 -07:00
Adam Townsend eed17d61a3 use tmp as a staging place for building the tgz file 2023-10-16 16:35:56 -07:00
Adam Townsend 9e5a4069a4 wrapping all the commands in one script, hope it works? 2023-10-16 15:44:50 -07:00
Adam Townsend f8c20541d5 removed shopt, added that in jenkins user's .profile 2023-10-16 15:09:44 -07:00
Adam Townsend ee07312b86 another shot at getting local shell 2023-10-16 13:48:31 -07:00
Adam Townsend e4eabf8aa6 looking to see what shell is used 2023-10-16 12:06:11 -07:00
Adam Townsend 3ec0f0ff7b mkdir -p and wrapped the steps in a catch so the clean up happens 2023-10-16 12:01:10 -07:00
Adam Townsend 27b32fc8f4 another shot 2023-10-16 11:57:20 -07:00
Adam Townsend ceab408ec0 build deliverable, store it, and clean up afterwards 2023-10-16 10:54:52 -07:00
Adam Townsend b56b618a8c added stages to build a deliverable and then clean it up when done 2023-10-16 10:50:22 -07:00
14 changed files with 334 additions and 107 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
*.db
.env.rb
coverage
vendor
.ruby-version

6
.rubocop.yml 100644
View File

@ -0,0 +1,6 @@
AllCops:
NewCops: enable
SuggestExtensions: false
Metrics/BlockLength:
AllowedMethods: ['describe', 'context', 'route', 'r.on', 'r.post']

33
Gemfile
View File

@ -1,32 +1,35 @@
# frozen_string_literal: true
source "https://rubygems.org"
source 'https://rubygems.org'
gem 'rackup', '~> 2.1'
gem "roda", "~> 3.72"
gem 'falcon', '~> 0.42.3'
gem "sequel", "~> 5.72"
gem 'roda', '~> 3.72'
gem "tilt", "~> 2.2"
gem 'sequel', '~> 5.72'
gem "sqlite3", "~> 1.6"
gem 'tilt', '~> 2.2'
gem "erubi", "~> 1.12"
gem 'sqlite3', '~> 1.6'
gem 'erubi', '~> 1.12'
group :test do
gem 'cucumber', '~> 9.0'
gem "cucumber", "~> 9.0"
gem 'capybara', '~> 3.39'
gem "capybara", "~> 3.39"
gem 'rspec', '~> 3.12'
gem "rspec", "~> 3.12"
gem 'selenium-webdriver', '~> 4.13'
gem "selenium-webdriver", "~> 4.13"
gem 'simplecov'
gem "simplecov"
gem 'rubocop', require: false
gem 'ruby_audit', '~> 2.2'
gem 'bundle-audit', '~> 0.1.0'
end
gem "puma", "~> 6.4"
gem "rackup", "~> 2.1"

View File

@ -3,8 +3,38 @@ GEM
specs:
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
async (2.6.5)
console (~> 1.10)
fiber-annotation
io-event (~> 1.1)
timers (~> 4.1)
async-container (0.16.12)
async
async-io
async-http (0.61.0)
async (>= 1.25)
async-io (>= 1.28)
async-pool (>= 0.2)
protocol-http (~> 0.25.0)
protocol-http1 (~> 0.16.0)
protocol-http2 (~> 0.15.0)
traces (>= 0.10.0)
async-http-cache (0.4.3)
async-http (~> 0.56)
async-io (1.37.0)
async
async-pool (0.4.0)
async (>= 1.25)
base64 (0.1.1)
bigdecimal (3.1.4)
build-environment (1.13.0)
builder (3.2.4)
bundle-audit (0.1.0)
bundler-audit
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
capybara (3.39.2)
addressable
matrix
@ -14,6 +44,9 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
console (1.23.2)
fiber-annotation
fiber-local
cucumber (9.0.2)
builder (~> 3.2, >= 3.2.4)
cucumber-ci-environment (~> 9.2, >= 9.2.0)
@ -41,18 +74,53 @@ GEM
diff-lcs (1.5.0)
docile (1.4.0)
erubi (1.12.0)
falcon (0.42.3)
async
async-container (~> 0.16.0)
async-http (~> 0.57)
async-http-cache (~> 0.4.0)
async-io (~> 1.22)
build-environment (~> 1.13)
bundler
localhost (~> 1.1)
openssl (~> 3.0)
process-metrics (~> 0.2.0)
protocol-rack (~> 0.1)
samovar (~> 2.1)
ffi (1.16.2)
fiber-annotation (0.2.0)
fiber-local (1.0.0)
io-event (1.3.3)
json (2.6.3)
language_server-protocol (3.17.0.3)
localhost (1.1.10)
mapping (1.1.1)
matrix (0.4.2)
mini_mime (1.1.5)
mini_portile2 (2.8.4)
multi_test (1.1.0)
nio4r (2.5.9)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
openssl (3.2.0)
parallel (1.23.0)
parser (3.2.2.4)
ast (~> 2.4.1)
racc
process-metrics (0.2.1)
console (~> 1.8)
samovar (~> 2.1)
protocol-hpack (1.4.2)
protocol-http (0.25.0)
protocol-http1 (0.16.0)
protocol-http (~> 0.22)
protocol-http2 (0.15.1)
protocol-hpack (~> 1.4)
protocol-http (~> 0.18)
protocol-rack (0.2.6)
protocol-http (~> 0.23)
rack (>= 1.0)
public_suffix (5.0.3)
puma (6.4.0)
nio4r (~> 2.0)
racc (1.7.1)
rack (3.0.8)
rack-test (2.1.0)
@ -60,6 +128,7 @@ GEM
rackup (2.1.0)
rack (>= 3)
webrick (~> 1.8)
rainbow (3.1.1)
regexp_parser (2.8.1)
rexml (3.2.6)
roda (3.72.0)
@ -77,7 +146,27 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.1)
rubocop (1.57.1)
base64 (~> 0.1.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.4)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
parser (>= 3.2.1.0)
ruby-progressbar (1.13.0)
ruby_audit (2.2.0)
bundler-audit (~> 0.9.0)
rubyzip (2.3.2)
samovar (2.2.0)
console (~> 1.0)
mapping (~> 1.0)
selenium-webdriver (4.13.1)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
@ -94,7 +183,11 @@ GEM
mini_portile2 (~> 2.8.0)
sys-uname (1.2.3)
ffi (~> 1.1)
thor (1.3.0)
tilt (2.3.0)
timers (4.3.5)
traces (0.11.1)
unicode-display_width (2.5.0)
webrick (1.8.1)
websocket (1.2.10)
xpath (3.2.0)
@ -104,13 +197,16 @@ PLATFORMS
x86_64-freebsd-13
DEPENDENCIES
bundle-audit (~> 0.1.0)
capybara (~> 3.39)
cucumber (~> 9.0)
erubi (~> 1.12)
puma (~> 6.4)
falcon (~> 0.42.3)
rackup (~> 2.1)
roda (~> 3.72)
rspec (~> 3.12)
rubocop
ruby_audit (~> 2.2)
selenium-webdriver (~> 4.13)
sequel (~> 5.72)
simplecov

136
Jenkinsfile vendored
View File

@ -1,20 +1,21 @@
def buildArtifact = true
pipeline {
agent any
agent { label 'ruby && freebsd' }
environment {
APP_SESSION_SECRET = ''
DB_NAME = 'url_shortener.db'
}
stages {
stage('Init') {
steps {
sh 'rbenv local 3.2.2'
script {
env.APP_SESSION_SECRET = sh(script: 'ruby secret.rb', returnStdout: true)
}
sh 'echo "ENV[\\\"APP_SESSION_SECRET\\\"] ||= $(ruby secret.rb)" > .env.rb'
sh 'echo "ENV[\\\"DB_NAME\\\"] ||= \\\"${DB_NAME}\\\"" >> .env.rb'
sh 'cat .env.rb'
sh ''' #!/usr/local/bin/bash
rbenv local 3.2.2
echo "# frozen_string_literal: true\n" > .env.rb
echo "ENV['APP_SESSION_SECRET'] ||= '$(ruby -rsecurerandom -e 'puts SecureRandom.base64(64)')'" >> .env.rb
echo "ENV['DB_NAME'] ||= '${DB_NAME}'" >> .env.rb
cat .env.rb
'''
}
}
stage('Build dependencies') {
@ -23,27 +24,131 @@ pipeline {
sh 'sequel -m db/migrations sqlite://db/${DB_NAME}'
}
}
stage('Audit Dependencies') {
steps {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
script {
try {
sh 'bundle exec ruby-audit check'
sh 'bundle exec bundle-audit check >> audit.html'
} catch (e) {
script {
buildArtifact = false
}
}
}
}
}
}
stage('Code Linting') {
steps {
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
script {
try {
sh 'bundle exec rubocop --format html --out rubocop.html'
} catch (e) {
script {
buildArtifact = false
}
}
}
}
}
}
stage('Run tests') {
steps {
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh 'cucumber features --format html --out cucumber.html'
script {
try {
sh 'bundle exec cucumber features --format html --out cucumber.html'
} catch (e) {
script {
buildArtifact = false
}
}
}
}
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh 'rspec spec --format html --out spec.html'
script {
try {
sh 'bundle exec rspec spec --format html --out spec.html'
} catch (e) {
script {
buildArtifact = false
}
}
}
}
}
}
stage('Report results') {
steps {
archive(includes: 'pkg/*.gem')
publishHTML (target: [
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: '.',
reportFiles: 'cucumber.html, spec.html, coverage/index.html',
reportFiles: 'rubocop.html, audit.html, cucumber.html, spec.html, coverage/index.html',
reportName: 'Test Results',
reportTitles: 'Cucumber Results, RSpec Results, Test Coverage'])
reportTitles: 'Rubocop Results, Bundler Audit Results, Cucumber Results, RSpec Results, Test Coverage'])
}
}
stage('Build production deliverable') {
when {
expression {
buildArtifact
}
}
steps {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh ''' #!/usr/local/bin/bash
ZIP_FILE="url-shortener_${BRANCH_NAME}_$(cat VERSION | cut -d"'" -f2).tgz"
CUR_DIR=$(pwd)
bundle config set --local without 'test'
bundle config set --local path "vendor"
bundle install
mkdir -p /tmp/url-shortener
cp -R * /tmp/url-shortener
cp .env.rb /tmp/url-shortener/
cp .ruby-version /tmp/url-shortener/
cd /tmp/url-shortener
rm -rf features spec coverage db/*.db .git* Jenkinsfile *.html .rubocop.yml
cd /tmp
tar -czvf $ZIP_FILE url-shortener/
mv /tmp/$ZIP_FILE $CUR_DIR/
'''
}
archiveArtifacts artifacts: '*.tgz'
}
}
stage('Generate SHA256 Hash and Upload to Artifact Repository') {
environment {
ARTIFACTS_KEY = credentials('artifactor-key')
}
steps {
sshagent(['artifactor-key']) {
sh ''' #!/usr/local/bin/bash
UUID=$(uuidgen -r)
VERSION=$(cat VERSION | cut -d"'" -f2)
BRANCH=${BRANCH_NAME}
ZIP_FILE="url-shortener_${BRANCH_NAME}_$(cat VERSION | cut -d"'" -f2).tgz"
sha256 $ZIP_FILE >> SHA256.sig
ssh artifactor@artifacts mkdir -p projects/url-shortener/$BRANCH/$VERSION/$UUID
rsync SHA256.sig artifactor@artifacts:projects/url-shortener/$BRANCH/$VERSION/$UUID/
rsync $ZIP_FILE artifactor@artifacts:projects/url-shortener/$BRANCH/$VERSION/$UUID/
'''
}
}
}
stage('Clean up deliverable') {
when {
expression {
buildArtifact
}
}
steps {
sh 'rm -rf /tmp/url-shortener'
sh 'rm SHA256.sig'
}
}
}
@ -57,5 +162,8 @@ pipeline {
failure {
mattermostSend channel: 'git-messages', color: 'danger', message: "[${JOB_NAME}](${JOB_URL}) [#${BUILD_NUMBER}](${BUILD_URL}) ([Gitea](${GIT_URL}))", text: "Build Failed"
}
always {
cleanWs deleteDirs: true, patterns: [[pattern: '*', type: 'INCLUDE']]
}
}
}

View File

@ -1,11 +1,11 @@
# simple url shortener
this project is a simple solution to build out a URL shortener using
Roda, Falcon, Sequel, and SQLite
Roda, Puma, Sequel, and SQLite on a FreeBSD Jail
the point of this project is to quickly build something and work on continuous deployment while making small refinements to the functional pieces.
the outside pieces of software that this project relies on are sqlite3 and pkgconf.
the outside pieces of software that this project relies on are rbenv, ruby-build, sqlite3, and pkgconf.
@ -14,9 +14,9 @@ first you have to install the dependencies:
`bundle install`
if you want the development group included run this first:
if you want to skip the test dependencies:
`bundle config set --local with 'development'`
`bundle config set --local without 'test'`
then create a .env.rb file in the root directory that contains the following ENV attributes:
@ -24,15 +24,19 @@ then create a .env.rb file in the root directory that contains the following ENV
```
ENV["APP_SESSION_SECRET"] = {output of a random 64 byte secret}
ENV["DB_NAME"] = {db file name}
ENV["DB_NAME"] = {DB_NAME}
```
after the dependencies are installed, you have to create the db
after the dependencies are installed, you have to create the db and schema
`sequel -m db/migrations sqlite://db/{DB_NAME}`
to start the application with Falcon:
to start the application with Puma:
`rackup -o {ip address} -p {port} -s falcon`
`rackup -o {ip address} -p {port}`
to run it as a daemon:
`rackup -o {ip address} -p {port} -D`

1
VERSION 100644
View File

@ -0,0 +1 @@
VERSION = '1.0.1'

69
app.rb
View File

@ -1,9 +1,12 @@
# frozen_string_literal: true
require 'roda'
require 'securerandom'
require 'json'
require 'sequel'
require 'open-uri'
# URL Shortener App class
class App < Roda
plugin :sessions, secret: ENV.delete('APP_SESSION_SECRET')
plugin :render, escape: true
@ -11,92 +14,92 @@ class App < Roda
plugin :json_parser
plugin :request_headers
DB = Sequel.sqlite("db/#{ENV['DB_NAME']}")
DB = Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}")
links = DB[:links]
route do |r|
r.root do
@message = flash['message'] || "Enter a URL"
@message = flash['message'] || 'Enter a URL'
view :home
end
r.get String do | url_code |
link = links.filter(:code => url_code)
r.get String do |url_code|
link = links.filter(code: url_code)
r.redirect link.first[:url] unless link.first.nil?
@message = "Link #{url_code} doesn't exist"
response.status = 404
view :home
end
r.post "create" do
r.post 'create' do
url = r.params['url']
if url.nil? or url.empty?
flash['message'] = "Please enter a valid URL";
if url.nil? || url.empty?
flash['message'] = 'Please enter a valid URL'
r.redirect '/'
end
begin
OpenURI.open_uri(url)
rescue URI::BadURIError
flash['message'] = "Invalid URL"
flash['message'] = 'Invalid URL'
r.redirect '/'
rescue OpenURI::HTTPError
flash['message'] = "URL not found"
flash['message'] = 'URL not found'
r.redirect '/'
rescue SocketError => e
flash['message'] = "URL does not resolve"
rescue SocketError
flash['message'] = 'URL does not resolve'
r.redirect '/'
end
if links.filter(:url => url).first.nil?
if links.filter(url:).first.nil?
code = SecureRandom.urlsafe_base64 4
links.insert(url: url, code: code)
@message = "Link created"
links.insert(url:, code:)
@message = 'Link created'
end
code = links.filter(:url => url).first[:code]
@message ||= "Link exists"
@new_link = 'http://' + request.env['HTTP_HOST'] + '/' + code
view :create
code = links.filter(url:).first[:code]
@message ||= 'Link exists'
@new_link = "http://#{request.env['HTTP_HOST']}/#{code}"
view :create
end
r.on "links" do
r.on 'links' do
r.post do
if 'application/json' != r.headers['CONTENT_TYPE']
if r.headers['CONTENT_TYPE'] != 'application/json'
response.status = 400
return {message: "not a valid json request"}.to_json
return { message: 'not a valid json request' }.to_json
end
url = r.params['url']
if url.nil?
response.status = 400
return {message: "missing url parameter"}.to_json
return { message: 'missing url parameter' }.to_json
end
if url.empty?
if url.empty?
response.status = 400
return {message: "invalid url parameter"}.to_json
return { message: 'invalid url parameter' }.to_json
end
begin
OpenURI.open_uri(url)
rescue URI::BadURIError
response.status = 400
return {message: "invalid url parameter"}.to_json
return { message: 'invalid url parameter' }.to_json
rescue OpenURI::HTTPError
response.status = 400
return {message: "url not found"}.to_json
rescue SocketError => e
return { message: 'url not found' }.to_json
rescue SocketError
response.status = 400
return {message: "url does not resolve"}.to_json
return { message: 'url does not resolve' }.to_json
end
if links.filter(:url => url).first.nil?
if links.filter(url:).first.nil?
code = SecureRandom.urlsafe_base64 4
links.insert(url: url, code: code)
links.insert(url:, code:)
end
code = links.filter(:url => url).first[:code]
@new_link = 'http://' + request.env['HTTP_HOST'] + '/' + code
return {url: url, code: code, link: @new_link}.to_json
code = links.filter(url:).first[:code]
@new_link = "http://#{request.env['HTTP_HOST']}/#{code}"
return { url:, code:, link: @new_link }.to_json
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require './.env'
require './app'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
Sequel.migration do
change do
create_table :links do

View File

@ -1,9 +1,10 @@
# frozen_string_literal: true
# BEFORE
Before('@db-test') do
@links = Sequel.sqlite("db/#{ENV['DB_NAME']}")[:links]
@links = Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}")[:links]
end
# GIVEN
Given('I visit the {string} page') do |string|
@ -11,18 +12,17 @@ Given('I visit the {string} page') do |string|
end
Given('A link already exists with the url {string}') do |string|
@links.insert(url: string, code: "aaaaaa")
@links.insert(url: string, code: 'aaaaaa')
end
Given('A link already exists with the url {string} and code {string}') do |url, code|
@links.insert(url: url, code: code)
@links.insert(url:, code:)
end
# WHEN
When('I click the {string} button') do |string|
click_button {string}
click_button { string }
end
When('I type {string} in the {string} field') do |text, field|
@ -33,7 +33,6 @@ When('I visit the {string} location') do |string|
visit string
end
# THEN
Then('I should see text {string}') do |string|
@ -66,7 +65,6 @@ Then('The status code should be {int}') do |code|
page.status_code.should eq(code)
end
# AFTER
After('@db-test') do

View File

@ -1,25 +1,27 @@
# frozen_string_literal: true
require 'simplecov'
SimpleCov.start
require_relative '../../.env'
ENV["DB_NAME"] = "test_#{ENV["DB_NAME"]}"
ENV['DB_NAME'] = "test_#{ENV.fetch('DB_NAME', nil)}"
require_relative '../../app'
require 'rubygems'
require 'roda'
require 'sequel'
require 'capybara'
require 'capybara/dsl'
require 'capybara/cucumber'
require 'rspec'
###
require 'rspec/expectations'
require 'rspec/matchers'
# DB initialization
Sequel.extension :migration
Sequel.sqlite("db/#{ENV['DB_NAME']}") do |db|
Sequel::Migrator.apply(db, "db/migrations")
Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}") do |db|
Sequel::Migrator.apply(db, 'db/migrations')
end
# attach app to Capybara
Capybara.app = App
include Capybara::DSL
include RSpec::Expectations
include RSpec::Matchers

View File

@ -1,2 +0,0 @@
require 'securerandom'
puts SecureRandom.base64(64).inspect()

View File

@ -1,8 +1,10 @@
# frozen_string_literal: true
require 'simplecov'
SimpleCov.start
require_relative '../.env'
ENV["DB_NAME"] = "test_#{ENV["DB_NAME"]}"
ENV['DB_NAME'] = "test_#{ENV.fetch('DB_NAME', nil)}"
require_relative '../app'
require 'rubygems'
require 'roda'
@ -12,48 +14,47 @@ require 'rack/test'
# DB initialization
Sequel.extension :migration
Sequel.sqlite("db/#{ENV['DB_NAME']}") do |db|
Sequel::Migrator.apply(db, "db/migrations")
Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}") do |db|
Sequel::Migrator.apply(db, 'db/migrations')
end
def app
App
end
describe "Submit API request to create new link" do
describe 'Submit API request to create new link' do
include Rack::Test::Methods
before :each do
@links = Sequel.sqlite("db/#{ENV['DB_NAME']}")[:links]
@links = Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}")[:links]
end
after :each do
@links.delete
end
it "should return link data in json format when a valid url is submitted" do
it 'should return link data in json format when a valid url is submitted' do
data = {
url: 'http://google.com'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response).to be_ok
response_json = JSON.parse(last_response.body)
expect(response_json['url']).to eq(data[:url])
expect(response_json['code']).not_to eq(nil)
expect(response_json['link']).to include(response_json['code'])
end
it "should return with a 400 status and 'invalid url parameter' message when an empty url is submitted" do
data = {
url: ''
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('invalid url parameter')
end
it "should return with a 400 status and 'missing url parameter' message when an empty url is submitted" do
data = {
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
data = {}
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('missing url parameter')
@ -63,7 +64,7 @@ describe "Submit API request to create new link" do
data = {
url: 'not-an-url'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('invalid url parameter')
@ -73,7 +74,7 @@ describe "Submit API request to create new link" do
data = {
url: 'http://google.com/example'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('url not found')
@ -83,13 +84,14 @@ describe "Submit API request to create new link" do
data = {
url: 'http://bad.tld'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
post('/links', data.to_json, 'CONTENT_TYPE' => 'application/json')
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('url does not resolve')
end
it "should return with a 400 status and 'not a valid json request' message when a request is made with the wrong content type header" do
it "should return with a 400 status and 'not a valid json request'
message when a request is made with the wrong content type header" do
data = {
url: 'http://google.com'
}