2022-08-30 21:32:52 +02:00
|
|
|
import * as google from '@googleapis/androidpublisher';
|
|
|
|
import * as fs from "fs";
|
|
|
|
import * as http from 'https';
|
|
|
|
import * as url from 'url';
|
|
|
|
|
|
|
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
|
|
|
|
|
|
const auth = new google.auth.GoogleAuth({
|
|
|
|
keyFile: '.secrets/service-account.json',
|
|
|
|
scopes: ['https://www.googleapis.com/auth/androidpublisher'],
|
|
|
|
})
|
|
|
|
|
|
|
|
const androidPublisher = google.androidpublisher({
|
|
|
|
version: 'v3',
|
|
|
|
auth: auth,
|
|
|
|
})
|
|
|
|
|
|
|
|
const universalApkPath = `${__dirname}/universal.apk`
|
|
|
|
|
|
|
|
export const release = async (github, version, applicationId, artifacts, config) => {
|
|
|
|
const appEditId = await startPlayRelease(applicationId)
|
|
|
|
|
|
|
|
console.log("Uploading bundle...")
|
|
|
|
await uploadBundle(appEditId, applicationId, artifacts.bundle)
|
|
|
|
|
|
|
|
console.log("Uploading mapping...")
|
|
|
|
await uploadMappingFile(appEditId, version.code, applicationId, artifacts.mapping)
|
|
|
|
|
|
|
|
console.log("Assign artifacts to beta release...")
|
|
|
|
await addReleaseToTrack(appEditId, version, applicationId)
|
|
|
|
|
|
|
|
console.log("Commiting draft release...")
|
|
|
|
await androidPublisher.edits.commit({
|
|
|
|
editId: appEditId,
|
|
|
|
packageName: applicationId,
|
|
|
|
}).catch((error) => Promise.reject(error.response.data))
|
|
|
|
|
|
|
|
console.log("Downloading generated universal apk...")
|
|
|
|
await dowloadSignedUniversalApk(
|
|
|
|
version,
|
|
|
|
applicationId,
|
|
|
|
await auth.getAccessToken(),
|
|
|
|
universalApkPath
|
|
|
|
)
|
|
|
|
|
|
|
|
const releaseResult = await github.rest.repos.createRelease({
|
|
|
|
owner: config.owner,
|
|
|
|
repo: config.repo,
|
|
|
|
tag_name: version.name,
|
|
|
|
prerelease: true,
|
|
|
|
generate_release_notes: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
console.log(releaseResult.data.id)
|
|
|
|
|
|
|
|
await github.rest.repos.uploadReleaseAsset({
|
|
|
|
owner: config.owner,
|
|
|
|
repo: config.repo,
|
|
|
|
release_id: releaseResult.data.id,
|
|
|
|
name: `universal-${version.name}.apk`,
|
|
|
|
data: fs.readFileSync(universalApkPath)
|
|
|
|
})
|
|
|
|
|
|
|
|
console.log("Promoting beta draft release to live...")
|
|
|
|
await promoteDraftToLive(applicationId)
|
|
|
|
}
|
|
|
|
|
|
|
|
const startPlayRelease = async (applicationId) => {
|
|
|
|
const result = await androidPublisher.edits.insert({
|
|
|
|
packageName: applicationId
|
|
|
|
}).catch((error) => Promise.reject(error.response.data))
|
|
|
|
return result.data.id
|
|
|
|
}
|
|
|
|
|
|
|
|
const uploadBundle = async (appEditId, applicationId, bundleReleaseFile) => {
|
|
|
|
const res = await androidPublisher.edits.bundles.upload({
|
|
|
|
packageName: applicationId,
|
|
|
|
editId: appEditId,
|
|
|
|
media: {
|
|
|
|
mimeType: 'application/octet-stream',
|
|
|
|
body: fs.createReadStream(bundleReleaseFile)
|
|
|
|
}
|
|
|
|
}).catch((error) => Promise.reject(error.response.data))
|
|
|
|
|
|
|
|
return res.data
|
|
|
|
}
|
|
|
|
|
|
|
|
const uploadMappingFile = async (appEditId, versionCode, applicationId, mappingFilePath) => {
|
|
|
|
await androidPublisher.edits.deobfuscationfiles.upload({
|
|
|
|
packageName: applicationId,
|
|
|
|
editId: appEditId,
|
|
|
|
apkVersionCode: versionCode,
|
|
|
|
deobfuscationFileType: 'proguard',
|
|
|
|
media: {
|
|
|
|
mimeType: 'application/octet-stream',
|
|
|
|
body: fs.createReadStream(mappingFilePath)
|
|
|
|
}
|
|
|
|
}).catch((error) => Promise.reject(error.response.data))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addReleaseToTrack = async (appEditId, version, applicationId) => {
|
|
|
|
const result = await androidPublisher.edits.tracks
|
|
|
|
.update({
|
|
|
|
editId: appEditId,
|
|
|
|
packageName: applicationId,
|
|
|
|
track: "beta",
|
|
|
|
requestBody: {
|
|
|
|
track: "beta",
|
|
|
|
releases: [
|
|
|
|
{
|
|
|
|
name: version.name,
|
|
|
|
status: "draft",
|
|
|
|
releaseNotes: {
|
|
|
|
language: "en-GB",
|
|
|
|
text: "Bug fixes and improvments - See https://github.com/ouchadam/small-talk/releases for more details",
|
|
|
|
},
|
|
|
|
versionCodes: [version.code]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((error) => Promise.reject(error.response.data))
|
|
|
|
return result.data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const dowloadSignedUniversalApk = async (version, applicationId, authToken, outputFile) => {
|
|
|
|
console.log("fetching universal apk")
|
|
|
|
|
|
|
|
const apkRes = await androidPublisher.generatedapks.list({
|
|
|
|
packageName: applicationId,
|
|
|
|
versionCode: version.code,
|
|
|
|
})
|
|
|
|
|
|
|
|
const apks = apkRes.data.generatedApks
|
|
|
|
const id = apks[0].generatedUniversalApk.downloadId
|
|
|
|
|
|
|
|
console.log(`downloading: ${id}`)
|
|
|
|
|
|
|
|
const downloadUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${applicationId}/generatedApks/${version.code}/downloads/${id}:download?alt=media`
|
|
|
|
const options = {
|
|
|
|
headers: {
|
|
|
|
"Authorization": `Bearer ${authToken}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await downloadToFile(downloadUrl, options, outputFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
const downloadToFile = async (url, options, outputFile) => {
|
|
|
|
return new Promise((resolve, error) => {
|
|
|
|
http.get(url, options, (response) => {
|
|
|
|
const file = fs.createWriteStream(outputFile)
|
|
|
|
response.pipe(file)
|
|
|
|
|
|
|
|
file.on("finish", () => {
|
|
|
|
file.close()
|
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
|
|
|
|
file.on("error", (cause) => {
|
|
|
|
error(cause)
|
|
|
|
})
|
|
|
|
}).on("error", (cause) => {
|
|
|
|
error(cause)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-31 22:38:08 +02:00
|
|
|
const promoteDraftToLive = async (applicationId) => {
|
|
|
|
const editId = await startPlayRelease(applicationId)
|
2022-08-30 21:32:52 +02:00
|
|
|
|
|
|
|
await androidPublisher.edits.tracks
|
|
|
|
.update({
|
2022-08-31 22:38:08 +02:00
|
|
|
editId: editId,
|
2022-08-30 21:32:52 +02:00
|
|
|
packageName: applicationId,
|
|
|
|
track: "beta",
|
|
|
|
requestBody: {
|
|
|
|
track: "beta",
|
|
|
|
releases: [
|
|
|
|
{
|
|
|
|
status: "completed",
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((error) => Promise.reject(error.response.data))
|
|
|
|
|
|
|
|
|
|
|
|
await androidPublisher.edits.commit({
|
2022-08-31 22:38:08 +02:00
|
|
|
editId: editId,
|
2022-08-30 21:32:52 +02:00
|
|
|
packageName: applicationId,
|
|
|
|
}).catch((error) => Promise.reject(error.response.data))
|
|
|
|
}
|
|
|
|
|