diff --git a/lib/io-utils.js b/lib/io-utils.js new file mode 100644 index 00000000..966975fb --- /dev/null +++ b/lib/io-utils.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const path = require('path'); +const fs = require('fs'); +function findReleaseFile(releaseDir) { + const releaseFiles = fs.readdirSync(releaseDir, { withFileTypes: true }) + .filter(item => !item.isDirectory()) + .filter(item => item.name.endsWith(".apk") || item.name.endsWith(".aab")); + if (releaseFiles.length > 0) { + return releaseFiles[0]; + } +} +exports.findReleaseFile = findReleaseFile; diff --git a/lib/main.js b/lib/main.js index 9598b7ef..536969f4 100644 --- a/lib/main.js +++ b/lib/main.js @@ -16,16 +16,47 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); const core = __importStar(require("@actions/core")); -const wait_1 = require("./wait"); +const signing_1 = require("./signing"); +const path = require('path'); +const fs = require('fs'); +const io = require('io-utils'); +const sign = require('signing'); function run() { return __awaiter(this, void 0, void 0, function* () { try { - const ms = core.getInput('milliseconds'); - console.log(`Waiting ${ms} milliseconds ...`); - core.debug((new Date()).toTimeString()); - wait_1.wait(parseInt(ms)); - core.debug((new Date()).toTimeString()); - core.setOutput('time', new Date().toTimeString()); + const releaseDir = core.getInput('releaseDirectory'); + const signingKeyBase64 = core.getInput('signingKeyBase64'); + const alias = core.getInput('alias'); + const keyStorePassword = core.getInput('keyStorePassword'); + const keyPassword = core.getInput('keyPassword'); + console.log(`Preparing to sign key @ ${releaseDir} with signing key`); + // 1. Find release file + const releaseFile = io.findReleaseFile(releaseDir); + if (releaseFile !== undefined) { + core.debug(`Found release to sign: ${releaseFile.name}`); + // 2. Now that we have a release file, decode and save the signing key + const signingKey = path.join(releaseDir, 'signingKey.jks'); + fs.writeFileSync(signingKey, signingKeyBase64, 'base64'); + // 3. Now zipalign the release file + const releaseFilePath = path.join(releaseDir, releaseFile.name); + let signedReleaseFile = ''; + if (releaseFile.name.endsWith('.apk')) { + signedReleaseFile = yield signing_1.signApkFile(releaseFilePath, signingKey, alias, keyStorePassword, keyPassword); + } + else if (releaseFile.name.endsWith('.aab')) { + signedReleaseFile = yield signing_1.signAabFile(releaseFilePath, signingKey, alias, keyStorePassword, keyPassword); + } + else { + core.error('No valid release file to sign, abort.'); + core.setFailed('No valid release file to sign.'); + } + core.exportVariable("SIGNED_RELEASE_FILE", signedReleaseFile); + core.setOutput('signedReleaseFile', signedReleaseFile); + } + else { + core.error("No release file (.apk or .aab) could be found. Abort."); + core.setFailed('No release file (.apk or .aab) could be found.'); + } } catch (error) { core.setFailed(error.message); diff --git a/lib/signing.js b/lib/signing.js new file mode 100644 index 00000000..984cdc21 --- /dev/null +++ b/lib/signing.js @@ -0,0 +1,56 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const exec = __importStar(require("@actions/exec")); +const core = __importStar(require("@actions/core")); +function signApkFile(apkFile, signingKeyFile, alias, keyStorePassword, keyPassword) { + return __awaiter(this, void 0, void 0, function* () { + core.debug("Zipaligning APK file"); + // Align the apk file + const alignedApkFile = apkFile.replace('.apk', '-aligned.apk'); + yield exec.exec('zipalign', [ + '-v', '-p 4', + apkFile, + alignedApkFile + ]); + core.debug("Signing APK file"); + // apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk + const signedApkFile = apkFile.replace('.apk', '-signed.apk'); + yield exec.exec('apksigner', [ + 'sign', + '--ks', signingKeyFile, + '--out', signedApkFile, + alignedApkFile + ]); + return signedApkFile; + }); +} +exports.signApkFile = signApkFile; +function signAabFile(aabFile, signingKeyFile, alias, keyStorePassword, keyPassword) { + return __awaiter(this, void 0, void 0, function* () { + core.debug("Signing AAB file"); + yield exec.exec(`jarsigner`, [ + '-keystore', signingKeyFile, + '-storepass', keyStorePassword, + '-keypass', keyPassword, + aabFile, + alias + ]); + return aabFile; + }); +} +exports.signAabFile = signAabFile; diff --git a/lib/wait.js b/lib/wait.js index 727df441..3dbdf73a 100644 --- a/lib/wait.js +++ b/lib/wait.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function wait(milliseconds) { - return new Promise((resolve, reject) => { - if (typeof (milliseconds) !== 'number') { + return new Promise((resolve) => { + if (isNaN(milliseconds)) { throw new Error('milleseconds not a number'); } setTimeout(() => resolve("done!"), milliseconds);