Minor merge conflict in package.json while merging `staging`
commit
63bf7b08c7
|
@ -42,4 +42,4 @@ jobs:
|
|||
- run:
|
||||
name: Check Coveralls coverage on staging
|
||||
command: |
|
||||
sudo docker-compose run -e CIRCLE_SHA1="$CIRCLE_SHA1" web rake coverage:run
|
||||
sudo docker-compose run -e CIRCLE_SHA1="$CIRCLE_SHA1" -e CIRCLE_BRANCH="$CIRCLE_BRANCH" web rake coverage:run
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
class SendNervesHubInfoJob < ApplicationJob
|
||||
WHOOPS = "SendNervesHubInfoJob Failure"
|
||||
queue_as :default
|
||||
|
||||
def perform(device_id:, serial_number:, tags:)
|
||||
device = Device.find(device_id)
|
||||
DeviceSerialNumber.transaction do
|
||||
device.update_attributes!(serial_number: serial_number)
|
||||
resp_data = NervesHub.create_or_update(serial_number, tags)
|
||||
certs = NervesHub.sign_device(resp_data.fetch(:identifier))
|
||||
Transport.current.amqp_send(certs.to_json, device_id, "nerves_hub")
|
||||
end
|
||||
device = Device.find(device_id)
|
||||
resp_data = NervesHub.create_or_update(serial_number, tags)
|
||||
certs = NervesHub.sign_device(resp_data.fetch(:identifier))
|
||||
Transport.current.amqp_send(certs.to_json, device_id, "nerves_hub")
|
||||
rescue => error
|
||||
Rollbar.error(WHOOPS, { error: error,
|
||||
device_id: device_id,
|
||||
serial_number: serial_number,
|
||||
tags: tags, })
|
||||
NervesHub.report_problem({ error: error,
|
||||
device_id: device_id,
|
||||
serial_number: serial_number,
|
||||
tags: tags, })
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
|
|
@ -298,4 +298,9 @@ private
|
|||
def self.current_ca_file
|
||||
@current_ca_file ||= (try_env_ca_file || try_file_ca_file || nil)
|
||||
end
|
||||
|
||||
WHOOPS = "🚨 NervesHub Anomaly Detected! 🚨"
|
||||
def self.report_problem(payload = {})
|
||||
Rollbar.error(WHOOPS, payload)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,7 +32,6 @@ class Device < ApplicationRecord
|
|||
has_many :diagnostic_dumps, dependent: :destroy
|
||||
has_many :fragments, dependent: :destroy
|
||||
has_one :fbos_config, dependent: :destroy
|
||||
has_one :device_serial_number, dependent: :destroy
|
||||
has_many :in_use_tools
|
||||
has_many :in_use_points
|
||||
has_many :users
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
class DeviceSerialNumber < ApplicationRecord
|
||||
belongs_to :device
|
||||
# DO NOT USE THIS TABLE. IT IS DEPRECATED. DESTROY FEB 2019.
|
||||
end
|
|
@ -13,7 +13,15 @@ class FbosConfig < ApplicationRecord
|
|||
|
||||
def sync_nerves
|
||||
serial = device.serial_number
|
||||
return unless serial
|
||||
unless serial
|
||||
# This feature can be removed in May '19
|
||||
# It is used to repair data damage on
|
||||
# production during the initial nervehub
|
||||
# deployment.
|
||||
problem = "Device #{device.id} missing serial"
|
||||
NervesHub.report_problem({ problem: problem })
|
||||
return
|
||||
end
|
||||
self.delay.push_changes_to_nerves_hub(serial, update_channel)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module DeviceCerts
|
|||
SendNervesHubInfoJob.perform_later(device_id: device.id,
|
||||
serial_number: serial_number,
|
||||
tags: tags)
|
||||
return {}
|
||||
return device.update_attributes!(serial_number: serial_number) && device
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
class DeprecateDeviceSerialNumberTable < ActiveRecord::Migration[5.2]
|
||||
|
||||
unless Kernel.const_defined?("DeviceSerialNumber")
|
||||
# Shim so that legacy users don't crash when (up|down)grading
|
||||
class DeviceSerialNumber
|
||||
def self.preload(*x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def change
|
||||
DeviceSerialNumber.preload(:devices) do |x|
|
||||
x.device
|
||||
.update_attributes!(serial_number: x.serial_number)
|
||||
x.device.update_attributes!(serial_number: x.serial_number)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class RemoveDeviceSerialNumberTable < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
drop_table :device_serial_numbers
|
||||
end
|
||||
end
|
|
@ -14,7 +14,6 @@ if Rails.env == "development"
|
|||
[
|
||||
Sensor,
|
||||
Peripheral,
|
||||
DeviceSerialNumber,
|
||||
Log,
|
||||
PinBinding,
|
||||
Point,
|
||||
|
|
|
@ -153,38 +153,6 @@ CREATE SEQUENCE public.delayed_jobs_id_seq
|
|||
ALTER SEQUENCE public.delayed_jobs_id_seq OWNED BY public.delayed_jobs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.device_serial_numbers (
|
||||
id bigint NOT NULL,
|
||||
device_id bigint,
|
||||
serial_number character varying(16) NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.device_serial_numbers_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.device_serial_numbers_id_seq OWNED BY public.device_serial_numbers.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: devices; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -385,8 +353,7 @@ CREATE TABLE public.farmware_installations (
|
|||
url character varying,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL,
|
||||
package character varying(80),
|
||||
package_error character varying
|
||||
package character varying(80)
|
||||
);
|
||||
|
||||
|
||||
|
@ -1580,13 +1547,6 @@ ALTER TABLE ONLY public.arg_sets ALTER COLUMN id SET DEFAULT nextval('public.arg
|
|||
ALTER TABLE ONLY public.delayed_jobs ALTER COLUMN id SET DEFAULT nextval('public.delayed_jobs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.device_serial_numbers ALTER COLUMN id SET DEFAULT nextval('public.device_serial_numbers_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: devices id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1850,14 +1810,6 @@ ALTER TABLE ONLY public.delayed_jobs
|
|||
ADD CONSTRAINT delayed_jobs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers device_serial_numbers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.device_serial_numbers
|
||||
ADD CONSTRAINT device_serial_numbers_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: devices devices_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2151,13 +2103,6 @@ CREATE INDEX index_arg_sets_on_fragment_id ON public.arg_sets USING btree (fragm
|
|||
CREATE INDEX index_arg_sets_on_node_id ON public.arg_sets USING btree (node_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_device_serial_numbers_on_device_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_device_serial_numbers_on_device_id ON public.device_serial_numbers USING btree (device_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_devices_on_mounted_tool_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2720,14 +2665,6 @@ ALTER TABLE ONLY public.edge_nodes
|
|||
ADD CONSTRAINT fk_rails_c86213fd78 FOREIGN KEY (sequence_id) REFERENCES public.sequences(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: device_serial_numbers fk_rails_d052988096; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.device_serial_numbers
|
||||
ADD CONSTRAINT fk_rails_d052988096 FOREIGN KEY (device_id) REFERENCES public.devices(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: points fk_rails_d6f3cdbe9a; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2878,6 +2815,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20190103211708'),
|
||||
('20190103213956'),
|
||||
('20190108211419'),
|
||||
('20190209133811');
|
||||
('20190209133811'),
|
||||
('20190212215842');
|
||||
|
||||
|
||||
|
|
|
@ -31,21 +31,23 @@ import { ready, storeToken } from "../actions";
|
|||
import { setToken, didLogin } from "../../auth/actions";
|
||||
import { Session } from "../../session";
|
||||
import { auth } from "../../__test_support__/fake_state/token";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
|
||||
describe("Actions", () => {
|
||||
it("calls didLogin()", () => {
|
||||
jest.resetAllMocks();
|
||||
const dispatch = jest.fn();
|
||||
const getState = jest.fn(() => mockState);
|
||||
const thunk = ready();
|
||||
thunk(dispatch, getState);
|
||||
thunk(dispatch, fakeState);
|
||||
expect(setToken).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Calls Session.clear() when missing auth", () => {
|
||||
jest.resetAllMocks();
|
||||
const dispatch = jest.fn();
|
||||
const getState = jest.fn(() => ({}));
|
||||
const state = fakeState();
|
||||
delete state.auth;
|
||||
const getState = () => state;
|
||||
const thunk = ready();
|
||||
thunk(dispatch, getState);
|
||||
expect(Session.clear).toHaveBeenCalled();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { toggleWebAppBool } from "../actions";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
|
||||
jest.mock("../../api/crud", () => {
|
||||
return { save: jest.fn(), edit: jest.fn() };
|
||||
|
@ -13,8 +14,7 @@ describe("toggleWebAppBool", () => {
|
|||
it("toggles things", () => {
|
||||
const action = toggleWebAppBool(BooleanSetting.show_first_party_farmware);
|
||||
const dispatch = jest.fn();
|
||||
const getState = jest.fn(() => ({ resources: { index: {} } }));
|
||||
const kaboom = () => action(dispatch, getState);
|
||||
const kaboom = () => action(dispatch, fakeState);
|
||||
expect(kaboom).toThrowError("Toggled settings before app was loaded.");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { toggleWebAppBool, getWebAppConfigValue, setWebAppConfigValue } from "../actions";
|
||||
import {
|
||||
toggleWebAppBool, getWebAppConfigValue, setWebAppConfigValue
|
||||
} from "../actions";
|
||||
import { BooleanSetting, NumericSetting } from "../../session_keys";
|
||||
import { edit, save } from "../../api/crud";
|
||||
import { fakeWebAppConfig } from "../../__test_support__/fake_state/resources";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
|
||||
jest.mock("../../api/crud", () => {
|
||||
return { save: jest.fn(), edit: jest.fn() };
|
||||
|
@ -18,8 +21,7 @@ describe("toggleWebAppBool", () => {
|
|||
it("toggles things", () => {
|
||||
const action = toggleWebAppBool(BooleanSetting.show_first_party_farmware);
|
||||
const dispatch = jest.fn();
|
||||
const getState = jest.fn(() => ({ resources: { index: {} } }));
|
||||
action(dispatch, getState);
|
||||
action(dispatch, fakeState);
|
||||
expect(edit).toHaveBeenCalledWith(mockConfig, {
|
||||
show_first_party_farmware: true
|
||||
});
|
||||
|
@ -28,8 +30,7 @@ describe("toggleWebAppBool", () => {
|
|||
});
|
||||
|
||||
describe("getWebAppConfigValue", () => {
|
||||
const getState = jest.fn(() => ({ resources: { index: {} } }));
|
||||
const getValue = getWebAppConfigValue(getState);
|
||||
const getValue = getWebAppConfigValue(fakeState);
|
||||
|
||||
it("gets a boolean setting value", () => {
|
||||
expect(getValue(BooleanSetting.show_first_party_farmware)).toEqual(false);
|
||||
|
@ -41,10 +42,8 @@ describe("getWebAppConfigValue", () => {
|
|||
});
|
||||
|
||||
describe("setWebAppConfigValue", () => {
|
||||
const getState = jest.fn(() => ({ resources: { index: {} } }));
|
||||
|
||||
it("sets a numeric setting value", () => {
|
||||
setWebAppConfigValue(NumericSetting.fun_log, 2)(jest.fn(), getState);
|
||||
setWebAppConfigValue(NumericSetting.fun_log, 2)(jest.fn(), fakeState);
|
||||
expect(edit).toHaveBeenCalledWith(mockConfig, { fun_log: 2 });
|
||||
expect(save).toHaveBeenCalledWith(mockConfig.uuid);
|
||||
});
|
||||
|
@ -53,7 +52,7 @@ describe("setWebAppConfigValue", () => {
|
|||
// tslint:disable-next-line:no-any
|
||||
mockConfig = undefined as any;
|
||||
const action = () => setWebAppConfigValue(NumericSetting.fun_log, 1)(
|
||||
jest.fn(), getState);
|
||||
jest.fn(), fakeState);
|
||||
expect(action).toThrowError("Changed settings before app was loaded.");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -222,7 +222,7 @@ describe("settingToggle()", () => {
|
|||
window.alert = jest.fn();
|
||||
const msg = "this is an alert.";
|
||||
actions.settingToggle(
|
||||
"param_mov_nr_retry", jest.fn(() => ({ value: "" })),
|
||||
"param_mov_nr_retry", jest.fn(() => ({ value: 1, consistent: true })),
|
||||
msg)(jest.fn(), fakeState);
|
||||
expect(window.alert).toHaveBeenCalledWith(msg);
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ describe("onInit()", () => {
|
|||
await onInit({}, jest.fn());
|
||||
expect({}).toBeTruthy();
|
||||
expect(render).toHaveBeenCalled();
|
||||
const [calls] = (render as jest.Mock<{}>).mock.calls;
|
||||
const [calls] = (render as jest.Mock).mock.calls;
|
||||
expect(calls[0].type.name).toBe("PasswordReset");
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -1,14 +1,64 @@
|
|||
COVERAGE_FILE_PATH = "./coverage_fe/index.html"
|
||||
THRESHOLD = 0.001
|
||||
REPO_URL = "https://api.github.com/repos/Farmbot/Farmbot-Web-App/git"\
|
||||
"/refs/heads/staging"
|
||||
REPO_URL = "https://api.github.com/repos/Farmbot/Farmbot-Web-App"
|
||||
CURRENT_BRANCH = ENV.fetch("CIRCLE_BRANCH", "staging")
|
||||
CURRENT_COMMIT = ENV.fetch("CIRCLE_SHA1", "")
|
||||
CSS_SELECTOR = ".fraction"
|
||||
FRACTION_DELIM = "/"
|
||||
|
||||
# Fetch JSON over HTTP. Rails probably already has a helper for this :shrug:
|
||||
def open_json(url)
|
||||
JSON.parse(open(url).read)
|
||||
begin
|
||||
JSON.parse(open(url).read)
|
||||
rescue OpenURI::HTTPError => exception
|
||||
puts exception.message
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
# Get pull request information from the GitHub API.
|
||||
def fetch_pull_data()
|
||||
if CURRENT_BRANCH.include? "/"
|
||||
return open_json("#{REPO_URL}/pulls/#{CURRENT_BRANCH.split("/")[1]}")
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
# Determine the base branch of the current build.
|
||||
def get_current_branch(pull_data)
|
||||
pull_data.dig("base", "ref") || CURRENT_BRANCH
|
||||
end
|
||||
|
||||
# Assemble the coverage data URL using the provided branch.
|
||||
def coverage_url(branch)
|
||||
commit = open_json("#{REPO_URL}/git/refs/heads/#{branch}").dig("object", "sha")
|
||||
return "https://coveralls.io/builds/#{commit}.json"
|
||||
end
|
||||
|
||||
# Fetch relevant remote coverage data.
|
||||
def fetch_build_data(url)
|
||||
build_data = open_json(url)
|
||||
return {
|
||||
branch: build_data["branch"],
|
||||
commit: build_data["commit_sha"],
|
||||
percent: build_data["covered_percent"]}
|
||||
end
|
||||
|
||||
# <commit hash> on <username>:<branch>
|
||||
def branch_info_string?(target, pull_data)
|
||||
unless pull_data.dig(target, "sha").nil?
|
||||
"#{pull_data.dig(target, "sha")} on #{pull_data.dig(target, "label")}"
|
||||
end
|
||||
end
|
||||
|
||||
# Print a coverage difference summary string.
|
||||
def print_summary_text(build_percent, remote, pull_data)
|
||||
diff = (build_percent - remote[:percent]).round(2)
|
||||
direction = diff > 0 ? "increased" : "decreased"
|
||||
description = diff == 0 ? "remained the same at" : "#{direction} (#{diff}%) to"
|
||||
puts "Coverage #{description} #{build_percent.round(3)}%"\
|
||||
" when pulling #{branch_info_string?("head", pull_data)}"\
|
||||
" into #{branch_info_string?("base", pull_data) || remote[:branch]}."
|
||||
end
|
||||
|
||||
def to_percent(pair)
|
||||
|
@ -18,6 +68,7 @@ end
|
|||
namespace :coverage do
|
||||
desc "Coveralls stats stopped working :("
|
||||
task run: :environment do
|
||||
# Fetch current build coverage data from the HTML summary.
|
||||
statements, branches, functions, lines = Nokogiri::HTML(open(COVERAGE_FILE_PATH))
|
||||
.css(CSS_SELECTOR)
|
||||
.map(&:text)
|
||||
|
@ -30,41 +81,66 @@ namespace :coverage do
|
|||
puts "Branches: #{to_percent(branches)}%"
|
||||
puts "Functions: #{to_percent(functions)}%"
|
||||
puts "Lines: #{to_percent(lines)}%"
|
||||
puts
|
||||
|
||||
# Calculate an aggregate coverage percentage for the current build.
|
||||
covered = lines.head + branches.head
|
||||
total = lines.tail + branches.tail
|
||||
build_percent = (covered / total) * 100
|
||||
puts "Aggregate: #{build_percent.round(4)}%"
|
||||
puts
|
||||
|
||||
latest_commit_staging = open_json(REPO_URL).dig("object", "sha")
|
||||
puts "staging: #{latest_commit_staging}"
|
||||
build_url = "https://coveralls.io/builds/#{latest_commit_staging}.json"
|
||||
any_build_url = "https://coveralls.io/github/FarmBot/Farmbot-Web-App.json"
|
||||
begin
|
||||
staging_percent = open_json(build_url).fetch("covered_percent") ||
|
||||
open_json(any_build_url).fetch("covered_percent")
|
||||
rescue OpenURI::HTTPError => exception
|
||||
puts exception.message
|
||||
# Attempt to fetch remote build coverage data for the current branch.
|
||||
pull_request_data = fetch_pull_data()
|
||||
current_branch = get_current_branch(pull_request_data)
|
||||
remote = fetch_build_data(coverage_url(current_branch))
|
||||
|
||||
if remote[:percent].nil? && CURRENT_COMMIT == remote[:commit]
|
||||
puts "Coverage already calculated for #{remote[:branch]}."
|
||||
puts "Using this build's data instead."
|
||||
remote[:percent] = build_percent
|
||||
end
|
||||
|
||||
if remote[:percent].nil? && current_branch != "staging"
|
||||
puts "Error getting coveralls data for #{current_branch}."
|
||||
puts "Attempting to use staging build coveralls data."
|
||||
remote = fetch_build_data(coverage_url("staging"))
|
||||
end
|
||||
|
||||
if remote[:percent].nil?
|
||||
puts "Error getting coveralls data for staging."
|
||||
puts "Attempting to use latest build coveralls data."
|
||||
latest_cov_url = "https://coveralls.io/github/FarmBot/Farmbot-Web-App.json"
|
||||
remote = fetch_build_data(latest_cov_url)
|
||||
end
|
||||
|
||||
if remote[:percent].nil?
|
||||
puts "Error getting coveralls data."
|
||||
puts "Wait for staging build to finish and try again."
|
||||
puts "If error continues, perhaps a blinky test failed the staging build."
|
||||
staging_percent = 100
|
||||
puts "Wait for build to finish and try again or check for build errors."
|
||||
puts "Using 100 instead of nil for remote coverage value."
|
||||
remote = {branch: "N/A", commit: "", percent: 100}
|
||||
end
|
||||
|
||||
if CURRENT_COMMIT == latest_commit_staging
|
||||
staging_percent = build_percent
|
||||
end
|
||||
# Adjust remote build data values for printing.
|
||||
r = {
|
||||
branch: (remote[:branch] + ' ' * 8)[0,8],
|
||||
percent: remote[:percent].round(8),
|
||||
commit: remote[:commit][0,8]}
|
||||
|
||||
diff = (build_percent - staging_percent)
|
||||
# Calculate coverage difference between the current and previous build.
|
||||
diff = (build_percent - remote[:percent])
|
||||
pass = (diff > -THRESHOLD)
|
||||
|
||||
puts
|
||||
puts "=" * 37
|
||||
puts "COVERAGE RESULTS"
|
||||
puts "This build: #{build_percent.round(8)}% #{CURRENT_COMMIT[0,8]}"
|
||||
puts "Staging build: #{staging_percent.round(8)}% #{latest_commit_staging[0,8]}"
|
||||
puts "This build: #{build_percent.round(8)}% #{CURRENT_COMMIT[0,8]}"
|
||||
puts "#{r[:branch]} build: #{r[:percent]}% #{r[:commit]}"
|
||||
puts "=" * 37
|
||||
puts "Difference: #{diff.round(8)}%"
|
||||
puts "Pass?: #{pass ? "yes" : "no"}"
|
||||
puts "Difference: #{diff.round(8)}%"
|
||||
puts "Pass? #{pass ? "yes" : "no"}"
|
||||
puts
|
||||
|
||||
print_summary_text(build_percent, remote, pull_request_data)
|
||||
|
||||
exit pass ? 0 : 1
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
PACKAGE_JSON_FILE = "./package.json"
|
||||
DEPS_KEY = "dependencies"
|
||||
EXCLUDE = ["i18next", "@types/i18next"]
|
||||
|
||||
# Load package.json as JSON.
|
||||
def load_package_json()
|
||||
return JSON.parse(open(PACKAGE_JSON_FILE).read)
|
||||
end
|
||||
|
||||
# Save JSON to package.json.
|
||||
def save_package_json(json)
|
||||
open(PACKAGE_JSON_FILE, "w") { |file|
|
||||
file.write(JSON.pretty_generate(json))
|
||||
file.puts
|
||||
}
|
||||
end
|
||||
|
||||
# Fetch latest versions for outdated dependencies.
|
||||
def fetch_available_upgrades()
|
||||
begin
|
||||
latest_json = JSON.parse(`npm outdated --json`)
|
||||
rescue JSON::ParserError => exception
|
||||
latest_json = {}
|
||||
end
|
||||
latest_versions = {}
|
||||
latest_json.each do |dep, data|
|
||||
unless EXCLUDE.include?(dep) || data["latest"].nil?
|
||||
latest_versions[dep] = data["latest"]
|
||||
end
|
||||
end
|
||||
return latest_versions
|
||||
end
|
||||
|
||||
# Install depdendency updates.
|
||||
def install_updates
|
||||
sh "sudo docker-compose run web npm install"
|
||||
end
|
||||
|
||||
namespace :fe do
|
||||
desc "Update frontend dependencies to the latest available."\
|
||||
"This often causes breakage. Use only for development."
|
||||
task update_deps: :environment do
|
||||
puts "begin?"; if !user_typed?("developer"); puts "done."; exit end
|
||||
available_upgrades = fetch_available_upgrades()
|
||||
if available_upgrades.length > 0
|
||||
max_key_length = available_upgrades.keys.max_by(&:length).length
|
||||
package_json = load_package_json()
|
||||
|
||||
puts
|
||||
puts "=" * 40
|
||||
puts "#{PACKAGE_JSON_FILE} AVAILABLE UPDATES:"
|
||||
available_upgrades.each do |dep, new_version|
|
||||
current_version = package_json[DEPS_KEY][dep]
|
||||
padding = ' ' * (max_key_length - dep.length)
|
||||
puts " #{dep} #{padding} #{current_version} -> #{new_version}"
|
||||
package_json[DEPS_KEY][dep] = new_version
|
||||
end
|
||||
puts "=" * 40
|
||||
|
||||
puts "Type 'save' to update #{PACKAGE_JSON_FILE}, enter to abort."
|
||||
save_package_json(package_json) if user_typed?("save")
|
||||
|
||||
puts "Saved. Use 'sudo docker-compose run web npm install' to upgrade."
|
||||
# install_updates if user_typed?("update")
|
||||
else
|
||||
puts "No updates available."
|
||||
end
|
||||
end
|
||||
end
|
55
package.json
55
package.json
|
@ -24,47 +24,48 @@
|
|||
"author": "farmbot.io",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "3.10.0",
|
||||
"@blueprintjs/datetime": "3.5.0",
|
||||
"@blueprintjs/select": "3.4.0",
|
||||
"@types/enzyme": "3.1.15",
|
||||
"@types/jest": "23.3.12",
|
||||
"@types/lodash": "4.14.120",
|
||||
"@blueprintjs/core": "3.13.0",
|
||||
"@blueprintjs/datetime": "3.7.1",
|
||||
"@blueprintjs/select": "3.6.1",
|
||||
"@types/enzyme": "3.1.18",
|
||||
"@types/i18next": "12.1.0",
|
||||
"@types/jest": "24.0.5",
|
||||
"@types/lodash": "4.14.121",
|
||||
"@types/markdown-it": "0.0.7",
|
||||
"@types/moxios": "0.4.8",
|
||||
"@types/node": "10.12.18",
|
||||
"@types/node": "11.9.4",
|
||||
"@types/promise-timeout": "1.3.0",
|
||||
"@types/react": "16.7.18",
|
||||
"@types/react-color": "2.14.0",
|
||||
"@types/react-dom": "16.0.11",
|
||||
"@types/react-redux": "6.0.12",
|
||||
"@types/react": "16.8.3",
|
||||
"@types/react-color": "2.14.1",
|
||||
"@types/react-dom": "16.8.1",
|
||||
"@types/react-redux": "7.0.1",
|
||||
"axios": "0.18.0",
|
||||
"boxed_value": "1.0.0",
|
||||
"browser-speech": "1.1.1",
|
||||
"coveralls": "3.0.2",
|
||||
"enzyme": "3.8.0",
|
||||
"enzyme-adapter-react-16": "1.7.1",
|
||||
"enzyme-adapter-react-16": "1.9.1",
|
||||
"farmbot": "7.0.0-rc7",
|
||||
"farmbot-toastr": "1.0.3",
|
||||
"i18next": "13.1.0",
|
||||
"jest": "23.6.0",
|
||||
"jest-cli": "23.6.0",
|
||||
"i18next": "12.1.0",
|
||||
"jest": "24.1.0",
|
||||
"jest-cli": "24.1.0",
|
||||
"lodash": "4.17.11",
|
||||
"markdown-it": "8.4.2",
|
||||
"markdown-it-emoji": "1.4.0",
|
||||
"moment": "2.23.0",
|
||||
"moment": "2.24.0",
|
||||
"moxios": "0.4.0",
|
||||
"parcel-bundler": "1.11.0",
|
||||
"promise-timeout": "1.3.0",
|
||||
"raf": "3.4.1",
|
||||
"react": "16.7.0",
|
||||
"react": "16.8.2",
|
||||
"react-addons-test-utils": "15.6.2",
|
||||
"react-color": "2.17.0",
|
||||
"react-dom": "16.7.0",
|
||||
"react-joyride": "2.0.2",
|
||||
"react-dom": "16.8.2",
|
||||
"react-joyride": "2.0.5",
|
||||
"react-redux": "6.0.0",
|
||||
"react-test-renderer": "16.7.0",
|
||||
"react-transition-group": "2.5.2",
|
||||
"react-test-renderer": "16.8.2",
|
||||
"react-transition-group": "2.5.3",
|
||||
"redux": "4.0.1",
|
||||
"redux-immutable-state-invariant": "2.1.0",
|
||||
"redux-thunk": "2.3.0",
|
||||
|
@ -72,14 +73,14 @@
|
|||
"takeme": "0.11.1",
|
||||
"ts-jest": "23.10.5",
|
||||
"ts-lint": "4.5.1",
|
||||
"tslint": "5.12.0",
|
||||
"typescript": "3.2.4",
|
||||
"tslint": "5.12.1",
|
||||
"typescript": "3.3.3",
|
||||
"which": "1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest-skipped-reporter": "0.0.4",
|
||||
"madge": "3.4.3",
|
||||
"sass": "1.16.1"
|
||||
"madge": "3.4.4",
|
||||
"sass": "1.17.0"
|
||||
},
|
||||
"jest": {
|
||||
"clearMocks": true,
|
||||
|
@ -130,6 +131,8 @@
|
|||
"lcov"
|
||||
],
|
||||
"coverageDirectory": "<rootDir>/coverage_fe",
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/frontend/__test_support__/customMatchers.js"
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/frontend/__test_support__/customMatchers.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ describe Api::DeviceCertsController do
|
|||
post_args = ["/orgs/farmbot/devices/456/certificates/sign",
|
||||
post_data,
|
||||
{"Content-Type"=>"application/json"}]
|
||||
old_count = DeviceSerialNumber.count
|
||||
|
||||
# Setup wiring ===========================================================
|
||||
NervesHub.set_conn(conn)
|
||||
|
@ -57,8 +56,8 @@ describe Api::DeviceCertsController do
|
|||
post :create, body: payl.to_json, params: {format: :json}
|
||||
end
|
||||
expect(response.status).to eq(200)
|
||||
expect(json).to eq({})
|
||||
expect(DeviceSerialNumber.count).to eq(old_count)
|
||||
expect(json).to be_kind_of(Hash)
|
||||
expect(json.fetch(:id)).to eq(device.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
FactoryBot.define do
|
||||
factory :device_serial_number do
|
||||
device { nil }
|
||||
serial_number { raise "Stop using this model" }
|
||||
end
|
||||
end
|
|
@ -1,17 +1,31 @@
|
|||
require 'spec_helper'
|
||||
require "spec_helper"
|
||||
|
||||
describe FbosConfig do
|
||||
let(:device) { FactoryBot.create(:device) }
|
||||
let(:config) { FbosConfig.create!(device: device) }
|
||||
let(:device) { FactoryBot.create(:device) }
|
||||
let(:config) { FbosConfig.create!(device: device) }
|
||||
|
||||
it 'triggers callbacks' do
|
||||
conn = double("Create a cert", :ca_file= => nil,
|
||||
:cert_store => nil,
|
||||
:cert_store= => nil,
|
||||
:use_ssl => nil,
|
||||
:use_ssl= => nil,
|
||||
:cert= => nil,
|
||||
:key= => nil)
|
||||
def fake_conn(desc)
|
||||
double(desc, :ca_file= => nil,
|
||||
:cert_store => nil,
|
||||
:cert_store= => nil,
|
||||
:use_ssl => nil,
|
||||
:use_ssl= => nil,
|
||||
:cert= => nil,
|
||||
:key= => nil)
|
||||
end
|
||||
|
||||
it "notifies us of broken production data" do
|
||||
# Remove this test by May 2019.
|
||||
config.device.update_attributes!(serial_number: nil)
|
||||
conn = fake_conn("Report broke data")
|
||||
NervesHub.set_conn(conn)
|
||||
problem = "Device #{device.id} missing serial"
|
||||
expect(NervesHub).to receive(:report_problem).with({ problem: problem })
|
||||
config.sync_nerves
|
||||
end
|
||||
|
||||
it "triggers callbacks" do
|
||||
conn = fake_conn("Create a cert")
|
||||
NervesHub.set_conn(conn)
|
||||
url = "/orgs/farmbot/devices/#{device.serial_number}"
|
||||
resp = StubResp.new("200", { "data" => { "tags": [] } }.to_json)
|
||||
|
|
|
@ -33,7 +33,7 @@ describe DeviceCerts::Create do
|
|||
result = DeviceCerts::Create.run!(tags: tags,
|
||||
device: device,
|
||||
serial_number: ser)
|
||||
expect(result).to eq({})
|
||||
expect(result).to eq(device)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import i18n from "i18next";
|
||||
|
||||
declare module "i18next" {
|
||||
export function init(options: i18n.InitOptions, callback?: i18n.Callback):
|
||||
Promise<i18n.TranslationFunction>;
|
||||
export const t: i18n.TranslationFunction;
|
||||
export type InitOptions = i18n.InitOptions;
|
||||
export type Callback = i18n.Callback;
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
/// <reference path="react-redux.d.ts" />
|
||||
/// <reference path="i18next.d.ts" />
|
||||
|
||||
/** This contains all of the global ENV vars passed from server => client.
|
||||
* Previously was `process.env.XYZ`. */
|
||||
|
|
Loading…
Reference in New Issue