From 6dcfdf8cb149382cd71b69942c0a38773e71f6ac Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 6 Nov 2021 21:42:17 -0400 Subject: [PATCH 1/9] Add new table to support projects for every report --- db/migrate/20211106175125_add_projects.rb | 18 ++++++++++++++++++ db/schema.rb | 17 ++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20211106175125_add_projects.rb diff --git a/db/migrate/20211106175125_add_projects.rb b/db/migrate/20211106175125_add_projects.rb new file mode 100644 index 0000000..75970bf --- /dev/null +++ b/db/migrate/20211106175125_add_projects.rb @@ -0,0 +1,18 @@ +class AddProjects < ActiveRecord::Migration[6.1] + def up + create_table :projects do |t| + t.string :git_url + t.string :permalink + t.string :name + t.timestamps + end + + add_reference :reports, :project, foreign_key: true + end + + def down + remove_reference :reports, :project, foreign_key: true + + drop_table :projects + end +end diff --git a/db/schema.rb b/db/schema.rb index 4bca949..d0ef234 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,15 +2,15 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# This file is the source Rails uses to define your schema when running `rails -# db:schema:load`. When creating a new database, `rails db:schema:load` tends to +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to # be faster and is potentially less error prone than running all of your # migrations from scratch. Old migrations may fail to apply correctly if those # migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_03_27_014813) do +ActiveRecord::Schema.define(version: 2021_11_06_175125) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -28,12 +28,23 @@ t.index ["report_id"], name: "index_analyzed_files_on_report_id" end + create_table "projects", force: :cascade do |t| + t.string "git_url" + t.string "permalink" + t.string "name" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "reports", id: :serial, force: :cascade do |t| t.text "report" t.boolean "compare" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "slug" + t.bigint "project_id" + t.index ["project_id"], name: "index_reports_on_project_id" end + add_foreign_key "reports", "projects" end From 4844614938a5d5b3a342d56757151af7de25c4b1 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 6 Nov 2021 21:42:42 -0400 Subject: [PATCH 2/9] Add support for projects Projects can be specified by permalink or id --- app/controllers/reports_controller.rb | 45 +++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 26d0726..d5219d8 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -5,15 +5,10 @@ class ReportsController < ApplicationController def create data = request.body.read - begin - input = JSON.parse data - rescue => err - logger.fatal("Error: #{err.message} || #{data}") - head 400 - return - end + input = JSON.parse data entries = input["entries"] + project = find_project(input) unless entries.is_a? Array head 400 @@ -38,7 +33,7 @@ def create end end - rep = Report.create report: JSON.generate(entries) + rep = create_report(project, entries) options = input["options"] || {} @@ -48,10 +43,42 @@ def create rep.save - render json: {id: rep.slug} + render json: response_hash(rep) + rescue => err + logger.fatal("Error: #{err.message} || #{data}") + head 400 + nil end def show @report = Report.find_by slug: params[:id] end + + private + + def create_report(project, entries) + if project + project.reports.create report: JSON.generate(entries) + else + Report.create report: JSON.generate(entries) + end + end + + def find_project(input) + return if input["project"].blank? + + if input["project"]["id"] + Project.find(input["project"]["id"]) + elsif input["project"]["permalink"] + Project.find_or_create_by(permalink: input["project"]["permalink"]) + end + end + + def response_hash(report) + if report.project.present? + {id: report.slug, project_id: report.project_id} + else + {id: report.slug} + end + end end From d20de69d2dd6d4139598de6de082b2a08099fdf6 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 6 Nov 2021 21:43:04 -0400 Subject: [PATCH 3/9] Add scenarios for users submitting reports for projects --- test/controllers/reports_controller_test.rb | 127 ++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/test/controllers/reports_controller_test.rb b/test/controllers/reports_controller_test.rb index e7fd801..a8c01bb 100644 --- a/test/controllers/reports_controller_test.rb +++ b/test/controllers/reports_controller_test.rb @@ -59,6 +59,96 @@ class ReportsControllerTest < ActionController::TestCase assert_equal JSON.parse(raw), report.data end + test "creates a project with a new permalink and attaches the report to it" do + permalink = "github/fastruby/skunk" + data = <<~DATA + { + "project": { + "permalink": "#{permalink}" + }, + "entries": + [{ + "file": "lib/skunk/share.rb", + "skunk_score": "127.64", + "churn_times_cost": "2.55", + "churn": "2", + "cost": "1.28", + "coverage": "0.0" + }], + "summary": { + "total_skunk_score": "278.58", + "analysed_modules_count": "17", + "skunk_score_average": "16.39", + "skunk_version": "0.4.2", + "worst_skunk_score": { + "file": "lib/skunk/share.rb", + "skunk_score": "127.64" + } + }, + "options": { + "compare": "false" + } + } + DATA + + post :create, body: data + + assert_equal "200", @response.code + + rep = JSON.parse @response.body + + report = Report.find_by slug: rep["id"] + project = report.project + + assert_equal project.permalink, permalink + end + + test "assigns a project to an existing project" do + permalink = "github/fastruby/skunk" + existing_project = Project.create(permalink: permalink) + project_id = existing_project.id + data = <<~DATA + { + "project": { + "id": "#{project_id}" + }, + "entries": + [{ + "file": "lib/skunk/share.rb", + "skunk_score": "127.64", + "churn_times_cost": "2.55", + "churn": "2", + "cost": "1.28", + "coverage": "0.0" + }], + "summary": { + "total_skunk_score": "278.58", + "analysed_modules_count": "17", + "skunk_score_average": "16.39", + "skunk_version": "0.4.2", + "worst_skunk_score": { + "file": "lib/skunk/share.rb", + "skunk_score": "127.64" + } + }, + "options": { + "compare": "false" + } + } + DATA + + post :create, body: data + + assert_equal "200", @response.code + + rep = JSON.parse @response.body + + report = Report.find_by slug: rep["id"] + project = report.project + + assert_equal project.permalink, permalink + end + test "errors on unknown data keys" do data = <<-DATA { @@ -93,6 +183,43 @@ class ReportsControllerTest < ActionController::TestCase assert_equal "400", @response.code end + test "errors on unknown project" do + project_id = "-1" + data = <<~DATA + { + "project": { + "id": "#{project_id}" + }, + "entries": + [{ + "file": "lib/skunk/share.rb", + "skunk_score": "127.64", + "churn_times_cost": "2.55", + "churn": "2", + "cost": "1.28", + "coverage": "0.0" + }], + "summary": { + "total_skunk_score": "278.58", + "analysed_modules_count": "17", + "skunk_score_average": "16.39", + "skunk_version": "0.4.2", + "worst_skunk_score": { + "file": "lib/skunk/share.rb", + "skunk_score": "127.64" + } + }, + "options": { + "compare": "false" + } + } + DATA + + post :create, body: data + + assert_equal "400", @response.code + end + test "errors out if there are keys missing" do data = <<-DATA { From 351382b3a70f13046ce841b6869c9d66c51b5438 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 6 Nov 2021 21:43:27 -0400 Subject: [PATCH 4/9] Add relationship between report and project A project can have many reports. --- app/models/project.rb | 3 +++ app/models/report.rb | 1 + 2 files changed, 4 insertions(+) create mode 100644 app/models/project.rb diff --git a/app/models/project.rb b/app/models/project.rb new file mode 100644 index 0000000..096798b --- /dev/null +++ b/app/models/project.rb @@ -0,0 +1,3 @@ +class Project < ActiveRecord::Base + has_many :reports +end diff --git a/app/models/report.rb b/app/models/report.rb index 6a92f41..3068241 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -8,6 +8,7 @@ class Report < ActiveRecord::Base validates :slug, uniqueness: true validate :validate_parseability + belongs_to :project, optional: true has_many :analyzed_files def build_files From 8fa461d40edbcdb034a2c6cef9a43a9a32e6cfe6 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 6 Nov 2021 21:43:51 -0400 Subject: [PATCH 5/9] Add projects to the madmin interface --- app/controllers/madmin/projects_controller.rb | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/controllers/madmin/projects_controller.rb diff --git a/app/controllers/madmin/projects_controller.rb b/app/controllers/madmin/projects_controller.rb new file mode 100644 index 0000000..7547e93 --- /dev/null +++ b/app/controllers/madmin/projects_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ProjectsController < Madmin::ResourceController + end +end From 8ee42404c88e2ed2c790a804c8bf8554f96ff958 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Mon, 8 Nov 2021 23:09:01 -0500 Subject: [PATCH 6/9] Add unique index to projects.permalink --- db/migrate/20211106175125_add_projects.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/migrate/20211106175125_add_projects.rb b/db/migrate/20211106175125_add_projects.rb index 75970bf..293376e 100644 --- a/db/migrate/20211106175125_add_projects.rb +++ b/db/migrate/20211106175125_add_projects.rb @@ -8,6 +8,7 @@ def up end add_reference :reports, :project, foreign_key: true + add_index :projects, :permalink, unique: true end def down From 3d6e22a362b7bdc703acf31e0ee36ad6b2be90f8 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Mon, 8 Nov 2021 23:09:18 -0500 Subject: [PATCH 7/9] Add uniqueness validation for permalink field --- app/models/project.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 096798b..2d23265 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,3 +1,5 @@ class Project < ActiveRecord::Base has_many :reports + + validates :permalink, uniqueness: true end From 858875b72f6388b364e52c5da67528e9c074135e Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Mon, 8 Nov 2021 23:09:33 -0500 Subject: [PATCH 8/9] Added a new index to the projects table --- db/schema.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/schema.rb b/db/schema.rb index d0ef234..0bc9393 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -34,6 +34,7 @@ t.string "name" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.index ["permalink"], name: "index_projects_on_permalink", unique: true end create_table "reports", id: :serial, force: :cascade do |t| From b48e88474b1719095e98f60277e16b698596494c Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Mon, 8 Nov 2021 23:10:29 -0500 Subject: [PATCH 9/9] Make comparison more generic --- test/controllers/reports_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/controllers/reports_controller_test.rb b/test/controllers/reports_controller_test.rb index a8c01bb..eb2e0ad 100644 --- a/test/controllers/reports_controller_test.rb +++ b/test/controllers/reports_controller_test.rb @@ -146,7 +146,7 @@ class ReportsControllerTest < ActionController::TestCase report = Report.find_by slug: rep["id"] project = report.project - assert_equal project.permalink, permalink + assert_equal project, existing_project end test "errors on unknown data keys" do