diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a1d16d13044d8..8238a471fc6fa 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -2,7 +2,7 @@ name: Build and Deploy Android on: push: - branches: [ master ] + tags: ['**'] jobs: build: diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml index ac5f3d87bdb0f..ecbb24894832a 100644 --- a/.github/workflows/desktop.yml +++ b/.github/workflows/desktop.yml @@ -2,7 +2,7 @@ name: Build and Deploy Desktop on: push: - branches: [ master ] + tags: ['**'] jobs: build: @@ -18,13 +18,6 @@ jobs: - name: Install node packages run: npm install - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - name: Decrypt Developer ID Certificate run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg env: @@ -37,9 +30,5 @@ jobs: CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - - - name: Zip desktop build - run: 7z a $GITHUB_WORKSPACE/dist/mac/Chat.app.zip $GITHUB_WORKSPACE/dist/mac/Chat.app - - - name: Deploy to S3 - run: aws s3 cp --acl public-read $GITHUB_WORKSPACE/dist/mac/Chat.app.zip s3://chat-test-expensify-com/Chat.app.zip + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 167217ae4a278..e66724314d511 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,6 +1,6 @@ name: eslint -on: [push] +on: push jobs: build: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index bb3f364bedaab..0000000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,60 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Build and Deploy Web - -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch -on: - push: - branches: [ master ] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-16.04 - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - # Installs node - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: '14.x' - - # Install python pre-reqs - - name: Setup python - run: sudo apt-get install python3-setuptools - - # Installs Cloudflare CLI, after installing/upgrading dependencies - - name: Setup Cloudflare CLI - run: | - pip3 install --upgrade pip - pip3 install wheel # need wheel before cloudflare, this is the only way to ensure order. - pip3 install cloudflare - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - # Install node modules - - name: Install dependenices - run: npm install - - - name: Build web - run: npm run build - - - name: Deploy to S3 - run: aws s3 cp --recursive --acl public-read $GITHUB_WORKSPACE/dist s3://chat-test-expensify-com/ - - - name: Purge Cloudflare cache - run: /home/runner/.local/bin/cli4 --delete hosts=["chat.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache - env: - CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }} diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml new file mode 100644 index 0000000000000..7f5826026e533 --- /dev/null +++ b/.github/workflows/version.yml @@ -0,0 +1,29 @@ +name: Create a new version + +on: + push: + branches: [master] + +jobs: + build: + runs-on: ubuntu-16.04 + + steps: + - uses: actions/checkout@v2 + + - name: Setup Node + uses: actions/setup-node@v1 + with: + node-version: '14.x' + + - name: Install dependenices + run: npm install + + - name: Set git user + run: git config user.name github-action + + - name: Generate version + run: npm version prerelease -m "Update version to %s" + + - name: Push new version + run: git push && git push --tags diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml new file mode 100644 index 0000000000000..5696cd4b6744b --- /dev/null +++ b/.github/workflows/web.yml @@ -0,0 +1,51 @@ +name: Build and Deploy Web + +on: + push: + tags: ['**'] + +jobs: + build: + runs-on: ubuntu-16.04 + + steps: + - uses: actions/checkout@v2 + + # Installs node + - name: Setup Node + uses: actions/setup-node@v1 + with: + node-version: '14.x' + + # Install python pre-reqs + - name: Setup python + run: sudo apt-get install python3-setuptools + + # Installs Cloudflare CLI, after installing/upgrading dependencies + - name: Setup Cloudflare CLI + run: | + pip3 install --upgrade pip + pip3 install wheel # need wheel before cloudflare, this is the only way to ensure order. + pip3 install cloudflare + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + # Install node modules + - name: Install dependenices + run: npm install + + - name: Build web + run: npm run build + + - name: Deploy to S3 + run: aws s3 cp --recursive --acl public-read $GITHUB_WORKSPACE/dist s3://chat-test-expensify-com/ + + - name: Purge Cloudflare cache + run: /home/runner/.local/bin/cli4 --delete hosts=["chat.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache + env: + CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }} diff --git a/android/app/build.gradle b/android/app/build.gradle index ba0b3890da916..777de1007303c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -138,8 +138,8 @@ android { applicationId "com.expensifyreactnative.chat" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 5 - versionName "1.0.1-4" + versionCode 18 + versionName "1.0.1-17" } splits { abi { diff --git a/desktop/electron.config.js b/desktop/electron.config.js index cf4ab39a9f846..846733d1fa592 100644 --- a/desktop/electron.config.js +++ b/desktop/electron.config.js @@ -10,6 +10,16 @@ module.exports = { entitlementsInherit: 'desktop/entitlements.mac.plist', type: 'distribution' }, + dmg: { + title: 'Chat', + artifactName: 'Chat.dmg', + internetEnabled: true + }, + publish: [{ + provider: 's3', + bucket: 'chat-test-expensify-com', + channel: 'latest' + }], files: [ './dist/**/*', './main.js' diff --git a/ios/ReactNativeChat/Info.plist b/ios/ReactNativeChat/Info.plist index 725edbf72f02b..2f0c281472fe6 100644 --- a/ios/ReactNativeChat/Info.plist +++ b/ios/ReactNativeChat/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 5 + 18 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/ios/ReactNativeChatTests/Info.plist b/ios/ReactNativeChatTests/Info.plist index 2a1c32ed7c004..061521b8cc177 100644 --- a/ios/ReactNativeChatTests/Info.plist +++ b/ios/ReactNativeChatTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 5 + 18 diff --git a/main.js b/main.js index 17e05f407ca95..ad1c5ebabee39 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,8 @@ const {app, BrowserWindow, shell} = require('electron'); const serve = require('electron-serve'); const contextMenu = require('electron-context-menu'); +const {autoUpdater} = require('electron-updater'); +const log = require('electron-log'); /** * Electron main process that handles wrapping the web application. @@ -8,42 +10,64 @@ const contextMenu = require('electron-context-menu'); * @see: https://www.electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes */ -// TODO: Turn this off, use web-security after alpha launch, currently we recieve a CORS issue preventing +// Interval that we check for new versions of the app +const UPDATE_INTERVAL = 1000 * 60 * 60; + +// TODO: Turn this off, use web-security after alpha launch, currently we receive a CORS issue preventing // the electron app from making any API requests. app.commandLine.appendSwitch('disable-web-security'); -const mainWindow = (async () => { +// Initialize the right click menu +// See https://github.com/sindresorhus/electron-context-menu +contextMenu(); + +// Send all autoUpdater logs to a log file: ~/Library/Logs/react-native-chat/main.log +// See https://www.npmjs.com/package/electron-log +autoUpdater.logger = log; +autoUpdater.logger.transports.file.level = 'info'; + +// Send all Console logs to a log file: ~/Library/Logs/react-native-chat/main.log +// See https://www.npmjs.com/package/electron-log +Object.assign(console, log.functions); + +const mainWindow = (() => { const loadURL = serve({directory: 'dist'}); - await app.whenReady(); - - // Initialize the right click menu - // See https://github.com/sindresorhus/electron-context-menu - contextMenu(); - - const browserWindow = new BrowserWindow({ - backgroundColor: '#FAFAFA', - width: 1200, - height: 900, - webPreferences: { - nodeIntegration: true, - }, - }); - - await loadURL(browserWindow); - - // When the user clicks a link that has target="_blank" (which is all external links) - // open the default browser instead of a new electron window - browserWindow.webContents.on('new-window', (e, url) => { - // make sure local urls stay in electron perimeter - if (url.substr(0, 'file://'.length) === 'file://') { - return; - } - - // and open every other protocol in the browser - e.preventDefault(); - shell.openExternal(url); - }); + return app.whenReady() + .then(() => { + const browserWindow = new BrowserWindow({ + backgroundColor: '#FAFAFA', + width: 1200, + height: 900, + webPreferences: { + nodeIntegration: true, + }, + }); + + // When the user clicks a link that has target="_blank" (which is all external links) + // open the default browser instead of a new electron window + browserWindow.webContents.on('new-window', (e, url) => { + // make sure local urls stay in electron perimeter + if (url.substr(0, 'file://'.length) === 'file://') { + return; + } + + // and open every other protocol in the browser + e.preventDefault(); + return shell.openExternal(url); + }); + + return browserWindow; + }) + + // After initializing and configuring the browser window, load the compiled JavaScript + .then(browserWindow => loadURL(browserWindow)) + + // Check for a new version of the app on launch + .then(() => autoUpdater.checkForUpdatesAndNotify()) + + // Set a timer to check for new versions of the app + .then(() => setInterval(() => autoUpdater.checkForUpdatesAndNotify(), UPDATE_INTERVAL)); }); -mainWindow(); +mainWindow().then(window => window); diff --git a/package-lock.json b/package-lock.json index 1f24912cbfc1f..6813e8b4ffb38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-native-chat", - "version": "1.0.1-4", + "version": "1.0.1-17", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1981,6 +1981,11 @@ "integrity": "sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==", "dev": true }, + "@types/semver": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.3.tgz", + "integrity": "sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q==" + }, "@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -3033,8 +3038,7 @@ "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, "atob": { "version": "2.1.2", @@ -3972,7 +3976,6 @@ "version": "8.7.2", "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz", "integrity": "sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==", - "dev": true, "requires": { "debug": "^4.1.1", "sax": "^1.2.4" @@ -3982,7 +3985,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -5928,6 +5930,11 @@ "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" }, + "electron-log": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.2.4.tgz", + "integrity": "sha512-CXbDU+Iwi+TjKzugKZmTRIORIPe3uQRqgChUl19fkW/reFUn5WP7dt+cNGT3bkLV8xfPilpkPFv33HgtmLLewQ==" + }, "electron-notarize": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.0.0.tgz", @@ -6040,6 +6047,52 @@ "integrity": "sha512-HiroW5ZbGwgT8kCnoEO8qnGjoTPzJxduvV/Vv/wH63eo2N6Zj3xT5fmmaSPAPUM05iN9/5fIEkIg3owTtV6QZg==", "dev": true }, + "electron-updater": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.4.tgz", + "integrity": "sha512-ekpgxDrYl+Wi24ktO4qfj2CtCABxrmK1C/oekp0tai6q4VR4ZdPkit4CX8+GenvKMme7uMmfPFnLp/vwhP/ThQ==", + "requires": { + "@types/semver": "^7.3.1", + "builder-util-runtime": "8.7.2", + "fs-extra": "^9.0.1", + "js-yaml": "^3.14.0", + "lazy-val": "^1.0.4", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.2" + }, + "dependencies": { + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + } + } + }, "electron-webpack": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/electron-webpack/-/electron-webpack-2.8.2.tgz", @@ -10785,8 +10838,7 @@ "lazy-val": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", - "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", - "dev": true + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==" }, "lcid": { "version": "1.0.0", @@ -10922,6 +10974,11 @@ "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", diff --git a/package.json b/package.json index 26bb299eece4f..e412a5c5dfd4d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "react-native-chat", - "version": "1.0.1-4", + "version": "1.0.1-17", "author": "Expensify, Inc.", "homepage": "https://expensify.com", + "description": "Expensify Chat", "private": true, "scripts": { "android": "react-native run-android", @@ -11,7 +12,7 @@ "start": "react-native start", "web": "webpack-dev-server --open --config webpack.dev.js", "build": "webpack --config webpack.prod.js", - "desktop-build": "webpack --config webpack.prod.js && electron-builder --dir --config desktop/electron.config.js", + "desktop-build": "webpack --config webpack.prod.js && electron-builder --config desktop/electron.config.js --publish always", "test": "jest", "lint": "eslint .", "deploy-ios": "npm version prerelease && git push && fastlane ios beta", @@ -23,7 +24,9 @@ "babel-plugin-transform-remove-console": "^6.9.4", "dotenv": "^8.2.0", "electron-context-menu": "^2.3.0", + "electron-log": "^4.2.4", "electron-serve": "^1.0.0", + "electron-updater": "^4.3.4", "file-loader": "^6.0.0", "html-entities": "^1.3.1", "jquery": "^3.5.1", diff --git a/src/page/home/sidebar/AppLinks.js b/src/page/home/sidebar/AppLinks.js index dec89abad5427..421263a09045c 100644 --- a/src/page/home/sidebar/AppLinks.js +++ b/src/page/home/sidebar/AppLinks.js @@ -6,7 +6,7 @@ const AppLinks = () => ( <> Desktop