Skip to content

Commit

Permalink
Merge branch 'staging' of github.com:FarmBot/Farmbot-Web-App into rec…
Browse files Browse the repository at this point in the history
…overy_deploy
  • Loading branch information
RickCarlino committed Jan 7, 2019
2 parents 2e94fc6 + 4e53486 commit 4a5550f
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 12 deletions.
7 changes: 4 additions & 3 deletions webpack/auth/__tests__/actions_test.ts
Expand Up @@ -22,14 +22,15 @@ jest.mock("../../api/api", () => ({

jest.mock("../../devices/actions", () => ({
fetchReleases: jest.fn(),
fetchLatestGHBetaRelease: jest.fn(),
fetchMinOsFeatureData: jest.fn(),
}));

import { didLogin } from "../actions";
import { Actions } from "../../constants";
import { API } from "../../api/api";
import { AuthState } from "../interfaces";
import { fetchReleases } from "../../devices/actions";
import { fetchReleases, fetchLatestGHBetaRelease } from "../../devices/actions";

const mockToken = (): AuthState => ({
token: {
Expand All @@ -56,7 +57,7 @@ describe("didLogin()", () => {
mockAuth.token.unencoded.beta_os_update_server = "beta_os_update_server";
didLogin(mockAuth, dispatch);
expect(fetchReleases).toHaveBeenCalledWith("os_update_server");
expect(fetchReleases).toHaveBeenCalledWith("beta_os_update_server",
{ beta: true });
expect(fetchLatestGHBetaRelease)
.toHaveBeenCalledWith("beta_os_update_server");
});
});
5 changes: 3 additions & 2 deletions webpack/auth/actions.ts
@@ -1,6 +1,7 @@
import axios from "axios";
import {
fetchReleases, fetchMinOsFeatureData, FEATURE_MIN_VERSIONS_URL
fetchReleases, fetchMinOsFeatureData, FEATURE_MIN_VERSIONS_URL,
fetchLatestGHBetaRelease
} from "../devices/actions";
import { AuthState } from "./interfaces";
import { ReduxAction } from "../redux/interfaces";
Expand All @@ -20,7 +21,7 @@ export function didLogin(authState: AuthState, dispatch: Function) {
const { os_update_server, beta_os_update_server } = authState.token.unencoded;
dispatch(fetchReleases(os_update_server));
beta_os_update_server && beta_os_update_server != "NOT_SET" &&
dispatch(fetchReleases(beta_os_update_server, { beta: true }));
dispatch(fetchLatestGHBetaRelease(beta_os_update_server));
dispatch(getFirstPartyFarmwareList());
dispatch(fetchMinOsFeatureData(FEATURE_MIN_VERSIONS_URL));
dispatch(setToken(authState));
Expand Down
26 changes: 26 additions & 0 deletions webpack/devices/__tests__/actions_test.ts
Expand Up @@ -410,6 +410,32 @@ describe("fetchReleases()", () => {
});
});

describe("fetchLatestGHBetaRelease()", () => {
it("fetches latest beta OS release version", async () => {
mockGetRelease = Promise.resolve({ data: [{ tag_name: "v1.0.0-beta" }] });
const dispatch = jest.fn();
await actions.fetchLatestGHBetaRelease("url/001")(dispatch);
expect(axios.get).toHaveBeenCalledWith("url");
expect(error).not.toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledWith({
payload: { version: "1.0.0-beta", commit: undefined },
type: Actions.FETCH_BETA_OS_UPDATE_INFO_OK
});
});

it("fails to fetches latest beta OS release version", async () => {
mockGetRelease = Promise.reject("error");
const dispatch = jest.fn();
await actions.fetchLatestGHBetaRelease("url/001")(dispatch);
await expect(axios.get).toHaveBeenCalledWith("url");
expect(error).not.toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledWith({
payload: "error",
type: Actions.FETCH_BETA_OS_UPDATE_INFO_ERROR
});
});
});

describe("fetchMinOsFeatureData()", () => {
afterEach(() =>
jest.restoreAllMocks());
Expand Down
33 changes: 32 additions & 1 deletion webpack/devices/actions.ts
Expand Up @@ -151,6 +151,37 @@ export function requestDiagnostic() {
return getDevice().dumpInfo().then(commandOK(noun), commandErr(noun));
}

const tagNameToVersionString = (tagName: string): string =>
tagName.toLowerCase().replace("v", "");

/**
* Fetch FarmBot OS beta release data.
* Ignores a specific release provided by the url (i.e., `releases/1234`)
* in favor of the latest `-beta` release.
*/
export const fetchLatestGHBetaRelease =
(url: string) =>
(dispatch: Function) => {
const urlArray = url.split("/");
const releasesURL = urlArray.splice(0, urlArray.length - 1).join("/");
axios
.get<GithubRelease[]>(releasesURL)
.then(resp => {
const latestBeta = resp.data
.filter(x => x.tag_name.includes("beta"))[0];
const { tag_name, target_commitish } = latestBeta;
const version = tagNameToVersionString(tag_name);
dispatch({
type: Actions.FETCH_BETA_OS_UPDATE_INFO_OK,
payload: { version, commit: target_commitish }
});
})
.catch(ferror => dispatch({
type: "FETCH_BETA_OS_UPDATE_INFO_ERROR",
payload: ferror
}));
};

/** Fetch FarmBot OS release data. */
export const fetchReleases =
(url: string, options = { beta: false }) =>
Expand All @@ -159,7 +190,7 @@ export const fetchReleases =
.get<GithubRelease>(url)
.then(resp => {
const { tag_name, target_commitish } = resp.data;
const version = tag_name.toLowerCase().replace("v", "");
const version = tagNameToVersionString(tag_name);
dispatch({
type: options.beta
? Actions.FETCH_BETA_OS_UPDATE_INFO_OK
Expand Down
Expand Up @@ -11,6 +11,7 @@ import { mount } from "enzyme";
import { bot } from "../../../../__test_support__/fake_state/bot";
import { OsUpdateButton } from "../os_update_button";
import { OsUpdateButtonProps } from "../interfaces";
import { ShouldDisplay } from "../../../interfaces";

describe("<OsUpdateButton/>", () => {
beforeEach(() => {
Expand All @@ -23,6 +24,7 @@ describe("<OsUpdateButton/>", () => {
sourceFbosConfig: x =>
({ value: bot.hardware.configuration[x], consistent: true }),
botOnline: true,
shouldDisplay: () => false,
});

interface TestProps {
Expand All @@ -34,6 +36,8 @@ describe("<OsUpdateButton/>", () => {
betaOptIn: boolean | undefined;
onBeta: boolean | undefined;
update_available?: boolean | undefined;
shouldDisplay: ShouldDisplay;
update_channel: string;
}

const defaultTestProps = (): TestProps => ({
Expand All @@ -44,6 +48,8 @@ describe("<OsUpdateButton/>", () => {
availableBetaCommit: undefined,
betaOptIn: false,
onBeta: false,
shouldDisplay: () => false,
update_channel: "stable",
});

interface Results {
Expand Down Expand Up @@ -90,7 +96,8 @@ describe("<OsUpdateButton/>", () => {
expected: Results) => {
const {
installedVersion, installedCommit, onBeta, update_available,
availableVersion, availableBetaVersion, availableBetaCommit, betaOptIn
availableVersion, availableBetaVersion, availableBetaCommit, betaOptIn,
shouldDisplay, update_channel,
} = testProps;
bot.hardware.informational_settings.controller_version = installedVersion;
bot.hardware.informational_settings.commit = installedCommit;
Expand All @@ -101,8 +108,12 @@ describe("<OsUpdateButton/>", () => {
bot.currentBetaOSVersion = availableBetaVersion;
bot.currentBetaOSCommit = availableBetaCommit;
bot.hardware.configuration.beta_opt_in = betaOptIn;
// tslint:disable-next-line:no-any
(bot.hardware.configuration as any).update_channel = update_channel;

const buttons = mount(<OsUpdateButton {...fakeProps()} />);
const p = fakeProps();
p.shouldDisplay = shouldDisplay;
const buttons = mount(<OsUpdateButton {...p} />);
const osUpdateButton = buttons.find("button").first();
expect(osUpdateButton.text()).toBe(expected.text);
expect(osUpdateButton.props().title).toBe(expected.title);
Expand Down Expand Up @@ -253,13 +264,51 @@ describe("<OsUpdateButton/>", () => {
testButtonState(testProps, expectedResults);
});

it("uses update_channel value", () => {
const testProps = defaultTestProps();
testProps.installedVersion = "3.1.6";
testProps.shouldDisplay = () => true;
testProps.update_channel = "stable";
testProps.availableBetaVersion = "3.1.7-beta";
const expectedResults = upToDate("3.1.6");
testButtonState(testProps, expectedResults);
});

it("uses update_channel value: beta", () => {
const testProps = defaultTestProps();
testProps.installedVersion = "3.1.6";
testProps.shouldDisplay = () => true;
testProps.update_channel = "beta";
testProps.availableBetaVersion = "3.1.7-beta";
const expectedResults = updateNeeded("3.1.7-beta");
testButtonState(testProps, expectedResults);
});

it("doesn't use update_channel value", () => {
const testProps = defaultTestProps();
testProps.installedVersion = "3.1.6";
testProps.shouldDisplay = () => false;
testProps.update_channel = "beta";
testProps.availableBetaVersion = "3.1.7-beta";
const expectedResults = upToDate("3.1.6");
testButtonState(testProps, expectedResults);
});

it("calls checkUpdates", () => {
const buttons = mount(<OsUpdateButton {...fakeProps()} />);
const osUpdateButton = buttons.find("button").first();
osUpdateButton.simulate("click");
expect(mockDevice.checkUpdates).toHaveBeenCalledTimes(1);
});

it("handles undefined jobs", () => {
// tslint:disable-next-line:no-any
bot.hardware.jobs = undefined as any;
const buttons = mount(<OsUpdateButton {...fakeProps()} />);
const osUpdateButton = buttons.find("button").first();
expect(osUpdateButton.text()).toEqual("UP TO DATE");
});

function bytesProgressTest(unit: string, progress: number, text: string) {
it(`shows update progress: ${unit}`, () => {
bot.hardware.jobs = {
Expand Down
Expand Up @@ -52,6 +52,7 @@ export function FarmbotOsRow(props: FarmbotOsRowProps) {
<OsUpdateButton
bot={bot}
sourceFbosConfig={sourceFbosConfig}
shouldDisplay={props.shouldDisplay}
botOnline={botOnline} />
</Col>
</Row >;
Expand Down
1 change: 1 addition & 0 deletions webpack/devices/components/fbos_settings/interfaces.ts
Expand Up @@ -68,4 +68,5 @@ export interface OsUpdateButtonProps {
bot: BotState;
sourceFbosConfig: SourceFbosConfig;
botOnline: boolean;
shouldDisplay: ShouldDisplay;
}
8 changes: 5 additions & 3 deletions webpack/devices/components/fbos_settings/os_update_button.tsx
@@ -1,11 +1,11 @@
import * as React from "react";
import { t } from "i18next";
import { JobProgress } from "farmbot/dist";
import { JobProgress, ConfigurationName } from "farmbot/dist";
import { SemverResult, semverCompare } from "../../../util";
import { OsUpdateButtonProps } from "./interfaces";
import { checkControllerUpdates } from "../../actions";
import { isString } from "lodash";
import { BotState } from "../../interfaces";
import { BotState, Feature } from "../../interfaces";

/** FBOS update button states. */
enum UpdateButton { upToDate, needsUpdate, unknown, none }
Expand Down Expand Up @@ -151,7 +151,9 @@ export const OsUpdateButton = (props: OsUpdateButtonProps) => {
const { bot, sourceFbosConfig, botOnline } = props;

/** FBOS beta release opt-in setting. */
const betaOptIn = !!sourceFbosConfig("beta_opt_in").value;
const betaOptIn = props.shouldDisplay(Feature.use_update_channel)
? sourceFbosConfig("update_channel" as ConfigurationName).value !== "stable"
: !!sourceFbosConfig("beta_opt_in").value;
/** FBOS update availability. */
const buttonStatusProps = buttonVersionStatus({ bot, betaOptIn });

Expand Down
8 changes: 8 additions & 0 deletions webpack/farmware/__tests__/state_to_props_test.tsx
Expand Up @@ -118,6 +118,14 @@ describe("mapStateToProps()", () => {
time: "2018-11-15 18:13:21.167440Z"
}]);
});

it("handles undefined jobs", () => {
const state = fakeState();
// tslint:disable-next-line:no-any
state.bot.hardware.jobs = undefined as any;
const props = mapStateToProps(state);
expect(props.imageJobs).toEqual([]);
});
});

describe("saveOrEditFarmwareEnv()", () => {
Expand Down
2 changes: 1 addition & 1 deletion webpack/farmware/state_to_props.ts
Expand Up @@ -99,7 +99,7 @@ export function mapStateToProps(props: Everything): FarmwareProps {
}
});

const { jobs } = props.bot.hardware;
const jobs = props.bot.hardware.jobs || {};
const imageJobNames = Object.keys(jobs).filter(x => x != "FBOS_OTA");
const imageJobs: JobProgress[] =
_(betterCompact(imageJobNames.map(x => jobs[x])))
Expand Down

0 comments on commit 4a5550f

Please sign in to comment.