Skip to content

Commit

Permalink
Merge pull request #197 from brafdlog/upgrade/vue-cli-plugin-electron…
Browse files Browse the repository at this point in the history
…-builder

Upgrade vue-cli-plugin-electron-builder and Release
  • Loading branch information
baruchiro authored Mar 14, 2021
2 parents f5623c4 + aa118d1 commit 55bcffd
Show file tree
Hide file tree
Showing 9 changed files with 1,440 additions and 942 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# Platforms to build on/for
strategy:
matrix:
os: [windows-2019, ubuntu-18.04, macos-10.15]
os: [windows-latest, ubuntu-latest, macos-latest]

steps:
- uses: actions/checkout@v1
Expand All @@ -35,16 +35,16 @@ jobs:
# debug: true
script: |
const releases = await github.repos.listReleases({
owner: 'baruchiro',
repo: 'israeli-bank-scrapers-desktop'
owner: 'brafdlog',
repo: 'budget-tracking'
})
// console.log(releases)
const published_release_tags = releases.data.filter(release => !release.draft).map(release => release.tag_name)
// console.log(published_release_tags)
// github.event_name: ${{ github.event_name }}
// github.ref: ${{ github.ref }}
const isPushToMaster = ${{ startsWith(github.event_name, 'push') && github.ref == 'refs/heads/master' }}
console.log('Is push to mster: ' + isPushToMaster)
console.log('Is push to master: ' + isPushToMaster)
const publishToRelease = !published_release_tags.includes('v${{ env.package_version }}') && isPushToMaster
console.log('publishToRelease: ' + publishToRelease)
return publishToRelease
Expand All @@ -56,6 +56,7 @@ jobs:
uses: samuelmeuli/action-snapcraft@06f69b882c878790b568f0247d623eaa49de2f3d
# Only install Snapcraft on Ubuntu
if: startsWith(matrix.os, 'ubuntu')
continue-on-error: true
with:
# Log in to Snap Store
snapcraft_token: ${{ secrets.snapcraft_token }}
Expand Down
49 changes: 31 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ In addition, it can automatically set an expense category for transactions accor

