Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7406d2c7a1 | ||
|
|
623184c55d | ||
|
|
91c8f42cf7 | ||
|
|
e00bb8ce1e |
16
.github/workflows/pr-validation.yml
vendored
16
.github/workflows/pr-validation.yml
vendored
@@ -18,13 +18,25 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Runs a single command using the runners shell
|
||||
# Set up NPM and deps
|
||||
- name: Set up NPM
|
||||
run: npm ci
|
||||
|
||||
# Runs a set of commands using the runners shell
|
||||
# Do a build
|
||||
- name: Run Build
|
||||
run: npm run build
|
||||
|
||||
# Check whether the compiled library changed
|
||||
- name: Check Build Updated
|
||||
uses: tj-actions/verify-changed-files@v9.2
|
||||
id: verify-built-lib
|
||||
with:
|
||||
files: lib/index.js
|
||||
|
||||
# If it did change, the authro forgot to build. Fail the action
|
||||
- name: Verify Build Updated
|
||||
if: steps.verify-changed-files.outputs.files_changed == 'true'
|
||||
run: exit 1
|
||||
|
||||
- name: Run Tests
|
||||
run: npm test
|
||||
|
||||
@@ -16,7 +16,9 @@ This action will help you upload an Android `.apk` or `.aab` (Android App Bundle
|
||||
| status | Release status. This can be set to `draft` to complete the release at some other time. Defaults to `completed` if targeting 100% rollout, else `inProgress` | One of `completed`, `inProgress`, `halted`, `draft` | false |
|
||||
| whatsNewDirectory | The directory of localized "whats new" files to upload as the release notes. The files contained in the `whatsNewDirectory` MUST use the pattern `whatsnew-<LOCALE>` where `LOCALE` is using the [`BCP 47`](https://tools.ietf.org/html/bcp47) format | A path to a valid `whatsNewDirectory` | false |
|
||||
| mappingFile | The mapping.txt file used to de-obfuscate your stack traces from crash reports | A path to a valid `mapping.txt` file | false |
|
||||
| changesNotSentForReview | Indicates that the changes in this edit will not be reviewed until they are explicitly sent for review from the Google Play Console. Defaults to `false` | `true` or `false` | `false` |
|
||||
| serviceAccountJson | The service account json private key file to authorize the upload request. Can be used instead of `serviceAccountJsonPlainText` to specify a file rather than provide a secret | A path to a valid `service-account.json` file | true (or serviceAccountJsonPlainText) |
|
||||
| existingEditId | The ID of an existing edit that has not been completed. If this is supplied, the action will append information to that rather than creating an edit | A valid, unpublished Edit ID | false |
|
||||
| ~~releaseFile~~ | Please switch to using `releaseFiles` as this will be removed in the future | | false |
|
||||
|
||||
## Outputs
|
||||
|
||||
@@ -43,6 +43,13 @@ inputs:
|
||||
mappingFile:
|
||||
description: "The mapping.txt file used to de-obfuscate your stack traces from crash reports"
|
||||
required: false
|
||||
changesNotSentForReview:
|
||||
description: "Indicates that the changes in this edit will not be reviewed until they are explicitly sent for review from the Google Play Console"
|
||||
default: false
|
||||
required: false
|
||||
existingEditId:
|
||||
description: "The ID of an existing edit that has not been completed. If this is supplied, the action will append information to that rather than creating an edit"
|
||||
required: false
|
||||
outputs:
|
||||
internalSharingDownloadUrl:
|
||||
description: "The internal app sharing download url if track was 'internalsharing'"
|
||||
|
||||
File diff suppressed because one or more lines are too long
2367
package-lock.json
generated
2367
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -20,16 +20,16 @@
|
||||
"author": "r0adkll",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.0",
|
||||
"@actions/core": "^1.9.1",
|
||||
"@googleapis/androidpublisher": "^3.0.0",
|
||||
"fast-glob": "^3.2.5"
|
||||
"fast-glob": "^3.2.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"@types/node": "^18.7.16",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"jest": "^28.1.1",
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "^4.7.4"
|
||||
"jest": "^29.0.3",
|
||||
"ts-jest": "^29.0.0",
|
||||
"typescript": "^4.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
66
src/edits.ts
66
src/edits.ts
@@ -1,19 +1,18 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as fs from "fs";
|
||||
import {readFileSync} from "fs";
|
||||
import { readFileSync } from "fs";
|
||||
|
||||
import * as google from '@googleapis/androidpublisher';
|
||||
import {androidpublisher_v3} from "@googleapis/androidpublisher";
|
||||
import { androidpublisher_v3 } from "@googleapis/androidpublisher";
|
||||
|
||||
import AndroidPublisher = androidpublisher_v3.Androidpublisher;
|
||||
import AppEdit = androidpublisher_v3.Schema$AppEdit;
|
||||
import Apk = androidpublisher_v3.Schema$Apk;
|
||||
import Bundle = androidpublisher_v3.Schema$Bundle;
|
||||
import Track = androidpublisher_v3.Schema$Track;
|
||||
import InternalAppSharingArtifact = androidpublisher_v3.Schema$InternalAppSharingArtifact;
|
||||
import {Compute} from "google-auth-library/build/src/auth/computeclient";
|
||||
import {JSONClient} from "google-auth-library/build/src/auth/googleauth"
|
||||
import {readLocalizedReleaseNotes} from "./whatsnew";
|
||||
import { Compute } from "google-auth-library/build/src/auth/computeclient";
|
||||
import { JSONClient } from "google-auth-library/build/src/auth/googleauth"
|
||||
import { readLocalizedReleaseNotes } from "./whatsnew";
|
||||
|
||||
const androidPublisher: AndroidPublisher = google.androidpublisher('v3');
|
||||
|
||||
@@ -27,6 +26,8 @@ export interface EditOptions {
|
||||
mappingFile?: string;
|
||||
name?: string;
|
||||
status?: string;
|
||||
changesNotSentForReview?: boolean;
|
||||
existingEditId?: string;
|
||||
}
|
||||
|
||||
export async function uploadToPlayStore(options: EditOptions, releaseFiles: string[]): Promise<string | undefined> {
|
||||
@@ -50,14 +51,14 @@ export async function uploadToPlayStore(options: EditOptions, releaseFiles: stri
|
||||
} else {
|
||||
// Create a new Edit
|
||||
core.info(`Creating a new Edit for this release`)
|
||||
const appEdit = await androidPublisher.edits.insert({
|
||||
const appEditId = options.existingEditId || (await androidPublisher.edits.insert({
|
||||
auth: options.auth,
|
||||
packageName: options.applicationId
|
||||
});
|
||||
})).data.id
|
||||
|
||||
// Validate the given track
|
||||
core.info(`Validating track '${options.track}'`)
|
||||
await validateSelectedTrack(appEdit.data, options).catch(reason => {
|
||||
await validateSelectedTrack(appEditId!, options).catch(reason => {
|
||||
core.setFailed(reason);
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
@@ -66,7 +67,7 @@ export async function uploadToPlayStore(options: EditOptions, releaseFiles: stri
|
||||
const versionCodes = new Array<number>();
|
||||
for (const releaseFile of releaseFiles) {
|
||||
core.info(`Uploading ${releaseFile}`);
|
||||
const versionCode = await uploadRelease(appEdit.data, options, releaseFile).catch(reason => {
|
||||
const versionCode = await uploadRelease(appEditId!, options, releaseFile).catch(reason => {
|
||||
core.setFailed(reason);
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
@@ -76,15 +77,16 @@ export async function uploadToPlayStore(options: EditOptions, releaseFiles: stri
|
||||
|
||||
// Add the uploaded artifacts to the Edit track
|
||||
core.info(`Adding ${versionCodes.length} artifacts to release on '${options.track}' track`)
|
||||
const track = await addReleasesToTrack(appEdit.data, options, versionCodes);
|
||||
const track = await addReleasesToTrack(appEditId!, options, versionCodes);
|
||||
core.debug(`Track: ${track}`);
|
||||
|
||||
// Commit the pending Edit
|
||||
core.info(`Committing the Edit`)
|
||||
const res = await androidPublisher.edits.commit({
|
||||
auth: options.auth,
|
||||
editId: appEdit.data.id!,
|
||||
packageName: options.applicationId
|
||||
editId: appEditId!,
|
||||
packageName: options.applicationId,
|
||||
changesNotSentForReview: options.changesNotSentForReview
|
||||
});
|
||||
|
||||
// Simple check to see whether commit was successful
|
||||
@@ -116,24 +118,24 @@ async function uploadInternalSharingRelease(options: EditOptions, releaseFile: s
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadRelease(appEdit: AppEdit, options: EditOptions, releaseFile: string): Promise<number | undefined | null> {
|
||||
async function uploadRelease(appEditId: string, options: EditOptions, releaseFile: string): Promise<number | undefined | null> {
|
||||
if (releaseFile.endsWith('.apk')) {
|
||||
const apk = await uploadApk(appEdit, options, releaseFile);
|
||||
await uploadMappingFile(appEdit, apk.versionCode!, options);
|
||||
const apk = await uploadApk(appEditId, options, releaseFile);
|
||||
await uploadMappingFile(appEditId, apk.versionCode!, options);
|
||||
return Promise.resolve(apk.versionCode);
|
||||
} else if (releaseFile.endsWith('.aab')) {
|
||||
const bundle = await uploadBundle(appEdit, options, releaseFile);
|
||||
await uploadMappingFile(appEdit, bundle.versionCode!, options);
|
||||
const bundle = await uploadBundle(appEditId, options, releaseFile);
|
||||
await uploadMappingFile(appEditId, bundle.versionCode!, options);
|
||||
return Promise.resolve(bundle.versionCode);
|
||||
} else {
|
||||
return Promise.reject(`${releaseFile} is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
async function validateSelectedTrack(appEdit: AppEdit, options: EditOptions): Promise<undefined> {
|
||||
async function validateSelectedTrack(appEditId: string, options: EditOptions): Promise<undefined> {
|
||||
const res = await androidPublisher.edits.tracks.list({
|
||||
auth: options.auth,
|
||||
editId: appEdit.id!,
|
||||
editId: appEditId,
|
||||
packageName: options.applicationId
|
||||
});
|
||||
const allTracks = res.data.tracks;
|
||||
@@ -142,7 +144,7 @@ async function validateSelectedTrack(appEdit: AppEdit, options: EditOptions): Pr
|
||||
}
|
||||
}
|
||||
|
||||
async function addReleasesToTrack(appEdit: AppEdit, options: EditOptions, versionCodes: number[]): Promise<Track> {
|
||||
async function addReleasesToTrack(appEditId: string, options: EditOptions, versionCodes: number[]): Promise<Track> {
|
||||
let status: string | undefined = options.status;
|
||||
if (!status) {
|
||||
if (options.userFraction != undefined) {
|
||||
@@ -152,11 +154,11 @@ async function addReleasesToTrack(appEdit: AppEdit, options: EditOptions, versio
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(`Creating Track Release for Edit(${appEdit.id}) for Track(${options.track}) with a UserFraction(${options.userFraction}), Status(${status}), and VersionCodes(${versionCodes})`);
|
||||
core.debug(`Creating Track Release for Edit(${appEditId}) for Track(${options.track}) with a UserFraction(${options.userFraction}), Status(${status}), and VersionCodes(${versionCodes})`);
|
||||
const res = await androidPublisher.edits.tracks
|
||||
.update({
|
||||
auth: options.auth,
|
||||
editId: appEdit.id!,
|
||||
editId: appEditId,
|
||||
packageName: options.applicationId,
|
||||
track: options.track,
|
||||
requestBody: {
|
||||
@@ -177,15 +179,15 @@ async function addReleasesToTrack(appEdit: AppEdit, options: EditOptions, versio
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function uploadMappingFile(appEdit: AppEdit, versionCode: number, options: EditOptions) {
|
||||
async function uploadMappingFile(appEditId: string, versionCode: number, options: EditOptions) {
|
||||
if (options.mappingFile != undefined && options.mappingFile.length > 0) {
|
||||
const mapping = readFileSync(options.mappingFile, 'utf-8');
|
||||
if (mapping != undefined) {
|
||||
core.debug(`[${appEdit.id}, versionCode=${versionCode}, packageName=${options.applicationId}]: Uploading Proguard mapping file @ ${options.mappingFile}`);
|
||||
core.debug(`[${appEditId}, versionCode=${versionCode}, packageName=${options.applicationId}]: Uploading Proguard mapping file @ ${options.mappingFile}`);
|
||||
await androidPublisher.edits.deobfuscationfiles.upload({
|
||||
auth: options.auth,
|
||||
packageName: options.applicationId,
|
||||
editId: appEdit.id!,
|
||||
editId: appEditId,
|
||||
apkVersionCode: versionCode,
|
||||
deobfuscationFileType: 'proguard',
|
||||
media: {
|
||||
@@ -227,13 +229,13 @@ async function internalSharingUploadBundle(options: EditOptions, bundleReleaseFi
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function uploadApk(appEdit: AppEdit, options: EditOptions, apkReleaseFile: string): Promise<Apk> {
|
||||
core.debug(`[${appEdit.id}, packageName=${options.applicationId}]: Uploading APK @ ${apkReleaseFile}`);
|
||||
async function uploadApk(appEditId: string, options: EditOptions, apkReleaseFile: string): Promise<Apk> {
|
||||
core.debug(`[${appEditId}, packageName=${options.applicationId}]: Uploading APK @ ${apkReleaseFile}`);
|
||||
|
||||
const res = await androidPublisher.edits.apks.upload({
|
||||
auth: options.auth,
|
||||
packageName: options.applicationId,
|
||||
editId: appEdit.id!,
|
||||
editId: appEditId,
|
||||
media: {
|
||||
mimeType: 'application/vnd.android.package-archive',
|
||||
body: fs.createReadStream(apkReleaseFile)
|
||||
@@ -243,12 +245,12 @@ async function uploadApk(appEdit: AppEdit, options: EditOptions, apkReleaseFile:
|
||||
return res.data
|
||||
}
|
||||
|
||||
async function uploadBundle(appEdit: AppEdit, options: EditOptions, bundleReleaseFile: string): Promise<Bundle> {
|
||||
core.debug(`[${appEdit.id}, packageName=${options.applicationId}]: Uploading App Bundle @ ${bundleReleaseFile}`);
|
||||
async function uploadBundle(appEditId: string, options: EditOptions, bundleReleaseFile: string): Promise<Bundle> {
|
||||
core.debug(`[${appEditId}, packageName=${options.applicationId}]: Uploading App Bundle @ ${bundleReleaseFile}`);
|
||||
const res = await androidPublisher.edits.bundles.upload({
|
||||
auth: options.auth,
|
||||
packageName: options.applicationId,
|
||||
editId: appEdit.id!,
|
||||
editId: appEditId,
|
||||
media: {
|
||||
mimeType: 'application/octet-stream',
|
||||
body: fs.createReadStream(bundleReleaseFile)
|
||||
|
||||
@@ -24,6 +24,8 @@ async function run() {
|
||||
const status = core.getInput('status', { required: false });
|
||||
const whatsNewDir = core.getInput('whatsNewDirectory', { required: false });
|
||||
const mappingFile = core.getInput('mappingFile', { required: false });
|
||||
const changesNotSentForReview = core.getInput('changesNotSentForReview', { required: false }) == 'true';
|
||||
const existingEditId = core.getInput('existingEditId')
|
||||
|
||||
// Validate that we have a service account json in some format
|
||||
if (!serviceAccountJson && !serviceAccountJsonRaw) {
|
||||
@@ -116,7 +118,9 @@ async function run() {
|
||||
status: status,
|
||||
whatsNewDir: whatsNewDir,
|
||||
mappingFile: mappingFile,
|
||||
name: releaseName
|
||||
name: releaseName,
|
||||
changesNotSentForReview: changesNotSentForReview,
|
||||
existingEditId: existingEditId
|
||||
}, validatedReleaseFiles);
|
||||
|
||||
console.log(`Finished uploading to the Play Store: ${result}`)
|
||||
|
||||
Reference in New Issue
Block a user