diff --git a/circle.yml b/circle.yml index 414bab57..a229b755 100644 --- a/circle.yml +++ b/circle.yml @@ -14,29 +14,14 @@ dependencies: - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list - sudo apt-get update - - sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils + - sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils jq - sudo apt-get install --no-install-recommends -y wine1.8 mono-devel ca-certificates-mono - sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib - unset DISPLAY && wineboot --init - npm run package:all - - npm run package:linux - - npm run installer - - mv release/Mattermost-win32-ia32 release/mattermost-desktop-win32 - - mv release/Mattermost-win32-x64 release/mattermost-desktop-win64 - - mv release/Mattermost-darwin-x64 release/mattermost-desktop-osx - - mv release/Mattermost-linux-ia32 release/mattermost-desktop-linux-ia32 - - mv release/Mattermost-linux-x64 release/mattermost-desktop-linux-x64 - - - cd release && zip -9 -r $CIRCLE_ARTIFACTS/mattermost-desktop-win32.zip mattermost-desktop-win32 - - cd release && zip -9 -r $CIRCLE_ARTIFACTS/mattermost-desktop-win64.zip mattermost-desktop-win64 - - tar zcvf $CIRCLE_ARTIFACTS/mattermost-desktop-osx.tar.gz -C release mattermost-desktop-osx - - tar zcvf $CIRCLE_ARTIFACTS/mattermost-desktop-linux-ia32.tar.gz -C release mattermost-desktop-linux-ia32 - - tar zcvf $CIRCLE_ARTIFACTS/mattermost-desktop-linux-x64.tar.gz -C release mattermost-desktop-linux-x64 - - cp release/*.deb $CIRCLE_ARTIFACTS/ - - cp release/windows-installer-ia32/mattermost-setup-ia32.exe $CIRCLE_ARTIFACTS/ - - cp release/windows-installer-x64/mattermost-setup-x64.exe $CIRCLE_ARTIFACTS/ + - sh -x ./scripts/cp_artifacts.sh release $CIRCLE_ARTIFACTS test: post: diff --git a/docs/development.md b/docs/development.md index 50fe2994..7f282bb3 100644 --- a/docs/development.md +++ b/docs/development.md @@ -24,6 +24,26 @@ $ npm run build After building is done, you can execute the application with `npm start`. +### Packaging +Package `dist/` directory as distributable formats with [`electron-builder`](https://github.com/electron-userland/electron-builder). +Packages will be generated into `release/` directory. + +``` +$ npm run package: +``` + +#### Code signing +Set environment variables to build trusted packages. +Please see [electron-builder wiki](https://github.com/electron-userland/electron-builder/wiki/Code-Signing) for detailed description. + +**Quoted from the wiki:** + +| Env name | Description | +|---|---| +| `CSC_LINK` | The HTTPS link (or base64-encoded data, or `file://` link) to certificate (`*.p12` or `*.pfx` file). | +| `CSC_KEY_PASSWORD` | The password to decrypt the certificate given in `CSC_LINK`. | +| `CSC_NAME` | *macOS-only* Name of certificate (to retrieve from login.keychain). Useful on a development machine (not on CI) if you have several identities (otherwise don't specify it). | + ### Tests Execute automated tests. @@ -53,23 +73,6 @@ Reload the application automatically when you have saved source codes. #### `mpm run prettify` Format the source codes to pass `npm test`. -#### `npm run package` -You can package this application with following commands. Packages will be created in `release/` directory. - -``` -$ npm run package (for your platform) -$ npm run package:windows (Requires Windows or Wine) -$ npm run package:osx (Requires macOS or Linux) -$ npm run package:linux -$ npm run package:all (Packages for all platform) -``` - -Create a windows installer with the following command. It will appear in the `release\windows-installer` directory. - -``` -$ npm run installer -``` - ## Directory Structure ``` diff --git a/gulpfile.js b/gulpfile.js index 659ecac5..209acad5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -11,7 +11,7 @@ var through = require('through2'); var electron = require('electron-connect').server.create({ path: './dist' }); -var packager = require('electron-packager'); + const fs = require('fs'); const distPackageAuthor = 'Mattermost, Inc.'; @@ -195,78 +195,6 @@ gulp.task('watch', ['build'], function() { gulp.watch(['dist/browser/*.js'], electron.reload); }); -function makePackage(platform, arch, callback) { - var packageJson = require('./src/package.json'); - packager({ - dir: './dist', - platform: platform, - arch: arch, - version: require('./package.json').devDependencies['electron-prebuilt'], - out: './release', - prune: true, - overwrite: true, - "app-version": packageJson.version, - icon: 'resources/icon', - "version-string": { - CompanyName: distPackageAuthor, - LegalCopyright: `Copyright (c) 2015 - ${new Date().getFullYear()} ${packageJson.author.name}`, - FileDescription: packageJson.productName, - OriginalFilename: packageJson.productName + '.exe', - ProductVersion: packageJson.version, - ProductName: packageJson.productName, - InternalName: packageJson.name - } - }, function(err, appPath) { - if (err) { - callback(err); - } - else { - if (platform === 'linux' || platform === 'all') { - const dest_32 = 'release/Mattermost-linux-ia32'; - const dest_64 = 'release/Mattermost-linux-x64'; - fs.createReadStream('resources/icon.png').pipe(fs.createWriteStream(`${dest_32}/icon.png`)); - fs.createReadStream('resources/icon.png').pipe(fs.createWriteStream(`${dest_64}/icon.png`)); - fs.createReadStream('resources/linux/create_desktop_file.sh') - .pipe(fs.createWriteStream(`${dest_32}/create_desktop_file.sh`)) - .on('finish', () => { - fs.chmodSync(`${dest_32}/create_desktop_file.sh`, '755'); - }); - fs.createReadStream('resources/linux/create_desktop_file.sh') - .pipe(fs.createWriteStream(`${dest_64}/create_desktop_file.sh`)) - .on('finish', () => { - fs.chmodSync(`${dest_64}/create_desktop_file.sh`, '755'); - }); - setTimeout(() => { - callback(); - }, 1000); // should wait all pipes - } - else { - callback(); - } - } - }); -} - -gulp.task('package', ['build'], function(cb) { - makePackage(process.platform, 'all', cb); -}); - -gulp.task('package:all', ['build'], function(cb) { - makePackage('all', 'all', cb); -}); - -gulp.task('package:windows', ['build'], function(cb) { - makePackage('win32', 'all', cb); -}); - -gulp.task('package:osx', ['build'], function(cb) { - makePackage('darwin', 'all', cb); -}); - -gulp.task('package:linux', ['build'], function(cb) { - makePackage('linux', 'all', cb); -}); - gulp.task('sync-meta', function() { var appPackageJson = require('./src/package.json'); var packageJson = require('./package.json'); diff --git a/package.json b/package.json index 18fd1ccc..3c4a3b27 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "mattermost", + "name": "mattermost-desktop", "productName": "Mattermost", "version": "3.4.1", - "description": "Mattermost Desktop application for Windows, Mac and Linux", + "description": "Mattermost", "main": "main.js", "author": { "name": "Yuya Ochiai", @@ -24,27 +24,24 @@ "watch": "gulp watch", "serve": "gulp watch", "test": "gulp build && mocha --reporter mocha-circleci-reporter --recursive test/specs && gulp prettify:verify", - "package": "gulp package", - "package:windows": "gulp package:windows", - "package:osx": "gulp package:osx", - "package:linux": "gulp build && build --platform linux --arch all && npm run linux-additions", - "linux-additions": "mkdir -p release/linux/ && cp resources/icon.png resources/linux/create_desktop_file.sh release/linux/ && mkdir -p release/linux-ia32/ && cp resources/icon.png resources/linux/create_desktop_file.sh release/linux-ia32/", - "package:all": "gulp package:all", - "prettify": "gulp prettify", - "installer": "node ./script/installer.js" + "package:all": "npm run package:windows && npm run package:mac && npm run package:linux", + "package:windows": "build --win --x64 --ia32 --em.name=mattermost && npm run manipulate-windows-zip", + "package:mac": "build --mac --x64 --ia32", + "package:linux": "build --linux --x64 --ia32 --em.name=mattermost-desktop", + "manipulate-windows-zip": "node scripts/manipulate_windows_zip.js", + "prettify": "gulp prettify" }, "devDependencies": { + "7zip-bin": "^2.0.1", "babel-core": "^6.7.5", "babel-loader": "^6.2.4", "babel-preset-react": "^6.5.0", "chai": "^3.5.0", "chai-as-promised": "^5.3.0", "devtron": "^1.3.0", - "electron-builder": "7.10.2", + "electron-builder": "^7.11.2", "electron-connect": "~0.6.0", - "electron-packager": "^7.0.1", "electron-prebuilt": "1.4.2", - "electron-winstaller": "^2.2.0", "esformatter": "^0.9.6", "esformatter-jsx": "^7.0.1", "gulp": "^3.9.1", @@ -54,7 +51,6 @@ "json-loader": "^0.5.4", "mocha": "^3.0.2", "mocha-circleci-reporter": "0.0.2", - "rimraf": "^2.5.4", "spectron": "~3.4.0", "style-loader": "^0.13.1", "through2": "^2.0.1", @@ -63,11 +59,35 @@ "webpack-stream": "^3.2.0" }, "build": { - "app-bundle-id": "com.mattermost.desktop", - "app-category-type": "public.app-category.productivity", + "appId": "com.mattermost.desktop", "linux": { - "synopsis": "Mattermost Desktop", - "target": "deb" + "category": "InstantMessaging", + "target": [ + "deb", + "tar.gz" + ], + "synopsis": "Mattermost", + "extraFiles": [{ + "from": "resources", + "filter": "icon.png" + }, { + "from": "resources/linux", + "filter": "create_desktop_file.sh" + }] + }, + "mac": { + "category": "public.app-category.productivity", + "target": [ + "tar.gz" + ] + }, + "win": { + "description": "Mattermost", + "target": [ + "squirrel", + "zip" + ], + "iconUrl": "https://raw.githubusercontent.com/mattermost/desktop/master/resources/icon.ico" } }, "directories": { diff --git a/script/installer.js b/script/installer.js deleted file mode 100644 index b9bb60be..00000000 --- a/script/installer.js +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -const createWindowsInstaller = require('electron-winstaller').createWindowsInstaller; -const path = require('path'); -const rimraf = require('rimraf'); - -const archList = ['ia32', 'x64']; -archList.forEach((arch) => { - deleteOutputFolder(arch) - .then(getInstallerConfig) - .then(createWindowsInstaller) - .catch((error) => { - console.error(error.message || error); - process.exit(1); - }); -}); - -function getInstallerConfig(arch) { - const rootPath = path.join(__dirname, '..'); - const outPath = path.join(rootPath, 'release'); - - return Promise.resolve({ - appDirectory: path.join(outPath, `Mattermost-win32-${arch}`), - authors: 'Mattermost, Inc.', - owners: 'Mattermost, Inc.', - iconUrl: 'https://raw.githubusercontent.com/mattermost/desktop/master/resources/icon.ico', - //loadingGif: path.join(rootPath, 'assets', 'img', 'loading.gif'), - noMsi: true, - outputDirectory: path.join(outPath, `windows-installer-${arch}`), - setupExe: `mattermost-setup-${arch}.exe`, - setupIcon: path.join(rootPath, 'resources', 'icon.ico'), - skipUpdateIcon: true, - exe: 'Mattermost.exe' - }); -} - -function deleteOutputFolder(arch) { - return new Promise((resolve, reject) => { - rimraf(path.join(__dirname, '..', 'out', `windows-installer-${arch}`), (error) => { - error ? reject(error) : resolve(arch); - }); - }); -} diff --git a/scripts/cp_artifacts.sh b/scripts/cp_artifacts.sh new file mode 100644 index 00000000..957f344a --- /dev/null +++ b/scripts/cp_artifacts.sh @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu + +VERSION=`cat package.json | jq -r '.version'` +SRC=$1 +DEST=$2 + +cp "${SRC}/Mattermost-${VERSION}-win.zip" "${DEST}/mattermost-desktop-${VERSION}-win64.zip" +cp "${SRC}/Mattermost-${VERSION}-ia32-win.zip" "${DEST}/mattermost-desktop-${VERSION}-win32.zip" +cp "${SRC}/win/Mattermost Setup ${VERSION}.exe" "${DEST}/mattermost-setup-${VERSION}-win64.exe" +cp "${SRC}/win-ia32/Mattermost Setup ${VERSION}-ia32.exe" "${DEST}/mattermost-setup-${VERSION}-win32.exe" + +cp "${SRC}/mac/Mattermost-${VERSION}-mac.tar.gz" "${DEST}/mattermost-desktop-${VERSION}-mac.tar.gz" + +cp "${SRC}/mattermost-desktop-${VERSION}.tar.gz" "${DEST}/mattermost-desktop-${VERSION}-linux-x64.tar.gz" +cp "${SRC}/mattermost-desktop-${VERSION}-ia32.tar.gz" "${DEST}/mattermost-desktop-${VERSION}-linux-ia32.tar.gz" +cp "${SRC}/mattermost-desktop-${VERSION}-amd64.deb" "${DEST}/mattermost-desktop-${VERSION}-linux-x64.deb" +cp "${SRC}/mattermost-desktop-${VERSION}-ia32.deb" "${DEST}/mattermost-desktop-${VERSION}-linux-ia32.deb" diff --git a/scripts/manipulate_windows_zip.js b/scripts/manipulate_windows_zip.js new file mode 100644 index 00000000..019105b6 --- /dev/null +++ b/scripts/manipulate_windows_zip.js @@ -0,0 +1,20 @@ +'use strict'; + +const spawnSync = require('child_process').spawnSync; +const path7za = require('7zip-bin').path7za; +const appVersion = require('../package.json').version; + +function renameInZip(zipPath, oldName, newName) { + const result = spawnSync(path7za, ['rn', zipPath, oldName, newName]); + return result.status === 0; +} + +console.log('Manipulating 64-bit zip...'); +if (!renameInZip(`release/Mattermost-${appVersion}-win.zip`, 'win-unpacked', `Mattermost-${appVersion}-win64`)) { + throw new Error('7za returned non-zero exit code for 64-bit zip'); +} + +console.log('Manipulating 32-bit zip...'); +if (!renameInZip(`release/Mattermost-${appVersion}-ia32-win.zip`, 'win-ia32-unpacked', `Mattermost-${appVersion}-win32`)) { + throw new Error('7za returned non-zero exit code for 32-bit zip'); +} diff --git a/src/package.json b/src/package.json index 1222a2b3..c1fb167d 100644 --- a/src/package.json +++ b/src/package.json @@ -1,14 +1,15 @@ { - "name": "mattermost", + "name": "mattermost-desktop", "productName": "Mattermost", "desktopName": "Mattermost.desktop", "version": "3.4.1", - "description": "Mattermost Desktop application for Windows, Mac and Linux", + "description": "Mattermost", "main": "main.js", "author": { "name": "Yuya Ochiai", "email": "yuya0321@gmail.com" }, + "homepage": "https://about.mattermost.com", "license": "Apache-2.0", "devDependencies": { "electron-connect": "~0.6.0"