Internally it uses the [Israeli bank scrapers](https://github.com/eshaham/israeli-bank-scrapers) npm package.

### What is currently supported:
## Features

- One click to fetch transactions from multiple Israeli banks and credit cards
- Exporting transactions to Google sheets, YNAB, CSV or JSON file
- Exporting transactions to *Google Sheets*, *YNAB*, *Excel (CSV)* or *JSON* file
- A basic UI for configuration
- A configuration for automatically classifying transactions to categories according to predefined patterns

## Running the app
You can download the app from [here](https://github.com/brafdlog/budget-tracking/actions?query=branch%3Amaster+workflow%3ABuild%2FRelease+is%3Asuccess+event%3Apush)

Download the latest version from [Releases](https://github.com/brafdlog/budget-tracking/releases) page, or build it from source, with the instructions below.

### Initial setup

The first time you run the app, you will need to set up the accounts you want to fetch data from (importers).

Now you can set up the exporters - where the data will be sent to. The CSV exporter is enabled by default.
Expand All @@ -44,9 +46,9 @@ Currently, this project depends on `libsecret`, so you may need to install it be

Depending on your distribution, you will need to run the following command:

* Debian/Ubuntu: `sudo apt-get install libsecret-1-dev`
* Red Hat-based: `sudo yum install libsecret-devel`
* Arch Linux: `sudo pacman -S libsecret`
- Debian/Ubuntu: `sudo apt-get install libsecret-1-dev`
- Red Hat-based: `sudo yum install libsecret-devel`
- Arch Linux: `sudo pacman -S libsecret`

### Start from Source

Expand All @@ -56,11 +58,12 @@ Depending on your distribution, you will need to run the following command:
- If you want to set up YNAB, see instructions below
- Run by clicking on the `Run` button in the app
- Configure automatic category classification (Optional)
- Open `categoryCalculationScript.js`. This file contains the patterns for classifying transactions to categories automatically.
- Edit this file to add any mapping from function description to category that fits your needs.
- If using YNAB, the categories you return must match category names in YNAB
- Open `categoryCalculationScript.js`. This file contains the patterns for classifying transactions to categories automatically.
- Edit this file to add any mapping from function description to category that fits your needs.
- If using YNAB, the categories you return must match category names in YNAB

### Building for production

- Run `yarn build`

### YNAB integration setup (optional)
Expand All @@ -70,17 +73,17 @@ YNAB is a budgeting software. If you want to manage your budget there and have y
- Create an account in [YNAB](https://ynab.com/referral/?ref=Z5wPbP0cYTWjdTQj&utm_source=customer_referral)
- Create in YNAB unlinked accounts for each financial account you want to track (bank accounts and credit cards)
- Get the **YNAB access token**
- In YNAB go to `Account settings -> Developer settings`
- Click on `New Token` and `generate`
- On the top of the screen you will see the full token (the token with XXXX in it is not the full one).
- Save this token in the YNAB settings in the app.
- In YNAB go to `Account settings -> Developer settings`
- Click on `New Token` and `generate`
- On the top of the screen you will see the full token (the token with XXXX in it is not the full one).
- Save this token in the YNAB settings in the app.
- Set your **YNAB budget id**
- Find your YNAB budget id by going into your budget and taking it from the url: `https://app.youneedabudget.com/XXXXXX-XXXXXX-XXXXXX-XXXXX/budget`
- Set this budget id in the YNAB settings and save.
- Find your YNAB budget id by going into your budget and taking it from the url: `https://app.youneedabudget.com/XXXXXX-XXXXXX-XXXXXX-XXXXX/budget`
- Set this budget id in the YNAB settings and save.
- Fill the table containing account number to ynab account id mapping
- For each account you want to track add another row to the table
- To get the `ynab account id` of the account navigate to that account in ynab and get the account id from the url: `https://app.youneedabudget.com/akfkmksdcscd/accounts/XXXXXXXX-XXXX-XXXX-XXXX-XXXX`
- The `account number` could be the credit card number, or the bank account number. To be sure, you can run the app so it exports transactions to a CSV and get the account number from there.
- For each account you want to track add another row to the table
- To get the `ynab account id` of the account navigate to that account in ynab and get the account id from the url: `https://app.youneedabudget.com/akfkmksdcscd/accounts/XXXXXXXX-XXXX-XXXX-XXXX-XXXX`
- The `account number` could be the credit card number, or the bank account number. To be sure, you can run the app so it exports transactions to a CSV and get the account number from there.
- **Click on Save to save the configuration**

### CSV (Excel) Note
Expand All @@ -92,6 +95,16 @@ In some cases you may get gibberish when you open the CSV file in Excel. In this
1. Select your CSV file.
1. For the "Encoding"/"File Origin", select `Unicode UTF-8 (65001)`.

## Release

The Release workflow, configured in `.github/workflows/release.yml`, will **draft** a new release or update the artifacts on an existing draft, according to the following conditions:

1. A change pushed to the `master` branch.
1. The `version` from the `package.json`, with the prefix `v`, is not a **published** release.
1. Upload the artifacts to the `v${package_version}` Github Release.

It means that after you published a new release, from the Github interface, you need to upgrade the version in the `package.json` file, to get a new draft.

#### Disclaimer

Providing your financial account credentials to software is not risk free. We will do our best to protect your credentials, but we take no responsibility for any possible damages. If you want to use this we suggest you ask your financial institution for credentials for a user that has only read access to the relevant account and use those credentials to reduce the potential risk.
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hiuvi",
"version": "0.1.3-beta",
"version": "0.0.1-beta",
"author": "Jonathan Goldfarb <brafdlog@gmail.com>",
"description": "An electron app for automating expense tracking",
"license": "MIT",
Expand Down Expand Up @@ -36,6 +36,7 @@
"csv-parse": "^4.14.1",
"csv-stringify": "^5.5.3",
"direct-vuex": "^0.12.0",
"electron-devtools-installer": "^3.1.1",
"electron-log": "^4.1.1",
"emittery": "^0.7.1",
"googleapis": "^59.0.0",
Expand Down Expand Up @@ -80,7 +81,7 @@
"babel-eslint": "^10.1.0",
"babel-jest": "^26.3.0",
"babel-plugin-component": "^1.1.1",
"electron": "^5.0.0",
"electron": "^9.0.0",
"eslint": "^7.1.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-config-prettier": "^6.11.0",
Expand All @@ -101,15 +102,17 @@
"jest-circus": "^26.4.2",
"jest-config": "^26.4.2",
"jest-each": "^26.4.2",
"jest-environment-jsdom": "^26.3.0",
"jest-environment-node": "^26.6.2",
"ncp": "^2.0.0",
"node-loader": "^1.0.2",
"prettier": "^2.0.5",
"replace-in-file": "5.0.2",
"sass": "^1.26.3",
"sass-loader": "^8.0.0",
"spectron": "^11.0.0",
"ts-jest": "^26.3.0",
"typescript": "^3.9.7",
"vue-cli-plugin-electron-builder": "^1.4.6",
"vue-cli-plugin-electron-builder": "^2.0.0-rc.6",
"vue-cli-plugin-vuetify": "~2.0.5",
"vue-jest": "4.0.0-beta.5",
"vue-template-compiler": "^2.6.11",
Expand Down
7 changes: 4 additions & 3 deletions src/background.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { app, BrowserWindow } from 'electron';
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
// eslint-disable-next-line import/no-extraneous-dependencies
import { createProtocol, installVueDevtools } from 'vue-cli-plugin-electron-builder/lib';
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
import CreateLogger from './logging/logger';
import Sentry from './logging/sentry';
// import './store';
Expand All @@ -23,7 +24,7 @@ function createWindow() {
useContentSize: true,
width: 1000,
webPreferences: {
nodeIntegration: true,
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION as unknown as boolean | undefined,
},
});

Expand Down Expand Up @@ -75,7 +76,7 @@ app.on('ready', async () => {
// In addition, if the linked issue is closed,
// you can upgrade electron and uncomment these lines
try {
await installVueDevtools();
await installExtension(VUEJS_DEVTOOLS);
} catch (e) {
logger.info('Vue Devtools failed to install:', e.toString());
}
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/screenshotEnvironment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const JSDOMEnvironment = require('jest-environment-jsdom');
const NodeEnvironment = require('jest-environment-node');

class ScreenshotEnvironment extends JSDOMEnvironment {
class ScreenshotEnvironment extends NodeEnvironment {
constructor(config, context) {
super(config, context);

Expand Down
49 changes: 26 additions & 23 deletions test/e2e/specs/launch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import fs from 'fs';
import path from 'path';
import { testWithSpectron } from 'vue-cli-plugin-electron-builder';
import spectron from 'spectron';
import {
Application, SpectronClient, SpectronWindow, StopServe
} from '../type';
import Interactions from '../utils/interactions';
// import Interactions from '../utils/interactions';

const screenshotsDir = './screenshots';

jest.setTimeout(100000);
jest.setTimeout(1000000);

// Remove when https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/625 closed
// const skip = process.env.GITHUB_ACTIONS && process.platform === 'win32';
const skip = true;
const skip = process.env.GITHUB_ACTIONS && process.platform === 'win32';

(skip ? describe.skip : describe)('Launch', () => {
let app: Application;
let stopServe: StopServe;
let browserWindow: SpectronWindow;
let client: SpectronClient;
let interactions: Interactions;
// let interactions: Interactions;

beforeAll(async () => {
let stdout: string;
({ app, stopServe, stdout } = await testWithSpectron());
({ app, stopServe, stdout } = await testWithSpectron(spectron));

// eslint-disable-next-line no-console
console.log(stdout);
Expand All @@ -34,7 +34,7 @@ const skip = true;

({ client, browserWindow } = app);
await client.waitUntilWindowLoaded();
interactions = new Interactions(client);
// interactions = new Interactions(client);
});

test('shows the proper application title', async () => {
Expand All @@ -49,24 +49,27 @@ const skip = true;
expect(width).toBeGreaterThan(0);
expect(height).toBeGreaterThan(0);
// App is loaded properly
expect(await client.getHTML('#app')).toMatch('Hiuvi');
const appElement = await client.$('#app');
expect(await appElement.getHTML()).toMatch('Hiuvi');
});

test('Hide AddScraper components by default', async () => {
const addScrapers = await interactions.getAddScrapers();
const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
expect(visiblities).not.toContain(true);
expect(visiblities).toContain(false);
});

test('Show AddScraper components when clicking on AddScraper', async () => {
await interactions.toggleLeftDrawer();
await interactions.clickCollapseAddImporter();

const addScrapers = await interactions.getAddScrapers();
const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
expect(visiblities).not.toContain(false);
});
// test.skip('Hide AddScraper components by default', async () => {
// const addScrapers = await interactions.getAddScrapers();
// // @ts-expect-error
// const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
// expect(visiblities).not.toContain(true);
// expect(visiblities).toContain(false);
// });

// test.skip('Show AddScraper components when clicking on AddScraper', async () => {
// await interactions.toggleLeftDrawer();
// await interactions.clickCollapseAddImporter();

// const addScrapers = await interactions.getAddScrapers();
// // @ts-expect-error
// const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
// expect(visiblities).not.toContain(false);
// });

afterEach(async () => {
if (global.lastTest.failed) {
Expand Down
3 changes: 1 addition & 2 deletions test/e2e/utils/interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ export default class Interactions {
}

async getAddScrapers() {
return Promise.all(this.client.$$(AddScrapers))
.then((elements) => elements.map(({ value }) => new Element(this.client, value)));
return this.client.$$(AddScrapers);
}

waitForAddScrapersVisible() {
Expand Down
15 changes: 6 additions & 9 deletions vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@ const defineGlobals = (config) => {
args[0] = globals;
return args;
});

config.module
.rule('babel')
.test(/base-scraper\.js$/)
.use('babel')
.loader('babel-loader')
.options({
presets: [['@babel/preset-env', { modules: false }]],
plugins: ['@babel/plugin-proposal-class-properties']
});
.rule('binary')
.test(/\.node$/)
.use()
.loader('node-loader');
};

module.exports = {
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
chainWebpackMainProcess: defineGlobals,
chainWebpackRendererProcess: defineGlobals,
// List native deps here if they don't work
Expand Down Expand Up @@ -54,7 +52,6 @@ module.exports = {
linux: {
target: [
'AppImage',
'snap',
'deb',
],
icon: 'build/icons',
Expand Down
Loading

0 comments on commit 55bcffd

Please sign in to comment.