Add Jenkins Integration (#1295)

* add jenkins changes

* run prettier

* update icons

* update icons to use latest favicon
This commit is contained in:
Danny Skubak 2018-03-19 11:42:42 -04:00 committed by Daniel Ternyak
parent 9be46bf8aa
commit 937cc3fde5
10 changed files with 261 additions and 8 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
electron-app/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,6 @@
FROM electronuserland/builder:wine-03.18
RUN mkdir /hostHome
RUN apt-get update && apt-get install -y libusb-1.0 nasm graphicsmagick autoconf automake libtool python-pip
RUN pip install awscli --upgrade --user
ENV PATH "$PATH:/root/.local/bin"

26
jenkins/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,26 @@
pipeline {
agent {
dockerfile {
filename 'Dockerfile'
dir 'jenkins/Docker'
args '--env ETH_SIGNING_KEY=$ETH_SIGNING_KEY --env S3_BUCKET_NAME=$S3_BUCKET_NAME'
}
}
stages {
stage('Build') {
environment {
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES = 1
}
steps {
sh 'rm -rf node_modules'
sh 'npm install'
sh 'npm run jenkins:build:linux'
}
}
stage('Upload') {
steps {
sh 'npm run jenkins:upload'
}
}
}
}

33
jenkins/constants.js Normal file
View File

@ -0,0 +1,33 @@
const VERSION = require('../package.json').version;
const GIT_COMMIT = process.env.GIT_COMMIT || 'commit-not-set';
const GIT_COMMIT_SHORT = GIT_COMMIT.substring(0, 7);
const JENKINS_BUILD_ID = process.env.BUILD_ID;
const LINUX_FILES = [`MyCrypto-${VERSION}-i386.AppImage`, `MyCrypto-${VERSION}-x86_64.AppImage`];
const WINDOWS_FILES = [`MyCrypto Setup ${VERSION}.exe`, `MyCrypto Setup ${VERSION}.exe.blockmap`];
const OSX_FILES = [];
const FLAVOR = (() => {
const { platform } = process;
if (platform === 'linux') {
return 'linux-windows';
} else if (platform === 'darwin') {
return 'mac';
} else {
throw new Error('Unsupported platform.');
}
})();
const S3_BUCKET = process.env.S3_BUCKET_NAME;
const ETH_SIGNING_KEY = process.env.ETH_SIGNING_KEY;
module.exports = {
VERSION,
GIT_COMMIT,
GIT_COMMIT_SHORT,
JENKINS_BUILD_ID,
LINUX_FILES,
WINDOWS_FILES,
OSX_FILES,
FLAVOR,
S3_BUCKET,
ETH_SIGNING_KEY
};

112
jenkins/lib.js Normal file
View File

@ -0,0 +1,112 @@
const path = require('path');
const { createHash } = require('crypto');
const { readFileSync } = require('fs');
const { spawn } = require('child_process');
const { hashPersonalMessage, ecsign, toBuffer, addHexPrefix } = require('ethereumjs-util');
const genCommitFilename = (name, version, commit, buildId) => {
const split = name.split(version);
return `${split[0]}${version}-${commit}-${buildId}${split[1]}`;
};
const genFileList = (linux, windows, osx) => {
const { platform } = process;
if (platform === 'linux') {
return [...linux, ...windows];
} else if (platform === 'darwin') {
return [...osx];
} else {
throw new Error('Unrecognized host platform.');
}
};
const genSha512 = filePath => {
const hash = createHash('sha512');
const data = readFileSync(filePath);
hash.update(data);
return hash.digest('hex');
};
const runChildProcess = cmd =>
new Promise((resolve, reject) => {
const child = spawn('sh', ['-c', cmd]);
child.stdout.on('data', data => {
process.stdout.write(data);
});
child.stderr.on('data', data => {
process.stderr.write(data);
});
child.on('close', code => {
if (code !== 0) {
return reject(`Child process exited with code: ${code}`);
}
resolve();
});
});
const uploadToS3 = (localFilePath, s3FilePath) =>
runChildProcess(`aws s3 cp "${localFilePath}" "${s3FilePath}"`);
const genS3Url = (filename, commit, bucket) => `s3://${bucket}/${commit}/${filename}`;
const genManifestFile = manifest =>
manifest.map(info => ({
Filename: info.commitFilename,
SHA512: info.fileHash
}));
const genManifestFilename = (flavor, version, commit, buildId) =>
`manifest.${flavor}.v${version}.${commit}.${buildId}.json`;
const genSignatureFile = (manifestHash, pKeyString) => {
const pKeyBuffer = Buffer.from(pKeyString, 'hex');
return signMessageWithPrivKeyV2(pKeyBuffer, manifestHash);
};
const genSignatureFilename = (flavor, version, commit, buildId) =>
`manifest.${flavor}.v${version}.${commit}.${buildId}.signature`;
const genManifest = (fileList, version, jenkinsBuildId, gitCommit, gitCommitShort, s3Bucket) =>
fileList.map(filename => {
const fullPath = path.resolve('dist/electron-builds/', filename);
const commitFilename = genCommitFilename(filename, version, gitCommitShort, jenkinsBuildId);
return {
fullPath,
filename,
commitFilename,
fileHash: genSha512(fullPath),
s3Url: genS3Url(commitFilename, gitCommit, s3Bucket)
};
});
function signMessageWithPrivKeyV2(privKey, msg) {
const hash = hashPersonalMessage(toBuffer(msg));
const signed = ecsign(hash, privKey);
const combined = Buffer.concat([
Buffer.from(signed.r),
Buffer.from(signed.s),
Buffer.from([signed.v])
]);
const combinedHex = combined.toString('hex');
return addHexPrefix(combinedHex);
}
module.exports = {
genCommitFilename,
genManifestFile,
genFileList,
genSha512,
genS3Url,
uploadToS3,
signMessageWithPrivKeyV2,
genManifestFilename,
genManifest,
genSignatureFile,
genSignatureFilename
};

68
jenkins/upload.js Normal file
View File

@ -0,0 +1,68 @@
const path = require('path');
const { writeFileSync } = require('fs');
const {
VERSION,
FLAVOR,
GIT_COMMIT,
GIT_COMMIT_SHORT,
LINUX_FILES,
WINDOWS_FILES,
OSX_FILES,
S3_BUCKET,
JENKINS_BUILD_ID,
ETH_SIGNING_KEY
} = require('./constants');
const {
genSha512,
genFileList,
genCommitFilename,
genS3Url,
genManifest,
genManifestFile,
genManifestFilename,
genSignatureFile,
genSignatureFilename,
uploadToS3
} = require('./lib');
const fileList = genFileList(WINDOWS_FILES, LINUX_FILES, OSX_FILES);
const manifest = genManifest(
fileList,
VERSION,
JENKINS_BUILD_ID,
GIT_COMMIT,
GIT_COMMIT_SHORT,
S3_BUCKET
);
const manifestFile = genManifestFile(manifest);
const manifestFilename = genManifestFilename(FLAVOR, VERSION, GIT_COMMIT_SHORT, JENKINS_BUILD_ID);
const manifestFilePath = path.resolve(`./${manifestFilename}`);
const manifestS3Url = genS3Url(manifestFilename, GIT_COMMIT, S3_BUCKET);
// write manifest file
writeFileSync(manifestFilename, JSON.stringify(manifestFile, null, 2), 'utf8');
const manifestHash = genSha512(manifestFilePath);
const signatureFile = genSignatureFile(manifestHash, ETH_SIGNING_KEY);
const signatureFilename = genSignatureFilename(FLAVOR, VERSION, GIT_COMMIT_SHORT, JENKINS_BUILD_ID);
const signatureFilePath = path.resolve(`./${signatureFilename}`);
const signatureS3Url = genS3Url(signatureFilename, GIT_COMMIT, S3_BUCKET);
// write signature file
writeFileSync(signatureFilePath, signatureFile, 'utf8');
// upload all the things to S3
(async () => {
for (let fileInfo of manifest) {
const { fullPath, s3Url } = fileInfo;
await uploadToS3(fullPath, s3Url);
}
await uploadToS3(manifestFilePath, manifestS3Url);
await uploadToS3(signatureFilePath, signatureS3Url);
})();

View File

@ -152,6 +152,9 @@
"build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
"build:electron:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
"prebuild:electron": "check-node-version --package",
"jenkins:build:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js",
"jenkins:build:mac": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js",
"jenkins:upload": "node jenkins/upload",
"test:coverage": "jest --config=jest_config/jest.config.json --coverage",
"test": "jest --config=jest_config/jest.config.json",
"test:unit": "jest --config=jest_config/jest.config.json --coverage",

View File

@ -6,7 +6,15 @@ const builder = require('electron-builder');
const config = require('./config');
function shouldBuildOs(os) {
return !process.env.ELECTRON_OS || process.env.ELECTRON_OS === os;
const { ELECTRON_OS } = process.env;
if (ELECTRON_OS === 'JENKINS_LINUX') {
return os === 'linux' || os === 'windows';
} else if (ELECTRON_OS === 'JENKINS_MAC') {
return os === 'mac';
} else {
return !process.env.ELECTRON_OS || process.env.ELECTRON_OS === os;
}
}
async function build() {
@ -36,7 +44,7 @@ async function build() {
productName: 'MyCrypto',
directories: {
app: jsBuildDir,
output: electronBuildsDir,
output: electronBuildsDir
},
mac: {
category: 'public.app-category.finance',
@ -49,14 +57,11 @@ async function build() {
},
linux: {
category: 'Finance',
icon: path.join(config.path.electron, 'icons/icon.png'),
compression
},
publish: {
provider: 'github',
owner: 'MyCryptoHQ',
repo: 'MyCrypto',
vPrefixedTagName: false
},
// IMPORTANT: Prevents from auto publishing to GitHub in CI environments
publish: null,
// IMPORTANT: Prevents extending configs in node_modules
extends: null
}